@napuketto/adapter 0.7.2 → 0.8.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["NOTIFY_SEARCH_COUNT","toUin","MS_TO_SEC","groupIdField","optStr","MS_TO_SEC","emptySchema"],"sources":["../../src/milky/api.ts","../../src/milky/helper/entities.ts","../../src/milky/helper/request.ts","../../src/milky/action/error-map.ts","../../src/milky/action/base-action.ts","../../src/milky/action/group.ts","../../src/milky/action/group-file.ts","../../src/milky/helper/media-uri.ts","../../src/milky/helper/segments.ts","../../src/milky/helper/translate.ts","../../src/milky/action/message.ts","../../src/milky/action/profile.ts","../../src/milky/action/social.ts","../../src/milky/action/system.ts","../../src/milky/action/index.ts","../../src/milky/helper/notice.ts","../../src/milky/helper/seq-index.ts","../../src/milky/transport.ts","../../src/milky/adapter.ts","../../src/milky/config.ts"],"sourcesContent":["/**\n * MilkyApi:Milky 动作统一依赖聚合(对齐 OneBotApi 模式,P2-16)\n *\n * 持有 P1 动作面所需 kernel apis + 协议层共享状态(seq 双向映射 / 转发索引 /\n * 版本 / 发送媒体缓存目录);动作经 Pick 视图取依赖,装配方只构造一次本对象。\n */\nimport type {\n BuddyReq,\n FriendApi,\n GroupApi,\n GroupCache,\n GroupNotify,\n GroupNotifyApi,\n MsgApi,\n Peer,\n ProfileApi,\n ProfileLikeApi,\n RawMessage,\n RichMediaApi,\n TicketApi,\n WebApi,\n} from \"@napuketto/kernel\";\nimport { ChatType, kernelError } from \"@napuketto/kernel\";\nimport type { MessageSeqIndex } from \"./helper/seq-index.js\";\nimport type { MilkyLoggerLike } from \"./transport.js\";\n\n/** MilkyApi 构造参数。 */\nexport interface MilkyApiOptions {\n msgApi: MsgApi;\n groupApi: GroupApi;\n friendApi: FriendApi;\n profileApi: ProfileApi;\n /** P1 扩面依赖(表态度 / 票据 / 精华列表 / 群通知 / 群文件)。 */\n profileLikeApi: ProfileLikeApi;\n ticketApi: TicketApi;\n webApi: WebApi;\n groupNotifyApi: GroupNotifyApi;\n richMediaApi: RichMediaApi;\n /** 登录身份(get_login_info / self_id / target_user_uid 用)。 */\n self: { uin: string; nickname: string; uid?: string };\n /** 群/成员缓存(群实体回填 / get_group_list;未装配时动作直查 api)。 */\n groupCache?: GroupCache;\n /** QQ 客户端版本(get_impl_info.qq_protocol_version)。 */\n qqVersion: string;\n /** 协议端版本(get_impl_info.impl_version)。 */\n implVersion: string;\n /** 发送媒体 http(s)/base64 URI 下载缓存目录(缺省 = 远程媒体发送不可用)。 */\n mediaDir?: string;\n /** 动作层可观测出口(P2 批次一:forward 临时消息撤回失败 warn;缺省静默)。 */\n logger?: MilkyLoggerLike;\n}\n\nexport class MilkyApi {\n readonly msgApi: MsgApi;\n readonly groupApi: GroupApi;\n readonly friendApi: FriendApi;\n readonly profileApi: ProfileApi;\n readonly profileLikeApi: ProfileLikeApi;\n readonly ticketApi: TicketApi;\n readonly webApi: WebApi;\n readonly groupNotifyApi: GroupNotifyApi;\n readonly richMediaApi: RichMediaApi;\n readonly self: { uin: string; nickname: string; uid?: string };\n readonly groupCache: GroupCache | undefined;\n readonly qqVersion: string;\n readonly implVersion: string;\n readonly mediaDir: string | undefined;\n /** 动作层可观测出口(缺省静默)。 */\n readonly logger: MilkyLoggerLike | undefined;\n /** message_seq ↔ msgId 双向映射(接收链路 record,动作侧反查)。 */\n readonly seqIndex: MessageSeqIndex;\n\n constructor(opts: MilkyApiOptions, seqIndex: MessageSeqIndex) {\n this.msgApi = opts.msgApi;\n this.groupApi = opts.groupApi;\n this.friendApi = opts.friendApi;\n this.profileApi = opts.profileApi;\n this.profileLikeApi = opts.profileLikeApi;\n this.ticketApi = opts.ticketApi;\n this.webApi = opts.webApi;\n this.groupNotifyApi = opts.groupNotifyApi;\n this.richMediaApi = opts.richMediaApi;\n this.self = opts.self;\n this.groupCache = opts.groupCache;\n this.qqVersion = opts.qqVersion;\n this.implVersion = opts.implVersion;\n this.mediaDir = opts.mediaDir;\n this.logger = opts.logger;\n this.seqIndex = seqIndex;\n }\n\n /** uin → uid(私聊目标 / at 段发送转换 / 群管动作的 uid 入参)。 */\n uinToUid(uins: string[]): Promise<Map<string, string>> {\n return this.groupApi.uinToUid(uins);\n }\n\n /** uid → uin(事件路径 mention 转换)。 */\n uidToUin(uids: string[]): Promise<Map<string, string>> {\n return this.groupApi.uidToUin(uids);\n }\n\n /**\n * uin(数字)→ uid(群管动作入参转换);转换失败抛 INVALID_PARAM\n * (Milky 入参 user_id 都是 uin,kernel 群管 API 要 uid)。\n */\n async resolveUidFromUin(uin: number | string): Promise<string> {\n const uinStr = String(uin);\n try {\n const uid = (await this.uinToUid([uinStr])).get(uinStr);\n if (uid !== undefined && uid !== \"\") {\n return uid;\n }\n } catch {\n // 落到下方报错\n }\n throw kernelError(`用户 ${uinStr} 不存在或 uin→uid 转换失败`, \"INVALID_PARAM\");\n }\n\n /**\n * message_scene + 数字 ID → NT Peer。\n * group = 群号直作 peerUid;friend/temp = uin → uid(失败退 uin 原样,交 QQ 端判断)。\n */\n async resolvePeer(scene: \"friend\" | \"group\" | \"temp\", id: number): Promise<Peer> {\n if (scene === \"group\") {\n return { chatType: ChatType.GROUP, peerUid: String(id) } satisfies Peer;\n }\n const uin = String(id);\n let uid: string | undefined;\n try {\n uid = (await this.uinToUid([uin])).get(uin);\n } catch {\n // 转换失败:退 uin 原样\n }\n return {\n chatType: scene === \"friend\" ? ChatType.C2C : ChatType.C2C_TEMP,\n peerUid: uid ?? uin,\n } satisfies Peer;\n }\n\n /**\n * seq → msgId(索引优先,未登记扫描近段历史兜底)。\n * 两层都未命中返回 undefined(调用方抛 NOT_FOUND)。\n */\n async resolveMsgIdBySeq(\n peer: Peer,\n seq: number,\n chatType: Peer[\"chatType\"],\n ): Promise<string | undefined> {\n const indexed = this.seqIndex.resolveMsgId(chatType, peer.peerUid, seq);\n if (indexed !== undefined) {\n return indexed;\n }\n const msgs = await this.msgApi.fetchMessages(peer, { count: 60 }).catch(() => []);\n const hit = msgs.find((m: RawMessage) => Number(m.msgSeq) === seq);\n if (hit === undefined) {\n return undefined;\n }\n this.seqIndex.record(hit);\n return hit.msgId;\n }\n\n /** 发送结果回查:msgId → {message_seq, time}(sendMessage 只回 msgId)。 */\n async resolveSentOutput(\n peer: Peer,\n msgId: string,\n ): Promise<{ message_seq: number; time: number }> {\n const [sent] = await this.msgApi.fetchMsgsByMsgId(peer, [msgId]);\n if (sent === undefined) {\n throw kernelError(\"发送结果回查失败(msgId 未命中)\", \"UNKNOWN\");\n }\n this.seqIndex.record(sent);\n return {\n message_seq: Number(sent.msgSeq),\n time: Math.floor(Number(sent.msgTime) / 1000),\n };\n }\n}\n\n/** 通知查找默认搜索数量(单屏全量,OB11 DEFAULT_COUNT 同值)。 */\nconst NOTIFY_SEARCH_COUNT = 100;\n\n/**\n * 按通知 seq 查找群通知(先非可疑后可疑,OB11 set_group_add_request 同路径)。\n * 未找到抛 NOT_FOUND(应答动作的 seq 无效或已过期)。\n * 模块级函数(非类成员):应答动作的公共入口,OB11 同路径。\n */\nexport async function findGroupNotify(api: MilkyApi, seq: string): Promise<GroupNotify> {\n const normal = await api.groupNotifyApi.getSingleScreenNotifies(false, NOTIFY_SEARCH_COUNT);\n const hit = normal.find((item) => item.seq === seq);\n if (hit !== undefined) {\n return hit;\n }\n const doubt = await api.groupNotifyApi.getSingleScreenNotifies(true, NOTIFY_SEARCH_COUNT);\n const doubtHit = doubt.find((item) => item.seq === seq);\n if (doubtHit !== undefined) {\n return doubtHit;\n }\n throw kernelError(`未找到通知 ${seq}(无效或已过期)`, \"NOT_FOUND\");\n}\n\n/** 按发起者 uid 查找好友申请(getBuddyReqList 匹配 friendUid);未找到抛 NOT_FOUND。 */\nexport async function findBuddyReq(api: MilkyApi, initiatorUid: string): Promise<BuddyReq> {\n const reqs = await api.friendApi.getBuddyReqList();\n const hit = reqs.find((req) => req.friendUid === initiatorUid);\n if (hit === undefined) {\n throw kernelError(`未找到来自 ${initiatorUid} 的好友申请`, \"NOT_FOUND\");\n }\n return hit;\n}\n","/**\n * kernel 实体 → Milky 实体翻译(纯函数,ADR-008)\n *\n * Milky 事件/查询输出要求完整实体(GroupEntity/GroupMemberEntity/FriendEntity\n * 的全部字段 required);kernel 实体字段是超集的子集,缺失字段按最小合法值兜底\n * (0 / 空串 / unknown),实触样本到位后逐步补真实值。\n */\n\nimport type { Friend } from \"@napuketto/kernel\";\nimport { GroupApi, type GroupDetailInfo, type GroupMember } from \"@napuketto/kernel\";\nimport type { FriendEntity, GroupEntity, GroupMemberEntity } from \"../types.js\";\n\n/** GroupDetailInfo / Group → GroupEntity(detail 缺失时全兜底)。 */\nexport function toGroupEntity(detail: GroupDetailInfo | undefined, groupCode: string): GroupEntity {\n return {\n group_id: Number(groupCode),\n group_name: detail?.groupName ?? \"\",\n member_count: detail?.memberNum ?? 0,\n max_member_count: detail?.maxMemberNum ?? 0,\n remark: detail?.remarkName ?? \"\",\n created_time: detail?.groupCreateTime ?? 0,\n description: \"\",\n question: \"\",\n announcement: \"\",\n };\n}\n\n/** 群列表项(GroupCache Group)→ GroupEntity。 */\nexport function groupListToEntity(group: {\n groupCode: string;\n groupName: string;\n memberCount: number;\n maxMember: number;\n}): GroupEntity {\n return {\n group_id: Number(group.groupCode),\n group_name: group.groupName,\n member_count: group.memberCount,\n max_member_count: group.maxMember,\n remark: \"\",\n created_time: 0,\n description: \"\",\n question: \"\",\n announcement: \"\",\n };\n}\n\n/** GroupMember → GroupMemberEntity(member 缺失时按 uin 兜底最小实体)。 */\nexport function toGroupMemberEntity(\n member: GroupMember | undefined,\n groupCode: string,\n uin: string,\n): GroupMemberEntity {\n const shutUpSeconds = member?.shutUpTime ?? 0;\n return {\n user_id: Number(member?.uin !== undefined && member.uin !== \"\" ? member.uin : uin),\n nickname: member?.nick ?? \"\",\n sex: \"unknown\",\n group_id: Number(groupCode),\n card: member?.cardName ?? \"\",\n title: member?.memberSpecialTitle ?? \"\",\n level: 0,\n role: GroupApi.roleToString(member?.role ?? 2),\n join_time: Number(member?.joinTime) || 0,\n last_sent_time: Number(member?.lastSpeakTime) || 0,\n shut_up_end_time: shutUpSeconds > 0 ? Math.floor(Date.now() / 1000) + shutUpSeconds : null,\n };\n}\n\n/** Friend → FriendEntity(kernel 无 qid/分类挂载,按最小实体兜底)。 */\nexport function toFriendEntity(\n friend: Friend | undefined,\n uin: string,\n nick: string,\n): FriendEntity {\n return {\n user_id: Number(friend?.uin !== undefined && friend.uin !== \"\" ? friend.uin : uin),\n nickname: friend?.nickname ?? nick,\n sex: \"unknown\",\n qid: \"\",\n remark: friend?.remark ?? \"\",\n category: { category_id: 0, category_name: \"\" },\n };\n}\n","/**\n * Milky request 事件翻译(通道系,P1 2026-10-30)\n *\n * 事件源(kernel 事件通道,与 OB11 helper/request.ts 同源):\n * - Buddy/onBuddyReqChange → friend_request\n * - Group/onGroupNotifiesUpdated → group_join_request / group_invited_join_request /\n * group_invitation(type 1=邀请自身 / 5=成员邀请他人 / 7=入群申请,仅未处理状态)\n *\n * 纯函数(ADR-008):uid→uin 由调用方批量转换后传入。\n * onBuddyReqChange 回调参数形状未经真实事件校准——narrowBuddyReqs 防御性收窄\n * (core/buddy-req.ts,OB11 同源),未知形状返回 null 由调用方打 raw 日志。\n */\nimport type { BuddyReq, GroupNotify } from \"@napuketto/kernel\";\nimport { GroupNotifyMsgStatus, GroupNotifyMsgType } from \"@napuketto/kernel\";\nimport { MS_TO_SEC, type RequestTranslateContext, resolveUin } from \"../../core/uid-uin.js\";\nimport type {\n FriendRequestData,\n GroupInvitationData,\n GroupInvitedJoinRequestData,\n GroupJoinRequestData,\n MilkyEvent,\n} from \"../types.js\";\n\n/** uid → uin(core 共享解析;ctx 携带映射)。 */\nfunction toUin(uid: string | undefined, ctx: RequestTranslateContext): number {\n return resolveUin(uid, ctx.uidToUin);\n}\n\n/** BuddyReq → friend_request 事件(comment 取 words 字段,形状待校准,缺省空串)。 */\nexport function toFriendRequestEvent(\n req: BuddyReq,\n ctx: RequestTranslateContext,\n): MilkyEvent<FriendRequestData> {\n const words = req[\"words\"];\n return {\n time: Math.floor(Date.now() / MS_TO_SEC),\n self_id: Number(ctx.selfUin),\n event_type: \"friend_request\",\n data: {\n initiator_id: toUin(req.friendUid, ctx),\n initiator_uid: req.friendUid,\n comment: typeof words === \"string\" ? words : \"\",\n via: req.sourceName ?? \"\",\n },\n };\n}\n\n/** GroupNotify → Milky 群请求事件(非未处理状态 / 非请求类返回 null)。 */\nexport function toGroupRequestEvent(\n notify: GroupNotify,\n doubt: boolean,\n ctx: RequestTranslateContext,\n): MilkyEvent | null {\n if (notify.status !== GroupNotifyMsgStatus.KUNHANDLE) {\n return null;\n }\n const groupId = Number(notify.group?.groupCode ?? 0);\n const seq = Number(notify.seq);\n const time = Math.floor(Date.now() / MS_TO_SEC);\n const selfId = Number(ctx.selfUin);\n switch (notify.type) {\n case GroupNotifyMsgType.REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS: {\n const data: GroupJoinRequestData = {\n group_id: groupId,\n notification_seq: seq,\n is_filtered: doubt,\n initiator_id: toUin(notify.user1?.uid, ctx),\n comment: notify.postscript ?? \"\",\n };\n return { time, self_id: selfId, event_type: \"group_join_request\", data };\n }\n case GroupNotifyMsgType.INVITED_NEED_ADMINI_STRATOR_PASS: {\n // user1=邀请者 / user2=被邀请者(与 OB11 get_group_system_msg 口径一致)\n const data: GroupInvitedJoinRequestData = {\n group_id: groupId,\n notification_seq: seq,\n initiator_id: toUin(notify.user1?.uid, ctx),\n target_user_id: toUin(notify.user2?.uid, ctx),\n };\n return { time, self_id: selfId, event_type: \"group_invited_join_request\", data };\n }\n case GroupNotifyMsgType.INVITED_BY_MEMBER: {\n const data: GroupInvitationData = {\n group_id: groupId,\n invitation_seq: seq,\n initiator_id: toUin(notify.user1?.uid, ctx),\n source_group_id: null,\n };\n return { time, self_id: selfId, event_type: \"group_invitation\", data };\n }\n default:\n return null;\n }\n}\n\n/**\n * 群通知涉及的 uid 集合(去重;get_group_notifications 与事件广播共用)。\n * kernel GroupEventChannel 的 onGroupNotifiesUpdated 回调参数已类型化\n * (GroupNotify[]),无需防御收窄。\n */\nexport function collectNotifyUids(notifies: GroupNotify[]): string[] {\n const uids = new Set<string>();\n for (const n of notifies) {\n for (const uid of [n.user1?.uid, n.user2?.uid]) {\n if (uid !== undefined && uid !== \"\") {\n uids.add(uid);\n }\n }\n }\n return [...uids];\n}\n","/**\n * Milky 错误码映射(ADR-017:KernelErrorCode → 协议错误码,各协议自持)\n *\n * 规范语义:-400 = 参数解析失败、-403 = 未登录;其余业务错误为自定负数\n * (规范允许),取常见 HTTP 语义近似值便于应用端排查。\n */\nimport type { KernelErrorCode } from \"@napuketto/kernel\";\n\n/** KernelErrorCode → Milky retcode 映射表(-400/-403 规范语义,其余自定负数)。 */\nexport type MilkyErrorCodeMap = Record<KernelErrorCode, number>;\n\nexport const milkyErrorCodeMap: MilkyErrorCodeMap = {\n SEND_FAILED: -500,\n PERMISSION_DENIED: -405,\n NOT_FOUND: -404,\n TIMEOUT: -504,\n NOT_LOGIN: -403,\n INVALID_PARAM: -400,\n INVALID_STATE: -409,\n UNKNOWN: -500,\n};\n","/**\n * MilkyAction:Milky 动作基类(zod 校验 + KernelError → 负数 retcode)\n *\n * 与 OB11 BaseAction 分离的原因:Milky 响应信封无 echo、参数解析失败恒\n * retcode=-400(规范),不复用 OB11 的 400/1400 语义。\n * 响应信封由 transport 组装(status/retcode/data/message)。\n */\nimport { isKernelError } from \"@napuketto/kernel\";\nimport type { ZodType } from \"zod\";\nimport type { MilkyApi } from \"../api.js\";\nimport { type MilkyErrorCodeMap, milkyErrorCodeMap } from \"./error-map.js\";\n\n/** Milky 动作结果(retcode 为规范负数族;transport 原样组装信封)。 */\nexport interface MilkyActionResult<T> {\n status: \"ok\" | \"failed\";\n retcode: number;\n data: T | null;\n message: string;\n}\n\n/** zod 错误摘要(单行,issues 取前 3 条)。 */\nfunction zodSummary(error: { issues: Array<{ path: PropertyKey[]; message: string }> }): string {\n const parts: string[] = [];\n for (const issue of error.issues.slice(0, 3)) {\n parts.push(`${issue.path.map(String).join(\".\")}: ${issue.message}`);\n }\n return parts.join(\"; \");\n}\n\nexport abstract class MilkyAction<TPayload, TReturn> {\n abstract readonly name: string;\n abstract readonly schema: ZodType<TPayload>;\n protected abstract readonly errorCodeMap: MilkyErrorCodeMap;\n\n protected abstract _handle(payload: TPayload): Promise<TReturn>;\n\n /** 校验并执行(HTTP /api 入口;WS /event 不承载动作)。 */\n async handle(payload: unknown): Promise<MilkyActionResult<TReturn>> {\n const parsed = this.schema.safeParse(payload);\n if (!parsed.success) {\n return {\n status: \"failed\",\n retcode: -400,\n data: null,\n message: `参数解析失败: ${zodSummary(parsed.error)}`,\n };\n }\n try {\n return { status: \"ok\", retcode: 0, data: await this._handle(parsed.data), message: \"\" };\n } catch (err) {\n if (isKernelError(err)) {\n const retcode = this.errorCodeMap[err.code] ?? this.errorCodeMap.UNKNOWN;\n return { status: \"failed\", retcode, data: null, message: err.message };\n }\n return {\n status: \"failed\",\n retcode: this.errorCodeMap.UNKNOWN,\n data: null,\n message: err instanceof Error ? err.message : \"未知错误\",\n };\n }\n }\n}\n\n/**\n * 持 MilkyApi 的动作基类:api 注入 + 统一错误映射表(milkyErrorCodeMap)收拢,\n * 动作子类只写 name / schema / _handle。\n */\nexport abstract class MilkyApiAction<TPayload, TReturn> extends MilkyAction<TPayload, TReturn> {\n protected readonly errorCodeMap: MilkyErrorCodeMap = milkyErrorCodeMap;\n protected readonly api: MilkyApi;\n\n constructor(api: MilkyApi) {\n super();\n this.api = api;\n }\n}\n","/**\n * Milky 群类动作(P1):群信息 / 群管 / 精华 / 表态 / 通知\n *\n * - 群管(set_group_member_card / set_group_member_admin / set_group_member_mute /\n * kick_group_member):user_id(uin) → uid 转换后进 kernel(resolveUidFromUin)。\n * - 精华:seq → msgId 经 seqIndex 反查;列表经 WebApi.getEssenceMsgList(客户端分页)。\n * - 通知实体/应答:seq → getSingleScreenNotifies 匹配(先非可疑后可疑)→\n * handleGroupRequest;通知类型 7=入群申请 / 5=成员邀请他人 / 8,12,13=管理员变更 /\n * 9,10=踢出 / 11=退群(1=邀请自身无实体变体,不产出)。\n */\nimport type { EssenceMsgItem, GroupMember, GroupNotify, Peer } from \"@napuketto/kernel\";\nimport { ChatType, kernelError, NTGroupRequestOperateTypes } from \"@napuketto/kernel\";\nimport { z } from \"zod\";\nimport { findGroupNotify, type MilkyApi } from \"../api.js\";\nimport { toGroupEntity, toGroupMemberEntity } from \"../helper/entities.js\";\nimport { collectNotifyUids } from \"../helper/request.js\";\nimport type {\n GetGroupEssenceMessagesOutput,\n GetGroupInfoOutput,\n GetGroupMemberInfoOutput,\n GetGroupMemberListOutput,\n GetGroupNotificationsOutput,\n GroupEssenceMessage,\n GroupNotificationEntity,\n IncomingSegment,\n} from \"../types.js\";\nimport { MilkyApiAction } from \"./base-action.js\";\n\nconst groupIdField = { group_id: z.number().int().min(10001) } as const;\nconst userIdField = { user_id: z.number().int().min(10001) } as const;\nconst optBool = z.boolean().nullable().optional();\nconst optStr = z.string().nullable().optional();\n\n/** get_group_info:获取群信息(GroupCache 详情缓存优先)。 */\nexport class GetGroupInfoAction extends MilkyApiAction<\n { group_id: number; no_cache?: boolean | null | undefined },\n GetGroupInfoOutput\n> {\n readonly name = \"get_group_info\";\n readonly schema = z.object({ ...groupIdField, no_cache: optBool });\n\n protected async _handle(payload: {\n group_id: number;\n no_cache?: boolean | null | undefined;\n }): Promise<GetGroupInfoOutput> {\n const groupCode = String(payload.group_id);\n const detail =\n this.api.groupCache !== undefined\n ? await this.api.groupCache.getGroupDetail(groupCode)\n : await this.api.groupApi.getGroupInfo(groupCode);\n return { group: toGroupEntity(detail, groupCode) };\n }\n}\n\n/** get_group_member_list:获取群成员列表(GroupCache 惰性回填)。 */\nexport class GetGroupMemberListAction extends MilkyApiAction<\n { group_id: number; no_cache?: boolean | null | undefined },\n GetGroupMemberListOutput\n> {\n readonly name = \"get_group_member_list\";\n readonly schema = z.object({ ...groupIdField, no_cache: optBool });\n\n protected async _handle(payload: {\n group_id: number;\n no_cache?: boolean | null | undefined;\n }): Promise<GetGroupMemberListOutput> {\n const members = await membersOf(this.api, String(payload.group_id));\n return {\n members: members.map((m) => toGroupMemberEntity(m, String(payload.group_id), m.uin)),\n };\n }\n}\n\n/** get_group_member_info:获取群成员信息(user_id = uin → 成员单查)。 */\nexport class GetGroupMemberInfoAction extends MilkyApiAction<\n { group_id: number; user_id: number; no_cache?: boolean | null | undefined },\n GetGroupMemberInfoOutput\n> {\n readonly name = \"get_group_member_info\";\n readonly schema = z.object({ ...groupIdField, ...userIdField, no_cache: optBool });\n\n protected async _handle(payload: {\n group_id: number;\n user_id: number;\n no_cache?: boolean | null | undefined;\n }): Promise<GetGroupMemberInfoOutput> {\n const member = await memberOf(this.api, payload.group_id, payload.user_id);\n return {\n member: toGroupMemberEntity(member, String(payload.group_id), String(payload.user_id)),\n };\n }\n}\n\n/** set_group_name:设置群名。 */\nexport class SetGroupNameAction extends MilkyApiAction<\n { group_id: number; new_group_name: string },\n Record<string, never>\n> {\n readonly name = \"set_group_name\";\n readonly schema = z.object({ ...groupIdField, new_group_name: z.string() });\n\n protected async _handle(payload: {\n group_id: number;\n new_group_name: string;\n }): Promise<Record<string, never>> {\n await this.api.groupApi.modifyGroupName(String(payload.group_id), payload.new_group_name);\n return {};\n }\n}\n\n/** set_group_member_card:设置群名片。 */\nexport class SetGroupMemberCardAction extends MilkyApiAction<\n { group_id: number; user_id: number; card: string },\n Record<string, never>\n> {\n readonly name = \"set_group_member_card\";\n readonly schema = z.object({ ...groupIdField, ...userIdField, card: z.string() });\n\n protected async _handle(payload: {\n group_id: number;\n user_id: number;\n card: string;\n }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n this.api.groupApi.setMemberCardName(String(payload.group_id), uid, payload.card);\n return {};\n }\n}\n\n/** set_group_member_admin:设置/取消管理员(is_set 缺省 true)。 */\nexport class SetGroupMemberAdminAction extends MilkyApiAction<\n { group_id: number; user_id: number; is_set?: boolean | null | undefined },\n Record<string, never>\n> {\n readonly name = \"set_group_member_admin\";\n readonly schema = z.object({ ...groupIdField, ...userIdField, is_set: optBool });\n\n protected async _handle(payload: {\n group_id: number;\n user_id: number;\n is_set?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n this.api.groupApi.setMemberRole(\n String(payload.group_id),\n uid,\n payload.is_set === false ? NTGroupMemberRoleMember : NTGroupMemberRoleAdmin,\n );\n return {};\n }\n}\n\n/** set_group_member_mute:禁言成员(duration 秒,0 解除)。 */\nexport class SetGroupMemberMuteAction extends MilkyApiAction<\n { group_id: number; user_id: number; duration?: number | null | undefined },\n Record<string, never>\n> {\n readonly name = \"set_group_member_mute\";\n readonly schema = z.object({\n ...groupIdField,\n ...userIdField,\n duration: z.number().int().min(0).nullable().optional(),\n });\n\n protected async _handle(payload: {\n group_id: number;\n user_id: number;\n duration?: number | null | undefined;\n }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n await this.api.groupApi.setMemberShutUp(String(payload.group_id), [\n { uid, duration: payload.duration ?? 0 },\n ]);\n return {};\n }\n}\n\n/** set_group_whole_mute:全员禁言开关(is_mute 缺省 true)。 */\nexport class SetGroupWholeMuteAction extends MilkyApiAction<\n { group_id: number; is_mute?: boolean | null | undefined },\n Record<string, never>\n> {\n readonly name = \"set_group_whole_mute\";\n readonly schema = z.object({ ...groupIdField, is_mute: optBool });\n\n protected async _handle(payload: {\n group_id: number;\n is_mute?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n await this.api.groupApi.setGroupShutUp(String(payload.group_id), payload.is_mute !== false);\n return {};\n }\n}\n\n/** kick_group_member:移除成员(reject_add_request 默认 false)。 */\nexport class KickGroupMemberAction extends MilkyApiAction<\n { group_id: number; user_id: number; reject_add_request?: boolean | null | undefined },\n Record<string, never>\n> {\n readonly name = \"kick_group_member\";\n readonly schema = z.object({\n ...groupIdField,\n ...userIdField,\n reject_add_request: optBool,\n });\n\n protected async _handle(payload: {\n group_id: number;\n user_id: number;\n reject_add_request?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n await this.api.groupApi.kickMember(\n String(payload.group_id),\n [uid],\n payload.reject_add_request === true,\n );\n return {};\n }\n}\n\n/** quit_group:退出群聊。 */\nexport class QuitGroupAction extends MilkyApiAction<{ group_id: number }, Record<string, never>> {\n readonly name = \"quit_group\";\n readonly schema = z.object({ ...groupIdField });\n\n protected async _handle(payload: { group_id: number }): Promise<Record<string, never>> {\n await this.api.groupApi.quitGroup(String(payload.group_id));\n return {};\n }\n}\n\n/**\n * get_group_essence_messages:获取精华消息列表。\n * WebApi.getEssenceMsgList 全量拉取后按 page_index/page_size 客户端分页\n * (kernel 无分页参数);message_time 无源取 operation_time 兜底。\n */\nexport class GetGroupEssenceMessagesAction extends MilkyApiAction<\n { group_id: number; page_index: number; page_size: number },\n GetGroupEssenceMessagesOutput\n> {\n readonly name = \"get_group_essence_messages\";\n readonly schema = z.object({\n ...groupIdField,\n page_index: z.number().int().min(0),\n page_size: z.number().int().min(0),\n });\n\n protected async _handle(payload: {\n group_id: number;\n page_index: number;\n page_size: number;\n }): Promise<GetGroupEssenceMessagesOutput> {\n const items = await this.api.webApi.getEssenceMsgList(String(payload.group_id));\n const start = payload.page_index * payload.page_size;\n const page = items.slice(start, start + payload.page_size);\n return {\n messages: page.map((item) => essenceToEntity(item, payload.group_id)),\n is_end: start + page.length >= items.length,\n };\n }\n}\n\n/** set_group_essence_message:设置/取消精华(seq → msgId 反查)。 */\nexport class SetGroupEssenceMessageAction extends MilkyApiAction<\n { group_id: number; message_seq: number; is_set?: boolean | null | undefined },\n Record<string, never>\n> {\n readonly name = \"set_group_essence_message\";\n readonly schema = z.object({\n ...groupIdField,\n message_seq: z.number().int().min(0),\n is_set: optBool,\n });\n\n protected async _handle(payload: {\n group_id: number;\n message_seq: number;\n is_set?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n const groupCode = String(payload.group_id);\n const peer: Peer = { chatType: ChatType.GROUP, peerUid: groupCode };\n const msgId = await this.api.resolveMsgIdBySeq(peer, payload.message_seq, ChatType.GROUP);\n if (msgId === undefined) {\n throw kernelError(`消息 ${payload.message_seq} 不存在`, \"NOT_FOUND\");\n }\n if (payload.is_set === false) {\n await this.api.groupApi.removeGroupEssence(groupCode, msgId);\n } else {\n await this.api.groupApi.addGroupEssence(groupCode, msgId);\n }\n return {};\n }\n}\n\n/** send_group_message_reaction:消息表情表态(reaction_type face→\"1\" / emoji→\"2\")。 */\nexport class SendGroupMessageReactionAction extends MilkyApiAction<\n {\n group_id: number;\n message_seq: number;\n reaction: string;\n reaction_type?: \"face\" | \"emoji\" | null | undefined;\n is_add?: boolean | null | undefined;\n },\n Record<string, never>\n> {\n readonly name = \"send_group_message_reaction\";\n readonly schema = z.object({\n ...groupIdField,\n message_seq: z.number().int().min(0),\n reaction: z.string().min(1),\n reaction_type: z.enum([\"face\", \"emoji\"]).nullable().optional(),\n is_add: z.boolean().nullable().optional(),\n });\n\n protected async _handle(payload: {\n group_id: number;\n message_seq: number;\n reaction: string;\n reaction_type?: \"face\" | \"emoji\" | null | undefined;\n is_add?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n const peer: Peer = { chatType: ChatType.GROUP, peerUid: String(payload.group_id) };\n await this.api.msgApi.setMsgEmojiLike(peer, {\n msgSeq: String(payload.message_seq),\n emojiId: payload.reaction,\n emojiType: payload.reaction_type === \"emoji\" ? \"2\" : \"1\",\n like: payload.is_add !== false,\n });\n return {};\n }\n}\n\n/**\n * get_group_notifications:获取群通知列表。\n * kernel getSingleScreenNotifies 为单屏快照(无翻页)——start_notification_seq\n * 作客户端过滤(取 seq 更小的记录);next = 本页最小 seq(仍有余量时)。\n */\nexport class GetGroupNotificationsAction extends MilkyApiAction<\n {\n start_notification_seq?: number | null | undefined;\n is_filtered?: boolean | null | undefined;\n limit?: number | null | undefined;\n },\n GetGroupNotificationsOutput\n> {\n readonly name = \"get_group_notifications\";\n readonly schema = z.object({\n start_notification_seq: z.number().int().min(0).nullable().optional(),\n is_filtered: optBool,\n limit: z.number().int().min(0).nullable().optional(),\n });\n\n protected async _handle(payload: {\n start_notification_seq?: number | null | undefined;\n is_filtered?: boolean | null | undefined;\n limit?: number | null | undefined;\n }): Promise<GetGroupNotificationsOutput> {\n const notifies = await this.api.groupNotifyApi.getSingleScreenNotifies(\n payload.is_filtered === true,\n NOTIFY_SEARCH_COUNT,\n );\n const start = payload.start_notification_seq;\n const filtered = notifies.filter(\n (n) => start === undefined || start === null || Number(n.seq) < start,\n );\n // 通知涉及的 uid → uin 批量转换(实体 user 字段都是 uin)\n const uidToUin = await this.collectUidToUin(filtered);\n const entities = filtered\n .map((n) => notifyToEntity(n, payload.is_filtered === true, uidToUin))\n .filter((e): e is GroupNotificationEntity => e !== null);\n const limit = payload.limit ?? NOTIFICATIONS_DEFAULT_LIMIT;\n const page = entities.slice(0, limit);\n const minSeq = page.reduce<number | null>(\n (acc, e) => (acc === null ? e.notification_seq : Math.min(acc, e.notification_seq)),\n null,\n );\n return {\n notifications: page,\n next_notification_seq: entities.length > page.length && minSeq !== null ? minSeq : null,\n };\n }\n\n /** 通知 user1/user2 uid → uin 批量转换(失败退空 Map,实体 id 兜底 0)。 */\n private async collectUidToUin(notifies: GroupNotify[]): Promise<Map<string, string>> {\n const uids = collectNotifyUids(notifies);\n if (uids.length === 0) {\n return new Map();\n }\n return await this.api.uidToUin(uids).catch(() => new Map<string, string>());\n }\n}\n\n/** accept/reject 群请求 / 群邀请公共基类:seq → 通知匹配 → handleGroupRequest。 */\nabstract class HandleGroupNotifyBase<TPayload> extends MilkyApiAction<\n TPayload,\n Record<string, never>\n> {\n /** 同意/拒绝。 */\n protected abstract readonly approve: boolean;\n\n protected async respond(seq: number, doubt: boolean): Promise<Record<string, never>> {\n const notify = await findGroupNotify(this.api, String(seq));\n await this.api.groupNotifyApi.handleGroupRequest(\n doubt,\n notify,\n this.approve ? NTGroupRequestOperateTypes.KAGREE : NTGroupRequestOperateTypes.KREFUSE,\n \" \",\n );\n return {};\n }\n}\n\n/** accept_group_request:同意入群请求(notification_type/group_id 仅 schema 校验)。 */\nexport class AcceptGroupRequestAction extends HandleGroupNotifyBase<{\n notification_seq: number;\n is_filtered?: boolean | null | undefined;\n}> {\n readonly name = \"accept_group_request\";\n readonly schema = z.object({\n notification_seq: z.number().int().min(0),\n notification_type: z.enum([\"join_request\", \"invited_join_request\"]),\n ...groupIdField,\n is_filtered: optBool,\n });\n protected readonly approve = true;\n\n protected async _handle(payload: {\n notification_seq: number;\n is_filtered?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n return await this.respond(payload.notification_seq, payload.is_filtered === true);\n }\n}\n\n/** reject_group_request:拒绝入群请求(reason 无源,kernel postscript 占位空格)。 */\nexport class RejectGroupRequestAction extends HandleGroupNotifyBase<{\n notification_seq: number;\n is_filtered?: boolean | null | undefined;\n}> {\n readonly name = \"reject_group_request\";\n readonly schema = z.object({\n notification_seq: z.number().int().min(0),\n notification_type: z.enum([\"join_request\", \"invited_join_request\"]),\n ...groupIdField,\n is_filtered: optBool,\n reason: optStr,\n });\n protected readonly approve = false;\n\n protected async _handle(payload: {\n notification_seq: number;\n is_filtered?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n return await this.respond(payload.notification_seq, payload.is_filtered === true);\n }\n}\n\n/** accept_group_invitation:接受入群邀请(按 invitation_seq 匹配)。 */\nexport class AcceptGroupInvitationAction extends HandleGroupNotifyBase<{ invitation_seq: number }> {\n readonly name = \"accept_group_invitation\";\n readonly schema = z.object({ ...groupIdField, invitation_seq: z.number().int().min(0) });\n protected readonly approve = true;\n\n protected async _handle(payload: { invitation_seq: number }): Promise<Record<string, never>> {\n return await this.respond(payload.invitation_seq, false);\n }\n}\n\n/** reject_group_invitation:拒绝入群邀请。 */\nexport class RejectGroupInvitationAction extends HandleGroupNotifyBase<{ invitation_seq: number }> {\n readonly name = \"reject_group_invitation\";\n readonly schema = z.object({ ...groupIdField, invitation_seq: z.number().int().min(0) });\n protected readonly approve = false;\n\n protected async _handle(payload: { invitation_seq: number }): Promise<Record<string, never>> {\n return await this.respond(payload.invitation_seq, false);\n }\n}\n\n/** ---------- 内部辅助 ---------- */\n\n/** 通知查找数量(单屏全量,OB11 DEFAULT_COUNT 同值)。 */\nconst NOTIFY_SEARCH_COUNT = 100;\n\n/** get_group_notifications 默认 limit(规范 default 20)。 */\nconst NOTIFICATIONS_DEFAULT_LIMIT = 20;\n\n/** NTGroupMemberRole 数值(ADMIN=3 / MEMBER=2,setMemberRole 入参)。 */\nconst NTGroupMemberRoleAdmin = 3;\nconst NTGroupMemberRoleMember = 2;\n\n/** 成员列表(GroupCache 优先,未装配直查)。 */\nasync function membersOf(api: MilkyApi, groupCode: string): Promise<GroupMember[]> {\n if (api.groupCache !== undefined) {\n return await api.groupCache.getMembers(groupCode);\n }\n return await api.groupApi.getGroupMemberList(groupCode, true);\n}\n\n/** 成员单查(user_id = uin;缓存路径经 uid,直查路径按 uin 匹配)。 */\nasync function memberOf(api: MilkyApi, groupId: number, userId: number): Promise<GroupMember> {\n const groupCode = String(groupId);\n const uin = String(userId);\n if (api.groupCache !== undefined) {\n const uid = await api.resolveUidFromUin(userId).catch(() => uin);\n const member = await api.groupCache.getMember(groupCode, uid);\n if (member === undefined) {\n throw kernelError(`成员 ${uin} 不在群 ${groupCode}`, \"NOT_FOUND\");\n }\n return member;\n }\n const list = await api.groupApi.getGroupMemberList(groupCode, true);\n const hit = list.find((m) => m.uin === uin);\n if (hit === undefined) {\n throw kernelError(`成员 ${uin} 不在群 ${groupCode}`, \"NOT_FOUND\");\n }\n return hit;\n}\n\n/** 精华项 → GroupEssenceMessage(msg_content 近似翻译:text / image)。 */\nfunction essenceToEntity(item: EssenceMsgItem, groupId: number): GroupEssenceMessage {\n const segments: IncomingSegment[] = [];\n for (const c of item.msg_content) {\n if (c.text !== undefined && c.text !== \"\") {\n segments.push({ type: \"text\", data: { text: c.text } });\n } else if (c.image_url !== undefined && c.image_url !== \"\") {\n segments.push({\n type: \"image\",\n data: {\n resource_id: c.image_url,\n temp_url: c.image_url,\n width: 0,\n height: 0,\n summary: \"\",\n sub_type: \"normal\",\n },\n });\n }\n }\n return {\n group_id: groupId,\n message_seq: item.msg_seq,\n message_time: item.add_digest_time,\n sender_id: Number(item.sender_uin) || 0,\n sender_name: item.sender_nick,\n operator_id: Number(item.add_digest_uin) || 0,\n operator_name: item.add_digest_nick,\n operation_time: item.add_digest_time,\n segments,\n };\n}\n\n/**\n * GroupNotify → GroupNotificationEntity(uidToUin 已由调用方批量转换)。\n * 类型→构造器表:7=入群申请 / 5=成员邀请他人 / 8=设管理 / 12,13=取消管理 /\n * 9,10=踢出 / 11=退群;1=邀请自身无实体变体(事件层表达),其余 null。\n */\nconst NOTIFY_ENTITY_BUILDERS: Partial<\n Record<\n number,\n (notify: GroupNotify, uinOf: (uid: string | undefined) => number) => GroupNotificationEntity\n >\n> = {\n 7: (n, uinOf) => ({\n type: \"join_request\",\n group_id: Number(n.group?.groupCode ?? 0),\n notification_seq: Number(n.seq),\n is_filtered: false,\n initiator_id: uinOf(n.user1?.uid),\n state: \"pending\",\n operator_id: null,\n comment: n.postscript ?? \"\",\n }),\n 5: (n, uinOf) => ({\n type: \"invited_join_request\",\n group_id: Number(n.group?.groupCode ?? 0),\n notification_seq: Number(n.seq),\n initiator_id: uinOf(n.user1?.uid),\n target_user_id: uinOf(n.user2?.uid),\n state: \"pending\",\n operator_id: null,\n }),\n 8: (n, uinOf) => adminChangeEntity(n, uinOf, true),\n 12: (n, uinOf) => adminChangeEntity(n, uinOf, false),\n 13: (n, uinOf) => adminChangeEntity(n, uinOf, false),\n 9: (n, uinOf) => kickEntity(n, uinOf),\n 10: (n, uinOf) => kickEntity(n, uinOf),\n 11: (n, uinOf) => ({\n type: \"quit\",\n group_id: Number(n.group?.groupCode ?? 0),\n notification_seq: Number(n.seq),\n target_user_id: uinOf(n.user1?.uid),\n }),\n};\n\n/** admin_change 实体(8/12/13 共用)。 */\nfunction adminChangeEntity(\n n: GroupNotify,\n uinOf: (uid: string | undefined) => number,\n isSet: boolean,\n): GroupNotificationEntity {\n return {\n type: \"admin_change\",\n group_id: Number(n.group?.groupCode ?? 0),\n notification_seq: Number(n.seq),\n target_user_id: uinOf(n.user1?.uid),\n is_set: isSet,\n operator_id: uinOf(n.user2?.uid),\n };\n}\n\n/** kick 实体(9/10 共用)。 */\nfunction kickEntity(\n n: GroupNotify,\n uinOf: (uid: string | undefined) => number,\n): GroupNotificationEntity {\n return {\n type: \"kick\",\n group_id: Number(n.group?.groupCode ?? 0),\n notification_seq: Number(n.seq),\n target_user_id: uinOf(n.user1?.uid),\n operator_id: uinOf(n.user2?.uid),\n };\n}\n\n/** GroupNotify → 实体(isFiltered 透传给 join_request;未识别类型 null)。 */\nfunction notifyToEntity(\n notify: GroupNotify,\n isFiltered: boolean,\n uidToUin: Map<string, string>,\n): GroupNotificationEntity | null {\n const uinOf = (uid: string | undefined): number =>\n uid === undefined || uid === \"\" ? 0 : Number(uidToUin.get(uid) ?? 0) || 0;\n const builder = NOTIFY_ENTITY_BUILDERS[notify.type];\n if (builder === undefined) {\n return null;\n }\n const entity = builder(notify, uinOf);\n if (entity.type === \"join_request\") {\n entity.is_filtered = isFiltered;\n }\n return entity;\n}\n","/**\n * Milky 群文件类动作(P1):get_group_files / move / rename / delete /\n * persist_group_file / create_group_folder / delete_group_folder\n *\n * 全部走 RichMediaApi(群文件系列)。rename_group_folder 与\n * get_group_file_download_url kernel 无出口(P2 探测,见 docs/protocols/milky.md)。\n * 实体字段以 GroupFileItemInfo / GroupFolderInfo 为源;下载次数 / 过期时间 /\n * 文件夹元数据等无源字段 0/null 兜底(待探测校准)。\n */\nimport type { GroupFileItemInfo, GroupFolderInfo } from \"@napuketto/kernel\";\nimport { z } from \"zod\";\nimport type {\n CreateGroupFolderOutput,\n GetGroupFilesOutput,\n GroupFileEntity,\n GroupFolderEntity,\n} from \"../types.js\";\nimport { MilkyApiAction } from \"./base-action.js\";\n\nconst groupIdField = { group_id: z.number().int().min(10001) } as const;\nconst fileIdField = { file_id: z.string().min(1) } as const;\nconst optStr = z.string().nullable().optional();\n\n/** get_group_files:获取群文件列表(根目录或指定文件夹;过滤 parent 匹配项)。 */\nexport class GetGroupFilesAction extends MilkyApiAction<\n { group_id: number; parent_folder_id?: string | null | undefined },\n GetGroupFilesOutput\n> {\n readonly name = \"get_group_files\";\n readonly schema = z.object({ ...groupIdField, parent_folder_id: optStr });\n\n protected async _handle(payload: {\n group_id: number;\n parent_folder_id?: string | null | undefined;\n }): Promise<GetGroupFilesOutput> {\n const groupCode = String(payload.group_id);\n const parent = payload.parent_folder_id ?? \"\";\n const items = await this.api.richMediaApi.getGroupFileList(groupCode, parent);\n const files: GroupFileEntity[] = [];\n const folders: GroupFolderEntity[] = [];\n for (const item of items) {\n if (item.fileInfo !== undefined) {\n files.push(fileToEntity(item.fileInfo, payload.group_id));\n } else if (item.folderInfo !== undefined) {\n folders.push(folderToEntity(item.folderInfo, payload.group_id));\n }\n }\n return { files, folders };\n }\n}\n\n/** move_group_file:移动文件(target_folder_id 空 = 移到根目录;parent 入参仅 schema 兼容)。 */\nexport class MoveGroupFileAction extends MilkyApiAction<\n {\n group_id: number;\n file_id: string;\n parent_folder_id?: string | null | undefined;\n target_folder_id?: string | null | undefined;\n },\n Record<string, never>\n> {\n readonly name = \"move_group_file\";\n readonly schema = z.object({\n ...groupIdField,\n ...fileIdField,\n parent_folder_id: optStr,\n target_folder_id: optStr,\n });\n\n protected async _handle(payload: {\n group_id: number;\n file_id: string;\n parent_folder_id?: string | null | undefined;\n target_folder_id?: string | null | undefined;\n }): Promise<Record<string, never>> {\n await this.api.richMediaApi.moveGroupFile(\n String(payload.group_id),\n [payload.file_id],\n payload.target_folder_id ?? \"\",\n );\n return {};\n }\n}\n\n/** rename_group_file:重命名文件。 */\nexport class RenameGroupFileAction extends MilkyApiAction<\n {\n group_id: number;\n file_id: string;\n parent_folder_id?: string | null | undefined;\n new_file_name: string;\n },\n Record<string, never>\n> {\n readonly name = \"rename_group_file\";\n readonly schema = z.object({\n ...groupIdField,\n ...fileIdField,\n parent_folder_id: optStr,\n new_file_name: z.string().min(1),\n });\n\n protected async _handle(payload: {\n group_id: number;\n file_id: string;\n parent_folder_id?: string | null | undefined;\n new_file_name: string;\n }): Promise<Record<string, never>> {\n await this.api.richMediaApi.renameGroupFile(\n String(payload.group_id),\n payload.file_id,\n payload.new_file_name,\n );\n return {};\n }\n}\n\n/** delete_group_file:删除文件。 */\nexport class DeleteGroupFileAction extends MilkyApiAction<\n { group_id: number; file_id: string },\n Record<string, never>\n> {\n readonly name = \"delete_group_file\";\n readonly schema = z.object({ ...groupIdField, ...fileIdField });\n\n protected async _handle(payload: {\n group_id: number;\n file_id: string;\n }): Promise<Record<string, never>> {\n await this.api.richMediaApi.deleteGroupFile(String(payload.group_id), [payload.file_id]);\n return {};\n }\n}\n\n/**\n * persist_group_file:转存文件(RichMediaApi.transGroupFile,转存语义待对齐)。\n */\nexport class PersistGroupFileAction extends MilkyApiAction<\n { group_id: number; file_id: string },\n Record<string, never>\n> {\n readonly name = \"persist_group_file\";\n readonly schema = z.object({ ...groupIdField, ...fileIdField });\n\n protected async _handle(payload: {\n group_id: number;\n file_id: string;\n }): Promise<Record<string, never>> {\n await this.api.richMediaApi.transGroupFile(String(payload.group_id), payload.file_id);\n return {};\n }\n}\n\n/** create_group_folder:创建文件夹(返回 folder_id)。 */\nexport class CreateGroupFolderAction extends MilkyApiAction<\n { group_id: number; folder_name: string },\n CreateGroupFolderOutput\n> {\n readonly name = \"create_group_folder\";\n readonly schema = z.object({ ...groupIdField, folder_name: z.string().min(1) });\n\n protected async _handle(payload: {\n group_id: number;\n folder_name: string;\n }): Promise<CreateGroupFolderOutput> {\n const folderId = await this.api.richMediaApi.createGroupFolder(\n String(payload.group_id),\n payload.folder_name,\n );\n return { folder_id: folderId };\n }\n}\n\n/** delete_group_folder:删除文件夹。 */\nexport class DeleteGroupFolderAction extends MilkyApiAction<\n { group_id: number; folder_id: string },\n Record<string, never>\n> {\n readonly name = \"delete_group_folder\";\n readonly schema = z.object({ ...groupIdField, folder_id: z.string().min(1) });\n\n protected async _handle(payload: {\n group_id: number;\n folder_id: string;\n }): Promise<Record<string, never>> {\n await this.api.richMediaApi.deleteGroupFolder(String(payload.group_id), payload.folder_id);\n return {};\n }\n}\n\n/** GroupFileItemInfo → GroupFileEntity(fileSize 原生为字符串;无源字段兜底)。 */\nfunction fileToEntity(info: GroupFileItemInfo, groupId: number): GroupFileEntity {\n return {\n group_id: groupId,\n file_id: info.fileId,\n file_name: info.fileName,\n parent_folder_id: info.parent ?? \"\",\n file_size: Number(info.fileSize) || 0,\n uploaded_time: Number(info.uploadTime) || 0,\n expire_time: null,\n uploader_id: Number(info.uploaderUin) || 0,\n downloaded_times: 0,\n };\n}\n\n/** GroupFolderInfo → GroupFolderEntity(元数据无类型字段防御读取,缺省 0)。 */\nfunction folderToEntity(info: GroupFolderInfo, groupId: number): GroupFolderEntity {\n const num = (key: string): number => {\n const v = info[key];\n return typeof v === \"number\" ? v : Number(v) || 0;\n };\n return {\n group_id: groupId,\n folder_id: info.folderId,\n parent_folder_id: info.folderUid ?? \"\",\n folder_name: info.folderName,\n created_time: num(\"createTime\"),\n last_modified_time: num(\"modifyTime\"),\n creator_id: 0,\n file_count: num(\"totalFileCount\"),\n };\n}\n","/**\n * 发送媒体 URI 解析(Milky OutgoingSegment uri → 本地路径)\n *\n * 规范支持 file:// / http(s):// / base64:// 三种(image/record/video 共用):\n * - file:// → 平台路径(segments.ts 的同步面已处理)\n * - base64:// → 解码落盘 cacheDir/milky/,file-type 探测扩展名后改名\n * - http(s):// → @napuketto/media downloadUrl 落盘 cacheDir/milky/\n * 未配置 mediaDir 时远程 URI 报错(不发静默空消息)。\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { mkdir, rename, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { kernelError } from \"@napuketto/kernel\";\nimport { detectFileType, downloadUrl, inferExtension } from \"@napuketto/media\";\n\n/** 解析远程媒体 URI 为本地绝对路径(base64:// / http(s)://;file:// 走同步面)。 */\nexport async function resolveMediaUri(uri: string, mediaDir: string | undefined): Promise<string> {\n if (mediaDir === undefined || mediaDir === \"\") {\n throw kernelError(\n \"远程媒体发送需要配置 [accounts.milky] cacheDir(下载缓存目录)\",\n \"INVALID_PARAM\",\n );\n }\n if (uri.startsWith(\"base64://\")) {\n return await writeBase64(uri.slice(\"base64://\".length), mediaDir);\n }\n const dest = join(mediaDir, `${randomUUID()}${inferExtension(null, uri)}`);\n await downloadUrl(uri, dest);\n return dest;\n}\n\n/** base64 载荷 → 落盘(先写 .bin,探测到扩展名再改名)。 */\nasync function writeBase64(payload: string, mediaDir: string): Promise<string> {\n let bytes: Buffer;\n try {\n bytes = Buffer.from(payload, \"base64\");\n } catch {\n throw kernelError(\"base64:// 载荷解码失败\", \"INVALID_PARAM\");\n }\n if (bytes.length === 0) {\n throw kernelError(\"base64:// 载荷为空\", \"INVALID_PARAM\");\n }\n await mkdir(mediaDir, { recursive: true });\n const raw = join(mediaDir, `${randomUUID()}.bin`);\n await writeFile(raw, bytes);\n try {\n const { ext } = await detectFileType(raw);\n const final = join(mediaDir, `${randomUUID()}${ext}`);\n await rename(raw, final);\n return final;\n } catch {\n // 类型探测失败:保留 .bin(QQ 端按内容嗅探)\n return raw;\n }\n}\n","/**\n * Milky 消息段 ↔ canonical 元素转换(纯函数,ADR-008)\n *\n * 接收方向:canonical → IncomingSegment(规范 14 种中映射 12 种;market_face /\n * markdown 无 canonical 对应(MFACE/MARKDOWN 原始元素形状未探测),unknown 一律\n * 跳过——规范兼容性要求「数组中未知项跳过」)。forward 接收段不经 canonical:\n * kernel 无 MULTI_FORWARD 分支,adapter 从 RawMessage 提取 resId 后经\n * incomingForwardSegment + ctx 注入。\n * 发送方向:OutgoingSegment → canonical(10 种全映射;forward 顶层段不走本转换器,\n * 由 sendMilkyMessage 分流到组装链——本转换器内 forward 报错只拦截混发/嵌套)。\n */\nimport { fileURLToPath } from \"node:url\";\nimport type { CanonicalElement } from \"@napuketto/kernel\";\nimport { kernelError } from \"@napuketto/kernel\";\nimport type { IncomingSegment, OutgoingSegment } from \"../types.js\";\n\n/** reply 段回填元信息(广播/action 路径异步取得,翻译纯函数消费)。 */\nexport interface ReplyMeta {\n messageSeq: number;\n senderId: number;\n time: number;\n}\n\n/** 接收段转换上下文(enrichment 产物)。 */\nexport interface ReceiveSegmentContext {\n /** at uid → uin(mention.user_id 需要 uin;缺省不转换,转换失败跳过该段)。 */\n uidToUin?: Map<string, string>;\n /** reply NT msgId → 引用消息元信息(回填 message_seq/sender_id/time)。 */\n replyMeta?: Map<string, ReplyMeta>;\n}\n\n/** uin 字符串 → Milky user_id(非有限正数 = 转换失败)。 */\nfunction toUserId(uin: string): number | undefined {\n const n = Number(uin);\n return Number.isFinite(n) && n >= 10001 ? n : undefined;\n}\n\n/** canonical 元素 → IncomingSegment 列表(unknown / 转换失败段跳过)。 */\nexport function canonicalToIncomingSegments(\n elements: CanonicalElement[],\n ctx: ReceiveSegmentContext = {},\n): IncomingSegment[] {\n const out: IncomingSegment[] = [];\n for (const el of elements) {\n const seg = canonicalToIncomingSegment(el, ctx);\n if (seg !== null) {\n out.push(seg);\n }\n }\n return out;\n}\n\n/** canonical image → image 段(resource_id = 本地路径优先,url 兜底)。 */\nfunction imageToIncoming(el: Extract<CanonicalElement, { type: \"image\" }>): IncomingSegment {\n return {\n type: \"image\",\n data: {\n resource_id: el.path !== \"\" ? el.path : (el.url ?? \"\"),\n temp_url: el.url ?? \"\",\n width: el.size?.width ?? 0,\n height: el.size?.height ?? 0,\n summary: \"\",\n sub_type: \"normal\",\n },\n };\n}\n\n/** canonical voice → record 段。 */\nfunction voiceToIncoming(el: Extract<CanonicalElement, { type: \"voice\" }>): IncomingSegment {\n return {\n type: \"record\",\n data: {\n resource_id: el.path !== \"\" ? el.path : (el.url ?? \"\"),\n temp_url: el.url ?? \"\",\n duration: el.durationMs !== undefined ? Math.round(el.durationMs / 1000) : 0,\n },\n };\n}\n\n/** canonical video → video 段。 */\nfunction videoToIncoming(el: Extract<CanonicalElement, { type: \"video\" }>): IncomingSegment {\n return {\n type: \"video\",\n data: {\n resource_id: el.path !== \"\" ? el.path : (el.url ?? \"\"),\n temp_url: el.url ?? \"\",\n width: el.width ?? 0,\n height: el.height ?? 0,\n duration: el.durationSec ?? 0,\n },\n };\n}\n\n/** 按类型分发的段映射器表(键 = canonical type;缺项 = 跳过)。 */\nconst INCOMING_MAPPERS: Partial<\n Record<\n CanonicalElement[\"type\"],\n (el: never, ctx: ReceiveSegmentContext) => IncomingSegment | null\n >\n> = {\n text: (el: Extract<CanonicalElement, { type: \"text\" }>) => ({\n type: \"text\",\n data: { text: el.text },\n }),\n at: atToIncoming,\n face: (el: Extract<CanonicalElement, { type: \"face\" }>) => ({\n type: \"face\",\n data: { face_id: el.id, is_large: false },\n }),\n reply: replyToIncoming,\n image: imageToIncoming,\n voice: voiceToIncoming,\n video: videoToIncoming,\n file: fileToIncoming,\n json: (el: Extract<CanonicalElement, { type: \"json\" }>) => ({\n type: \"light_app\",\n data: { app_name: parseAppName(el.raw), json_payload: rawToPayload(el.raw) },\n }),\n xml: (el: Extract<CanonicalElement, { type: \"xml\" }>) => ({\n type: \"xml\",\n data: { service_id: 0, xml_payload: rawToPayload(el.raw) },\n }),\n};\n\nfunction canonicalToIncomingSegment(\n el: CanonicalElement,\n ctx: ReceiveSegmentContext,\n): IncomingSegment | null {\n const mapper = INCOMING_MAPPERS[el.type];\n // unknown / 未映射类型:跳过(规范兼容性要求)\n return mapper === undefined ? null : mapper(el as never, ctx);\n}\n\n/** canonical at → mention / mention_all(uid→uin 失败跳过该段)。 */\nfunction atToIncoming(\n el: Extract<CanonicalElement, { type: \"at\" }>,\n ctx: ReceiveSegmentContext,\n): IncomingSegment | null {\n if (el.target === \"all\") {\n return { type: \"mention_all\", data: {} };\n }\n const uin = ctx.uidToUin?.get(el.target) ?? el.target;\n const userId = toUserId(uin);\n if (userId === undefined) {\n return null;\n }\n return { type: \"mention\", data: { user_id: userId, name: el.display ?? \"\" } };\n}\n\n/** canonical reply → reply 段(引用元信息经 ctx 回填,未命中全 0 兜底)。 */\nfunction replyToIncoming(\n el: Extract<CanonicalElement, { type: \"reply\" }>,\n ctx: ReceiveSegmentContext,\n): IncomingSegment {\n const meta = ctx.replyMeta?.get(el.messageId);\n return {\n type: \"reply\",\n data: {\n message_seq: meta?.messageSeq ?? 0,\n sender_id: meta?.senderId ?? 0,\n sender_name: null,\n time: meta?.time ?? 0,\n segments: [],\n },\n };\n}\n\n/** canonical file → file 段。 */\nfunction fileToIncoming(el: Extract<CanonicalElement, { type: \"file\" }>): IncomingSegment {\n return {\n type: \"file\",\n data: {\n file_id: el.path,\n file_name: el.name ?? \"\",\n file_size: el.size ?? 0,\n },\n };\n}\n\n/**\n * 合并转发 → forward 段(P1)。\n * 接收方向 canonical 不承载 MULTI_FORWARD(kernel toCanonicalElement 无此分支),\n * 由 adapter 从 RawMessage 提取 resId 后调用本函数经 ctx 注入(翻译保持纯函数)。\n * title 取 NT fileName(转发卡片标题语义)。\n */\nexport function incomingForwardSegment(resId: string, title: string): IncomingSegment {\n return {\n type: \"forward\",\n data: {\n forward_id: resId,\n title,\n preview: [],\n summary: \"\",\n },\n };\n}\n\n/** json 载荷 → 小程序名(spec app_name:JSON 顶层 app 字段,取不到空串)。 */\nfunction parseAppName(raw: unknown): string {\n let obj: unknown = raw;\n if (typeof raw === \"string\") {\n try {\n obj = JSON.parse(raw);\n } catch {\n return \"\";\n }\n }\n if (typeof obj !== \"object\" || obj === null || !(\"app\" in obj)) {\n return \"\";\n }\n const app = (obj as Record<string, unknown>)[\"app\"];\n return typeof app === \"string\" ? app : \"\";\n}\n\n/** canonical json/xml raw → 字符串载荷(字符串原样,其余 JSON 序列化)。 */\nfunction rawToPayload(raw: unknown): string {\n if (typeof raw === \"string\") {\n return raw;\n }\n try {\n return JSON.stringify(raw) ?? \"\";\n } catch {\n return \"\";\n }\n}\n\n/**\n * OutgoingSegment 数组 → canonical 元素(同步映射;媒体 URI 解析与 at uin→uid\n * 由调用方在返回值上继续处理)。\n * forward 在此报错:顶层 forward 已由 sendMilkyMessage 分流到组装链(message.ts,\n * P2 批次一),命中本分支 = forward 与其他段混发漏网或嵌套 forward(组装链内逐项\n * 转换经过此处)——均显式拒绝。\n */\nexport function outgoingSegmentsToCanonical(segments: OutgoingSegment[]): {\n elements: CanonicalElement[];\n atUins: string[];\n replySeqs: number[];\n} {\n const elements: CanonicalElement[] = [];\n const atUins: string[] = [];\n const replySeqs: number[] = [];\n for (const seg of segments) {\n switch (seg.type) {\n case \"text\":\n elements.push({ type: \"text\", text: seg.data.text });\n break;\n case \"mention\": {\n const uin = String(seg.data.user_id);\n atUins.push(uin);\n elements.push({ type: \"at\", target: uin });\n break;\n }\n case \"mention_all\":\n elements.push({ type: \"at\", target: \"all\" });\n break;\n case \"face\":\n elements.push({ type: \"face\", id: seg.data.face_id });\n break;\n case \"reply\": {\n replySeqs.push(seg.data.message_seq);\n elements.push({ type: \"reply\", messageId: String(seg.data.message_seq) });\n break;\n }\n case \"image\":\n elements.push({ type: \"image\", path: resolveUriToPathPlaceholder(seg.data.uri) });\n break;\n case \"record\":\n elements.push({ type: \"voice\", path: resolveUriToPathPlaceholder(seg.data.uri) });\n break;\n case \"video\":\n elements.push({ type: \"video\", path: resolveUriToPathPlaceholder(seg.data.uri) });\n break;\n case \"light_app\":\n elements.push({ type: \"json\", raw: seg.data.json_payload });\n break;\n case \"forward\":\n throw kernelError(\n \"forward 段不可与其他消息段混发或嵌套(顶层 forward 须单独发送)\",\n \"INVALID_PARAM\",\n );\n default:\n // 未知段:跳过(规范兼容性要求)\n break;\n }\n }\n return { elements, atUins, replySeqs };\n}\n\n/**\n * 媒体 URI → 本地路径(同步面:file:// / 裸路径直接给 canonical;base64:// 与\n * http(s):// 需要异步落盘,由 send 核心在 canonical 上二次解析——此处先放原始\n * URI 作占位,send 核心按元素类型调用 resolveMediaUri 替换)。\n */\nfunction resolveUriToPathPlaceholder(uri: string): string {\n if (uri.startsWith(\"file://\")) {\n return fileUriToPath(uri);\n }\n if (uri.startsWith(\"http://\") || uri.startsWith(\"https://\") || uri.startsWith(\"base64://\")) {\n return uri;\n }\n // 裸路径(go-cqhttp 惯例):按本地路径处理\n return uri;\n}\n\n/** file:// 前缀(fileURLToPath 失败时的裸剥离兜底)。 */\nconst FILE_URI_PREFIX_RE = /^file:\\/\\//;\n\n/** file:// URI → 平台路径(Windows 盘符兼容)。 */\nfunction fileUriToPath(uri: string): string {\n try {\n return fileURLToPath(uri);\n } catch {\n return uri.replace(FILE_URI_PREFIX_RE, \"\");\n }\n}\n","/**\n * Milky 事件翻译(RawMessage → Milky 事件,纯函数,ADR-008)\n *\n * P0 事件两种:message_receive(onRecvMsg)/ message_recall(grayTip REVOKE)。\n * 实体与 reply 回填在广播路径异步取得后经 ctx 注入(翻译保持纯函数);\n * 撤回事件的 sender_id 取 RawMessage.senderUin(grayTip 系统消息的 sender\n * 即被撤回原消息的发送者,口径待真实事件校准)。\n */\nimport {\n type CanonicalElement,\n ChatType,\n type RawMessage,\n toCanonicalElements,\n} from \"@napuketto/kernel\";\nimport type {\n GroupEntity,\n GroupFileUploadData,\n GroupMemberEntity,\n IncomingMessage,\n IncomingSegment,\n MessageRecallData,\n MilkyEvent,\n} from \"../types.js\";\nimport { toFriendEntity, toGroupEntity, toGroupMemberEntity } from \"./entities.js\";\nimport { canonicalToIncomingSegments, type ReceiveSegmentContext } from \"./segments.js\";\n\n/** 毫秒 → 秒(Unix 时间戳)。 */\nconst MS_TO_SEC = 1000;\n\n/** 接收事件翻译上下文。 */\nexport interface ReceiveTranslateContext extends ReceiveSegmentContext {\n /** 登录 uin(self_id)。 */\n selfUin: string;\n /** friend 场景:好友实体(广播路径 best-effort 构造;缺省最小实体)。 */\n friendEntity?: import(\"../types.js\").FriendEntity;\n /** group 场景:群实体(缺省最小实体)。 */\n groupEntity?: GroupEntity;\n /** group 场景:群成员实体(缺省最小实体)。 */\n groupMemberEntity?: GroupMemberEntity;\n /**\n * 合并转发段(P1):adapter 从 RawMessage 的 multiForwardMsgElement 提取\n * resId 后预构建(canonical 不承载 MULTI_FORWARD),追加到段尾。\n */\n forwardSegments?: IncomingSegment[];\n}\n\n/** chatType → message_scene。 */\nexport function chatTypeToScene(chatType: number): \"friend\" | \"group\" | \"temp\" {\n if (chatType === ChatType.GROUP) {\n return \"group\";\n }\n if (chatType === ChatType.C2C_TEMP) {\n return \"temp\";\n }\n return \"friend\";\n}\n\n/** peer_id:群聊 = 群号(peerUid);好友/临时 = 对端 uin(peerUin,空退 peerUid)。 */\nfunction peerIdOf(msg: RawMessage, scene: \"friend\" | \"group\" | \"temp\"): number {\n const raw = scene === \"group\" ? msg.peerUid : msg.peerUin !== \"\" ? msg.peerUin : msg.peerUid;\n return Number(raw);\n}\n\n/** RawMessage → message_receive 事件(实体缺省最小合法值,schema 形状完整)。 */\nexport function toMessageReceiveEvent(\n msg: RawMessage,\n ctx: ReceiveTranslateContext,\n): MilkyEvent<IncomingMessage> {\n const elements: CanonicalElement[] = toCanonicalElements(msg);\n const segments = canonicalToIncomingSegments(elements, {\n ...(ctx.uidToUin !== undefined ? { uidToUin: ctx.uidToUin } : {}),\n ...(ctx.replyMeta !== undefined ? { replyMeta: ctx.replyMeta } : {}),\n });\n if (ctx.forwardSegments !== undefined) {\n segments.push(...ctx.forwardSegments);\n }\n const scene = chatTypeToScene(msg.chatType);\n const time = Math.floor(Number(msg.msgTime) / MS_TO_SEC);\n let data: IncomingMessage;\n if (scene === \"group\") {\n data = {\n message_scene: \"group\",\n peer_id: peerIdOf(msg, scene),\n message_seq: Number(msg.msgSeq),\n sender_id: Number(msg.senderUin),\n time,\n segments,\n group: ctx.groupEntity ?? toGroupEntity(undefined, msg.peerUid),\n group_member:\n ctx.groupMemberEntity ?? toGroupMemberEntity(undefined, msg.peerUid, msg.senderUin),\n };\n } else if (scene === \"friend\") {\n data = {\n message_scene: \"friend\",\n peer_id: peerIdOf(msg, scene),\n message_seq: Number(msg.msgSeq),\n sender_id: Number(msg.senderUin),\n time,\n segments,\n friend:\n ctx.friendEntity ??\n toFriendEntity(\n undefined,\n msg.peerUin !== \"\" ? msg.peerUin : msg.senderUin,\n msg.peerName,\n ),\n };\n } else {\n data = {\n message_scene: \"temp\",\n peer_id: peerIdOf(msg, scene),\n message_seq: Number(msg.msgSeq),\n sender_id: Number(msg.senderUin),\n time,\n segments,\n group: ctx.groupEntity ?? null,\n };\n }\n return {\n time,\n self_id: Number(ctx.selfUin),\n event_type: \"message_receive\",\n data,\n };\n}\n\n/** 撤回 grayTip → message_recall 事件(非撤回 grayTip 返回 null)。 */\nexport function toMessageRecallEvent(\n msg: RawMessage,\n ctx: { selfUin: string; uidToUin?: Map<string, string> },\n): MilkyEvent<MessageRecallData> | null {\n const gray = msg.elements.find((el) => el.grayTipElement !== undefined)?.grayTipElement;\n const revoke = gray?.revokeElement;\n if (revoke === undefined) {\n return null;\n }\n const scene = chatTypeToScene(msg.chatType);\n const operatorUin = ctx.uidToUin?.get(revoke.operatorUid) ?? revoke.operatorUid;\n return {\n time: Math.floor(Number(msg.msgTime) / MS_TO_SEC),\n self_id: Number(ctx.selfUin),\n event_type: \"message_recall\",\n data: {\n message_scene: scene,\n peer_id: peerIdOf(msg, scene),\n message_seq: Number(msg.msgSeq),\n sender_id: Number(msg.senderUin),\n operator_id: Number(operatorUin) || 0,\n display_suffix: revoke.wording ?? \"\",\n },\n };\n}\n\n/** 群文件上传事件(群场景文件消息 → group_file_upload,替代 message_receive)。 */\nexport function toGroupFileUploadEvent(\n msg: RawMessage,\n selfUin: string,\n): MilkyEvent<GroupFileUploadData> | null {\n if (msg.chatType !== ChatType.GROUP) {\n return null;\n }\n const file = msg.elements.find((el) => el.fileElement !== undefined)?.fileElement;\n if (file === undefined) {\n return null;\n }\n return {\n time: Math.floor(Number(msg.msgTime) / MS_TO_SEC),\n self_id: Number(selfUin),\n event_type: \"group_file_upload\",\n data: {\n group_id: Number(msg.peerUid),\n user_id: Number(msg.senderUin) || 0,\n file_id: file.fileUuid ?? file.fileName ?? \"\",\n file_name: file.fileName ?? \"\",\n file_size: Number(file.fileSize ?? 0),\n },\n };\n}\n","/**\n * Milky 消息类动作(P0:send_private_message / send_group_message / get_message /\n * recall_private_message / recall_group_message;\n * P1 +3:get_history_messages / get_forwarded_messages / mark_message_as_read;\n * P2 批次一:forward 发送段组装链)\n *\n * 发送核心 sendMilkyMessage:OutgoingSegment → canonical(媒体 URI 异步落盘 +\n * at uin→uid + reply seq→msgId 原样兜底)→ MsgApi.sendMessage → 回查 msgSeq/time。\n * forward 段走专用组装链(sendForwardComposition,临时消息法,见 milky.md §0.6)。\n * get/recall 入口是 message_seq(Milky ID 模型),经 seqIndex 反查 msgId。\n * get_forwarded_messages 经 seqIndex 转发索引(resId → peer)定位。\n */\nimport type {\n CanonicalElement,\n GroupDetailInfo,\n GroupMember,\n Peer,\n RawMessage,\n} from \"@napuketto/kernel\";\nimport { ChatType, kernelError, toCanonicalElements } from \"@napuketto/kernel\";\nimport { type ZodType, z } from \"zod\";\nimport type { MilkyApi } from \"../api.js\";\nimport { toGroupEntity, toGroupMemberEntity } from \"../helper/entities.js\";\nimport { resolveMediaUri } from \"../helper/media-uri.js\";\nimport {\n canonicalToIncomingSegments,\n incomingForwardSegment,\n outgoingSegmentsToCanonical,\n} from \"../helper/segments.js\";\nimport { type ReceiveTranslateContext, toMessageReceiveEvent } from \"../helper/translate.js\";\nimport type {\n GetForwardedMessagesOutput,\n GetHistoryMessagesOutput,\n GetMessageOutput,\n IncomingForwardedMessage,\n IncomingMessage,\n IncomingSegment,\n MessageScene,\n OutgoingForwardedMessage,\n OutgoingSegment,\n SendMessageOutput,\n} from \"../types.js\";\nimport { MilkyApiAction } from \"./base-action.js\";\n\n/**\n * OutgoingSegment 宽松校验:入口只保证「{type, data}」形状,字段级转换在\n * outgoingSegmentsToCanonical 内做(未知段跳过 = 规范兼容性要求)。\n */\nconst outgoingSegmentSchema = z\n .object({ type: z.string(), data: z.record(z.string(), z.unknown()) })\n .loose() as unknown as ZodType<OutgoingSegment>;\n\nconst sendMessageFields = { message: z.array(outgoingSegmentSchema).min(1) } as const;\nconst recallFields = { message_seq: z.number().int().min(0) } as const;\n\n/** send_private_message:发送私聊消息。 */\nexport class SendPrivateMessageAction extends MilkyApiAction<\n { user_id: number; message: OutgoingSegment[] },\n SendMessageOutput\n> {\n readonly name = \"send_private_message\";\n readonly schema = z.object({ user_id: z.number().int().min(10001), ...sendMessageFields });\n\n protected async _handle(payload: {\n user_id: number;\n message: OutgoingSegment[];\n }): Promise<SendMessageOutput> {\n const peer = await this.api.resolvePeer(\"friend\", payload.user_id);\n return await sendMilkyMessage(peer, payload.message, this.api);\n }\n}\n\n/** send_group_message:发送群聊消息。 */\nexport class SendGroupMessageAction extends MilkyApiAction<\n { group_id: number; message: OutgoingSegment[] },\n SendMessageOutput\n> {\n readonly name = \"send_group_message\";\n readonly schema = z.object({ group_id: z.number().int().min(10001), ...sendMessageFields });\n\n protected async _handle(payload: {\n group_id: number;\n message: OutgoingSegment[];\n }): Promise<SendMessageOutput> {\n const peer = await this.api.resolvePeer(\"group\", payload.group_id);\n return await sendMilkyMessage(peer, payload.message, this.api);\n }\n}\n\n/** get_message:获取单条消息(seq → msgId 反查 + 实体回填)。 */\nexport class GetMessageAction extends MilkyApiAction<\n { message_scene: MessageScene; peer_id: number; message_seq: number },\n GetMessageOutput\n> {\n readonly name = \"get_message\";\n readonly schema = z.object({ ...peerMessageFields });\n\n protected async _handle(payload: {\n message_scene: MessageScene;\n peer_id: number;\n message_seq: number;\n }): Promise<GetMessageOutput> {\n const peer = await this.api.resolvePeer(payload.message_scene, payload.peer_id);\n const msgId = await this.api.resolveMsgIdBySeq(peer, payload.message_seq, peer.chatType);\n if (msgId === undefined) {\n throw kernelError(`消息 ${payload.message_seq} 不存在`, \"NOT_FOUND\");\n }\n const [msg] = await this.api.msgApi.fetchMsgsByMsgId(peer, [msgId]);\n if (msg === undefined) {\n throw kernelError(`消息 ${payload.message_seq} 不存在`, \"NOT_FOUND\");\n }\n return { message: await this.translateWithEntities(payload.message_scene, peer, msg) };\n }\n\n /** 实体回填(group 场景 schema 要求完整实体)→ IncomingMessage。 */\n private async translateWithEntities(\n scene: MessageScene,\n peer: Peer,\n msg: RawMessage,\n ): Promise<IncomingMessage> {\n const ctx: ReceiveTranslateContext = { selfUin: this.api.self.uin };\n if (scene === \"group\") {\n const [detail, member] = await Promise.all([\n this.api.groupCache?.getGroupDetail(peer.peerUid).catch(() => undefined),\n this.api.groupCache?.getMember(peer.peerUid, msg.senderUid).catch(() => undefined),\n ]);\n ctx.groupEntity = toGroupEntity(detail, peer.peerUid);\n ctx.groupMemberEntity = toGroupMemberEntity(member, peer.peerUid, msg.senderUin);\n }\n return toMessageReceiveEvent(msg, ctx).data;\n }\n}\n\n/** recall_private_message:撤回私聊消息。 */ export class RecallPrivateMessageAction extends MilkyApiAction<\n { user_id: number; message_seq: number },\n Record<string, never>\n> {\n readonly name = \"recall_private_message\";\n readonly schema = z.object({ user_id: z.number().int().min(10001), ...recallFields });\n\n protected async _handle(payload: {\n user_id: number;\n message_seq: number;\n }): Promise<Record<string, never>> {\n const peer = await this.api.resolvePeer(\"friend\", payload.user_id);\n await recallBySeq(peer, payload.message_seq, this.api);\n return {};\n }\n}\n\n/** recall_group_message:撤回群消息。 */\nexport class RecallGroupMessageAction extends MilkyApiAction<\n { group_id: number; message_seq: number },\n Record<string, never>\n> {\n readonly name = \"recall_group_message\";\n readonly schema = z.object({ group_id: z.number().int().min(10001), ...recallFields });\n\n protected async _handle(payload: {\n group_id: number;\n message_seq: number;\n }): Promise<Record<string, never>> {\n const peer = await this.api.resolvePeer(\"group\", payload.group_id);\n await recallBySeq(peer, payload.message_seq, this.api);\n return {};\n }\n}\n\n/** seq → msgId(反查)→ recallMessage。 */\nasync function recallBySeq(peer: Peer, seq: number, api: MilkyApi): Promise<void> {\n const msgId = await api.resolveMsgIdBySeq(peer, seq, peer.chatType);\n if (msgId === undefined) {\n throw kernelError(`消息 ${seq} 不存在`, \"NOT_FOUND\");\n }\n await api.msgApi.recallMessage(peer, [msgId]);\n}\n\n/** 发送核心:segments → canonical(URI/ID 转换)→ sendMessage → 回查输出。\n * forward 段分流到组装链(P2 批次一,临时消息法)。 */\nexport async function sendMilkyMessage(\n peer: Peer,\n segments: OutgoingSegment[],\n api: MilkyApi,\n): Promise<SendMessageOutput> {\n if (segments.some((s) => s.type === \"forward\")) {\n return await sendForwardComposition(peer, segments, api);\n }\n const { elements, atUins } = outgoingSegmentsToCanonical(segments);\n const resolved = await resolveElements(elements, atUins, api);\n if (resolved.length === 0) {\n throw kernelError(\"消息内容为空(全部消息段不可用)\", \"INVALID_PARAM\");\n }\n const { msgId } = await api.msgApi.sendMessage(peer, resolved);\n return await api.resolveSentOutput(peer, msgId);\n}\n\n/**\n * forward 段组装链(P2 批次一,milky.md §0.6):仅支持单 forward 单独发。\n * 临时消息法:逐条发送 messages[i].segments → sendForwardMessage(buildMultiForwardMsg\n * 以目标 peer 的真实消息组装 → sendMsg)→ best-effort 撤回临时消息 → 回查输出。\n *\n * 已知差异(规范语义 vs kernel 出口,待实机联调):节点发送者恒为机器人自己\n * (user_id / sender_name / time 不参与组装);title / preview / summary / prompt 忽略。\n */\nasync function sendForwardComposition(\n peer: Peer,\n segments: OutgoingSegment[],\n api: MilkyApi,\n): Promise<SendMessageOutput> {\n if (segments.length !== 1) {\n throw kernelError(\"forward 段必须单独发送(不支持与其他消息段混发)\", \"INVALID_PARAM\");\n }\n const [forward] = segments;\n if (forward === undefined || forward.type !== \"forward\") {\n throw kernelError(\"forward 组装链收到非 forward 段\", \"UNKNOWN\");\n }\n const messages = narrowForwardMessages(forward);\n const srcMsgIds: string[] = [];\n for (const [i, item] of messages.entries()) {\n const { elements, atUins } = outgoingSegmentsToCanonical(item.segments);\n const resolved = await resolveElements(elements, atUins, api);\n if (resolved.length === 0) {\n throw kernelError(`forward 第 ${i + 1} 条消息无可用内容段`, \"INVALID_PARAM\");\n }\n const { msgId } = await api.msgApi.sendMessage(peer, resolved);\n srcMsgIds.push(msgId);\n }\n const { msgId } = await api.msgApi.sendForwardMessage(peer, peer, srcMsgIds);\n await recallTempMessages(peer, srcMsgIds, api);\n return await api.resolveSentOutput(peer, msgId);\n}\n\n/**\n * forward 段载荷收窄(入口 schema 只保证 data 为 record):messages 非空数组,\n * 项内 segments 非空数组。user_id / sender_name / time 不参与组装不校验\n * (丢弃字段不设门槛);title / preview / summary / prompt 忽略。\n */\nfunction narrowForwardMessages(\n forward: Extract<OutgoingSegment, { type: \"forward\" }>,\n): OutgoingForwardedMessage[] {\n const raw = (forward.data as { messages?: unknown }).messages;\n if (!Array.isArray(raw) || raw.length === 0) {\n throw kernelError(\"forward 段 messages 必须是非空数组\", \"INVALID_PARAM\");\n }\n const out: OutgoingForwardedMessage[] = [];\n for (const item of raw) {\n if (typeof item !== \"object\" || item === null) {\n throw kernelError(\"forward 段 messages 项必须是对象\", \"INVALID_PARAM\");\n }\n const segments = (item as { segments?: unknown }).segments;\n if (!Array.isArray(segments) || segments.length === 0) {\n throw kernelError(\"forward 段 messages 项的 segments 必须是非空数组\", \"INVALID_PARAM\");\n }\n out.push(item as OutgoingForwardedMessage);\n }\n return out;\n}\n\n/** 临时消息清理(best-effort:失败只留可见垃圾,转发已发出——warn 可观测不抛)。 */\nasync function recallTempMessages(peer: Peer, msgIds: string[], api: MilkyApi): Promise<void> {\n try {\n await api.msgApi.recallMessage(peer, msgIds);\n } catch (e) {\n api.logger?.warn(\n {\n peer: peer.peerUid,\n count: msgIds.length,\n error: e instanceof Error ? e.message : String(e),\n },\n \"milky: forward 临时消息撤回失败(转发已发出)\",\n );\n }\n}\n\n/** 元素二次解析:at uin→uid + 远程媒体 URI 落盘(reply seq 已在映射层兜底原样)。 */\nasync function resolveElements(\n elements: CanonicalElement[],\n atUins: string[],\n api: MilkyApi,\n): Promise<CanonicalElement[]> {\n const uinToUid = await resolveAtUins(atUins, api);\n const out: CanonicalElement[] = [];\n for (const el of elements) {\n out.push(await resolveElement(el, uinToUid, api));\n }\n return out;\n}\n\n/** at uin→uid 批量转换(失败返回 undefined:at 原样 uin,交 QQ 端判断)。 */\nasync function resolveAtUins(\n atUins: string[],\n api: MilkyApi,\n): Promise<Map<string, string> | undefined> {\n if (atUins.length === 0) {\n return undefined;\n }\n try {\n return await api.uinToUid(atUins);\n } catch {\n return undefined;\n }\n}\n\n/** 单元素解析:at 目标替换 / 远程媒体 URI 落盘 / 其余原样。 */\nasync function resolveElement(\n el: CanonicalElement,\n uinToUid: Map<string, string> | undefined,\n api: MilkyApi,\n): Promise<CanonicalElement> {\n if (el.type === \"at\" && el.target !== \"all\") {\n return { ...el, target: uinToUid?.get(el.target) ?? el.target };\n }\n if (isRemoteMediaUri(el)) {\n const media = el as Extract<CanonicalElement, { type: \"image\" | \"voice\" | \"video\" }>;\n return { ...media, path: await resolveMediaUri(media.path, api.mediaDir) };\n }\n return el;\n}\n\n/** 远程媒体元素(image/voice/video 且 path 为需落盘的 URI)。 */\nfunction isRemoteMediaUri(el: CanonicalElement): boolean {\n return (\n (el.type === \"image\" || el.type === \"voice\" || el.type === \"video\") &&\n (el.path.startsWith(\"http://\") ||\n el.path.startsWith(\"https://\") ||\n el.path.startsWith(\"base64://\"))\n );\n}\n\n/** get_history_messages:获取历史消息(start seq 锚点 → 原生翻页 → 升序输出)。 */\nexport class GetHistoryMessagesAction extends MilkyApiAction<\n {\n message_scene: MessageScene;\n peer_id: number;\n start_message_seq?: number | null | undefined;\n limit?: number | null | undefined;\n },\n GetHistoryMessagesOutput\n> {\n readonly name = \"get_history_messages\";\n readonly schema = z.object({\n message_scene: z.enum([\"friend\", \"group\", \"temp\"]),\n peer_id: z.number().int().min(10001),\n start_message_seq: z.number().int().min(0).nullable().optional(),\n limit: z.number().int().min(0).nullable().optional(),\n });\n\n protected async _handle(payload: {\n message_scene: MessageScene;\n peer_id: number;\n start_message_seq?: number | null | undefined;\n limit?: number | null | undefined;\n }): Promise<GetHistoryMessagesOutput> {\n const limit = payload.limit ?? HISTORY_DEFAULT_LIMIT;\n const peer = await this.api.resolvePeer(payload.message_scene, payload.peer_id);\n const anchor = await this.resolveAnchor(peer, payload.start_message_seq);\n const msgs = await this.api.msgApi.fetchMessages(peer, {\n count: limit,\n ...(anchor !== undefined ? { msgId: anchor } : {}),\n });\n for (const m of msgs) {\n this.api.seqIndex.record(m);\n }\n // 群场景实体回填一次(群详情 + 整群成员表),避免逐消息回填\n const groupData =\n payload.message_scene === \"group\" ? await this.loadGroupData(peer.peerUid) : null;\n // 原生新→旧,规范要求 seq 升序 → 反转\n const ordered = [...msgs].reverse();\n const messages = ordered.map((m) =>\n this.translateHistoryMessage(m, peer.peerUid, groupData),\n );\n const hasMore = msgs.length >= limit;\n const oldest = ordered[0];\n return {\n messages,\n next_message_seq: hasMore && oldest !== undefined ? Number(oldest.msgSeq) : null,\n };\n }\n\n /** start_message_seq → 锚点 msgId(给了 seq 却反查不到 = NOT_FOUND)。 */\n private async resolveAnchor(\n peer: Peer,\n startSeq: number | null | undefined,\n ): Promise<string | undefined> {\n if (startSeq === undefined || startSeq === null) {\n return undefined;\n }\n const msgId = await this.api.resolveMsgIdBySeq(peer, startSeq, peer.chatType);\n if (msgId === undefined) {\n throw kernelError(`起始消息 ${startSeq} 不存在`, \"NOT_FOUND\");\n }\n return msgId;\n }\n\n /** 群场景回填数据(详情 + 成员表;缓存未装配返回空数据)。 */\n private async loadGroupData(\n groupCode: string,\n ): Promise<{ detail: GroupDetailInfo | undefined; members: Map<string, GroupMember> }> {\n if (this.api.groupCache === undefined) {\n return { detail: undefined, members: new Map() };\n }\n const [detail, members] = await Promise.all([\n this.api.groupCache.getGroupDetail(groupCode).catch(() => undefined),\n this.api.groupCache.getMembers(groupCode).catch(() => []),\n ]);\n const memberByUid = new Map<string, GroupMember>();\n for (const m of members) {\n memberByUid.set(m.uid, m);\n }\n return { detail, members: memberByUid };\n }\n\n /** 单条历史消息 → IncomingMessage(群场景注入实体,fail-soft)。 */\n private translateHistoryMessage(\n msg: RawMessage,\n peerUid: string,\n groupData: {\n detail: GroupDetailInfo | undefined;\n members: Map<string, GroupMember>;\n } | null,\n ): IncomingMessage {\n const ctx: ReceiveTranslateContext = { selfUin: this.api.self.uin };\n if (groupData !== null) {\n if (groupData.detail !== undefined) {\n ctx.groupEntity = toGroupEntity(groupData.detail, peerUid);\n }\n const member = groupData.members.get(msg.senderUid);\n if (member !== undefined) {\n ctx.groupMemberEntity = toGroupMemberEntity(member, peerUid, msg.senderUin);\n }\n }\n return toMessageReceiveEvent(msg, ctx).data;\n }\n}\n\n/** get_forwarded_messages:获取合并转发内容(resId → 转发索引 → fetchForwardMessage)。 */\nexport class GetForwardedMessagesAction extends MilkyApiAction<\n { forward_id: string },\n GetForwardedMessagesOutput\n> {\n readonly name = \"get_forwarded_messages\";\n readonly schema = z.object({ forward_id: z.string().min(1) });\n\n protected async _handle(payload: { forward_id: string }): Promise<GetForwardedMessagesOutput> {\n const entry = this.api.seqIndex.resolveForward(payload.forward_id);\n if (entry === undefined) {\n throw kernelError(`转发消息 ${payload.forward_id} 不存在(未登记)`, \"NOT_FOUND\");\n }\n const peer: Peer = { chatType: entry.chatType, peerUid: entry.peerUid };\n const msgs = await this.api.msgApi.fetchForwardMessage(peer, entry.msgId);\n for (const m of msgs) {\n this.api.seqIndex.record(m);\n }\n const uidToUin = await this.collectUidToUin(msgs);\n const messages: IncomingForwardedMessage[] = [];\n for (const m of msgs) {\n messages.push({\n message_seq: Number(m.msgSeq),\n sender_name: await this.senderNameOf(m),\n avatar_url: avatarUrlOf(m.senderUin),\n time: Math.floor(Number(m.msgTime) / 1000),\n segments: receiveSegmentsOf(m, uidToUin),\n });\n }\n return { messages };\n }\n\n /** at 段 uid → uin 批量转换(mention 翻译;失败退空 Map)。 */\n private async collectUidToUin(msgs: RawMessage[]): Promise<Map<string, string>> {\n const uids = new Set<string>();\n for (const m of msgs) {\n for (const el of toCanonicalElements(m)) {\n if (el.type === \"at\" && el.target !== \"all\") {\n uids.add((el as { target: string }).target);\n }\n }\n }\n if (uids.size === 0) {\n return new Map();\n }\n return await this.api.uidToUin([...uids]).catch(() => new Map<string, string>());\n }\n\n /** 发送者名(群场景成员缓存昵称/名片,失败退 uin 字符串)。 */\n private async senderNameOf(msg: RawMessage): Promise<string> {\n if (this.api.groupCache !== undefined && msg.chatType === ChatType.GROUP) {\n const member = await this.api.groupCache\n .getMember(msg.peerUid, msg.senderUid)\n .catch(() => undefined);\n const name =\n member?.cardName !== undefined && member.cardName !== \"\"\n ? member.cardName\n : member?.nick;\n if (name !== undefined && name !== \"\") {\n return name;\n }\n }\n return msg.senderUin;\n }\n}\n\n/** mark_message_as_read:标记会话已读(NT setMsgRead 以会话为粒度,seq 入参仅兼容 schema)。 */\nexport class MarkMessageAsReadAction extends MilkyApiAction<\n { message_scene: MessageScene; peer_id: number; message_seq: number },\n Record<string, never>\n> {\n readonly name = \"mark_message_as_read\";\n readonly schema = z.object({ ...peerMessageFields });\n\n protected async _handle(payload: {\n message_scene: MessageScene;\n peer_id: number;\n message_seq: number;\n }): Promise<Record<string, never>> {\n const peer = await this.api.resolvePeer(payload.message_scene, payload.peer_id);\n await this.api.msgApi.markRead(peer);\n return {};\n }\n}\n\n/** 历史消息默认条数(规范 default 20)。 */\nconst HISTORY_DEFAULT_LIMIT = 20;\n\n/** get_message / mark_message_as_read 共入参(场景 + 对端 + seq)。 */\nconst peerMessageFields = {\n message_scene: z.enum([\"friend\", \"group\", \"temp\"]),\n peer_id: z.number().int().min(10001),\n message_seq: z.number().int().min(0),\n} as const;\n\n/** 单条消息 → 接收段(canonical 映射 + forward 段注入,forward 不经 canonical)。 */\nfunction receiveSegmentsOf(msg: RawMessage, uidToUin: Map<string, string>): IncomingSegment[] {\n const segments = canonicalToIncomingSegments(toCanonicalElements(msg), {\n ...(uidToUin.size > 0 ? { uidToUin } : {}),\n });\n const fwd = msg.elements.find(\n (el) => el.multiForwardMsgElement !== undefined,\n )?.multiForwardMsgElement;\n if (fwd !== undefined) {\n segments.push(incomingForwardSegment(fwd.resId, fwd.fileName));\n }\n return segments;\n}\n\n/** QQ 头像 URL(公开头像服务,640px)。 */\nfunction avatarUrlOf(uin: string): string {\n return uin === \"\" ? \"\" : `https://q1.qlogo.cn/g?b=qq&nk=${uin}&s=640`;\n}\n","/**\n * Milky 资料类动作(P1):get_user_profile / get_friend_info / set_avatar /\n * set_nickname / set_bio / get_cookies / get_csrf_token\n *\n * set_avatar 的 uri 经 media-uri 解析(本地路径 / file:// 直用,http(s)/base64\n * 落盘 mediaDir);get_cookies 输出规范为单字符串(k=v 分号拼接);\n * get_csrf_token = qun.qq.com cookies 的 skey → bkn(OB11 get_csrf_token 同口径)。\n */\nimport { kernelError, TicketApi } from \"@napuketto/kernel\";\nimport { z } from \"zod\";\nimport { toFriendEntity } from \"../helper/entities.js\";\nimport { resolveMediaUri } from \"../helper/media-uri.js\";\nimport type {\n GetCookiesOutput,\n GetCSRFTokenOutput,\n GetFriendInfoOutput,\n GetUserProfileOutput,\n} from \"../types.js\";\nimport { MilkyApiAction } from \"./base-action.js\";\n\n/** CSRF 计算域名(bkn 口径,OB11 get_csrf_token 同源)。 */\nconst CSRF_DOMAIN = \"qun.qq.com\";\n\n/** get_user_profile:获取用户个人信息(陌生人信息 API;country/city/school 无源空兜底)。 */\nexport class GetUserProfileAction extends MilkyApiAction<\n { user_id: number },\n GetUserProfileOutput\n> {\n readonly name = \"get_user_profile\";\n readonly schema = z.object({ user_id: z.number().int().min(10001) });\n\n protected async _handle(payload: { user_id: number }): Promise<GetUserProfileOutput> {\n const info = await this.api.profileApi.getStrangerInfo(String(payload.user_id));\n return {\n nickname: info.nickname,\n qid: info.qid,\n age: info.age,\n sex: info.sex,\n remark: info.remark,\n bio: info.long_nick,\n level: info.qq_level,\n country: \"\",\n city: \"\",\n school: \"\",\n };\n }\n}\n\n/** get_friend_info:获取好友信息(好友列表单查)。 */\nexport class GetFriendInfoAction extends MilkyApiAction<\n { user_id: number; no_cache?: boolean | null | undefined },\n GetFriendInfoOutput\n> {\n readonly name = \"get_friend_info\";\n readonly schema = z.object({\n user_id: z.number().int().min(10001),\n no_cache: z.boolean().nullable().optional(),\n });\n\n protected async _handle(payload: {\n user_id: number;\n no_cache?: boolean | null | undefined;\n }): Promise<GetFriendInfoOutput> {\n const uin = String(payload.user_id);\n const friend = (await this.api.friendApi.getFriendList()).find((f) => f.uin === uin);\n if (friend === undefined) {\n throw kernelError(`好友 ${uin} 不存在`, \"NOT_FOUND\");\n }\n return { friend: toFriendEntity(friend, friend.uin, friend.nickname) };\n }\n}\n\n/** set_avatar:设置头像(uri → 本地路径)。 */\nexport class SetAvatarAction extends MilkyApiAction<{ uri: string }, Record<string, never>> {\n readonly name = \"set_avatar\";\n readonly schema = z.object({ uri: z.string().min(1) });\n\n protected async _handle(payload: { uri: string }): Promise<Record<string, never>> {\n const path = await resolveMediaUri(payload.uri, this.api.mediaDir);\n await this.api.profileApi.setHeader(path);\n return {};\n }\n}\n\n/** set_nickname:设置昵称。 */\nexport class SetNicknameAction extends MilkyApiAction<\n { new_nickname: string },\n Record<string, never>\n> {\n readonly name = \"set_nickname\";\n readonly schema = z.object({ new_nickname: z.string() });\n\n protected async _handle(payload: { new_nickname: string }): Promise<Record<string, never>> {\n await this.api.profileApi.setNickName(payload.new_nickname);\n return {};\n }\n}\n\n/** set_bio:设置个性签名。 */\nexport class SetBioAction extends MilkyApiAction<{ new_bio: string }, Record<string, never>> {\n readonly name = \"set_bio\";\n readonly schema = z.object({ new_bio: z.string() });\n\n protected async _handle(payload: { new_bio: string }): Promise<Record<string, never>> {\n await this.api.profileApi.setLongNick(payload.new_bio);\n return {};\n }\n}\n\n/** get_cookies:获取 cookies(规范输出为 k=v 分号拼接字符串)。 */\nexport class GetCookiesAction extends MilkyApiAction<{ domain: string }, GetCookiesOutput> {\n readonly name = \"get_cookies\";\n readonly schema = z.object({ domain: z.string().min(1) });\n\n protected async _handle(payload: { domain: string }): Promise<GetCookiesOutput> {\n const cookies = await this.api.ticketApi.getCookies(payload.domain, this.api.self.uin);\n return {\n cookies: Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \"),\n };\n }\n}\n\n/** get_csrf_token:bkn(qun.qq.com skey 派生,OB11 get_csrf_token 同口径)。 */\nexport class GetCSRFTokenAction extends MilkyApiAction<Record<string, never>, GetCSRFTokenOutput> {\n readonly name = \"get_csrf_token\";\n readonly schema = z.object({}).strict();\n\n protected async _handle(): Promise<GetCSRFTokenOutput> {\n const cookies = await this.api.ticketApi.getCookies(CSRF_DOMAIN, this.api.self.uin);\n return { csrf_token: TicketApi.getBkn(cookies[\"skey\"] ?? \"\") };\n }\n}\n","/**\n * Milky 社交类动作(P0:get_friend_list / get_group_list;\n * P1 +5:send_profile_like / delete_friend / get_friend_requests /\n * accept_friend_request / reject_friend_request)\n */\n\nimport { z } from \"zod\";\nimport { findBuddyReq } from \"../api.js\";\nimport { groupListToEntity, toFriendEntity } from \"../helper/entities.js\";\nimport type {\n FriendRequestEntity,\n GetFriendListOutput,\n GetFriendRequestsOutput,\n GetGroupListOutput,\n} from \"../types.js\";\nimport { MilkyApiAction } from \"./base-action.js\";\n\nconst emptySchema = z.object({}).strict();\n\n/** get_friend_list:获取好友列表。 */\nexport class GetFriendListAction extends MilkyApiAction<\n Record<string, never>,\n GetFriendListOutput\n> {\n readonly name = \"get_friend_list\";\n readonly schema = emptySchema;\n\n protected async _handle(): Promise<GetFriendListOutput> {\n const friends = await this.api.friendApi.getFriendList();\n return {\n friends: friends.map((f) => toFriendEntity(f, f.uin, f.nickname)),\n };\n }\n}\n\n/** get_group_list:获取群列表。\n * 实测校准(2026-08-08,OB11 同款):原生 getGroupList 返回值无数据,列表经\n * onGroupListUpdate 事件进 GroupCache——缓存优先,为空触发刷新回填。\n */\nexport class GetGroupListAction extends MilkyApiAction<Record<string, never>, GetGroupListOutput> {\n readonly name = \"get_group_list\";\n readonly schema = emptySchema;\n\n protected async _handle(): Promise<GetGroupListOutput> {\n const groups =\n this.api.groupCache !== undefined\n ? await this.api.groupCache.listGroupsRefreshed()\n : await this.api.groupApi.getGroupList(true);\n return { groups: groups.map(groupListToEntity) };\n }\n}\n\n/** send_profile_like:发送好友赞(count 缺省 1,规范 default 同值)。 */\nexport class SendProfileLikeAction extends MilkyApiAction<\n { user_id: number; count?: number | null | undefined },\n Record<string, never>\n> {\n readonly name = \"send_profile_like\";\n readonly schema = z.object({\n user_id: z.number().int().min(10001),\n count: z.number().int().min(0).nullable().optional(),\n });\n\n protected async _handle(payload: {\n user_id: number;\n count?: number | null | undefined;\n }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n await this.api.profileLikeApi.sendLike(uid, payload.count ?? 1);\n return {};\n }\n}\n\n/** delete_friend:删除好友。 */\nexport class DeleteFriendAction extends MilkyApiAction<{ user_id: number }, Record<string, never>> {\n readonly name = \"delete_friend\";\n readonly schema = z.object({ user_id: z.number().int().min(10001) });\n\n protected async _handle(payload: { user_id: number }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n await this.api.friendApi.deleteFriend(uid);\n return {};\n }\n}\n\n/**\n * get_friend_requests:获取好友请求列表。\n * kernel getBuddyReqList 无过滤/数量参数——is_filtered 入参仅作 schema 兼容\n * (全量返回);state 无源字段恒 pending(真实状态待探测校准)。\n */\nexport class GetFriendRequestsAction extends MilkyApiAction<\n { limit?: number | null | undefined; is_filtered?: boolean | null | undefined },\n GetFriendRequestsOutput\n> {\n readonly name = \"get_friend_requests\";\n readonly schema = z.object({\n limit: z.number().int().min(0).nullable().optional(),\n is_filtered: z.boolean().nullable().optional(),\n });\n\n protected async _handle(payload: {\n limit?: number | null | undefined;\n is_filtered?: boolean | null | undefined;\n }): Promise<GetFriendRequestsOutput> {\n const reqs = await this.api.friendApi.getBuddyReqList();\n // 发起者 uid → uin 批量转换(initiator_id 需要 uin;失败 0 兜底)\n let uidToUin = new Map<string, string>();\n if (reqs.length > 0) {\n uidToUin = await this.api\n .uidToUin(reqs.map((req) => req.friendUid))\n .catch(() => new Map<string, string>());\n }\n const requests: FriendRequestEntity[] = reqs.map((req) => ({\n time: Number(req.reqTime) || 0,\n initiator_id: Number(uidToUin.get(req.friendUid)) || 0,\n initiator_uid: req.friendUid,\n target_user_id: Number(this.api.self.uin),\n target_user_uid: this.api.self.uid ?? \"\",\n state: \"pending\",\n comment: typeof req[\"words\"] === \"string\" ? (req[\"words\"] as string) : \"\",\n via: req.sourceName ?? \"\",\n is_filtered: false,\n }));\n const limit = payload.limit ?? requests.length;\n return { requests: requests.slice(0, limit) };\n }\n}\n\n/**\n * accept/reject_friend_request 公共基类:initiator_uid → 查申请 → 应答。\n * kernel handleFriendRequest 无 reason 参数(拒绝理由无源,入参仅 schema 兼容)。\n */\nabstract class HandleFriendRequestBase extends MilkyApiAction<\n {\n initiator_uid: string;\n is_filtered?: boolean | null | undefined;\n reason?: string | null | undefined;\n },\n Record<string, never>\n> {\n readonly schema = z.object({\n initiator_uid: z.string().min(1),\n is_filtered: z.boolean().nullable().optional(),\n reason: z.string().nullable().optional(),\n });\n\n /** accept=true 同意 / false 拒绝。 */\n protected abstract readonly accept: boolean;\n\n protected async _handle(payload: {\n initiator_uid: string;\n is_filtered?: boolean | null | undefined;\n reason?: string | null | undefined;\n }): Promise<Record<string, never>> {\n const notify = await findBuddyReq(this.api, payload.initiator_uid);\n await this.api.friendApi.handleFriendRequest(notify, this.accept);\n return {};\n }\n}\n\n/** accept_friend_request:同意好友申请。 */\nexport class AcceptFriendRequestAction extends HandleFriendRequestBase {\n readonly name = \"accept_friend_request\";\n protected readonly accept = true;\n}\n\n/** reject_friend_request:拒绝好友申请。 */\nexport class RejectFriendRequestAction extends HandleFriendRequestBase {\n readonly name = \"reject_friend_request\";\n protected readonly accept = false;\n}\n","/**\n * Milky 系统类动作(P0):get_login_info / get_impl_info\n *\n * get_impl_info 是 Milky 的版本协商面(规范 §compatibility):milky_version\n * 固定 \"1.3\"(目标协议版本 1.3.0),qq_protocol_type 固定 windows(自建宿主)。\n */\nimport { z } from \"zod\";\nimport type { GetImplInfoOutput, GetLoginInfoOutput } from \"../types.js\";\nimport { MilkyApiAction } from \"./base-action.js\";\n\n/** Milky 协议版本(docs/protocols/milky.md:目标 1.3.0)。 */\nconst MILKY_VERSION = \"1.3\";\n\nconst emptySchema = z.object({}).strict();\n\n/** get_login_info:获取登录信息。 */\nexport class GetLoginInfoAction extends MilkyApiAction<Record<string, never>, GetLoginInfoOutput> {\n readonly name = \"get_login_info\";\n readonly schema = emptySchema;\n\n protected async _handle(): Promise<GetLoginInfoOutput> {\n return { uin: Number(this.api.self.uin), nickname: this.api.self.nickname };\n }\n}\n\n/** get_impl_info:获取协议端信息(版本协商)。 */\nexport class GetImplInfoAction extends MilkyApiAction<Record<string, never>, GetImplInfoOutput> {\n readonly name = \"get_impl_info\";\n readonly schema = emptySchema;\n\n protected async _handle(): Promise<GetImplInfoOutput> {\n return {\n impl_name: \"napukettoqq\",\n impl_version: this.api.implVersion,\n qq_protocol_version: this.api.qqVersion,\n qq_protocol_type: \"windows\",\n milky_version: MILKY_VERSION,\n };\n }\n}\n","/**\n * Milky 动作注册表(P0 9 个 + P1 40 个 = 49 个)\n *\n * P0 面 = docs/protocols/milky.md §9 P0 清单;P1 面 = §9 P1 清单(群管/精华/\n * 群文件/好友操作/票据/历史与转发)。延后项(nudge 发送 / rename_folder /\n * download_url / resource 反查 / 置顶 / 公告 / 上传)见 milky.md §6。\n */\nimport { ActionRegistry } from \"../../core/index.js\";\nimport type { MilkyApi } from \"../api.js\";\nimport type { MilkyAction } from \"./base-action.js\";\nimport {\n AcceptGroupInvitationAction,\n AcceptGroupRequestAction,\n GetGroupEssenceMessagesAction,\n GetGroupInfoAction,\n GetGroupMemberInfoAction,\n GetGroupMemberListAction,\n GetGroupNotificationsAction,\n KickGroupMemberAction,\n QuitGroupAction,\n RejectGroupInvitationAction,\n RejectGroupRequestAction,\n SendGroupMessageReactionAction,\n SetGroupEssenceMessageAction,\n SetGroupMemberAdminAction,\n SetGroupMemberCardAction,\n SetGroupMemberMuteAction,\n SetGroupNameAction,\n SetGroupWholeMuteAction,\n} from \"./group.js\";\nimport {\n CreateGroupFolderAction,\n DeleteGroupFileAction,\n DeleteGroupFolderAction,\n GetGroupFilesAction,\n MoveGroupFileAction,\n PersistGroupFileAction,\n RenameGroupFileAction,\n} from \"./group-file.js\";\nimport {\n GetForwardedMessagesAction,\n GetHistoryMessagesAction,\n GetMessageAction,\n MarkMessageAsReadAction,\n RecallGroupMessageAction,\n RecallPrivateMessageAction,\n SendGroupMessageAction,\n SendPrivateMessageAction,\n} from \"./message.js\";\nimport {\n GetCookiesAction,\n GetCSRFTokenAction,\n GetFriendInfoAction,\n GetUserProfileAction,\n SetAvatarAction,\n SetBioAction,\n SetNicknameAction,\n} from \"./profile.js\";\nimport {\n AcceptFriendRequestAction,\n DeleteFriendAction,\n GetFriendListAction,\n GetFriendRequestsAction,\n GetGroupListAction,\n RejectFriendRequestAction,\n SendProfileLikeAction,\n} from \"./social.js\";\nimport { GetImplInfoAction, GetLoginInfoAction } from \"./system.js\";\n\n/** Milky 动作注册表(P0+P1 49 动作)。 */\nexport function createMilkyActionRegistry(opts: {\n api: MilkyApi;\n}): ActionRegistry<MilkyAction<unknown, unknown>> {\n const registry = new ActionRegistry<MilkyAction<unknown, unknown>>();\n const { api } = opts;\n // P0\n registry.register(new GetLoginInfoAction(api));\n registry.register(new GetImplInfoAction(api));\n registry.register(new SendPrivateMessageAction(api));\n registry.register(new SendGroupMessageAction(api));\n registry.register(new GetMessageAction(api));\n registry.register(new RecallPrivateMessageAction(api));\n registry.register(new RecallGroupMessageAction(api));\n registry.register(new GetFriendListAction(api));\n registry.register(new GetGroupListAction(api));\n // P1 资料/票据\n registry.register(new GetUserProfileAction(api));\n registry.register(new GetFriendInfoAction(api));\n registry.register(new SetAvatarAction(api));\n registry.register(new SetNicknameAction(api));\n registry.register(new SetBioAction(api));\n registry.register(new GetCookiesAction(api));\n registry.register(new GetCSRFTokenAction(api));\n // P1 好友\n registry.register(new SendProfileLikeAction(api));\n registry.register(new DeleteFriendAction(api));\n registry.register(new GetFriendRequestsAction(api));\n registry.register(new AcceptFriendRequestAction(api));\n registry.register(new RejectFriendRequestAction(api));\n // P1 消息\n registry.register(new GetHistoryMessagesAction(api));\n registry.register(new GetForwardedMessagesAction(api));\n registry.register(new MarkMessageAsReadAction(api));\n // P1 群\n registry.register(new GetGroupInfoAction(api));\n registry.register(new GetGroupMemberListAction(api));\n registry.register(new GetGroupMemberInfoAction(api));\n registry.register(new SetGroupNameAction(api));\n registry.register(new SetGroupMemberCardAction(api));\n registry.register(new SetGroupMemberAdminAction(api));\n registry.register(new SetGroupMemberMuteAction(api));\n registry.register(new SetGroupWholeMuteAction(api));\n registry.register(new KickGroupMemberAction(api));\n registry.register(new QuitGroupAction(api));\n registry.register(new GetGroupEssenceMessagesAction(api));\n registry.register(new SetGroupEssenceMessageAction(api));\n registry.register(new SendGroupMessageReactionAction(api));\n registry.register(new GetGroupNotificationsAction(api));\n registry.register(new AcceptGroupRequestAction(api));\n registry.register(new RejectGroupRequestAction(api));\n registry.register(new AcceptGroupInvitationAction(api));\n registry.register(new RejectGroupInvitationAction(api));\n // P1 群文件\n registry.register(new GetGroupFilesAction(api));\n registry.register(new MoveGroupFileAction(api));\n registry.register(new RenameGroupFileAction(api));\n registry.register(new DeleteGroupFileAction(api));\n registry.register(new PersistGroupFileAction(api));\n registry.register(new CreateGroupFolderAction(api));\n registry.register(new DeleteGroupFolderAction(api));\n return registry;\n}\n","/**\n * Milky notice 事件翻译(grayTip 系,P1 2026-10-30)\n *\n * NT QQ 中群成员变动/禁言/戳一戳等系统事件通过消息的灰色提示元素(grayTip)\n * 广播。本模块把 RawMessage 里的 grayTip 翻译为 Milky notice 事件(纯函数,\n * ADR-008),判据与 OB11 helper/notice.ts 同源(同一 wrapper 事实):\n * - group_member_increase / group_member_decrease(subType=GROUP + type MEMBER_ADD/QUIT)\n * - group_mute / group_whole_mute(SHUT_UP;member uid 空 = 全员禁言口径)\n * - group_nudge / friend_nudge(aioOpGrayTipElement;形状待真实事件校准,\n * best-effort + raw 校准日志,与 OB11 poke 同口径)\n * - group_name_change / group_disband(GROUP_NAME_MODIFIED / DISBANDED;操作者\n * uid 不可得时不产出事件,避免违反 schema operator_id 下限)\n *\n * user_id / operator_id 都是 uin:接收 uidToUin Map(调用方批量转换后传入)。\n * 未知/未翻译的 grayTip 子类型打 raw JSON 日志(为后续真实事件校准积累数据)。\n */\nimport type { RawMessage } from \"@napuketto/kernel\";\nimport {\n ChatType,\n type GrayTipElement,\n GrayTipSubType,\n type TipGroupElement,\n TipGroupElementType,\n} from \"@napuketto/kernel\";\nimport { firstUntranslatedGrayTip } from \"../../core/gray-tip.js\";\nimport { resolveUin } from \"../../core/uid-uin.js\";\nimport type {\n FriendNudgeData,\n GroupDisbandData,\n GroupMemberDecreaseData,\n GroupMemberIncreaseData,\n GroupMuteData,\n GroupNameChangeData,\n GroupNudgeData,\n GroupWholeMuteData,\n MilkyEvent,\n} from \"../types.js\";\n\n/** 毫秒 → 秒(Unix 时间戳)。 */\nconst MS_TO_SEC = 1000;\n\n/** grayTip 翻译上下文(uid→uin 映射,调用方批量转换)。 */\nexport interface NoticeTranslateContext {\n selfUin: string;\n uidToUin: Map<string, string>;\n /** 校准日志(可选:未知子类型 / aioOp raw JSON;缺省静默)。 */\n logger?: { warn(obj: unknown, msg?: string): void };\n}\n\n/** uid → uin(core 共享解析;ctx 携带映射)。 */\nfunction toUin(uid: string | undefined, ctx: NoticeTranslateContext): number {\n return resolveUin(uid, ctx.uidToUin);\n}\n\n/** 事件信封公共字段。 */\nfunction envelope<T>(\n msg: RawMessage,\n ctx: NoticeTranslateContext,\n eventType: string,\n data: T,\n): MilkyEvent<T> {\n return {\n time: Math.floor(Number(msg.msgTime) / MS_TO_SEC),\n self_id: Number(ctx.selfUin),\n event_type: eventType,\n data,\n };\n}\n\n/** 单个 grayTip → Milky notice 事件(null = 不可翻译)。 */\nfunction translateGrayTip(\n msg: RawMessage,\n g: GrayTipElement,\n ctx: NoticeTranslateContext,\n): MilkyEvent | null {\n // aioOp 优先于子类型判定:群戳一戳载荷挂 GROUP 子类型(归属未实证,\n // 与 OB11 poke 同口径——按元素存在性识别)\n if (g.aioOpGrayTipElement !== undefined) {\n return aioOpToEvent(msg, g, ctx);\n }\n if (g.subElementType === GrayTipSubType.GROUP) {\n return groupElementToEvent(msg, g.groupElement, ctx);\n }\n return null;\n}\n\n/** TipGroupElement → 群成员变动 / 禁言 / 改名 / 解散事件(按类型分发的映射表键)。 */\ninterface GroupChangeCommon {\n groupId: number;\n memberUid: string;\n adminUid: string;\n}\n\n/** 群成员变动类映射器表(键 = TipGroupElementType;缺项 = 不可翻译返回 null)。 */\nconst GROUP_CHANGE_MAPPERS: Partial<\n Record<\n TipGroupElementType,\n (\n msg: RawMessage,\n common: GroupChangeCommon,\n grp: TipGroupElement,\n ctx: NoticeTranslateContext,\n ) => MilkyEvent | null\n >\n> = {\n [TipGroupElementType.MEMBER_ADD]: toMemberIncrease,\n [TipGroupElementType.QUIT]: toMemberDecrease,\n [TipGroupElementType.SHUT_UP]: toShutUpEvent,\n [TipGroupElementType.GROUP_NAME_MODIFIED]: toNameChange,\n [TipGroupElementType.DISBANDED]: toDisband,\n};\n\nfunction groupElementToEvent(\n msg: RawMessage,\n grp: TipGroupElement | undefined,\n ctx: NoticeTranslateContext,\n): MilkyEvent | null {\n if (grp === undefined || grp.type === undefined) {\n return null;\n }\n const mapper = GROUP_CHANGE_MAPPERS[grp.type];\n if (mapper === undefined) {\n return null;\n }\n return mapper(msg, groupChangeCommon(grp, Number(msg.peerUid)), grp, ctx);\n}\n\n/** 禁言载荷优先(shutUp.member/admin 覆盖顶层 memberUid/adminUid)。 */\nfunction groupChangeCommon(grp: TipGroupElement, groupId: number): GroupChangeCommon {\n return {\n groupId,\n memberUid: grp.shutUp?.member?.uid ?? grp.memberUid ?? \"\",\n adminUid: grp.shutUp?.admin?.uid ?? grp.adminUid ?? \"\",\n };\n}\n\n/** 群成员增加(管理员同意 → operator_id;邀请入群 → invitor_id)。 */\nfunction toMemberIncrease(\n msg: RawMessage,\n common: GroupChangeCommon,\n _grp: TipGroupElement,\n ctx: NoticeTranslateContext,\n): MilkyEvent {\n const { groupId, memberUid, adminUid } = common;\n const data: GroupMemberIncreaseData = {\n group_id: groupId,\n user_id: toUin(memberUid, ctx),\n operator_id: adminUid !== \"\" && adminUid === memberUid ? toUin(adminUid, ctx) : null,\n invitor_id: adminUid !== \"\" && adminUid !== memberUid ? toUin(adminUid, ctx) : null,\n };\n return envelope(msg, ctx, \"group_member_increase\", data);\n}\n\n/** 群成员减少(操作者与本人不同 = 被踢;主动退群无操作者)。 */\nfunction toMemberDecrease(\n msg: RawMessage,\n common: GroupChangeCommon,\n _grp: TipGroupElement,\n ctx: NoticeTranslateContext,\n): MilkyEvent {\n const { groupId, memberUid, adminUid } = common;\n const data: GroupMemberDecreaseData = {\n group_id: groupId,\n user_id: toUin(memberUid, ctx),\n operator_id: adminUid !== \"\" && adminUid !== memberUid ? toUin(adminUid, ctx) : null,\n };\n return envelope(msg, ctx, \"group_member_decrease\", data);\n}\n\n/** 禁言(member 空 = 全员禁言口径;is_mute = 是否处于禁言态)。 */\nfunction toShutUpEvent(\n msg: RawMessage,\n common: GroupChangeCommon,\n grp: TipGroupElement,\n ctx: NoticeTranslateContext,\n): MilkyEvent {\n const { groupId, memberUid, adminUid } = common;\n const duration = Number(grp.shutUp?.duration ?? 0);\n if (memberUid === \"\") {\n const data: GroupWholeMuteData = {\n group_id: groupId,\n operator_id: toUin(adminUid, ctx),\n is_mute: duration > 0,\n };\n return envelope(msg, ctx, \"group_whole_mute\", data);\n }\n const data: GroupMuteData = {\n group_id: groupId,\n user_id: toUin(memberUid, ctx),\n operator_id: toUin(adminUid, ctx),\n duration,\n };\n return envelope(msg, ctx, \"group_mute\", data);\n}\n\n/** 改名 / 解散公共守卫:操作者 uid 不可得时不产出(schema operator_id 下限)。 */\nfunction operatorOf(common: GroupChangeCommon): string {\n return common.adminUid !== \"\" ? common.adminUid : common.memberUid;\n}\n\nfunction toNameChange(\n msg: RawMessage,\n common: GroupChangeCommon,\n grp: TipGroupElement,\n ctx: NoticeTranslateContext,\n): MilkyEvent | null {\n const operatorUid = operatorOf(common);\n if (operatorUid === \"\") {\n return null;\n }\n const data: GroupNameChangeData = {\n group_id: common.groupId,\n new_group_name: grp.groupName ?? \"\",\n operator_id: toUin(operatorUid, ctx),\n };\n return envelope(msg, ctx, \"group_name_change\", data);\n}\n\nfunction toDisband(\n msg: RawMessage,\n common: GroupChangeCommon,\n _grp: TipGroupElement,\n ctx: NoticeTranslateContext,\n): MilkyEvent | null {\n const operatorUid = operatorOf(common);\n if (operatorUid === \"\") {\n return null;\n }\n const data: GroupDisbandData = {\n group_id: common.groupId,\n operator_id: toUin(operatorUid, ctx),\n };\n return envelope(msg, ctx, \"group_disband\", data);\n}\n\n/**\n * aioOp → 戳一戳事件(friend_nudge / group_nudge)。\n * aioOp 载荷完整字段形状未经实测(已证字段仅 operateType/peerUid):\n * sender 取消息发送者、receiver 取 aioOp.peerUid(口径与 OB11 poke 一致,待校准);\n * display_* 字段无来源,恒空串;始终打 raw 日志积累校准数据。\n */\nfunction aioOpToEvent(msg: RawMessage, g: GrayTipElement, ctx: NoticeTranslateContext): MilkyEvent {\n const aioOp = g.aioOpGrayTipElement;\n ctx.logger?.warn(\n { raw: JSON.stringify(g)?.slice(0, 2000) },\n \"milky: aioOp grayTip raw(戳一戳待真实事件校准)\",\n );\n if (msg.chatType === ChatType.GROUP) {\n const data: GroupNudgeData = {\n group_id: Number(msg.peerUid),\n sender_id: toUin(msg.senderUid, ctx),\n receiver_id: toUin(aioOp?.peerUid ?? \"\", ctx),\n display_action: \"\",\n display_suffix: \"\",\n display_action_img_url: \"\",\n };\n return envelope(msg, ctx, \"group_nudge\", data);\n }\n const senderUin = toUin(msg.senderUid, ctx);\n const data: FriendNudgeData = {\n user_id: senderUin,\n is_self_send: senderUin === Number(ctx.selfUin),\n is_self_receive: senderUin !== Number(ctx.selfUin),\n display_action: \"\",\n display_suffix: \"\",\n display_action_img_url: \"\",\n };\n return envelope(msg, ctx, \"friend_nudge\", data);\n}\n\n/**\n * RawMessage → Milky notice 事件(无 grayTip / 不可翻译返回 null)。\n * 未知子类型打 raw JSON 日志(JSON/BUDDY/ESSENCE/FILE 等——校准数据积累入口)。\n */\nexport function toMilkyNoticeEvent(\n msg: RawMessage,\n ctx: NoticeTranslateContext,\n): MilkyEvent | null {\n for (const el of msg.elements) {\n const g = el.grayTipElement;\n if (g === undefined) {\n continue;\n }\n const event = translateGrayTip(msg, g, ctx);\n if (event !== null) {\n return event;\n }\n }\n const untranslated = firstUntranslatedGrayTip(msg);\n if (untranslated !== undefined) {\n ctx.logger?.warn(\n {\n subType: untranslated.subElementType,\n raw: JSON.stringify(untranslated)?.slice(0, 2000),\n },\n \"milky: 未翻译的 grayTip 子类型(raw 校准数据)\",\n );\n }\n return null;\n}\n","/**\n * MessageSeqIndex:message_seq ↔ msgId 双向映射(docs/protocols/milky.md §5 方案二)\n *\n * Milky 对外用会话内 message_seq(kernel RawMessage.msgSeq),NT 撤回/取消息入口\n * 是 msgId——两套 ID 空间都要用,这层跳不掉。接收链路 record(双向写入),\n * 动作侧 resolveMsgId 反查;反查不到由动作做历史扫描兜底(fetchMessages 近段匹配)。\n *\n * 容量封顶(FIFO 淘汰,Map 插入序 = 时间序):映射只服务近期消息操作\n * (撤回 2 分钟窗口 / get_message 最近引用),不做全量持久索引。\n */\nimport type { ChatType, RawMessage } from \"@napuketto/kernel\";\n\n/** 单方向最大条目数(测试用例引用容量语义)。 */\nexport const MAX_ENTRIES = 4096;\n\n/** msgId → seq 元信息(collectReplyMeta 回填用)。 */\ninterface SeqMeta {\n seq: number;\n senderUin: string;\n timeSec: number;\n}\n\n/** 合并转发 resId → 定位信息(get_forwarded_messages 取 peer 用)。 */\nexport interface ForwardEntry {\n chatType: ChatType;\n peerUid: string;\n msgId: string;\n}\n\nexport class MessageSeqIndex {\n /** `${chatType}:${peerUid}:${seq}` → msgId。 */\n private readonly seqToMsg = new Map<string, string>();\n /** msgId → seq 元信息。 */\n private readonly msgToMeta = new Map<string, SeqMeta>();\n /** 合并转发 resId → 定位信息(P1:get_forwarded_messages)。 */\n private readonly forwards = new Map<string, ForwardEntry>();\n\n /** 接收链路登记(一条消息双向写入;重复 msgId 覆盖)。 */\n record(msg: RawMessage): void {\n const seq = Number(msg.msgSeq);\n if (!Number.isFinite(seq) || seq < 0) {\n return;\n }\n this.seqToMsg.set(this.key(msg.chatType, msg.peerUid, seq), msg.msgId);\n this.msgToMeta.set(msg.msgId, {\n seq,\n senderUin: msg.senderUin,\n timeSec: Math.floor(Number(msg.msgTime) / 1000),\n });\n this.evict();\n }\n\n /** seq → msgId(反查;未登记返回 undefined)。 */\n resolveMsgId(chatType: ChatType, peerUid: string, seq: number): string | undefined {\n return this.seqToMsg.get(this.key(chatType, peerUid, seq));\n }\n\n /**\n * 批量回填 reply 引用元信息(msgId → Milky reply 段 data 所需三元组)。\n * 未命中的 id 不进表(翻译层按 0 兜底)。\n */\n collectReplyMeta(\n msgIds: string[],\n ): Map<string, { messageSeq: number; senderId: number; time: number }> {\n const out = new Map<string, { messageSeq: number; senderId: number; time: number }>();\n for (const id of msgIds) {\n const m = this.msgToMeta.get(id);\n if (m !== undefined) {\n out.set(id, {\n messageSeq: m.seq,\n senderId: Number(m.senderUin) || 0,\n time: m.timeSec,\n });\n }\n }\n return out;\n }\n\n /** key 规则(chatType 数值 + peerUid + seq;peerUid 群聊=群号,C2C=uid)。 */\n private key(chatType: ChatType, peerUid: string, seq: number): string {\n return `${chatType}:${peerUid}:${seq}`;\n }\n\n /**\n * 登记合并转发(接收链路:消息含 multiForwardMsgElement 时调用)。\n * resId 是 Milky forward_id 的来源;同一 resId 重复覆盖。\n */\n recordForward(resId: string, entry: ForwardEntry): void {\n if (resId === \"\") {\n return;\n }\n this.forwards.set(resId, entry);\n while (this.forwards.size > MAX_ENTRIES) {\n const oldest = this.forwards.keys().next().value;\n if (oldest === undefined) {\n break;\n }\n this.forwards.delete(oldest);\n }\n }\n\n /** resId → 转发定位(get_forwarded_messages;未登记返回 undefined)。 */\n resolveForward(resId: string): ForwardEntry | undefined {\n return this.forwards.get(resId);\n }\n\n /** FIFO 淘汰到容量上限内。 */\n private evict(): void {\n while (this.seqToMsg.size > MAX_ENTRIES) {\n const oldest = this.seqToMsg.keys().next().value;\n if (oldest === undefined) {\n break;\n }\n this.seqToMsg.delete(oldest);\n }\n while (this.msgToMeta.size > MAX_ENTRIES) {\n const oldest = this.msgToMeta.keys().next().value;\n if (oldest === undefined) {\n break;\n }\n this.msgToMeta.delete(oldest);\n }\n }\n}\n","/**\n * Milky 传输装配(单端口 HTTP:POST /api/:api + GET /event SSE + /event WS 升级\n * + WebHook 主动推送,docs/protocols/milky.md §4)\n *\n * - HTTP API:HttpServer onPathRequest 分发 → 动作注册表 → 规范响应信封\n * (200 ok / 200 failed(-400/-403/自定) / 401 鉴权 / 404 API 不存在(空 body)/\n * 415 Content-Type)。\n * - /event:onRawRequest 承接 SSE(createSseResponse,event: milky_event);\n * onUpgrade 承接同端口 WS 升级(网络原语 2026-10-28 下沉 network)。\n * - WebHook:HttpClient(fire-and-forget POST,Authorization 头带 token)。\n *\n * 事件推送统一经 MilkyEventHub(注册到 EventBroadcaster,send → SSE/WS 客户端)。\n */\nimport type {\n AuthorizeHook,\n EventBroadcaster,\n HttpRouteContext,\n RequestContext,\n Respond,\n TransportAdapter,\n} from \"@napuketto/network\";\nimport { createSseResponse, HttpClient, HttpServer } from \"@napuketto/network\";\nimport { WebSocket } from \"ws\";\nimport type { ActionRegistry } from \"../core/index.js\";\nimport type { MilkyAction } from \"./action/base-action.js\";\nimport type { MilkyConfig } from \"./config.js\";\n\n/** /event 路径(规范固定)。 */\nconst EVENT_PATH = \"/event\";\n/** /api/ 前缀 + 动作名(小写字母开头,小写/数字/下划线)。 */\nconst API_PATH_RE = /^\\/api\\/([a-z][a-z0-9_]*)$/;\n/** Bearer 前缀。 */\nconst BEARER_PREFIX = \"Bearer \";\n\n/** 校准 logger 最小面(webhook 失败 / 配置异常提示;缺省静默)。 */\nexport interface MilkyLoggerLike {\n warn(obj: unknown, msg?: string): void;\n info(obj: unknown, msg?: string): void;\n}\n\n/** 传输装配结果。 */\nexport interface MilkyTransportSet {\n /** 已注册 broadcaster 的传输(HTTP server + webhook clients + 事件枢纽)。 */\n adapters: TransportAdapter[];\n /** 停止:关闭传输 + 注销广播(幂等)。 */\n close: () => Promise<void>;\n}\n\n/**\n * Milky 事件枢纽:SSE 客户端 + WS 客户端集合,send 即广播。\n * 传输适配器面(open/close/send,EventBroadcaster 多态派发)——生命周期随\n * HttpServer。连接注册经 attachTo 挂到 HttpServer 注入点(本类内部闭环);\n * WS 入帧忽略(规范:/event 为纯事件推送通道)。\n */\nclass MilkyEventHub implements TransportAdapter {\n private readonly sseClients = new Set<SseClientHandle>();\n private readonly sockets = new Set<WebSocket>();\n\n /** 把 /event 的 SSE(onRawRequest)与 WS 升级(onUpgrade)挂到 HTTP server。 */\n attachTo(server: HttpServer, config: MilkyConfig): void {\n server.onRawRequest = (ctx) => {\n if (ctx.path !== EVENT_PATH || ctx.method !== \"GET\") {\n return undefined;\n }\n if (!config.eventModes.includes(\"sse\")) {\n return new Response(\"event mode sse disabled\", { status: 404 });\n }\n return createSseResponse((client) => {\n this.sseClients.add(client);\n return () => {\n this.sseClients.delete(client);\n };\n });\n };\n server.onUpgrade = (req, accept, reject) => {\n if (pathnameOf(req.url) !== EVENT_PATH) {\n return;\n }\n if (!config.eventModes.includes(\"ws\")) {\n reject(404, \"event mode ws disabled\");\n return;\n }\n if (config.token !== \"\" && !tokenMatches(req, config.token)) {\n reject(401, \"unauthorized\");\n return;\n }\n accept((socket) => {\n this.sockets.add(socket);\n const remove = (): void => {\n this.sockets.delete(socket);\n };\n socket.on(\"close\", remove);\n socket.on(\"error\", remove);\n });\n };\n }\n\n /** 广播事件(EventBroadcaster emit 入口)。 */\n send<T>(event: T): void {\n const json = JSON.stringify(event);\n for (const client of this.sseClients) {\n client.send(json, \"milky_event\");\n }\n for (const socket of this.sockets) {\n if (socket.readyState === WebSocket.OPEN) {\n socket.send(json);\n }\n }\n }\n\n open(): void {\n // 生命周期随 HttpServer\n }\n\n async close(): Promise<void> {\n for (const client of this.sseClients) {\n client.close();\n }\n this.sseClients.clear();\n for (const socket of this.sockets) {\n socket.close(1001, \"server shutdown\");\n }\n this.sockets.clear();\n }\n\n onRequest?: (req: unknown, respond: Respond) => void;\n}\n\n/** SSE 客户端句柄(network SseClient + 显式关闭)。 */\ninterface SseClientHandle {\n send(data: string, event?: string): void;\n close(): void;\n}\n\n/** 按配置装配 Milky 传输。 */\nexport function assembleMilkyTransports(opts: {\n config: MilkyConfig;\n broadcaster: EventBroadcaster;\n registry: ActionRegistry<MilkyAction<unknown, unknown>>;\n logger?: MilkyLoggerLike;\n}): MilkyTransportSet {\n const { config, broadcaster, registry, logger } = opts;\n const hub = new MilkyEventHub();\n const token = config.token;\n const authorize = token !== \"\" ? makeMilkyAuthorize(token) : undefined;\n\n const server = new HttpServer({\n host: config.host,\n port: config.port,\n ...(authorize !== undefined ? { authorize } : {}),\n });\n hub.attachTo(server, config);\n server.onPathRequest = (ctx, req, respond) => {\n handleMilkyHttpRequest(ctx, req, respond, registry);\n };\n\n const adapters: TransportAdapter[] = [server, hub];\n for (const url of config.webhooks) {\n const client = new HttpClient({\n url,\n ...(token !== \"\" ? { headers: { authorization: `${BEARER_PREFIX}${token}` } } : {}),\n timeoutMs: 5000,\n onError: (err: unknown) => {\n logger?.warn({ url, err: String(err) }, \"milky: webhook 推送失败\");\n },\n });\n adapters.push(client);\n }\n\n for (const adapter of adapters) {\n broadcaster.register(adapter);\n }\n return {\n adapters,\n close: async () => {\n await server.close();\n await hub.close();\n for (const adapter of adapters) {\n broadcaster.unregister(adapter);\n }\n },\n };\n}\n\n/** HTTP /api 分发(规范信封 + 404/415 语义)。 */\nfunction handleMilkyHttpRequest(\n ctx: HttpRouteContext,\n req: unknown,\n respond: Respond,\n registry: ActionRegistry<MilkyAction<unknown, unknown>>,\n): void {\n if (ctx.method !== \"POST\") {\n respond(undefined, 404);\n return;\n }\n const match = API_PATH_RE.exec(ctx.path);\n if (match === null) {\n respond(undefined, 404);\n return;\n }\n const contentType = ctx.headers?.[\"content-type\"];\n if (contentType !== undefined && !contentType.toLowerCase().includes(\"application/json\")) {\n respond(undefined, 415);\n return;\n }\n const action = registry.get(match[1] ?? \"\");\n if (action === undefined) {\n // API 不存在:HTTP 404 + 空 body(规范)\n respond(undefined, 404);\n return;\n }\n action\n .handle(req)\n .then((result) => {\n if (result.status === \"ok\") {\n respond({ status: \"ok\", retcode: 0, data: result.data ?? {} });\n } else {\n respond({\n status: \"failed\",\n retcode: result.retcode,\n data: null,\n message: result.message,\n });\n }\n })\n .catch(() => {\n respond({ status: \"failed\", retcode: -500, data: null, message: \"internal error\" });\n });\n}\n\n/** 鉴权钩子:Bearer 头或 access_token 查询参数(规范允许 SSE/WS 查询参数兜底)。 */\nfunction makeMilkyAuthorize(token: string): AuthorizeHook {\n return (ctx) => tokenMatches(ctx, token);\n}\n\n/** 请求凭据匹配(头优先,查询参数兜底)。 */\nfunction tokenMatches(ctx: RequestContext, token: string): boolean {\n const auth = ctx.headers[\"authorization\"] ?? ctx.headers[\"Authorization\"];\n if (auth?.startsWith(BEARER_PREFIX)) {\n return auth.slice(BEARER_PREFIX.length) === token;\n }\n try {\n const url = new URL(ctx.url, \"http://localhost\");\n return url.searchParams.get(\"access_token\") === token;\n } catch {\n return false;\n }\n}\n\n/** URL 路径部分(无 scheme 相对 url 容错)。 */\nfunction pathnameOf(url: string): string {\n try {\n return new URL(url, \"http://localhost\").pathname;\n } catch {\n return url.split(\"?\")[0] ?? \"\";\n }\n}\n","/**\n * NapukettoMilkyAdapter:Milky 协议适配器(P0 2026-10-28,P1 2026-10-30)\n *\n * 第四个协议适配器(与 OB11/Satori/KuroBot 并行):单端口 HTTP(/api + /event)\n * + WebHook。收链路三源(P1):\n * - 消息通道(Msg/onRecvMsg):seq 登记 → grayTip→notice / 文件消息→group_file_upload\n * (群场景)/ 普通→message_receive(自消息不上报);\n * - 群通知通道(Group/onGroupNotifiesUpdated):入群请求 / 成员邀请 / 邀请自身;\n * - 好友请求通道(Buddy/onBuddyReqChange):friend_request(防御收窄)。\n * 发链路 /api 动作 → kernel apis。\n *\n * 生命周期走 BaseProtocolAdapter 骨架;config.enabled=false 时空转(不订阅、\n * 不起传输)。翻译为纯函数(ADR-008):实体回填 / ID 转换在广播路径异步取得\n * 后经 ctx 注入。\n */\nimport type {\n BuddyEventChannel,\n CanonicalElement,\n GroupEventChannel,\n GroupNotify,\n MsgEventChannel,\n RawMessage,\n} from \"@napuketto/kernel\";\nimport { ChatType, toCanonicalElements } from \"@napuketto/kernel\";\nimport type { EventBroadcaster } from \"@napuketto/network\";\nimport { narrowBuddyReqs } from \"../core/buddy-req.js\";\nimport { collectGrayTipUids } from \"../core/gray-tip.js\";\nimport { BaseProtocolAdapter, type ProtocolConfig, type ProtocolHooks } from \"../core/index.js\";\nimport { subscribeRawMessages } from \"../core/raw-message.js\";\nimport type { RequestTranslateContext } from \"../core/uid-uin.js\";\nimport { createMilkyActionRegistry } from \"./action/index.js\";\nimport { MilkyApi, type MilkyApiOptions } from \"./api.js\";\nimport type { MilkyConfig } from \"./config.js\";\nimport { toGroupEntity, toGroupMemberEntity } from \"./helper/entities.js\";\nimport { type NoticeTranslateContext, toMilkyNoticeEvent } from \"./helper/notice.js\";\nimport { collectNotifyUids, toFriendRequestEvent, toGroupRequestEvent } from \"./helper/request.js\";\nimport { incomingForwardSegment } from \"./helper/segments.js\";\nimport { MessageSeqIndex } from \"./helper/seq-index.js\";\nimport {\n type ReceiveTranslateContext,\n toGroupFileUploadEvent,\n toMessageRecallEvent,\n toMessageReceiveEvent,\n} from \"./helper/translate.js\";\nimport { assembleMilkyTransports, type MilkyLoggerLike } from \"./transport.js\";\n\n/** 适配器构造参数(api 相关字段继承 MilkyApiOptions)。 */\nexport interface MilkyAdapterOptions extends MilkyApiOptions {\n config: ProtocolConfig<MilkyConfig>;\n broadcaster: EventBroadcaster;\n /** kernel 消息事件通道(收链路入口)。 */\n msgChannel: MsgEventChannel;\n /** kernel 群事件通道(P1:群请求/邀请推送;缺省不订阅)。 */\n groupChannel?: GroupEventChannel;\n /** kernel 好友事件通道(P1:好友申请推送;缺省不订阅)。 */\n buddyChannel?: BuddyEventChannel;\n /** 校准日志(webhook 失败 / 启停提示 / 未知事件形状;IPC 模式传 loader pino 实例)。 */\n logger?: MilkyLoggerLike;\n}\n\nexport class NapukettoMilkyAdapter extends BaseProtocolAdapter<MilkyConfig> {\n readonly protocol = \"milky\";\n\n private readonly msgChannel: MsgEventChannel;\n private readonly groupChannel: GroupEventChannel | undefined;\n private readonly buddyChannel: BuddyEventChannel | undefined;\n private readonly calibLogger: MilkyLoggerLike | undefined;\n private readonly api: MilkyApi;\n private readonly seqIndex = new MessageSeqIndex();\n /** 动作注册表(公共只读:装配方/测试枚举)。 */\n readonly registry: ReturnType<typeof createMilkyActionRegistry>;\n private unsubscribes: Array<() => void> = [];\n private stopTransports: (() => Promise<void>) | null = null;\n\n constructor(opts: MilkyAdapterOptions) {\n const hooks: ProtocolHooks = {\n onStart: (config) => this.startTransports(config as MilkyConfig),\n onStop: () => this.stopAll(),\n onReload: (config) => this.reloadTransports(config as MilkyConfig),\n };\n super({\n config: opts.config,\n broadcaster: opts.broadcaster,\n hooks,\n });\n this.msgChannel = opts.msgChannel;\n this.groupChannel = opts.groupChannel;\n this.buddyChannel = opts.buddyChannel;\n this.calibLogger = opts.logger;\n this.api = new MilkyApi(opts, this.seqIndex);\n this.registry = createMilkyActionRegistry({ api: this.api });\n }\n\n /** 启动传输 + 订阅(enabled=false 空转:不订阅不起传输)。 */\n private async startTransports(config: MilkyConfig): Promise<void> {\n if (!config.enabled) {\n this.calibLogger?.info({}, \"milky: 未启用(enabled=false),跳过装配\");\n return;\n }\n const broadcaster = this.getBroadcaster();\n if (broadcaster !== undefined) {\n const set = assembleMilkyTransports({\n config,\n broadcaster,\n registry: this.registry,\n ...(this.calibLogger !== undefined ? { logger: this.calibLogger } : {}),\n });\n this.stopTransports = set.close;\n }\n this.subscribe();\n this.calibLogger?.info(\n { host: config.host, port: config.port, modes: config.eventModes },\n \"milky: adapter started\",\n );\n }\n\n /** 热更新:停止重建(enabled 切换生效)。 */\n private async reloadTransports(config: MilkyConfig): Promise<void> {\n await this.stopAll();\n await this.startTransports(config);\n }\n\n /** 停止:退订 + 关传输。 */\n private async stopAll(): Promise<void> {\n this.unsubscribeAll();\n if (this.stopTransports !== null) {\n await this.stopTransports();\n this.stopTransports = null;\n }\n }\n\n /** 订阅 kernel 事件(消息 + 群通知 + 好友请求,幂等)。 */\n private subscribe(): void {\n if (this.unsubscribes.length > 0) {\n return;\n }\n this.unsubscribes.push(\n subscribeRawMessages(this.msgChannel, (msg) => {\n void this.handleIncoming(msg);\n }),\n );\n if (this.groupChannel !== undefined) {\n const groupChannel = this.groupChannel;\n this.unsubscribes.push(\n groupChannel.on(\"Group/onGroupNotifiesUpdated\", (doubt, notifies) => {\n void this.handleGroupNotifies(doubt, notifies);\n }),\n );\n }\n if (this.buddyChannel !== undefined) {\n const buddyChannel = this.buddyChannel;\n this.unsubscribes.push(\n buddyChannel.on(\"Buddy/onBuddyReqChange\", (arg) => {\n this.handleBuddyReqs(arg);\n }),\n );\n }\n }\n\n /** 退订(幂等)。 */\n private unsubscribeAll(): void {\n for (const off of this.unsubscribes) {\n off();\n }\n this.unsubscribes = [];\n }\n\n /** 单条消息:seq 登记 → grayTip→notice / 群文件上传 / message_receive(自消息不上报)。 */\n private async handleIncoming(msg: RawMessage): Promise<void> {\n // seq 双向登记(含自消息:本账号发出的消息也要可反查);转发 resId 登记索引\n this.seqIndex.record(msg);\n this.recordForward(msg);\n if (hasGrayTip(msg)) {\n await this.broadcastNotice(msg);\n return;\n }\n // 群文件上传:群场景文件消息 → group_file_upload 事件(Milky 语义,\n // 场景守卫在翻译函数内)\n const upload = toGroupFileUploadEvent(msg, this.api.self.uin);\n if (upload !== null) {\n this.broadcastEvent(upload);\n return;\n }\n // 自消息不上报(与 OB11 默认一致)\n if (String(msg.senderUin) === this.api.self.uin) {\n return;\n }\n this.broadcastEvent(await this.buildMessageReceiveEvent(msg));\n }\n\n /** grayTip → notice 事件广播(REVOKE 走 message_recall,其余走 notice 翻译)。 */\n private async broadcastNotice(msg: RawMessage): Promise<void> {\n const uidToUin = await this.resolveUidToUin(collectGrayTipUids(msg));\n const event =\n findRevokeElement(msg) !== undefined\n ? toMessageRecallEvent(msg, {\n selfUin: this.api.self.uin,\n ...(uidToUin !== undefined ? { uidToUin } : {}),\n })\n : toMilkyNoticeEvent(msg, this.noticeCtx(uidToUin));\n if (event !== null) {\n this.broadcastEvent(event);\n }\n }\n\n /** notice 翻译上下文(uidToUin 缺省空 Map;logger 透传校准日志)。 */\n private noticeCtx(uidToUin: Map<string, string> | undefined): NoticeTranslateContext {\n return {\n selfUin: this.api.self.uin,\n ...(uidToUin !== undefined ? { uidToUin } : { uidToUin: new Map() }),\n ...(this.calibLogger !== undefined ? { logger: this.calibLogger } : {}),\n };\n }\n\n /** 群通知通道:入群请求 / 成员邀请 / 邀请自身(uid→uin 批量后翻译)。 */\n private async handleGroupNotifies(doubt: boolean, notifies: GroupNotify[]): Promise<void> {\n const ctx = await this.requestCtx(collectNotifyUids(notifies));\n for (const notify of notifies) {\n const event = toGroupRequestEvent(notify, doubt, ctx);\n if (event !== null) {\n this.broadcastEvent(event);\n }\n }\n }\n\n /** 好友请求通道:Buddy/onBuddyReqChange(防御收窄,未知形状 raw 日志)。 */\n private handleBuddyReqs(arg: unknown): void {\n const reqs = narrowBuddyReqs(arg);\n if (reqs === null) {\n this.calibLogger?.warn(\n { raw: truncate(JSON.stringify(arg)) },\n \"milky: onBuddyReqChange 未知参数形状\",\n );\n return;\n }\n void (async () => {\n const ctx = await this.requestCtx(reqs.map((req) => req.friendUid));\n for (const req of reqs) {\n this.broadcastEvent(toFriendRequestEvent(req, ctx));\n }\n })();\n }\n\n /** request 翻译上下文(uid→uin 批量转换)。 */\n private async requestCtx(uids: string[]): Promise<RequestTranslateContext> {\n const uidToUin = await this.resolveUidToUin(uids);\n return {\n selfUin: this.api.self.uin,\n ...(uidToUin !== undefined ? { uidToUin } : { uidToUin: new Map() }),\n };\n }\n\n /** message_receive 组装:at uid→uin + reply 回填 + 群实体回填 + 转发段(全部 fail-soft)。 */\n private async buildMessageReceiveEvent(msg: RawMessage): Promise<unknown> {\n const elements = toCanonicalElements(msg);\n const ctx: ReceiveTranslateContext = { selfUin: this.api.self.uin };\n await this.fillMentionUids(elements, ctx);\n this.fillReplyMeta(elements, ctx);\n await this.fillGroupEntities(msg, ctx);\n const forward = msg.elements.find(\n (el) => el.multiForwardMsgElement !== undefined,\n )?.multiForwardMsgElement;\n if (forward !== undefined) {\n ctx.forwardSegments = [incomingForwardSegment(forward.resId, forward.fileName)];\n }\n return toMessageReceiveEvent(msg, ctx);\n }\n\n /** at uid → uin 批量转换(mention.user_id 用;失败 mention 段跳过)。 */\n private async fillMentionUids(\n elements: CanonicalElement[],\n ctx: ReceiveTranslateContext,\n ): Promise<void> {\n const atUids = elements\n .filter((el) => el.type === \"at\" && el.target !== \"all\")\n .map((el) => (el as { target: string }).target);\n if (atUids.length === 0) {\n return;\n }\n try {\n ctx.uidToUin = await this.api.uidToUin(atUids);\n } catch {\n // 转换失败:mention 段跳过\n }\n }\n\n /** reply 引用元信息回填(seqIndex 命中即用;未命中不强查)。 */\n private fillReplyMeta(elements: CanonicalElement[], ctx: ReceiveTranslateContext): void {\n const replyIds = elements\n .filter((el) => el.type === \"reply\")\n .map((el) => (el as { messageId: string }).messageId);\n const meta = this.seqIndex.collectReplyMeta(replyIds);\n if (meta.size > 0) {\n ctx.replyMeta = meta;\n }\n }\n\n /** 群场景实体回填(GroupCache 缓存优先,失败最小实体兜底)。 */\n private async fillGroupEntities(msg: RawMessage, ctx: ReceiveTranslateContext): Promise<void> {\n if (msg.chatType !== ChatType.GROUP || this.api.groupCache === undefined) {\n return;\n }\n const [detail, member] = await Promise.all([\n this.api.groupCache.getGroupDetail(msg.peerUid).catch(() => undefined),\n this.api.groupCache.getMember(msg.peerUid, msg.senderUid).catch(() => undefined),\n ]);\n ctx.groupEntity = toGroupEntity(detail, msg.peerUid);\n ctx.groupMemberEntity = toGroupMemberEntity(member, msg.peerUid, msg.senderUin);\n }\n\n /** 转发 resId → 定位登记(get_forwarded_messages 反查用)。 */\n private recordForward(msg: RawMessage): void {\n const forward = msg.elements.find(\n (el) => el.multiForwardMsgElement !== undefined,\n )?.multiForwardMsgElement;\n if (forward !== undefined && forward.resId !== \"\") {\n this.seqIndex.recordForward(forward.resId, {\n chatType: msg.chatType,\n peerUid: msg.peerUid,\n msgId: msg.msgId,\n });\n }\n }\n\n /** uid 批量 → uin(空集/失败返回 undefined 语义:调用方用空 Map)。 */\n private resolveUidToUin(uids: string[]): Promise<Map<string, string> | undefined> {\n const unique = [...new Set(uids.filter((uid) => uid !== \"\"))];\n if (unique.length === 0) {\n return Promise.resolve(undefined);\n }\n return this.api.uidToUin(unique).catch(() => undefined);\n }\n}\n\n/** 是否含 grayTip 元素(与 OB11 收链路同判据)。 */\nfunction hasGrayTip(msg: RawMessage): boolean {\n return msg.elements.some((el) => el.grayTipElement !== undefined);\n}\n\n/** 撤回 grayTip 元素(非撤回消息返回 undefined)。 */\nfunction findRevokeElement(msg: RawMessage) {\n return msg.elements.find((el) => el.grayTipElement?.revokeElement !== undefined)?.grayTipElement\n ?.revokeElement;\n}\n\n/** 字符串截断(raw 日志防刷屏)。 */\nfunction truncate(raw: string | undefined): string {\n return raw === undefined ? \"\" : raw.slice(0, 2000);\n}\n","/**\n * Milky 协议配置(zod schema,归属本包,ADR-012)\n *\n * 单一 TOML 的 `[accounts.milky]` 账号段(docs/protocols/milky.md §4):\n * 单端口 HTTP 模型(/api + /event 同端口),`enabled` 缺省 false = 不启用。\n */\nimport { z } from \"zod\";\n\n/** Milky 配置 schema。 */\nexport const milkyConfigSchema = z.object({\n /** 启用开关(缺省 false:账号段存在但 enabled 未开 = 装配为空转)。 */\n enabled: z.boolean().default(false),\n /** HTTP 监听地址。 */\n host: z.string().min(1).default(\"127.0.0.1\"),\n /** HTTP 监听端口(/api 与 /event 同端口)。 */\n port: z.number().int().min(0).max(65535).default(3001),\n /** access_token(空 = 不校验,仅限内网)。 */\n token: z.string().default(\"\"),\n /** /event 允许的连接形态(缺省两者都开)。 */\n eventModes: z.array(z.enum([\"sse\", \"ws\"])).default([\"sse\", \"ws\"]),\n /** 额外事件推送地址(WebHook,可多个;协议端在请求头发 Bearer token)。 */\n webhooks: z.array(z.string().min(1)).default([]),\n /** 发送媒体 http(s) URI 下载缓存目录(缺省不下载 = http(s) 发送媒体不可用)。 */\n cacheDir: z.string().optional(),\n});\n\n/** Milky 配置类型(由 schema 推导)。 */\nexport type MilkyConfig = z.infer<typeof milkyConfigSchema>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["NOTIFY_SEARCH_COUNT","FILE_URI_PREFIX_RE","toUin","MS_TO_SEC","groupIdField","optStr","requireSelfUid","MS_TO_SEC","emptySchema"],"sources":["../../src/milky/api.ts","../../src/milky/helper/entities.ts","../../src/milky/helper/media-uri.ts","../../src/milky/helper/request.ts","../../src/milky/action/error-map.ts","../../src/milky/action/base-action.ts","../../src/milky/action/group.ts","../../src/milky/helper/segments.ts","../../src/milky/helper/translate.ts","../../src/milky/action/message.ts","../../src/milky/action/group-file.ts","../../src/milky/action/profile.ts","../../src/milky/action/social.ts","../../src/milky/action/system.ts","../../src/milky/action/index.ts","../../src/milky/helper/notice.ts","../../src/milky/helper/seq-index.ts","../../src/milky/transport.ts","../../src/milky/adapter.ts","../../src/milky/config.ts"],"sourcesContent":["/**\n * MilkyApi:Milky 动作统一依赖聚合(对齐 OneBotApi 模式,P2-16)\n *\n * 持有 P1 动作面所需 kernel apis + 协议层共享状态(seq 双向映射 / 转发索引 /\n * 版本 / 发送媒体缓存目录);动作经 Pick 视图取依赖,装配方只构造一次本对象。\n */\nimport type {\n BuddyReq,\n FriendApi,\n GroupApi,\n GroupCache,\n GroupNotify,\n GroupNotifyApi,\n MsgApi,\n Peer,\n ProfileApi,\n ProfileLikeApi,\n RawMessage,\n RecentContactApi,\n RichMediaApi,\n TicketApi,\n WebApi,\n} from \"@napuketto/kernel\";\nimport { ChatType, kernelError } from \"@napuketto/kernel\";\nimport type { MessageSeqIndex } from \"./helper/seq-index.js\";\nimport type { MilkyLoggerLike } from \"./transport.js\";\n\n/** MilkyApi 构造参数。 */\nexport interface MilkyApiOptions {\n msgApi: MsgApi;\n groupApi: GroupApi;\n friendApi: FriendApi;\n profileApi: ProfileApi;\n /** P1 扩面依赖(表态度 / 票据 / 精华列表 / 群通知 / 群文件)。 */\n profileLikeApi: ProfileLikeApi;\n ticketApi: TicketApi;\n webApi: WebApi;\n groupNotifyApi: GroupNotifyApi;\n richMediaApi: RichMediaApi;\n /** P2 批次二:会话列表(get_peer_pins 数据源)。 */\n recentContactApi: RecentContactApi;\n /** 登录身份(get_login_info / self_id / target_user_uid 用)。 */\n self: { uin: string; nickname: string; uid?: string };\n /** 群/成员缓存(群实体回填 / get_group_list;未装配时动作直查 api)。 */\n groupCache?: GroupCache;\n /** QQ 客户端版本(get_impl_info.qq_protocol_version)。 */\n qqVersion: string;\n /** 协议端版本(get_impl_info.impl_version)。 */\n implVersion: string;\n /** 发送媒体 http(s)/base64 URI 下载缓存目录(缺省 = 远程媒体发送不可用)。 */\n mediaDir?: string;\n /** 动作层可观测出口(P2 批次一:forward 临时消息撤回失败 warn;缺省静默)。 */\n logger?: MilkyLoggerLike;\n}\n\nexport class MilkyApi {\n readonly msgApi: MsgApi;\n readonly groupApi: GroupApi;\n readonly friendApi: FriendApi;\n readonly profileApi: ProfileApi;\n readonly profileLikeApi: ProfileLikeApi;\n readonly ticketApi: TicketApi;\n readonly webApi: WebApi;\n readonly groupNotifyApi: GroupNotifyApi;\n readonly richMediaApi: RichMediaApi;\n readonly recentContactApi: RecentContactApi;\n readonly self: { uin: string; nickname: string; uid?: string };\n readonly groupCache: GroupCache | undefined;\n readonly qqVersion: string;\n readonly implVersion: string;\n readonly mediaDir: string | undefined;\n /** 动作层可观测出口(缺省静默)。 */\n readonly logger: MilkyLoggerLike | undefined;\n /** message_seq ↔ msgId 双向映射(接收链路 record,动作侧反查)。 */\n readonly seqIndex: MessageSeqIndex;\n\n constructor(opts: MilkyApiOptions, seqIndex: MessageSeqIndex) {\n this.msgApi = opts.msgApi;\n this.groupApi = opts.groupApi;\n this.friendApi = opts.friendApi;\n this.profileApi = opts.profileApi;\n this.profileLikeApi = opts.profileLikeApi;\n this.ticketApi = opts.ticketApi;\n this.webApi = opts.webApi;\n this.groupNotifyApi = opts.groupNotifyApi;\n this.richMediaApi = opts.richMediaApi;\n this.recentContactApi = opts.recentContactApi;\n this.self = opts.self;\n this.groupCache = opts.groupCache;\n this.qqVersion = opts.qqVersion;\n this.implVersion = opts.implVersion;\n this.mediaDir = opts.mediaDir;\n this.logger = opts.logger;\n this.seqIndex = seqIndex;\n }\n\n /** uin → uid(私聊目标 / at 段发送转换 / 群管动作的 uid 入参)。 */\n uinToUid(uins: string[]): Promise<Map<string, string>> {\n return this.groupApi.uinToUid(uins);\n }\n\n /** uid → uin(事件路径 mention 转换)。 */\n uidToUin(uids: string[]): Promise<Map<string, string>> {\n return this.groupApi.uidToUin(uids);\n }\n\n /**\n * uin(数字)→ uid(群管动作入参转换);转换失败抛 INVALID_PARAM\n * (Milky 入参 user_id 都是 uin,kernel 群管 API 要 uid)。\n */\n async resolveUidFromUin(uin: number | string): Promise<string> {\n const uinStr = String(uin);\n try {\n const uid = (await this.uinToUid([uinStr])).get(uinStr);\n if (uid !== undefined && uid !== \"\") {\n return uid;\n }\n } catch {\n // 落到下方报错\n }\n throw kernelError(`用户 ${uinStr} 不存在或 uin→uid 转换失败`, \"INVALID_PARAM\");\n }\n\n /**\n * message_scene + 数字 ID → NT Peer。\n * group = 群号直作 peerUid;friend/temp = uin → uid(失败退 uin 原样,交 QQ 端判断)。\n */\n async resolvePeer(scene: \"friend\" | \"group\" | \"temp\", id: number): Promise<Peer> {\n if (scene === \"group\") {\n return { chatType: ChatType.GROUP, peerUid: String(id) } satisfies Peer;\n }\n const uin = String(id);\n let uid: string | undefined;\n try {\n uid = (await this.uinToUid([uin])).get(uin);\n } catch {\n // 转换失败:退 uin 原样\n }\n return {\n chatType: scene === \"friend\" ? ChatType.C2C : ChatType.C2C_TEMP,\n peerUid: uid ?? uin,\n } satisfies Peer;\n }\n\n /**\n * seq → msgId(索引优先,未登记扫描近段历史兜底)。\n * 两层都未命中返回 undefined(调用方抛 NOT_FOUND)。\n */\n async resolveMsgIdBySeq(\n peer: Peer,\n seq: number,\n chatType: Peer[\"chatType\"],\n ): Promise<string | undefined> {\n const indexed = this.seqIndex.resolveMsgId(chatType, peer.peerUid, seq);\n if (indexed !== undefined) {\n return indexed;\n }\n const msgs = await this.msgApi.fetchMessages(peer, { count: 60 }).catch(() => []);\n const hit = msgs.find((m: RawMessage) => Number(m.msgSeq) === seq);\n if (hit === undefined) {\n return undefined;\n }\n this.seqIndex.record(hit);\n return hit.msgId;\n }\n\n /** 发送结果回查:msgId → {message_seq, time}(sendMessage 只回 msgId)。 */\n async resolveSentOutput(\n peer: Peer,\n msgId: string,\n ): Promise<{ message_seq: number; time: number }> {\n const [sent] = await this.msgApi.fetchMsgsByMsgId(peer, [msgId]);\n if (sent === undefined) {\n throw kernelError(\"发送结果回查失败(msgId 未命中)\", \"UNKNOWN\");\n }\n this.seqIndex.record(sent);\n return {\n message_seq: Number(sent.msgSeq),\n time: Math.floor(Number(sent.msgTime) / 1000),\n };\n }\n}\n\n/** 通知查找默认搜索数量(单屏全量,OB11 DEFAULT_COUNT 同值)。 */\nconst NOTIFY_SEARCH_COUNT = 100;\n\n/**\n * 按通知 seq 查找群通知(先非可疑后可疑,OB11 set_group_add_request 同路径)。\n * 未找到抛 NOT_FOUND(应答动作的 seq 无效或已过期)。\n * 模块级函数(非类成员):应答动作的公共入口,OB11 同路径。\n */\nexport async function findGroupNotify(api: MilkyApi, seq: string): Promise<GroupNotify> {\n const normal = await api.groupNotifyApi.getSingleScreenNotifies(false, NOTIFY_SEARCH_COUNT);\n const hit = normal.find((item) => item.seq === seq);\n if (hit !== undefined) {\n return hit;\n }\n const doubt = await api.groupNotifyApi.getSingleScreenNotifies(true, NOTIFY_SEARCH_COUNT);\n const doubtHit = doubt.find((item) => item.seq === seq);\n if (doubtHit !== undefined) {\n return doubtHit;\n }\n throw kernelError(`未找到通知 ${seq}(无效或已过期)`, \"NOT_FOUND\");\n}\n\n/** 按发起者 uid 查找好友申请(getBuddyReqList 匹配 friendUid);未找到抛 NOT_FOUND。 */\nexport async function findBuddyReq(api: MilkyApi, initiatorUid: string): Promise<BuddyReq> {\n const reqs = await api.friendApi.getBuddyReqList();\n const hit = reqs.find((req) => req.friendUid === initiatorUid);\n if (hit === undefined) {\n throw kernelError(`未找到来自 ${initiatorUid} 的好友申请`, \"NOT_FOUND\");\n }\n return hit;\n}\n","/**\n * kernel 实体 → Milky 实体翻译(纯函数,ADR-008)\n *\n * Milky 事件/查询输出要求完整实体(GroupEntity/GroupMemberEntity/FriendEntity\n * 的全部字段 required);kernel 实体字段是超集的子集,缺失字段按最小合法值兜底\n * (0 / 空串 / unknown),实触样本到位后逐步补真实值。\n */\n\nimport type { Friend } from \"@napuketto/kernel\";\nimport { GroupApi, type GroupDetailInfo, type GroupMember } from \"@napuketto/kernel\";\nimport type { FriendEntity, GroupEntity, GroupMemberEntity } from \"../types.js\";\n\n/** GroupDetailInfo / Group → GroupEntity(detail 缺失时全兜底)。 */\nexport function toGroupEntity(detail: GroupDetailInfo | undefined, groupCode: string): GroupEntity {\n return {\n group_id: Number(groupCode),\n group_name: detail?.groupName ?? \"\",\n member_count: detail?.memberNum ?? 0,\n max_member_count: detail?.maxMemberNum ?? 0,\n remark: detail?.remarkName ?? \"\",\n created_time: detail?.groupCreateTime ?? 0,\n description: \"\",\n question: \"\",\n announcement: \"\",\n };\n}\n\n/** 群列表项(GroupCache Group)→ GroupEntity。 */\nexport function groupListToEntity(group: {\n groupCode: string;\n groupName: string;\n memberCount: number;\n maxMember: number;\n}): GroupEntity {\n return {\n group_id: Number(group.groupCode),\n group_name: group.groupName,\n member_count: group.memberCount,\n max_member_count: group.maxMember,\n remark: \"\",\n created_time: 0,\n description: \"\",\n question: \"\",\n announcement: \"\",\n };\n}\n\n/** GroupMember → GroupMemberEntity(member 缺失时按 uin 兜底最小实体)。 */\nexport function toGroupMemberEntity(\n member: GroupMember | undefined,\n groupCode: string,\n uin: string,\n): GroupMemberEntity {\n const shutUpSeconds = member?.shutUpTime ?? 0;\n return {\n user_id: Number(member?.uin !== undefined && member.uin !== \"\" ? member.uin : uin),\n nickname: member?.nick ?? \"\",\n sex: \"unknown\",\n group_id: Number(groupCode),\n card: member?.cardName ?? \"\",\n title: member?.memberSpecialTitle ?? \"\",\n level: 0,\n role: GroupApi.roleToString(member?.role ?? 2),\n join_time: Number(member?.joinTime) || 0,\n last_sent_time: Number(member?.lastSpeakTime) || 0,\n shut_up_end_time: shutUpSeconds > 0 ? Math.floor(Date.now() / 1000) + shutUpSeconds : null,\n };\n}\n\n/** Friend → FriendEntity(kernel 无 qid/分类挂载,按最小实体兜底)。 */\nexport function toFriendEntity(\n friend: Friend | undefined,\n uin: string,\n nick: string,\n): FriendEntity {\n return {\n user_id: Number(friend?.uin !== undefined && friend.uin !== \"\" ? friend.uin : uin),\n nickname: friend?.nickname ?? nick,\n sex: \"unknown\",\n qid: \"\",\n remark: friend?.remark ?? \"\",\n category: { category_id: 0, category_name: \"\" },\n };\n}\n","/**\n * 发送媒体 URI 解析(Milky OutgoingSegment uri → 本地路径)\n *\n * 规范支持 file:// / http(s):// / base64:// 三种(image/record/video 共用):\n * - file:// → 平台路径(segments.ts 的同步面已处理)\n * - base64:// → 解码落盘 cacheDir/milky/,file-type 探测扩展名后改名\n * - http(s):// → @napuketto/media downloadUrl 落盘 cacheDir/milky/\n * 未配置 mediaDir 时远程 URI 报错(不发静默空消息)。\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { mkdir, rename, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/** file:// 前缀(fileURLToPath 失败时的裸剥离兜底)。 */\nconst FILE_URI_PREFIX_RE = /^file:\\/\\//;\n\nimport { kernelError } from \"@napuketto/kernel\";\nimport { detectFileType, downloadUrl, inferExtension } from \"@napuketto/media\";\n\n/** 解析远程媒体 URI 为本地绝对路径(base64:// / http(s)://;file:// 走同步面)。 */\nexport async function resolveMediaUri(uri: string, mediaDir: string | undefined): Promise<string> {\n if (mediaDir === undefined || mediaDir === \"\") {\n throw kernelError(\n \"远程媒体发送需要配置 [accounts.milky] cacheDir(下载缓存目录)\",\n \"INVALID_PARAM\",\n );\n }\n if (uri.startsWith(\"base64://\")) {\n return await writeBase64(uri.slice(\"base64://\".length), mediaDir);\n }\n const dest = join(mediaDir, `${randomUUID()}${inferExtension(null, uri)}`);\n await downloadUrl(uri, dest);\n return dest;\n}\n\n/**\n * 动作参数 URI(image_uri / file_uri)→ 本地路径:file:// 同步展开(fileURLToPath\n * 失败裸剥离兜底,与 segments.ts 同步面同规则);http(s):// / base64:// 复用\n * resolveMediaUri 落盘;裸路径(go-cqhttp 惯例)原样。\n */\nexport async function resolveUriToPath(uri: string, mediaDir: string | undefined): Promise<string> {\n if (uri.startsWith(\"file://\")) {\n try {\n return fileURLToPath(uri);\n } catch {\n return uri.replace(FILE_URI_PREFIX_RE, \"\");\n }\n }\n if (uri.startsWith(\"http://\") || uri.startsWith(\"https://\") || uri.startsWith(\"base64://\")) {\n return await resolveMediaUri(uri, mediaDir);\n }\n return uri;\n}\n\n/** base64 载荷 → 落盘(先写 .bin,探测到扩展名再改名)。 */\nasync function writeBase64(payload: string, mediaDir: string): Promise<string> {\n let bytes: Buffer;\n try {\n bytes = Buffer.from(payload, \"base64\");\n } catch {\n throw kernelError(\"base64:// 载荷解码失败\", \"INVALID_PARAM\");\n }\n if (bytes.length === 0) {\n throw kernelError(\"base64:// 载荷为空\", \"INVALID_PARAM\");\n }\n await mkdir(mediaDir, { recursive: true });\n const raw = join(mediaDir, `${randomUUID()}.bin`);\n await writeFile(raw, bytes);\n try {\n const { ext } = await detectFileType(raw);\n const final = join(mediaDir, `${randomUUID()}${ext}`);\n await rename(raw, final);\n return final;\n } catch {\n // 类型探测失败:保留 .bin(QQ 端按内容嗅探)\n return raw;\n }\n}\n","/**\n * Milky request 事件翻译(通道系,P1 2026-10-30)\n *\n * 事件源(kernel 事件通道,与 OB11 helper/request.ts 同源):\n * - Buddy/onBuddyReqChange → friend_request\n * - Group/onGroupNotifiesUpdated → group_join_request / group_invited_join_request /\n * group_invitation(type 1=邀请自身 / 5=成员邀请他人 / 7=入群申请,仅未处理状态)\n *\n * 纯函数(ADR-008):uid→uin 由调用方批量转换后传入。\n * onBuddyReqChange 回调参数形状未经真实事件校准——narrowBuddyReqs 防御性收窄\n * (core/buddy-req.ts,OB11 同源),未知形状返回 null 由调用方打 raw 日志。\n */\nimport type { BuddyReq, GroupNotify } from \"@napuketto/kernel\";\nimport { GroupNotifyMsgStatus, GroupNotifyMsgType } from \"@napuketto/kernel\";\nimport { MS_TO_SEC, type RequestTranslateContext, resolveUin } from \"../../core/uid-uin.js\";\nimport type {\n FriendRequestData,\n GroupInvitationData,\n GroupInvitedJoinRequestData,\n GroupJoinRequestData,\n MilkyEvent,\n} from \"../types.js\";\n\n/** uid → uin(core 共享解析;ctx 携带映射)。 */\nfunction toUin(uid: string | undefined, ctx: RequestTranslateContext): number {\n return resolveUin(uid, ctx.uidToUin);\n}\n\n/** BuddyReq → friend_request 事件(comment 取 words 字段,形状待校准,缺省空串)。 */\nexport function toFriendRequestEvent(\n req: BuddyReq,\n ctx: RequestTranslateContext,\n): MilkyEvent<FriendRequestData> {\n const words = req[\"words\"];\n return {\n time: Math.floor(Date.now() / MS_TO_SEC),\n self_id: Number(ctx.selfUin),\n event_type: \"friend_request\",\n data: {\n initiator_id: toUin(req.friendUid, ctx),\n initiator_uid: req.friendUid,\n comment: typeof words === \"string\" ? words : \"\",\n via: req.sourceName ?? \"\",\n },\n };\n}\n\n/** GroupNotify → Milky 群请求事件(非未处理状态 / 非请求类返回 null)。 */\nexport function toGroupRequestEvent(\n notify: GroupNotify,\n doubt: boolean,\n ctx: RequestTranslateContext,\n): MilkyEvent | null {\n if (notify.status !== GroupNotifyMsgStatus.KUNHANDLE) {\n return null;\n }\n const groupId = Number(notify.group?.groupCode ?? 0);\n const seq = Number(notify.seq);\n const time = Math.floor(Date.now() / MS_TO_SEC);\n const selfId = Number(ctx.selfUin);\n switch (notify.type) {\n case GroupNotifyMsgType.REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS: {\n const data: GroupJoinRequestData = {\n group_id: groupId,\n notification_seq: seq,\n is_filtered: doubt,\n initiator_id: toUin(notify.user1?.uid, ctx),\n comment: notify.postscript ?? \"\",\n };\n return { time, self_id: selfId, event_type: \"group_join_request\", data };\n }\n case GroupNotifyMsgType.INVITED_NEED_ADMINI_STRATOR_PASS: {\n // user1=邀请者 / user2=被邀请者(与 OB11 get_group_system_msg 口径一致)\n const data: GroupInvitedJoinRequestData = {\n group_id: groupId,\n notification_seq: seq,\n initiator_id: toUin(notify.user1?.uid, ctx),\n target_user_id: toUin(notify.user2?.uid, ctx),\n };\n return { time, self_id: selfId, event_type: \"group_invited_join_request\", data };\n }\n case GroupNotifyMsgType.INVITED_BY_MEMBER: {\n const data: GroupInvitationData = {\n group_id: groupId,\n invitation_seq: seq,\n initiator_id: toUin(notify.user1?.uid, ctx),\n source_group_id: null,\n };\n return { time, self_id: selfId, event_type: \"group_invitation\", data };\n }\n default:\n return null;\n }\n}\n\n/**\n * 群通知涉及的 uid 集合(去重;get_group_notifications 与事件广播共用)。\n * kernel GroupEventChannel 的 onGroupNotifiesUpdated 回调参数已类型化\n * (GroupNotify[]),无需防御收窄。\n */\nexport function collectNotifyUids(notifies: GroupNotify[]): string[] {\n const uids = new Set<string>();\n for (const n of notifies) {\n for (const uid of [n.user1?.uid, n.user2?.uid]) {\n if (uid !== undefined && uid !== \"\") {\n uids.add(uid);\n }\n }\n }\n return [...uids];\n}\n","/**\n * Milky 错误码映射(ADR-017:KernelErrorCode → 协议错误码,各协议自持)\n *\n * 规范语义:-400 = 参数解析失败、-403 = 未登录;其余业务错误为自定负数\n * (规范允许),取常见 HTTP 语义近似值便于应用端排查。\n */\nimport type { KernelErrorCode } from \"@napuketto/kernel\";\n\n/** KernelErrorCode → Milky retcode 映射表(-400/-403 规范语义,其余自定负数)。 */\nexport type MilkyErrorCodeMap = Record<KernelErrorCode, number>;\n\nexport const milkyErrorCodeMap: MilkyErrorCodeMap = {\n SEND_FAILED: -500,\n PERMISSION_DENIED: -405,\n NOT_FOUND: -404,\n TIMEOUT: -504,\n NOT_LOGIN: -403,\n INVALID_PARAM: -400,\n INVALID_STATE: -409,\n UNKNOWN: -500,\n};\n","/**\n * MilkyAction:Milky 动作基类(zod 校验 + KernelError → 负数 retcode)\n *\n * 与 OB11 BaseAction 分离的原因:Milky 响应信封无 echo、参数解析失败恒\n * retcode=-400(规范),不复用 OB11 的 400/1400 语义。\n * 响应信封由 transport 组装(status/retcode/data/message)。\n */\nimport { isKernelError } from \"@napuketto/kernel\";\nimport type { ZodType } from \"zod\";\nimport type { MilkyApi } from \"../api.js\";\nimport { type MilkyErrorCodeMap, milkyErrorCodeMap } from \"./error-map.js\";\n\n/** Milky 动作结果(retcode 为规范负数族;transport 原样组装信封)。 */\nexport interface MilkyActionResult<T> {\n status: \"ok\" | \"failed\";\n retcode: number;\n data: T | null;\n message: string;\n}\n\n/** zod 错误摘要(单行,issues 取前 3 条)。 */\nfunction zodSummary(error: { issues: Array<{ path: PropertyKey[]; message: string }> }): string {\n const parts: string[] = [];\n for (const issue of error.issues.slice(0, 3)) {\n parts.push(`${issue.path.map(String).join(\".\")}: ${issue.message}`);\n }\n return parts.join(\"; \");\n}\n\nexport abstract class MilkyAction<TPayload, TReturn> {\n abstract readonly name: string;\n abstract readonly schema: ZodType<TPayload>;\n protected abstract readonly errorCodeMap: MilkyErrorCodeMap;\n\n protected abstract _handle(payload: TPayload): Promise<TReturn>;\n\n /** 校验并执行(HTTP /api 入口;WS /event 不承载动作)。 */\n async handle(payload: unknown): Promise<MilkyActionResult<TReturn>> {\n const parsed = this.schema.safeParse(payload);\n if (!parsed.success) {\n return {\n status: \"failed\",\n retcode: -400,\n data: null,\n message: `参数解析失败: ${zodSummary(parsed.error)}`,\n };\n }\n try {\n return { status: \"ok\", retcode: 0, data: await this._handle(parsed.data), message: \"\" };\n } catch (err) {\n if (isKernelError(err)) {\n const retcode = this.errorCodeMap[err.code] ?? this.errorCodeMap.UNKNOWN;\n return { status: \"failed\", retcode, data: null, message: err.message };\n }\n return {\n status: \"failed\",\n retcode: this.errorCodeMap.UNKNOWN,\n data: null,\n message: err instanceof Error ? err.message : \"未知错误\",\n };\n }\n }\n}\n\n/**\n * 持 MilkyApi 的动作基类:api 注入 + 统一错误映射表(milkyErrorCodeMap)收拢,\n * 动作子类只写 name / schema / _handle。\n */\nexport abstract class MilkyApiAction<TPayload, TReturn> extends MilkyAction<TPayload, TReturn> {\n protected readonly errorCodeMap: MilkyErrorCodeMap = milkyErrorCodeMap;\n protected readonly api: MilkyApi;\n\n constructor(api: MilkyApi) {\n super();\n this.api = api;\n }\n}\n","/**\n * Milky 群类动作(P1):群信息 / 群管 / 精华 / 表态 / 通知\n *\n * - 群管(set_group_member_card / set_group_member_admin / set_group_member_mute /\n * kick_group_member):user_id(uin) → uid 转换后进 kernel(resolveUidFromUin)。\n * - 精华:seq → msgId 经 seqIndex 反查;列表经 WebApi.getEssenceMsgList(客户端分页)。\n * - 通知实体/应答:seq → getSingleScreenNotifies 匹配(先非可疑后可疑)→\n * handleGroupRequest;通知类型 7=入群申请 / 5=成员邀请他人 / 8,12,13=管理员变更 /\n * 9,10=踢出 / 11=退群(1=邀请自身无实体变体,不产出)。\n */\nimport type {\n EssenceMsgItem,\n GroupBulletin,\n GroupMember,\n GroupNotify,\n Peer,\n} from \"@napuketto/kernel\";\nimport { ChatType, kernelError, NTGroupRequestOperateTypes } from \"@napuketto/kernel\";\nimport { z } from \"zod\";\nimport { findGroupNotify, type MilkyApi } from \"../api.js\";\nimport { toGroupEntity, toGroupMemberEntity } from \"../helper/entities.js\";\nimport { resolveUriToPath } from \"../helper/media-uri.js\";\nimport { collectNotifyUids } from \"../helper/request.js\";\nimport type {\n GetGroupAnnouncementsOutput,\n GetGroupEssenceMessagesOutput,\n GetGroupInfoOutput,\n GetGroupMemberInfoOutput,\n GetGroupMemberListOutput,\n GetGroupNotificationsOutput,\n GroupAnnouncementEntity,\n GroupEssenceMessage,\n GroupNotificationEntity,\n IncomingSegment,\n} from \"../types.js\";\nimport { MilkyApiAction } from \"./base-action.js\";\n\nconst groupIdField = { group_id: z.number().int().min(10001) } as const;\nconst userIdField = { user_id: z.number().int().min(10001) } as const;\nconst optBool = z.boolean().nullable().optional();\nconst optStr = z.string().nullable().optional();\n\n/** get_group_info:获取群信息(GroupCache 详情缓存优先)。 */\nexport class GetGroupInfoAction extends MilkyApiAction<\n { group_id: number; no_cache?: boolean | null | undefined },\n GetGroupInfoOutput\n> {\n readonly name = \"get_group_info\";\n readonly schema = z.object({ ...groupIdField, no_cache: optBool });\n\n protected async _handle(payload: {\n group_id: number;\n no_cache?: boolean | null | undefined;\n }): Promise<GetGroupInfoOutput> {\n const groupCode = String(payload.group_id);\n const detail =\n this.api.groupCache !== undefined\n ? await this.api.groupCache.getGroupDetail(groupCode)\n : await this.api.groupApi.getGroupInfo(groupCode);\n return { group: toGroupEntity(detail, groupCode) };\n }\n}\n\n/** get_group_member_list:获取群成员列表(GroupCache 惰性回填)。 */\nexport class GetGroupMemberListAction extends MilkyApiAction<\n { group_id: number; no_cache?: boolean | null | undefined },\n GetGroupMemberListOutput\n> {\n readonly name = \"get_group_member_list\";\n readonly schema = z.object({ ...groupIdField, no_cache: optBool });\n\n protected async _handle(payload: {\n group_id: number;\n no_cache?: boolean | null | undefined;\n }): Promise<GetGroupMemberListOutput> {\n const members = await membersOf(this.api, String(payload.group_id));\n return {\n members: members.map((m) => toGroupMemberEntity(m, String(payload.group_id), m.uin)),\n };\n }\n}\n\n/** get_group_member_info:获取群成员信息(user_id = uin → 成员单查)。 */\nexport class GetGroupMemberInfoAction extends MilkyApiAction<\n { group_id: number; user_id: number; no_cache?: boolean | null | undefined },\n GetGroupMemberInfoOutput\n> {\n readonly name = \"get_group_member_info\";\n readonly schema = z.object({ ...groupIdField, ...userIdField, no_cache: optBool });\n\n protected async _handle(payload: {\n group_id: number;\n user_id: number;\n no_cache?: boolean | null | undefined;\n }): Promise<GetGroupMemberInfoOutput> {\n const member = await memberOf(this.api, payload.group_id, payload.user_id);\n return {\n member: toGroupMemberEntity(member, String(payload.group_id), String(payload.user_id)),\n };\n }\n}\n\n/** set_group_name:设置群名。 */\nexport class SetGroupNameAction extends MilkyApiAction<\n { group_id: number; new_group_name: string },\n Record<string, never>\n> {\n readonly name = \"set_group_name\";\n readonly schema = z.object({ ...groupIdField, new_group_name: z.string() });\n\n protected async _handle(payload: {\n group_id: number;\n new_group_name: string;\n }): Promise<Record<string, never>> {\n await this.api.groupApi.modifyGroupName(String(payload.group_id), payload.new_group_name);\n return {};\n }\n}\n\n/** set_group_member_card:设置群名片。 */\nexport class SetGroupMemberCardAction extends MilkyApiAction<\n { group_id: number; user_id: number; card: string },\n Record<string, never>\n> {\n readonly name = \"set_group_member_card\";\n readonly schema = z.object({ ...groupIdField, ...userIdField, card: z.string() });\n\n protected async _handle(payload: {\n group_id: number;\n user_id: number;\n card: string;\n }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n this.api.groupApi.setMemberCardName(String(payload.group_id), uid, payload.card);\n return {};\n }\n}\n\n/** set_group_member_admin:设置/取消管理员(is_set 缺省 true)。 */\nexport class SetGroupMemberAdminAction extends MilkyApiAction<\n { group_id: number; user_id: number; is_set?: boolean | null | undefined },\n Record<string, never>\n> {\n readonly name = \"set_group_member_admin\";\n readonly schema = z.object({ ...groupIdField, ...userIdField, is_set: optBool });\n\n protected async _handle(payload: {\n group_id: number;\n user_id: number;\n is_set?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n this.api.groupApi.setMemberRole(\n String(payload.group_id),\n uid,\n payload.is_set === false ? NTGroupMemberRoleMember : NTGroupMemberRoleAdmin,\n );\n return {};\n }\n}\n\n/** set_group_member_mute:禁言成员(duration 秒,0 解除)。 */\nexport class SetGroupMemberMuteAction extends MilkyApiAction<\n { group_id: number; user_id: number; duration?: number | null | undefined },\n Record<string, never>\n> {\n readonly name = \"set_group_member_mute\";\n readonly schema = z.object({\n ...groupIdField,\n ...userIdField,\n duration: z.number().int().min(0).nullable().optional(),\n });\n\n protected async _handle(payload: {\n group_id: number;\n user_id: number;\n duration?: number | null | undefined;\n }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n await this.api.groupApi.setMemberShutUp(String(payload.group_id), [\n { uid, duration: payload.duration ?? 0 },\n ]);\n return {};\n }\n}\n\n/** set_group_whole_mute:全员禁言开关(is_mute 缺省 true)。 */\nexport class SetGroupWholeMuteAction extends MilkyApiAction<\n { group_id: number; is_mute?: boolean | null | undefined },\n Record<string, never>\n> {\n readonly name = \"set_group_whole_mute\";\n readonly schema = z.object({ ...groupIdField, is_mute: optBool });\n\n protected async _handle(payload: {\n group_id: number;\n is_mute?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n await this.api.groupApi.setGroupShutUp(String(payload.group_id), payload.is_mute !== false);\n return {};\n }\n}\n\n/** kick_group_member:移除成员(reject_add_request 默认 false)。 */\nexport class KickGroupMemberAction extends MilkyApiAction<\n { group_id: number; user_id: number; reject_add_request?: boolean | null | undefined },\n Record<string, never>\n> {\n readonly name = \"kick_group_member\";\n readonly schema = z.object({\n ...groupIdField,\n ...userIdField,\n reject_add_request: optBool,\n });\n\n protected async _handle(payload: {\n group_id: number;\n user_id: number;\n reject_add_request?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n await this.api.groupApi.kickMember(\n String(payload.group_id),\n [uid],\n payload.reject_add_request === true,\n );\n return {};\n }\n}\n\n/** quit_group:退出群聊。 */\nexport class QuitGroupAction extends MilkyApiAction<{ group_id: number }, Record<string, never>> {\n readonly name = \"quit_group\";\n readonly schema = z.object({ ...groupIdField });\n\n protected async _handle(payload: { group_id: number }): Promise<Record<string, never>> {\n await this.api.groupApi.quitGroup(String(payload.group_id));\n return {};\n }\n}\n\n/**\n * get_group_essence_messages:获取精华消息列表。\n * WebApi.getEssenceMsgList 全量拉取后按 page_index/page_size 客户端分页\n * (kernel 无分页参数);message_time 无源取 operation_time 兜底。\n */\nexport class GetGroupEssenceMessagesAction extends MilkyApiAction<\n { group_id: number; page_index: number; page_size: number },\n GetGroupEssenceMessagesOutput\n> {\n readonly name = \"get_group_essence_messages\";\n readonly schema = z.object({\n ...groupIdField,\n page_index: z.number().int().min(0),\n page_size: z.number().int().min(0),\n });\n\n protected async _handle(payload: {\n group_id: number;\n page_index: number;\n page_size: number;\n }): Promise<GetGroupEssenceMessagesOutput> {\n const items = await this.api.webApi.getEssenceMsgList(String(payload.group_id));\n const start = payload.page_index * payload.page_size;\n const page = items.slice(start, start + payload.page_size);\n return {\n messages: page.map((item) => essenceToEntity(item, payload.group_id)),\n is_end: start + page.length >= items.length,\n };\n }\n}\n\n/** set_group_essence_message:设置/取消精华(seq → msgId 反查)。 */\nexport class SetGroupEssenceMessageAction extends MilkyApiAction<\n { group_id: number; message_seq: number; is_set?: boolean | null | undefined },\n Record<string, never>\n> {\n readonly name = \"set_group_essence_message\";\n readonly schema = z.object({\n ...groupIdField,\n message_seq: z.number().int().min(0),\n is_set: optBool,\n });\n\n protected async _handle(payload: {\n group_id: number;\n message_seq: number;\n is_set?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n const groupCode = String(payload.group_id);\n const peer: Peer = { chatType: ChatType.GROUP, peerUid: groupCode };\n const msgId = await this.api.resolveMsgIdBySeq(peer, payload.message_seq, ChatType.GROUP);\n if (msgId === undefined) {\n throw kernelError(`消息 ${payload.message_seq} 不存在`, \"NOT_FOUND\");\n }\n if (payload.is_set === false) {\n await this.api.groupApi.removeGroupEssence(groupCode, msgId);\n } else {\n await this.api.groupApi.addGroupEssence(groupCode, msgId);\n }\n return {};\n }\n}\n\n/** send_group_message_reaction:消息表情表态(reaction_type face→\"1\" / emoji→\"2\")。 */\nexport class SendGroupMessageReactionAction extends MilkyApiAction<\n {\n group_id: number;\n message_seq: number;\n reaction: string;\n reaction_type?: \"face\" | \"emoji\" | null | undefined;\n is_add?: boolean | null | undefined;\n },\n Record<string, never>\n> {\n readonly name = \"send_group_message_reaction\";\n readonly schema = z.object({\n ...groupIdField,\n message_seq: z.number().int().min(0),\n reaction: z.string().min(1),\n reaction_type: z.enum([\"face\", \"emoji\"]).nullable().optional(),\n is_add: z.boolean().nullable().optional(),\n });\n\n protected async _handle(payload: {\n group_id: number;\n message_seq: number;\n reaction: string;\n reaction_type?: \"face\" | \"emoji\" | null | undefined;\n is_add?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n const peer: Peer = { chatType: ChatType.GROUP, peerUid: String(payload.group_id) };\n await this.api.msgApi.setMsgEmojiLike(peer, {\n msgSeq: String(payload.message_seq),\n emojiId: payload.reaction,\n emojiType: payload.reaction_type === \"emoji\" ? \"2\" : \"1\",\n like: payload.is_add !== false,\n });\n return {};\n }\n}\n\n/**\n * get_group_notifications:获取群通知列表。\n * kernel getSingleScreenNotifies 为单屏快照(无翻页)——start_notification_seq\n * 作客户端过滤(取 seq 更小的记录);next = 本页最小 seq(仍有余量时)。\n */\nexport class GetGroupNotificationsAction extends MilkyApiAction<\n {\n start_notification_seq?: number | null | undefined;\n is_filtered?: boolean | null | undefined;\n limit?: number | null | undefined;\n },\n GetGroupNotificationsOutput\n> {\n readonly name = \"get_group_notifications\";\n readonly schema = z.object({\n start_notification_seq: z.number().int().min(0).nullable().optional(),\n is_filtered: optBool,\n limit: z.number().int().min(0).nullable().optional(),\n });\n\n protected async _handle(payload: {\n start_notification_seq?: number | null | undefined;\n is_filtered?: boolean | null | undefined;\n limit?: number | null | undefined;\n }): Promise<GetGroupNotificationsOutput> {\n const notifies = await this.api.groupNotifyApi.getSingleScreenNotifies(\n payload.is_filtered === true,\n NOTIFY_SEARCH_COUNT,\n );\n const start = payload.start_notification_seq;\n const filtered = notifies.filter(\n (n) => start === undefined || start === null || Number(n.seq) < start,\n );\n // 通知涉及的 uid → uin 批量转换(实体 user 字段都是 uin)\n const uidToUin = await this.collectUidToUin(filtered);\n const entities = filtered\n .map((n) => notifyToEntity(n, payload.is_filtered === true, uidToUin))\n .filter((e): e is GroupNotificationEntity => e !== null);\n const limit = payload.limit ?? NOTIFICATIONS_DEFAULT_LIMIT;\n const page = entities.slice(0, limit);\n const minSeq = page.reduce<number | null>(\n (acc, e) => (acc === null ? e.notification_seq : Math.min(acc, e.notification_seq)),\n null,\n );\n return {\n notifications: page,\n next_notification_seq: entities.length > page.length && minSeq !== null ? minSeq : null,\n };\n }\n\n /** 通知 user1/user2 uid → uin 批量转换(失败退空 Map,实体 id 兜底 0)。 */\n private async collectUidToUin(notifies: GroupNotify[]): Promise<Map<string, string>> {\n const uids = collectNotifyUids(notifies);\n if (uids.length === 0) {\n return new Map();\n }\n return await this.api.uidToUin(uids).catch(() => new Map<string, string>());\n }\n}\n\n/** accept/reject 群请求 / 群邀请公共基类:seq → 通知匹配 → handleGroupRequest。 */\nabstract class HandleGroupNotifyBase<TPayload> extends MilkyApiAction<\n TPayload,\n Record<string, never>\n> {\n /** 同意/拒绝。 */\n protected abstract readonly approve: boolean;\n\n protected async respond(seq: number, doubt: boolean): Promise<Record<string, never>> {\n const notify = await findGroupNotify(this.api, String(seq));\n await this.api.groupNotifyApi.handleGroupRequest(\n doubt,\n notify,\n this.approve ? NTGroupRequestOperateTypes.KAGREE : NTGroupRequestOperateTypes.KREFUSE,\n \" \",\n );\n return {};\n }\n}\n\n/** accept_group_request:同意入群请求(notification_type/group_id 仅 schema 校验)。 */\nexport class AcceptGroupRequestAction extends HandleGroupNotifyBase<{\n notification_seq: number;\n is_filtered?: boolean | null | undefined;\n}> {\n readonly name = \"accept_group_request\";\n readonly schema = z.object({\n notification_seq: z.number().int().min(0),\n notification_type: z.enum([\"join_request\", \"invited_join_request\"]),\n ...groupIdField,\n is_filtered: optBool,\n });\n protected readonly approve = true;\n\n protected async _handle(payload: {\n notification_seq: number;\n is_filtered?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n return await this.respond(payload.notification_seq, payload.is_filtered === true);\n }\n}\n\n/** reject_group_request:拒绝入群请求(reason 无源,kernel postscript 占位空格)。 */\nexport class RejectGroupRequestAction extends HandleGroupNotifyBase<{\n notification_seq: number;\n is_filtered?: boolean | null | undefined;\n}> {\n readonly name = \"reject_group_request\";\n readonly schema = z.object({\n notification_seq: z.number().int().min(0),\n notification_type: z.enum([\"join_request\", \"invited_join_request\"]),\n ...groupIdField,\n is_filtered: optBool,\n reason: optStr,\n });\n protected readonly approve = false;\n\n protected async _handle(payload: {\n notification_seq: number;\n is_filtered?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n return await this.respond(payload.notification_seq, payload.is_filtered === true);\n }\n}\n\n/** accept_group_invitation:接受入群邀请(按 invitation_seq 匹配)。 */\nexport class AcceptGroupInvitationAction extends HandleGroupNotifyBase<{ invitation_seq: number }> {\n readonly name = \"accept_group_invitation\";\n readonly schema = z.object({ ...groupIdField, invitation_seq: z.number().int().min(0) });\n protected readonly approve = true;\n\n protected async _handle(payload: { invitation_seq: number }): Promise<Record<string, never>> {\n return await this.respond(payload.invitation_seq, false);\n }\n}\n\n/** reject_group_invitation:拒绝入群邀请。 */\nexport class RejectGroupInvitationAction extends HandleGroupNotifyBase<{ invitation_seq: number }> {\n readonly name = \"reject_group_invitation\";\n readonly schema = z.object({ ...groupIdField, invitation_seq: z.number().int().min(0) });\n protected readonly approve = false;\n\n protected async _handle(payload: { invitation_seq: number }): Promise<Record<string, never>> {\n return await this.respond(payload.invitation_seq, false);\n }\n}\n\n/** send_group_nudge:发送群戳一戳(self.uid 缺失报 INVALID_PARAM)。 */\nexport class SendGroupNudgeAction extends MilkyApiAction<\n { group_id: number; user_id: number },\n Record<string, never>\n> {\n readonly name = \"send_group_nudge\";\n readonly schema = z.object({ ...groupIdField, ...userIdField });\n\n protected async _handle(payload: {\n group_id: number;\n user_id: number;\n }): Promise<Record<string, never>> {\n const receiverUid = await this.api.resolveUidFromUin(payload.user_id);\n const peer = await this.api.resolvePeer(\"group\", payload.group_id);\n await this.api.msgApi.sendNudge(peer, {\n receiverUid,\n callerUid: requireSelfUid(this.api),\n });\n return {};\n }\n}\n\n/** get_group_announcements:获取群公告列表(bulletin 形状待校准,宽松映射)。 */\nexport class GetGroupAnnouncementsAction extends MilkyApiAction<\n { group_id: number },\n GetGroupAnnouncementsOutput\n> {\n readonly name = \"get_group_announcements\";\n readonly schema = z.object({ ...groupIdField });\n\n protected async _handle(payload: { group_id: number }): Promise<GetGroupAnnouncementsOutput> {\n const groupCode = String(payload.group_id);\n const bulletins = await this.api.groupApi.getGroupAnnouncements(groupCode);\n const announcements = await Promise.all(\n bulletins.map((b) => bulletinToEntity(b, payload.group_id, this.api)),\n );\n return { announcements };\n }\n}\n\n/** send_group_announcement:发群公告(image_uri 落盘后经上传+发布两步)。 */\nexport class SendGroupAnnouncementAction extends MilkyApiAction<\n { group_id: number; content: string; image_uri?: string | null | undefined },\n Record<string, never>\n> {\n readonly name = \"send_group_announcement\";\n readonly schema = z.object({ ...groupIdField, content: z.string().min(1), image_uri: optStr });\n\n protected async _handle(payload: {\n group_id: number;\n content: string;\n image_uri?: string | null | undefined;\n }): Promise<Record<string, never>> {\n const groupCode = String(payload.group_id);\n let imagePath: string | undefined;\n if (\n payload.image_uri !== undefined &&\n payload.image_uri !== null &&\n payload.image_uri !== \"\"\n ) {\n imagePath = await resolveUriToPath(payload.image_uri, this.api.mediaDir);\n }\n await this.api.groupApi.publishGroupAnnouncement(groupCode, payload.content, imagePath);\n return {};\n }\n}\n\n/** delete_group_announcement:删除群公告。 */\nexport class DeleteGroupAnnouncementAction extends MilkyApiAction<\n { group_id: number; announcement_id: string },\n Record<string, never>\n> {\n readonly name = \"delete_group_announcement\";\n readonly schema = z.object({ ...groupIdField, announcement_id: z.string().min(1) });\n\n protected async _handle(payload: {\n group_id: number;\n announcement_id: string;\n }): Promise<Record<string, never>> {\n await this.api.groupApi.deleteGroupAnnouncement(\n String(payload.group_id),\n payload.announcement_id,\n );\n return {};\n }\n}\n\n/** set_group_avatar:设置群头像(image_uri → 本地路径)。 */\nexport class SetGroupAvatarAction extends MilkyApiAction<\n { group_id: number; image_uri: string },\n Record<string, never>\n> {\n readonly name = \"set_group_avatar\";\n readonly schema = z.object({ ...groupIdField, image_uri: z.string().min(1) });\n\n protected async _handle(payload: {\n group_id: number;\n image_uri: string;\n }): Promise<Record<string, never>> {\n const imagePath = await resolveUriToPath(payload.image_uri, this.api.mediaDir);\n await this.api.groupApi.setGroupAvatar(String(payload.group_id), imagePath);\n return {};\n }\n}\n\n/** set_group_member_special_title:设置专属头衔(uin → uid)。 */\nexport class SetGroupMemberSpecialTitleAction extends MilkyApiAction<\n { group_id: number; user_id: number; special_title: string },\n Record<string, never>\n> {\n readonly name = \"set_group_member_special_title\";\n readonly schema = z.object({\n ...groupIdField,\n ...userIdField,\n special_title: z.string(),\n });\n\n protected async _handle(payload: {\n group_id: number;\n user_id: number;\n special_title: string;\n }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n await this.api.groupApi.setMemberSpecialTitle(\n String(payload.group_id),\n uid,\n payload.special_title,\n );\n return {};\n }\n}\n\n/** ---------- 内部辅助 ---------- */\n\n/** 通知查找数量(单屏全量,OB11 DEFAULT_COUNT 同值)。 */\nconst NOTIFY_SEARCH_COUNT = 100;\n\n/** get_group_notifications 默认 limit(规范 default 20)。 */\nconst NOTIFICATIONS_DEFAULT_LIMIT = 20;\n\n/** NTGroupMemberRole 数值(ADMIN=3 / MEMBER=2,setMemberRole 入参)。 */\nconst NTGroupMemberRoleAdmin = 3;\nconst NTGroupMemberRoleMember = 2;\n\n/** 成员列表(GroupCache 优先,未装配直查)。 */\nasync function membersOf(api: MilkyApi, groupCode: string): Promise<GroupMember[]> {\n if (api.groupCache !== undefined) {\n return await api.groupCache.getMembers(groupCode);\n }\n return await api.groupApi.getGroupMemberList(groupCode, true);\n}\n\n/** 成员单查(user_id = uin;缓存路径经 uid,直查路径按 uin 匹配)。 */\nasync function memberOf(api: MilkyApi, groupId: number, userId: number): Promise<GroupMember> {\n const groupCode = String(groupId);\n const uin = String(userId);\n if (api.groupCache !== undefined) {\n const uid = await api.resolveUidFromUin(userId).catch(() => uin);\n const member = await api.groupCache.getMember(groupCode, uid);\n if (member === undefined) {\n throw kernelError(`成员 ${uin} 不在群 ${groupCode}`, \"NOT_FOUND\");\n }\n return member;\n }\n const list = await api.groupApi.getGroupMemberList(groupCode, true);\n const hit = list.find((m) => m.uin === uin);\n if (hit === undefined) {\n throw kernelError(`成员 ${uin} 不在群 ${groupCode}`, \"NOT_FOUND\");\n }\n return hit;\n}\n\n/** 精华项 → GroupEssenceMessage(msg_content 近似翻译:text / image)。 */\nfunction essenceToEntity(item: EssenceMsgItem, groupId: number): GroupEssenceMessage {\n const segments: IncomingSegment[] = [];\n for (const c of item.msg_content) {\n if (c.text !== undefined && c.text !== \"\") {\n segments.push({ type: \"text\", data: { text: c.text } });\n } else if (c.image_url !== undefined && c.image_url !== \"\") {\n segments.push({\n type: \"image\",\n data: {\n resource_id: c.image_url,\n temp_url: c.image_url,\n width: 0,\n height: 0,\n summary: \"\",\n sub_type: \"normal\",\n },\n });\n }\n }\n return {\n group_id: groupId,\n message_seq: item.msg_seq,\n message_time: item.add_digest_time,\n sender_id: Number(item.sender_uin) || 0,\n sender_name: item.sender_nick,\n operator_id: Number(item.add_digest_uin) || 0,\n operator_name: item.add_digest_nick,\n operation_time: item.add_digest_time,\n segments,\n };\n}\n\n/**\n * GroupNotify → GroupNotificationEntity(uidToUin 已由调用方批量转换)。\n * 类型→构造器表:7=入群申请 / 5=成员邀请他人 / 8=设管理 / 12,13=取消管理 /\n * 9,10=踢出 / 11=退群;1=邀请自身无实体变体(事件层表达),其余 null。\n */\nconst NOTIFY_ENTITY_BUILDERS: Partial<\n Record<\n number,\n (notify: GroupNotify, uinOf: (uid: string | undefined) => number) => GroupNotificationEntity\n >\n> = {\n 7: (n, uinOf) => ({\n type: \"join_request\",\n group_id: Number(n.group?.groupCode ?? 0),\n notification_seq: Number(n.seq),\n is_filtered: false,\n initiator_id: uinOf(n.user1?.uid),\n state: \"pending\",\n operator_id: null,\n comment: n.postscript ?? \"\",\n }),\n 5: (n, uinOf) => ({\n type: \"invited_join_request\",\n group_id: Number(n.group?.groupCode ?? 0),\n notification_seq: Number(n.seq),\n initiator_id: uinOf(n.user1?.uid),\n target_user_id: uinOf(n.user2?.uid),\n state: \"pending\",\n operator_id: null,\n }),\n 8: (n, uinOf) => adminChangeEntity(n, uinOf, true),\n 12: (n, uinOf) => adminChangeEntity(n, uinOf, false),\n 13: (n, uinOf) => adminChangeEntity(n, uinOf, false),\n 9: (n, uinOf) => kickEntity(n, uinOf),\n 10: (n, uinOf) => kickEntity(n, uinOf),\n 11: (n, uinOf) => ({\n type: \"quit\",\n group_id: Number(n.group?.groupCode ?? 0),\n notification_seq: Number(n.seq),\n target_user_id: uinOf(n.user1?.uid),\n }),\n};\n\n/** admin_change 实体(8/12/13 共用)。 */\nfunction adminChangeEntity(\n n: GroupNotify,\n uinOf: (uid: string | undefined) => number,\n isSet: boolean,\n): GroupNotificationEntity {\n return {\n type: \"admin_change\",\n group_id: Number(n.group?.groupCode ?? 0),\n notification_seq: Number(n.seq),\n target_user_id: uinOf(n.user1?.uid),\n is_set: isSet,\n operator_id: uinOf(n.user2?.uid),\n };\n}\n\n/** kick 实体(9/10 共用)。 */\nfunction kickEntity(\n n: GroupNotify,\n uinOf: (uid: string | undefined) => number,\n): GroupNotificationEntity {\n return {\n type: \"kick\",\n group_id: Number(n.group?.groupCode ?? 0),\n notification_seq: Number(n.seq),\n target_user_id: uinOf(n.user1?.uid),\n operator_id: uinOf(n.user2?.uid),\n };\n}\n\n/** GroupNotify → 实体(isFiltered 透传给 join_request;未识别类型 null)。 */\nfunction notifyToEntity(\n notify: GroupNotify,\n isFiltered: boolean,\n uidToUin: Map<string, string>,\n): GroupNotificationEntity | null {\n const uinOf = (uid: string | undefined): number =>\n uid === undefined || uid === \"\" ? 0 : Number(uidToUin.get(uid) ?? 0) || 0;\n const builder = NOTIFY_ENTITY_BUILDERS[notify.type];\n if (builder === undefined) {\n return null;\n }\n const entity = builder(notify, uinOf);\n if (entity.type === \"join_request\") {\n entity.is_filtered = isFiltered;\n }\n return entity;\n}\n\n/** self.uid 必备(nudge 发送的 callerUid;缺配置报 INVALID_PARAM)。 */\nfunction requireSelfUid(api: MilkyApi): string {\n const uid = api.self.uid;\n if (uid === undefined || uid === \"\") {\n throw kernelError(\"登录身份缺 uid(无法发起戳一戳)\", \"INVALID_PARAM\");\n }\n return uid;\n}\n\n/** GroupBulletin → 群公告实体(senderUid → uin 反查;无源字段兜底,待校准)。 */\nasync function bulletinToEntity(\n b: GroupBulletin,\n groupId: number,\n api: MilkyApi,\n): Promise<GroupAnnouncementEntity> {\n return {\n group_id: groupId,\n announcement_id: b.announcementId ?? \"\",\n user_id: await senderUinOf(b, api),\n time: Number(b.publishTime) || 0,\n content: b.content ?? \"\",\n image_url: picUrlOf(b),\n };\n}\n\n/** 公告发送者 uid → uin(缺省/转换失败 0 兜底)。 */\nasync function senderUinOf(b: GroupBulletin, api: MilkyApi): Promise<number> {\n const uid = b.senderUid;\n if (typeof uid !== \"string\" || uid === \"\") {\n return 0;\n }\n const uins = await api.uidToUin([uid]).catch(() => undefined);\n return Number(uins?.get(uid)) || 0;\n}\n\n/** 公告图片 url(缺省 null)。 */\nfunction picUrlOf(b: GroupBulletin): string | null {\n const url = b.pic?.url;\n return typeof url === \"string\" && url !== \"\" ? url : null;\n}\n","/**\n * Milky 消息段 ↔ canonical 元素转换(纯函数,ADR-008)\n *\n * 接收方向:canonical → IncomingSegment(规范 14 种中映射 12 种;market_face /\n * markdown 无 canonical 对应(MFACE/MARKDOWN 原始元素形状未探测),unknown 一律\n * 跳过——规范兼容性要求「数组中未知项跳过」)。forward 接收段不经 canonical:\n * kernel 无 MULTI_FORWARD 分支,adapter 从 RawMessage 提取 resId 后经\n * incomingForwardSegment + ctx 注入。\n * 发送方向:OutgoingSegment → canonical(10 种全映射;forward 顶层段不走本转换器,\n * 由 sendMilkyMessage 分流到组装链——本转换器内 forward 报错只拦截混发/嵌套)。\n */\nimport { fileURLToPath } from \"node:url\";\nimport type { CanonicalElement } from \"@napuketto/kernel\";\nimport { kernelError } from \"@napuketto/kernel\";\nimport type { IncomingSegment, OutgoingSegment } from \"../types.js\";\n\n/** reply 段回填元信息(广播/action 路径异步取得,翻译纯函数消费)。 */\nexport interface ReplyMeta {\n messageSeq: number;\n senderId: number;\n time: number;\n}\n\n/** 接收段转换上下文(enrichment 产物)。 */\nexport interface ReceiveSegmentContext {\n /** at uid → uin(mention.user_id 需要 uin;缺省不转换,转换失败跳过该段)。 */\n uidToUin?: Map<string, string>;\n /** reply NT msgId → 引用消息元信息(回填 message_seq/sender_id/time)。 */\n replyMeta?: Map<string, ReplyMeta>;\n}\n\n/** uin 字符串 → Milky user_id(非有限正数 = 转换失败)。 */\nfunction toUserId(uin: string): number | undefined {\n const n = Number(uin);\n return Number.isFinite(n) && n >= 10001 ? n : undefined;\n}\n\n/** canonical 元素 → IncomingSegment 列表(unknown / 转换失败段跳过)。 */\nexport function canonicalToIncomingSegments(\n elements: CanonicalElement[],\n ctx: ReceiveSegmentContext = {},\n): IncomingSegment[] {\n const out: IncomingSegment[] = [];\n for (const el of elements) {\n const seg = canonicalToIncomingSegment(el, ctx);\n if (seg !== null) {\n out.push(seg);\n }\n }\n return out;\n}\n\n/** canonical image → image 段(resource_id = 本地路径优先,url 兜底)。 */\nfunction imageToIncoming(el: Extract<CanonicalElement, { type: \"image\" }>): IncomingSegment {\n return {\n type: \"image\",\n data: {\n resource_id: el.path !== \"\" ? el.path : (el.url ?? \"\"),\n temp_url: el.url ?? \"\",\n width: el.size?.width ?? 0,\n height: el.size?.height ?? 0,\n summary: \"\",\n sub_type: \"normal\",\n },\n };\n}\n\n/** canonical voice → record 段。 */\nfunction voiceToIncoming(el: Extract<CanonicalElement, { type: \"voice\" }>): IncomingSegment {\n return {\n type: \"record\",\n data: {\n resource_id: el.path !== \"\" ? el.path : (el.url ?? \"\"),\n temp_url: el.url ?? \"\",\n duration: el.durationMs !== undefined ? Math.round(el.durationMs / 1000) : 0,\n },\n };\n}\n\n/** canonical video → video 段。 */\nfunction videoToIncoming(el: Extract<CanonicalElement, { type: \"video\" }>): IncomingSegment {\n return {\n type: \"video\",\n data: {\n resource_id: el.path !== \"\" ? el.path : (el.url ?? \"\"),\n temp_url: el.url ?? \"\",\n width: el.width ?? 0,\n height: el.height ?? 0,\n duration: el.durationSec ?? 0,\n },\n };\n}\n\n/** 按类型分发的段映射器表(键 = canonical type;缺项 = 跳过)。 */\nconst INCOMING_MAPPERS: Partial<\n Record<\n CanonicalElement[\"type\"],\n (el: never, ctx: ReceiveSegmentContext) => IncomingSegment | null\n >\n> = {\n text: (el: Extract<CanonicalElement, { type: \"text\" }>) => ({\n type: \"text\",\n data: { text: el.text },\n }),\n at: atToIncoming,\n face: (el: Extract<CanonicalElement, { type: \"face\" }>) => ({\n type: \"face\",\n data: { face_id: el.id, is_large: false },\n }),\n reply: replyToIncoming,\n image: imageToIncoming,\n voice: voiceToIncoming,\n video: videoToIncoming,\n file: fileToIncoming,\n json: (el: Extract<CanonicalElement, { type: \"json\" }>) => ({\n type: \"light_app\",\n data: { app_name: parseAppName(el.raw), json_payload: rawToPayload(el.raw) },\n }),\n xml: (el: Extract<CanonicalElement, { type: \"xml\" }>) => ({\n type: \"xml\",\n data: { service_id: 0, xml_payload: rawToPayload(el.raw) },\n }),\n};\n\nfunction canonicalToIncomingSegment(\n el: CanonicalElement,\n ctx: ReceiveSegmentContext,\n): IncomingSegment | null {\n const mapper = INCOMING_MAPPERS[el.type];\n // unknown / 未映射类型:跳过(规范兼容性要求)\n return mapper === undefined ? null : mapper(el as never, ctx);\n}\n\n/** canonical at → mention / mention_all(uid→uin 失败跳过该段)。 */\nfunction atToIncoming(\n el: Extract<CanonicalElement, { type: \"at\" }>,\n ctx: ReceiveSegmentContext,\n): IncomingSegment | null {\n if (el.target === \"all\") {\n return { type: \"mention_all\", data: {} };\n }\n const uin = ctx.uidToUin?.get(el.target) ?? el.target;\n const userId = toUserId(uin);\n if (userId === undefined) {\n return null;\n }\n return { type: \"mention\", data: { user_id: userId, name: el.display ?? \"\" } };\n}\n\n/** canonical reply → reply 段(引用元信息经 ctx 回填,未命中全 0 兜底)。 */\nfunction replyToIncoming(\n el: Extract<CanonicalElement, { type: \"reply\" }>,\n ctx: ReceiveSegmentContext,\n): IncomingSegment {\n const meta = ctx.replyMeta?.get(el.messageId);\n return {\n type: \"reply\",\n data: {\n message_seq: meta?.messageSeq ?? 0,\n sender_id: meta?.senderId ?? 0,\n sender_name: null,\n time: meta?.time ?? 0,\n segments: [],\n },\n };\n}\n\n/** canonical file → file 段。 */\nfunction fileToIncoming(el: Extract<CanonicalElement, { type: \"file\" }>): IncomingSegment {\n return {\n type: \"file\",\n data: {\n file_id: el.path,\n file_name: el.name ?? \"\",\n file_size: el.size ?? 0,\n },\n };\n}\n\n/**\n * 合并转发 → forward 段(P1)。\n * 接收方向 canonical 不承载 MULTI_FORWARD(kernel toCanonicalElement 无此分支),\n * 由 adapter 从 RawMessage 提取 resId 后调用本函数经 ctx 注入(翻译保持纯函数)。\n * title 取 NT fileName(转发卡片标题语义)。\n */\nexport function incomingForwardSegment(resId: string, title: string): IncomingSegment {\n return {\n type: \"forward\",\n data: {\n forward_id: resId,\n title,\n preview: [],\n summary: \"\",\n },\n };\n}\n\n/** json 载荷 → 小程序名(spec app_name:JSON 顶层 app 字段,取不到空串)。 */\nfunction parseAppName(raw: unknown): string {\n let obj: unknown = raw;\n if (typeof raw === \"string\") {\n try {\n obj = JSON.parse(raw);\n } catch {\n return \"\";\n }\n }\n if (typeof obj !== \"object\" || obj === null || !(\"app\" in obj)) {\n return \"\";\n }\n const app = (obj as Record<string, unknown>)[\"app\"];\n return typeof app === \"string\" ? app : \"\";\n}\n\n/** canonical json/xml raw → 字符串载荷(字符串原样,其余 JSON 序列化)。 */\nfunction rawToPayload(raw: unknown): string {\n if (typeof raw === \"string\") {\n return raw;\n }\n try {\n return JSON.stringify(raw) ?? \"\";\n } catch {\n return \"\";\n }\n}\n\n/**\n * OutgoingSegment 数组 → canonical 元素(同步映射;媒体 URI 解析与 at uin→uid\n * 由调用方在返回值上继续处理)。\n * forward 在此报错:顶层 forward 已由 sendMilkyMessage 分流到组装链(message.ts,\n * P2 批次一),命中本分支 = forward 与其他段混发漏网或嵌套 forward(组装链内逐项\n * 转换经过此处)——均显式拒绝。\n */\nexport function outgoingSegmentsToCanonical(segments: OutgoingSegment[]): {\n elements: CanonicalElement[];\n atUins: string[];\n replySeqs: number[];\n} {\n const elements: CanonicalElement[] = [];\n const atUins: string[] = [];\n const replySeqs: number[] = [];\n for (const seg of segments) {\n switch (seg.type) {\n case \"text\":\n elements.push({ type: \"text\", text: seg.data.text });\n break;\n case \"mention\": {\n const uin = String(seg.data.user_id);\n atUins.push(uin);\n elements.push({ type: \"at\", target: uin });\n break;\n }\n case \"mention_all\":\n elements.push({ type: \"at\", target: \"all\" });\n break;\n case \"face\":\n elements.push({ type: \"face\", id: seg.data.face_id });\n break;\n case \"reply\": {\n replySeqs.push(seg.data.message_seq);\n elements.push({ type: \"reply\", messageId: String(seg.data.message_seq) });\n break;\n }\n case \"image\":\n elements.push({ type: \"image\", path: resolveUriToPathPlaceholder(seg.data.uri) });\n break;\n case \"record\":\n elements.push({ type: \"voice\", path: resolveUriToPathPlaceholder(seg.data.uri) });\n break;\n case \"video\":\n elements.push({ type: \"video\", path: resolveUriToPathPlaceholder(seg.data.uri) });\n break;\n case \"light_app\":\n elements.push({ type: \"json\", raw: seg.data.json_payload });\n break;\n case \"forward\":\n throw kernelError(\n \"forward 段不可与其他消息段混发或嵌套(顶层 forward 须单独发送)\",\n \"INVALID_PARAM\",\n );\n default:\n // 未知段:跳过(规范兼容性要求)\n break;\n }\n }\n return { elements, atUins, replySeqs };\n}\n\n/**\n * 媒体 URI → 本地路径(同步面:file:// / 裸路径直接给 canonical;base64:// 与\n * http(s):// 需要异步落盘,由 send 核心在 canonical 上二次解析——此处先放原始\n * URI 作占位,send 核心按元素类型调用 resolveMediaUri 替换)。\n */\nfunction resolveUriToPathPlaceholder(uri: string): string {\n if (uri.startsWith(\"file://\")) {\n return fileUriToPath(uri);\n }\n if (uri.startsWith(\"http://\") || uri.startsWith(\"https://\") || uri.startsWith(\"base64://\")) {\n return uri;\n }\n // 裸路径(go-cqhttp 惯例):按本地路径处理\n return uri;\n}\n\n/** file:// 前缀(fileURLToPath 失败时的裸剥离兜底)。 */\nconst FILE_URI_PREFIX_RE = /^file:\\/\\//;\n\n/** file:// URI → 平台路径(Windows 盘符兼容)。 */\nfunction fileUriToPath(uri: string): string {\n try {\n return fileURLToPath(uri);\n } catch {\n return uri.replace(FILE_URI_PREFIX_RE, \"\");\n }\n}\n","/**\n * Milky 事件翻译(RawMessage → Milky 事件,纯函数,ADR-008)\n *\n * P0 事件两种:message_receive(onRecvMsg)/ message_recall(grayTip REVOKE)。\n * 实体与 reply 回填在广播路径异步取得后经 ctx 注入(翻译保持纯函数);\n * 撤回事件的 sender_id 取 RawMessage.senderUin(grayTip 系统消息的 sender\n * 即被撤回原消息的发送者,口径待真实事件校准)。\n */\nimport {\n type CanonicalElement,\n ChatType,\n type RawMessage,\n toCanonicalElements,\n} from \"@napuketto/kernel\";\nimport type {\n GroupEntity,\n GroupFileUploadData,\n GroupMemberEntity,\n IncomingMessage,\n IncomingSegment,\n MessageRecallData,\n MilkyEvent,\n} from \"../types.js\";\nimport { toFriendEntity, toGroupEntity, toGroupMemberEntity } from \"./entities.js\";\nimport { canonicalToIncomingSegments, type ReceiveSegmentContext } from \"./segments.js\";\n\n/** 毫秒 → 秒(Unix 时间戳)。 */\nconst MS_TO_SEC = 1000;\n\n/** 接收事件翻译上下文。 */\nexport interface ReceiveTranslateContext extends ReceiveSegmentContext {\n /** 登录 uin(self_id)。 */\n selfUin: string;\n /** friend 场景:好友实体(广播路径 best-effort 构造;缺省最小实体)。 */\n friendEntity?: import(\"../types.js\").FriendEntity;\n /** group 场景:群实体(缺省最小实体)。 */\n groupEntity?: GroupEntity;\n /** group 场景:群成员实体(缺省最小实体)。 */\n groupMemberEntity?: GroupMemberEntity;\n /**\n * 合并转发段(P1):adapter 从 RawMessage 的 multiForwardMsgElement 提取\n * resId 后预构建(canonical 不承载 MULTI_FORWARD),追加到段尾。\n */\n forwardSegments?: IncomingSegment[];\n}\n\n/** chatType → message_scene。 */\nexport function chatTypeToScene(chatType: number): \"friend\" | \"group\" | \"temp\" {\n if (chatType === ChatType.GROUP) {\n return \"group\";\n }\n if (chatType === ChatType.C2C_TEMP) {\n return \"temp\";\n }\n return \"friend\";\n}\n\n/** peer_id:群聊 = 群号(peerUid);好友/临时 = 对端 uin(peerUin,空退 peerUid)。 */\nfunction peerIdOf(msg: RawMessage, scene: \"friend\" | \"group\" | \"temp\"): number {\n const raw = scene === \"group\" ? msg.peerUid : msg.peerUin !== \"\" ? msg.peerUin : msg.peerUid;\n return Number(raw);\n}\n\n/** RawMessage → message_receive 事件(实体缺省最小合法值,schema 形状完整)。 */\nexport function toMessageReceiveEvent(\n msg: RawMessage,\n ctx: ReceiveTranslateContext,\n): MilkyEvent<IncomingMessage> {\n const elements: CanonicalElement[] = toCanonicalElements(msg);\n const segments = canonicalToIncomingSegments(elements, {\n ...(ctx.uidToUin !== undefined ? { uidToUin: ctx.uidToUin } : {}),\n ...(ctx.replyMeta !== undefined ? { replyMeta: ctx.replyMeta } : {}),\n });\n if (ctx.forwardSegments !== undefined) {\n segments.push(...ctx.forwardSegments);\n }\n const scene = chatTypeToScene(msg.chatType);\n const time = Math.floor(Number(msg.msgTime) / MS_TO_SEC);\n let data: IncomingMessage;\n if (scene === \"group\") {\n data = {\n message_scene: \"group\",\n peer_id: peerIdOf(msg, scene),\n message_seq: Number(msg.msgSeq),\n sender_id: Number(msg.senderUin),\n time,\n segments,\n group: ctx.groupEntity ?? toGroupEntity(undefined, msg.peerUid),\n group_member:\n ctx.groupMemberEntity ?? toGroupMemberEntity(undefined, msg.peerUid, msg.senderUin),\n };\n } else if (scene === \"friend\") {\n data = {\n message_scene: \"friend\",\n peer_id: peerIdOf(msg, scene),\n message_seq: Number(msg.msgSeq),\n sender_id: Number(msg.senderUin),\n time,\n segments,\n friend:\n ctx.friendEntity ??\n toFriendEntity(\n undefined,\n msg.peerUin !== \"\" ? msg.peerUin : msg.senderUin,\n msg.peerName,\n ),\n };\n } else {\n data = {\n message_scene: \"temp\",\n peer_id: peerIdOf(msg, scene),\n message_seq: Number(msg.msgSeq),\n sender_id: Number(msg.senderUin),\n time,\n segments,\n group: ctx.groupEntity ?? null,\n };\n }\n return {\n time,\n self_id: Number(ctx.selfUin),\n event_type: \"message_receive\",\n data,\n };\n}\n\n/** 撤回 grayTip → message_recall 事件(非撤回 grayTip 返回 null)。 */\nexport function toMessageRecallEvent(\n msg: RawMessage,\n ctx: { selfUin: string; uidToUin?: Map<string, string> },\n): MilkyEvent<MessageRecallData> | null {\n const gray = msg.elements.find((el) => el.grayTipElement !== undefined)?.grayTipElement;\n const revoke = gray?.revokeElement;\n if (revoke === undefined) {\n return null;\n }\n const scene = chatTypeToScene(msg.chatType);\n const operatorUin = ctx.uidToUin?.get(revoke.operatorUid) ?? revoke.operatorUid;\n return {\n time: Math.floor(Number(msg.msgTime) / MS_TO_SEC),\n self_id: Number(ctx.selfUin),\n event_type: \"message_recall\",\n data: {\n message_scene: scene,\n peer_id: peerIdOf(msg, scene),\n message_seq: Number(msg.msgSeq),\n sender_id: Number(msg.senderUin),\n operator_id: Number(operatorUin) || 0,\n display_suffix: revoke.wording ?? \"\",\n },\n };\n}\n\n/** 群文件上传事件(群场景文件消息 → group_file_upload,替代 message_receive)。 */\nexport function toGroupFileUploadEvent(\n msg: RawMessage,\n selfUin: string,\n): MilkyEvent<GroupFileUploadData> | null {\n if (msg.chatType !== ChatType.GROUP) {\n return null;\n }\n const file = msg.elements.find((el) => el.fileElement !== undefined)?.fileElement;\n if (file === undefined) {\n return null;\n }\n return {\n time: Math.floor(Number(msg.msgTime) / MS_TO_SEC),\n self_id: Number(selfUin),\n event_type: \"group_file_upload\",\n data: {\n group_id: Number(msg.peerUid),\n user_id: Number(msg.senderUin) || 0,\n file_id: file.fileUuid ?? file.fileName ?? \"\",\n file_name: file.fileName ?? \"\",\n file_size: Number(file.fileSize ?? 0),\n },\n };\n}\n","/**\n * Milky 消息类动作(P0:send_private_message / send_group_message / get_message /\n * recall_private_message / recall_group_message;\n * P1 +3:get_history_messages / get_forwarded_messages / mark_message_as_read;\n * P2 批次一:forward 发送段组装链)\n *\n * 发送核心 sendMilkyMessage:OutgoingSegment → canonical(媒体 URI 异步落盘 +\n * at uin→uid + reply seq→msgId 原样兜底)→ MsgApi.sendMessage → 回查 msgSeq/time。\n * forward 段走专用组装链(sendForwardComposition,临时消息法,见 milky.md §0.6)。\n * get/recall 入口是 message_seq(Milky ID 模型),经 seqIndex 反查 msgId。\n * get_forwarded_messages 经 seqIndex 转发索引(resId → peer)定位。\n */\nimport type {\n CanonicalElement,\n GroupDetailInfo,\n GroupMember,\n Peer,\n RawMessage,\n} from \"@napuketto/kernel\";\nimport { ChatType, kernelError, toCanonicalElements } from \"@napuketto/kernel\";\nimport { type ZodType, z } from \"zod\";\nimport type { MilkyApi } from \"../api.js\";\nimport { toGroupEntity, toGroupMemberEntity } from \"../helper/entities.js\";\nimport { resolveMediaUri, resolveUriToPath } from \"../helper/media-uri.js\";\nimport {\n canonicalToIncomingSegments,\n incomingForwardSegment,\n outgoingSegmentsToCanonical,\n} from \"../helper/segments.js\";\nimport { type ReceiveTranslateContext, toMessageReceiveEvent } from \"../helper/translate.js\";\nimport type {\n GetCustomFaceUrlListOutput,\n GetForwardedMessagesOutput,\n GetHistoryMessagesOutput,\n GetMessageOutput,\n GetResourceTempUrlOutput,\n IncomingForwardedMessage,\n IncomingMessage,\n IncomingSegment,\n MessageScene,\n OutgoingForwardedMessage,\n OutgoingSegment,\n SendMessageOutput,\n UploadFileOutput,\n} from \"../types.js\";\nimport { MilkyApiAction } from \"./base-action.js\";\n\n/**\n * OutgoingSegment 宽松校验:入口只保证「{type, data}」形状,字段级转换在\n * outgoingSegmentsToCanonical 内做(未知段跳过 = 规范兼容性要求)。\n */\nconst outgoingSegmentSchema = z\n .object({ type: z.string(), data: z.record(z.string(), z.unknown()) })\n .loose() as unknown as ZodType<OutgoingSegment>;\n\nconst sendMessageFields = { message: z.array(outgoingSegmentSchema).min(1) } as const;\nconst recallFields = { message_seq: z.number().int().min(0) } as const;\n\n/** send_private_message:发送私聊消息。 */\nexport class SendPrivateMessageAction extends MilkyApiAction<\n { user_id: number; message: OutgoingSegment[] },\n SendMessageOutput\n> {\n readonly name = \"send_private_message\";\n readonly schema = z.object({ user_id: z.number().int().min(10001), ...sendMessageFields });\n\n protected async _handle(payload: {\n user_id: number;\n message: OutgoingSegment[];\n }): Promise<SendMessageOutput> {\n const peer = await this.api.resolvePeer(\"friend\", payload.user_id);\n return await sendMilkyMessage(peer, payload.message, this.api);\n }\n}\n\n/** send_group_message:发送群聊消息。 */\nexport class SendGroupMessageAction extends MilkyApiAction<\n { group_id: number; message: OutgoingSegment[] },\n SendMessageOutput\n> {\n readonly name = \"send_group_message\";\n readonly schema = z.object({ group_id: z.number().int().min(10001), ...sendMessageFields });\n\n protected async _handle(payload: {\n group_id: number;\n message: OutgoingSegment[];\n }): Promise<SendMessageOutput> {\n const peer = await this.api.resolvePeer(\"group\", payload.group_id);\n return await sendMilkyMessage(peer, payload.message, this.api);\n }\n}\n\n/** get_message:获取单条消息(seq → msgId 反查 + 实体回填)。 */\nexport class GetMessageAction extends MilkyApiAction<\n { message_scene: MessageScene; peer_id: number; message_seq: number },\n GetMessageOutput\n> {\n readonly name = \"get_message\";\n readonly schema = z.object({ ...peerMessageFields });\n\n protected async _handle(payload: {\n message_scene: MessageScene;\n peer_id: number;\n message_seq: number;\n }): Promise<GetMessageOutput> {\n const peer = await this.api.resolvePeer(payload.message_scene, payload.peer_id);\n const msgId = await this.api.resolveMsgIdBySeq(peer, payload.message_seq, peer.chatType);\n if (msgId === undefined) {\n throw kernelError(`消息 ${payload.message_seq} 不存在`, \"NOT_FOUND\");\n }\n const [msg] = await this.api.msgApi.fetchMsgsByMsgId(peer, [msgId]);\n if (msg === undefined) {\n throw kernelError(`消息 ${payload.message_seq} 不存在`, \"NOT_FOUND\");\n }\n return { message: await this.translateWithEntities(payload.message_scene, peer, msg) };\n }\n\n /** 实体回填(group 场景 schema 要求完整实体)→ IncomingMessage。 */\n private async translateWithEntities(\n scene: MessageScene,\n peer: Peer,\n msg: RawMessage,\n ): Promise<IncomingMessage> {\n const ctx: ReceiveTranslateContext = { selfUin: this.api.self.uin };\n if (scene === \"group\") {\n const [detail, member] = await Promise.all([\n this.api.groupCache?.getGroupDetail(peer.peerUid).catch(() => undefined),\n this.api.groupCache?.getMember(peer.peerUid, msg.senderUid).catch(() => undefined),\n ]);\n ctx.groupEntity = toGroupEntity(detail, peer.peerUid);\n ctx.groupMemberEntity = toGroupMemberEntity(member, peer.peerUid, msg.senderUin);\n }\n return toMessageReceiveEvent(msg, ctx).data;\n }\n}\n\n/** recall_private_message:撤回私聊消息。 */ export class RecallPrivateMessageAction extends MilkyApiAction<\n { user_id: number; message_seq: number },\n Record<string, never>\n> {\n readonly name = \"recall_private_message\";\n readonly schema = z.object({ user_id: z.number().int().min(10001), ...recallFields });\n\n protected async _handle(payload: {\n user_id: number;\n message_seq: number;\n }): Promise<Record<string, never>> {\n const peer = await this.api.resolvePeer(\"friend\", payload.user_id);\n await recallBySeq(peer, payload.message_seq, this.api);\n return {};\n }\n}\n\n/** recall_group_message:撤回群消息。 */\nexport class RecallGroupMessageAction extends MilkyApiAction<\n { group_id: number; message_seq: number },\n Record<string, never>\n> {\n readonly name = \"recall_group_message\";\n readonly schema = z.object({ group_id: z.number().int().min(10001), ...recallFields });\n\n protected async _handle(payload: {\n group_id: number;\n message_seq: number;\n }): Promise<Record<string, never>> {\n const peer = await this.api.resolvePeer(\"group\", payload.group_id);\n await recallBySeq(peer, payload.message_seq, this.api);\n return {};\n }\n}\n\n/** seq → msgId(反查)→ recallMessage。 */\nasync function recallBySeq(peer: Peer, seq: number, api: MilkyApi): Promise<void> {\n const msgId = await api.resolveMsgIdBySeq(peer, seq, peer.chatType);\n if (msgId === undefined) {\n throw kernelError(`消息 ${seq} 不存在`, \"NOT_FOUND\");\n }\n await api.msgApi.recallMessage(peer, [msgId]);\n}\n\n/** 发送核心:segments → canonical(URI/ID 转换)→ sendMessage → 回查输出。\n * forward 段分流到组装链(P2 批次一,临时消息法)。 */\nexport async function sendMilkyMessage(\n peer: Peer,\n segments: OutgoingSegment[],\n api: MilkyApi,\n): Promise<SendMessageOutput> {\n if (segments.some((s) => s.type === \"forward\")) {\n return await sendForwardComposition(peer, segments, api);\n }\n const { elements, atUins } = outgoingSegmentsToCanonical(segments);\n const resolved = await resolveElements(elements, atUins, api);\n if (resolved.length === 0) {\n throw kernelError(\"消息内容为空(全部消息段不可用)\", \"INVALID_PARAM\");\n }\n const { msgId } = await api.msgApi.sendMessage(peer, resolved);\n return await api.resolveSentOutput(peer, msgId);\n}\n\n/**\n * forward 段组装链(P2 批次一,milky.md §0.6):仅支持单 forward 单独发。\n * 临时消息法:逐条发送 messages[i].segments → sendForwardMessage(buildMultiForwardMsg\n * 以目标 peer 的真实消息组装 → sendMsg)→ best-effort 撤回临时消息 → 回查输出。\n *\n * 已知差异(规范语义 vs kernel 出口,待实机联调):节点发送者恒为机器人自己\n * (user_id / sender_name / time 不参与组装);title / preview / summary / prompt 忽略。\n */\nasync function sendForwardComposition(\n peer: Peer,\n segments: OutgoingSegment[],\n api: MilkyApi,\n): Promise<SendMessageOutput> {\n if (segments.length !== 1) {\n throw kernelError(\"forward 段必须单独发送(不支持与其他消息段混发)\", \"INVALID_PARAM\");\n }\n const [forward] = segments;\n if (forward === undefined || forward.type !== \"forward\") {\n throw kernelError(\"forward 组装链收到非 forward 段\", \"UNKNOWN\");\n }\n const messages = narrowForwardMessages(forward);\n const srcMsgIds: string[] = [];\n for (const [i, item] of messages.entries()) {\n const { elements, atUins } = outgoingSegmentsToCanonical(item.segments);\n const resolved = await resolveElements(elements, atUins, api);\n if (resolved.length === 0) {\n throw kernelError(`forward 第 ${i + 1} 条消息无可用内容段`, \"INVALID_PARAM\");\n }\n const { msgId } = await api.msgApi.sendMessage(peer, resolved);\n srcMsgIds.push(msgId);\n }\n const { msgId } = await api.msgApi.sendForwardMessage(peer, peer, srcMsgIds);\n await recallTempMessages(peer, srcMsgIds, api);\n return await api.resolveSentOutput(peer, msgId);\n}\n\n/**\n * forward 段载荷收窄(入口 schema 只保证 data 为 record):messages 非空数组,\n * 项内 segments 非空数组。user_id / sender_name / time 不参与组装不校验\n * (丢弃字段不设门槛);title / preview / summary / prompt 忽略。\n */\nfunction narrowForwardMessages(\n forward: Extract<OutgoingSegment, { type: \"forward\" }>,\n): OutgoingForwardedMessage[] {\n const raw = (forward.data as { messages?: unknown }).messages;\n if (!Array.isArray(raw) || raw.length === 0) {\n throw kernelError(\"forward 段 messages 必须是非空数组\", \"INVALID_PARAM\");\n }\n const out: OutgoingForwardedMessage[] = [];\n for (const item of raw) {\n if (typeof item !== \"object\" || item === null) {\n throw kernelError(\"forward 段 messages 项必须是对象\", \"INVALID_PARAM\");\n }\n const segments = (item as { segments?: unknown }).segments;\n if (!Array.isArray(segments) || segments.length === 0) {\n throw kernelError(\"forward 段 messages 项的 segments 必须是非空数组\", \"INVALID_PARAM\");\n }\n out.push(item as OutgoingForwardedMessage);\n }\n return out;\n}\n\n/** 临时消息清理(best-effort:失败只留可见垃圾,转发已发出——warn 可观测不抛)。 */\nasync function recallTempMessages(peer: Peer, msgIds: string[], api: MilkyApi): Promise<void> {\n try {\n await api.msgApi.recallMessage(peer, msgIds);\n } catch (e) {\n api.logger?.warn(\n {\n peer: peer.peerUid,\n count: msgIds.length,\n error: e instanceof Error ? e.message : String(e),\n },\n \"milky: forward 临时消息撤回失败(转发已发出)\",\n );\n }\n}\n\n/** 元素二次解析:at uin→uid + 远程媒体 URI 落盘(reply seq 已在映射层兜底原样)。 */\nasync function resolveElements(\n elements: CanonicalElement[],\n atUins: string[],\n api: MilkyApi,\n): Promise<CanonicalElement[]> {\n const uinToUid = await resolveAtUins(atUins, api);\n const out: CanonicalElement[] = [];\n for (const el of elements) {\n out.push(await resolveElement(el, uinToUid, api));\n }\n return out;\n}\n\n/** at uin→uid 批量转换(失败返回 undefined:at 原样 uin,交 QQ 端判断)。 */\nasync function resolveAtUins(\n atUins: string[],\n api: MilkyApi,\n): Promise<Map<string, string> | undefined> {\n if (atUins.length === 0) {\n return undefined;\n }\n try {\n return await api.uinToUid(atUins);\n } catch {\n return undefined;\n }\n}\n\n/** 单元素解析:at 目标替换 / 远程媒体 URI 落盘 / 其余原样。 */\nasync function resolveElement(\n el: CanonicalElement,\n uinToUid: Map<string, string> | undefined,\n api: MilkyApi,\n): Promise<CanonicalElement> {\n if (el.type === \"at\" && el.target !== \"all\") {\n return { ...el, target: uinToUid?.get(el.target) ?? el.target };\n }\n if (isRemoteMediaUri(el)) {\n const media = el as Extract<CanonicalElement, { type: \"image\" | \"voice\" | \"video\" }>;\n return { ...media, path: await resolveMediaUri(media.path, api.mediaDir) };\n }\n return el;\n}\n\n/** 远程媒体元素(image/voice/video 且 path 为需落盘的 URI)。 */\nfunction isRemoteMediaUri(el: CanonicalElement): boolean {\n return (\n (el.type === \"image\" || el.type === \"voice\" || el.type === \"video\") &&\n (el.path.startsWith(\"http://\") ||\n el.path.startsWith(\"https://\") ||\n el.path.startsWith(\"base64://\"))\n );\n}\n\n/** get_history_messages:获取历史消息(start seq 锚点 → 原生翻页 → 升序输出)。 */\nexport class GetHistoryMessagesAction extends MilkyApiAction<\n {\n message_scene: MessageScene;\n peer_id: number;\n start_message_seq?: number | null | undefined;\n limit?: number | null | undefined;\n },\n GetHistoryMessagesOutput\n> {\n readonly name = \"get_history_messages\";\n readonly schema = z.object({\n message_scene: z.enum([\"friend\", \"group\", \"temp\"]),\n peer_id: z.number().int().min(10001),\n start_message_seq: z.number().int().min(0).nullable().optional(),\n limit: z.number().int().min(0).nullable().optional(),\n });\n\n protected async _handle(payload: {\n message_scene: MessageScene;\n peer_id: number;\n start_message_seq?: number | null | undefined;\n limit?: number | null | undefined;\n }): Promise<GetHistoryMessagesOutput> {\n const limit = payload.limit ?? HISTORY_DEFAULT_LIMIT;\n const peer = await this.api.resolvePeer(payload.message_scene, payload.peer_id);\n const anchor = await this.resolveAnchor(peer, payload.start_message_seq);\n const msgs = await this.api.msgApi.fetchMessages(peer, {\n count: limit,\n ...(anchor !== undefined ? { msgId: anchor } : {}),\n });\n for (const m of msgs) {\n this.api.seqIndex.record(m);\n }\n // 群场景实体回填一次(群详情 + 整群成员表),避免逐消息回填\n const groupData =\n payload.message_scene === \"group\" ? await this.loadGroupData(peer.peerUid) : null;\n // 原生新→旧,规范要求 seq 升序 → 反转\n const ordered = [...msgs].reverse();\n const messages = ordered.map((m) =>\n this.translateHistoryMessage(m, peer.peerUid, groupData),\n );\n const hasMore = msgs.length >= limit;\n const oldest = ordered[0];\n return {\n messages,\n next_message_seq: hasMore && oldest !== undefined ? Number(oldest.msgSeq) : null,\n };\n }\n\n /** start_message_seq → 锚点 msgId(给了 seq 却反查不到 = NOT_FOUND)。 */\n private async resolveAnchor(\n peer: Peer,\n startSeq: number | null | undefined,\n ): Promise<string | undefined> {\n if (startSeq === undefined || startSeq === null) {\n return undefined;\n }\n const msgId = await this.api.resolveMsgIdBySeq(peer, startSeq, peer.chatType);\n if (msgId === undefined) {\n throw kernelError(`起始消息 ${startSeq} 不存在`, \"NOT_FOUND\");\n }\n return msgId;\n }\n\n /** 群场景回填数据(详情 + 成员表;缓存未装配返回空数据)。 */\n private async loadGroupData(\n groupCode: string,\n ): Promise<{ detail: GroupDetailInfo | undefined; members: Map<string, GroupMember> }> {\n if (this.api.groupCache === undefined) {\n return { detail: undefined, members: new Map() };\n }\n const [detail, members] = await Promise.all([\n this.api.groupCache.getGroupDetail(groupCode).catch(() => undefined),\n this.api.groupCache.getMembers(groupCode).catch(() => []),\n ]);\n const memberByUid = new Map<string, GroupMember>();\n for (const m of members) {\n memberByUid.set(m.uid, m);\n }\n return { detail, members: memberByUid };\n }\n\n /** 单条历史消息 → IncomingMessage(群场景注入实体,fail-soft)。 */\n private translateHistoryMessage(\n msg: RawMessage,\n peerUid: string,\n groupData: {\n detail: GroupDetailInfo | undefined;\n members: Map<string, GroupMember>;\n } | null,\n ): IncomingMessage {\n const ctx: ReceiveTranslateContext = { selfUin: this.api.self.uin };\n if (groupData !== null) {\n if (groupData.detail !== undefined) {\n ctx.groupEntity = toGroupEntity(groupData.detail, peerUid);\n }\n const member = groupData.members.get(msg.senderUid);\n if (member !== undefined) {\n ctx.groupMemberEntity = toGroupMemberEntity(member, peerUid, msg.senderUin);\n }\n }\n return toMessageReceiveEvent(msg, ctx).data;\n }\n}\n\n/** get_forwarded_messages:获取合并转发内容(resId → 转发索引 → fetchForwardMessage)。 */\nexport class GetForwardedMessagesAction extends MilkyApiAction<\n { forward_id: string },\n GetForwardedMessagesOutput\n> {\n readonly name = \"get_forwarded_messages\";\n readonly schema = z.object({ forward_id: z.string().min(1) });\n\n protected async _handle(payload: { forward_id: string }): Promise<GetForwardedMessagesOutput> {\n const entry = this.api.seqIndex.resolveForward(payload.forward_id);\n if (entry === undefined) {\n throw kernelError(`转发消息 ${payload.forward_id} 不存在(未登记)`, \"NOT_FOUND\");\n }\n const peer: Peer = { chatType: entry.chatType, peerUid: entry.peerUid };\n const msgs = await this.api.msgApi.fetchForwardMessage(peer, entry.msgId);\n for (const m of msgs) {\n this.api.seqIndex.record(m);\n }\n const uidToUin = await this.collectUidToUin(msgs);\n const messages: IncomingForwardedMessage[] = [];\n for (const m of msgs) {\n messages.push({\n message_seq: Number(m.msgSeq),\n sender_name: await this.senderNameOf(m),\n avatar_url: avatarUrlOf(m.senderUin),\n time: Math.floor(Number(m.msgTime) / 1000),\n segments: receiveSegmentsOf(m, uidToUin),\n });\n }\n return { messages };\n }\n\n /** at 段 uid → uin 批量转换(mention 翻译;失败退空 Map)。 */\n private async collectUidToUin(msgs: RawMessage[]): Promise<Map<string, string>> {\n const uids = new Set<string>();\n for (const m of msgs) {\n for (const el of toCanonicalElements(m)) {\n if (el.type === \"at\" && el.target !== \"all\") {\n uids.add((el as { target: string }).target);\n }\n }\n }\n if (uids.size === 0) {\n return new Map();\n }\n return await this.api.uidToUin([...uids]).catch(() => new Map<string, string>());\n }\n\n /** 发送者名(群场景成员缓存昵称/名片,失败退 uin 字符串)。 */\n private async senderNameOf(msg: RawMessage): Promise<string> {\n if (this.api.groupCache !== undefined && msg.chatType === ChatType.GROUP) {\n const member = await this.api.groupCache\n .getMember(msg.peerUid, msg.senderUid)\n .catch(() => undefined);\n const name =\n member?.cardName !== undefined && member.cardName !== \"\"\n ? member.cardName\n : member?.nick;\n if (name !== undefined && name !== \"\") {\n return name;\n }\n }\n return msg.senderUin;\n }\n}\n\n/** mark_message_as_read:标记会话已读(NT setMsgRead 以会话为粒度,seq 入参仅兼容 schema)。 */\nexport class MarkMessageAsReadAction extends MilkyApiAction<\n { message_scene: MessageScene; peer_id: number; message_seq: number },\n Record<string, never>\n> {\n readonly name = \"mark_message_as_read\";\n readonly schema = z.object({ ...peerMessageFields });\n\n protected async _handle(payload: {\n message_scene: MessageScene;\n peer_id: number;\n message_seq: number;\n }): Promise<Record<string, never>> {\n const peer = await this.api.resolvePeer(payload.message_scene, payload.peer_id);\n await this.api.msgApi.markRead(peer);\n return {};\n }\n}\n\n/** 历史消息默认条数(规范 default 20)。 */\nconst HISTORY_DEFAULT_LIMIT = 20;\n\n/** get_message / mark_message_as_read 共入参(场景 + 对端 + seq)。 */\nconst peerMessageFields = {\n message_scene: z.enum([\"friend\", \"group\", \"temp\"]),\n peer_id: z.number().int().min(10001),\n message_seq: z.number().int().min(0),\n} as const;\n\n/** 单条消息 → 接收段(canonical 映射 + forward 段注入,forward 不经 canonical)。 */\nfunction receiveSegmentsOf(msg: RawMessage, uidToUin: Map<string, string>): IncomingSegment[] {\n const segments = canonicalToIncomingSegments(toCanonicalElements(msg), {\n ...(uidToUin.size > 0 ? { uidToUin } : {}),\n });\n const fwd = msg.elements.find(\n (el) => el.multiForwardMsgElement !== undefined,\n )?.multiForwardMsgElement;\n if (fwd !== undefined) {\n segments.push(incomingForwardSegment(fwd.resId, fwd.fileName));\n }\n return segments;\n}\n\n/** QQ 头像 URL(公开头像服务,640px)。 */\nfunction avatarUrlOf(uin: string): string {\n return uin === \"\" ? \"\" : `https://q1.qlogo.cn/g?b=qq&nk=${uin}&s=640`;\n}\n\n/** get_custom_face_url_list:收藏表情链接(queryFavEmojiByDesc 形状待校准)。 */\nexport class GetCustomFaceUrlListAction extends MilkyApiAction<\n Record<string, never>,\n GetCustomFaceUrlListOutput\n> {\n readonly name = \"get_custom_face_url_list\";\n readonly schema = z.object({});\n\n protected async _handle(): Promise<GetCustomFaceUrlListOutput> {\n return { urls: await this.api.msgApi.queryFavEmojis() };\n }\n}\n\n/**\n * get_resource_temp_url:资源临时链接。\n * 已知差异(P0 模型):接收段 resource_id 即临时链接(本地路径优先 url 兜底),\n * 无独立资源索引——http(s)/base64 形态原样返回,其余 NOT_FOUND。\n */\nexport class GetResourceTempUrlAction extends MilkyApiAction<\n { resource_id: string },\n GetResourceTempUrlOutput\n> {\n readonly name = \"get_resource_temp_url\";\n readonly schema = z.object({ resource_id: z.string().min(1) });\n\n protected async _handle(payload: { resource_id: string }): Promise<GetResourceTempUrlOutput> {\n const id = payload.resource_id;\n if (id.startsWith(\"http://\") || id.startsWith(\"https://\") || id.startsWith(\"base64://\")) {\n return { url: id };\n }\n throw kernelError(`资源 ${id} 无临时链接(resource_id 非链接形态)`, \"NOT_FOUND\");\n }\n}\n\n/** upload_private_file:上传私聊文件(file 元素消息链,file_id 取 fileUuid)。 */\nexport class UploadPrivateFileAction extends MilkyApiAction<\n { user_id: number; file_uri: string; file_name: string },\n UploadFileOutput\n> {\n readonly name = \"upload_private_file\";\n readonly schema = z.object({\n user_id: z.number().int().min(10001),\n file_uri: z.string().min(1),\n file_name: z.string().min(1),\n });\n\n protected async _handle(payload: {\n user_id: number;\n file_uri: string;\n file_name: string;\n }): Promise<UploadFileOutput> {\n const path = await resolveUriToPath(payload.file_uri, this.api.mediaDir);\n const peer = await this.api.resolvePeer(\"friend\", payload.user_id);\n const fileId = await sendFileMessage(this.api, peer, path, payload.file_name);\n return { file_id: fileId };\n }\n}\n\n/**\n * 发送文件消息并回查 file_id:sendMessage(canonical file 元素,kernel 走\n * prepareFileElement 链)→ fetchMsgsByMsgId 取 fileElement.fileUuid(缺省 msgId)。\n * upload_private/group_file 共用。\n */\nexport async function sendFileMessage(\n api: MilkyApi,\n peer: Peer,\n path: string,\n fileName: string,\n): Promise<string> {\n const { msgId } = await api.msgApi.sendMessage(peer, [{ type: \"file\", path, name: fileName }]);\n const [sent] = await api.msgApi.fetchMsgsByMsgId(peer, [msgId]);\n const el = sent?.elements.find((e) => e.fileElement !== undefined);\n const uuid = el?.fileElement?.fileUuid;\n return uuid !== undefined && uuid !== \"\" ? uuid : msgId;\n}\n","/**\n * Milky 群文件类动作(P1 + P2 批次二):get_group_files / move / rename / delete /\n * persist_group_file / create_group_folder / delete_group_folder /\n * upload_group_file / get_group_file_download_url / rename_group_folder\n *\n * 全部走 RichMediaApi(群文件系列)。upload_group_file 走消息发送链(生态同款,\n * 群内产文件消息;parent_folder_id 暂不参与定位);download_url 仅根目录可达。\n * 实体字段以 GroupFileItemInfo / GroupFolderInfo 为源;下载次数 / 过期时间 /\n * 文件夹元数据等无源字段 0/null 兜底(待探测校准)。\n */\nimport type { GroupFileItemInfo, GroupFolderInfo, Peer } from \"@napuketto/kernel\";\nimport { ChatType } from \"@napuketto/kernel\";\nimport { z } from \"zod\";\nimport { resolveUriToPath } from \"../helper/media-uri.js\";\nimport type {\n CreateGroupFolderOutput,\n GetFileDownloadUrlOutput,\n GetGroupFilesOutput,\n GroupFileEntity,\n GroupFolderEntity,\n UploadFileOutput,\n} from \"../types.js\";\nimport { MilkyApiAction } from \"./base-action.js\";\nimport { sendFileMessage } from \"./message.js\";\n\nconst groupIdField = { group_id: z.number().int().min(10001) } as const;\nconst fileIdField = { file_id: z.string().min(1) } as const;\nconst optStr = z.string().nullable().optional();\n\n/** get_group_files:获取群文件列表(根目录或指定文件夹;过滤 parent 匹配项)。 */\nexport class GetGroupFilesAction extends MilkyApiAction<\n { group_id: number; parent_folder_id?: string | null | undefined },\n GetGroupFilesOutput\n> {\n readonly name = \"get_group_files\";\n readonly schema = z.object({ ...groupIdField, parent_folder_id: optStr });\n\n protected async _handle(payload: {\n group_id: number;\n parent_folder_id?: string | null | undefined;\n }): Promise<GetGroupFilesOutput> {\n const groupCode = String(payload.group_id);\n const parent = payload.parent_folder_id ?? \"\";\n const items = await this.api.richMediaApi.getGroupFileList(groupCode, parent);\n const files: GroupFileEntity[] = [];\n const folders: GroupFolderEntity[] = [];\n for (const item of items) {\n if (item.fileInfo !== undefined) {\n files.push(fileToEntity(item.fileInfo, payload.group_id));\n } else if (item.folderInfo !== undefined) {\n folders.push(folderToEntity(item.folderInfo, payload.group_id));\n }\n }\n return { files, folders };\n }\n}\n\n/** move_group_file:移动文件(target_folder_id 空 = 移到根目录;parent 入参仅 schema 兼容)。 */\nexport class MoveGroupFileAction extends MilkyApiAction<\n {\n group_id: number;\n file_id: string;\n parent_folder_id?: string | null | undefined;\n target_folder_id?: string | null | undefined;\n },\n Record<string, never>\n> {\n readonly name = \"move_group_file\";\n readonly schema = z.object({\n ...groupIdField,\n ...fileIdField,\n parent_folder_id: optStr,\n target_folder_id: optStr,\n });\n\n protected async _handle(payload: {\n group_id: number;\n file_id: string;\n parent_folder_id?: string | null | undefined;\n target_folder_id?: string | null | undefined;\n }): Promise<Record<string, never>> {\n await this.api.richMediaApi.moveGroupFile(\n String(payload.group_id),\n [payload.file_id],\n payload.target_folder_id ?? \"\",\n );\n return {};\n }\n}\n\n/** rename_group_file:重命名文件。 */\nexport class RenameGroupFileAction extends MilkyApiAction<\n {\n group_id: number;\n file_id: string;\n parent_folder_id?: string | null | undefined;\n new_file_name: string;\n },\n Record<string, never>\n> {\n readonly name = \"rename_group_file\";\n readonly schema = z.object({\n ...groupIdField,\n ...fileIdField,\n parent_folder_id: optStr,\n new_file_name: z.string().min(1),\n });\n\n protected async _handle(payload: {\n group_id: number;\n file_id: string;\n parent_folder_id?: string | null | undefined;\n new_file_name: string;\n }): Promise<Record<string, never>> {\n await this.api.richMediaApi.renameGroupFile(\n String(payload.group_id),\n payload.file_id,\n payload.new_file_name,\n );\n return {};\n }\n}\n\n/** delete_group_file:删除文件。 */\nexport class DeleteGroupFileAction extends MilkyApiAction<\n { group_id: number; file_id: string },\n Record<string, never>\n> {\n readonly name = \"delete_group_file\";\n readonly schema = z.object({ ...groupIdField, ...fileIdField });\n\n protected async _handle(payload: {\n group_id: number;\n file_id: string;\n }): Promise<Record<string, never>> {\n await this.api.richMediaApi.deleteGroupFile(String(payload.group_id), [payload.file_id]);\n return {};\n }\n}\n\n/**\n * persist_group_file:转存文件(RichMediaApi.transGroupFile,转存语义待对齐)。\n */\nexport class PersistGroupFileAction extends MilkyApiAction<\n { group_id: number; file_id: string },\n Record<string, never>\n> {\n readonly name = \"persist_group_file\";\n readonly schema = z.object({ ...groupIdField, ...fileIdField });\n\n protected async _handle(payload: {\n group_id: number;\n file_id: string;\n }): Promise<Record<string, never>> {\n await this.api.richMediaApi.transGroupFile(String(payload.group_id), payload.file_id);\n return {};\n }\n}\n\n/** create_group_folder:创建文件夹(返回 folder_id)。 */\nexport class CreateGroupFolderAction extends MilkyApiAction<\n { group_id: number; folder_name: string },\n CreateGroupFolderOutput\n> {\n readonly name = \"create_group_folder\";\n readonly schema = z.object({ ...groupIdField, folder_name: z.string().min(1) });\n\n protected async _handle(payload: {\n group_id: number;\n folder_name: string;\n }): Promise<CreateGroupFolderOutput> {\n const folderId = await this.api.richMediaApi.createGroupFolder(\n String(payload.group_id),\n payload.folder_name,\n );\n return { folder_id: folderId };\n }\n}\n\n/** delete_group_folder:删除文件夹。 */\nexport class DeleteGroupFolderAction extends MilkyApiAction<\n { group_id: number; folder_id: string },\n Record<string, never>\n> {\n readonly name = \"delete_group_folder\";\n readonly schema = z.object({ ...groupIdField, folder_id: z.string().min(1) });\n\n protected async _handle(payload: {\n group_id: number;\n folder_id: string;\n }): Promise<Record<string, never>> {\n await this.api.richMediaApi.deleteGroupFolder(String(payload.group_id), payload.folder_id);\n return {};\n }\n}\n\n/** GroupFileItemInfo → GroupFileEntity(fileSize 原生为字符串;无源字段兜底)。 */\nfunction fileToEntity(info: GroupFileItemInfo, groupId: number): GroupFileEntity {\n return {\n group_id: groupId,\n file_id: info.fileId,\n file_name: info.fileName,\n parent_folder_id: info.parent ?? \"\",\n file_size: Number(info.fileSize) || 0,\n uploaded_time: Number(info.uploadTime) || 0,\n expire_time: null,\n uploader_id: Number(info.uploaderUin) || 0,\n downloaded_times: 0,\n };\n}\n\n/** GroupFolderInfo → GroupFolderEntity(元数据无类型字段防御读取,缺省 0)。 */\nfunction folderToEntity(info: GroupFolderInfo, groupId: number): GroupFolderEntity {\n const num = (key: string): number => {\n const v = info[key];\n return typeof v === \"number\" ? v : Number(v) || 0;\n };\n return {\n group_id: groupId,\n folder_id: info.folderId,\n parent_folder_id: info.folderUid ?? \"\",\n folder_name: info.folderName,\n created_time: num(\"createTime\"),\n last_modified_time: num(\"modifyTime\"),\n creator_id: 0,\n file_count: num(\"totalFileCount\"),\n };\n}\n\n/** upload_group_file:上传群文件(消息发送链;parent_folder_id 暂不参与定位)。 */\nexport class UploadGroupFileAction extends MilkyApiAction<\n {\n group_id: number;\n parent_folder_id?: string | null | undefined;\n file_uri: string;\n file_name: string;\n },\n UploadFileOutput\n> {\n readonly name = \"upload_group_file\";\n readonly schema = z.object({\n ...groupIdField,\n parent_folder_id: optStr,\n file_uri: z.string().min(1),\n file_name: z.string().min(1),\n });\n\n protected async _handle(payload: {\n group_id: number;\n parent_folder_id?: string | null | undefined;\n file_uri: string;\n file_name: string;\n }): Promise<UploadFileOutput> {\n const path = await resolveUriToPath(payload.file_uri, this.api.mediaDir);\n const peer: Peer = { chatType: ChatType.GROUP, peerUid: String(payload.group_id) };\n const fileId = await sendFileMessage(this.api, peer, path, payload.file_name);\n return { file_id: fileId };\n }\n}\n\n/** get_group_file_download_url:群文件下载链接(url 字段待实机确认,仅根目录)。 */\nexport class GetGroupFileDownloadUrlAction extends MilkyApiAction<\n { group_id: number; file_id: string },\n GetFileDownloadUrlOutput\n> {\n readonly name = \"get_group_file_download_url\";\n readonly schema = z.object({ ...groupIdField, ...fileIdField });\n\n protected async _handle(payload: {\n group_id: number;\n file_id: string;\n }): Promise<GetFileDownloadUrlOutput> {\n const url = await this.api.richMediaApi.getGroupFileDownloadUrl(\n String(payload.group_id),\n payload.file_id,\n );\n return { download_url: url };\n }\n}\n\n/** rename_group_folder:重命名群文件夹(renameGroupFile 同款形态,待校准)。 */\nexport class RenameGroupFolderAction extends MilkyApiAction<\n { group_id: number; folder_id: string; new_folder_name: string },\n Record<string, never>\n> {\n readonly name = \"rename_group_folder\";\n readonly schema = z.object({\n ...groupIdField,\n folder_id: z.string().min(1),\n new_folder_name: z.string().min(1),\n });\n\n protected async _handle(payload: {\n group_id: number;\n folder_id: string;\n new_folder_name: string;\n }): Promise<Record<string, never>> {\n await this.api.richMediaApi.renameGroupFolder(\n String(payload.group_id),\n payload.folder_id,\n payload.new_folder_name,\n );\n return {};\n }\n}\n","/**\n * Milky 资料类动作(P1):get_user_profile / get_friend_info / set_avatar /\n * set_nickname / set_bio / get_cookies / get_csrf_token\n *\n * set_avatar 的 uri 经 media-uri 解析(本地路径 / file:// 直用,http(s)/base64\n * 落盘 mediaDir);get_cookies 输出规范为单字符串(k=v 分号拼接);\n * get_csrf_token = qun.qq.com cookies 的 skey → bkn(OB11 get_csrf_token 同口径)。\n */\nimport { kernelError, TicketApi } from \"@napuketto/kernel\";\nimport { z } from \"zod\";\nimport { toFriendEntity } from \"../helper/entities.js\";\nimport { resolveMediaUri } from \"../helper/media-uri.js\";\nimport type {\n GetCookiesOutput,\n GetCSRFTokenOutput,\n GetFriendInfoOutput,\n GetUserProfileOutput,\n} from \"../types.js\";\nimport { MilkyApiAction } from \"./base-action.js\";\n\n/** CSRF 计算域名(bkn 口径,OB11 get_csrf_token 同源)。 */\nconst CSRF_DOMAIN = \"qun.qq.com\";\n\n/** get_user_profile:获取用户个人信息(陌生人信息 API;country/city/school 无源空兜底)。 */\nexport class GetUserProfileAction extends MilkyApiAction<\n { user_id: number },\n GetUserProfileOutput\n> {\n readonly name = \"get_user_profile\";\n readonly schema = z.object({ user_id: z.number().int().min(10001) });\n\n protected async _handle(payload: { user_id: number }): Promise<GetUserProfileOutput> {\n const info = await this.api.profileApi.getStrangerInfo(String(payload.user_id));\n return {\n nickname: info.nickname,\n qid: info.qid,\n age: info.age,\n sex: info.sex,\n remark: info.remark,\n bio: info.long_nick,\n level: info.qq_level,\n country: \"\",\n city: \"\",\n school: \"\",\n };\n }\n}\n\n/** get_friend_info:获取好友信息(好友列表单查)。 */\nexport class GetFriendInfoAction extends MilkyApiAction<\n { user_id: number; no_cache?: boolean | null | undefined },\n GetFriendInfoOutput\n> {\n readonly name = \"get_friend_info\";\n readonly schema = z.object({\n user_id: z.number().int().min(10001),\n no_cache: z.boolean().nullable().optional(),\n });\n\n protected async _handle(payload: {\n user_id: number;\n no_cache?: boolean | null | undefined;\n }): Promise<GetFriendInfoOutput> {\n const uin = String(payload.user_id);\n const friend = (await this.api.friendApi.getFriendList()).find((f) => f.uin === uin);\n if (friend === undefined) {\n throw kernelError(`好友 ${uin} 不存在`, \"NOT_FOUND\");\n }\n return { friend: toFriendEntity(friend, friend.uin, friend.nickname) };\n }\n}\n\n/** set_avatar:设置头像(uri → 本地路径)。 */\nexport class SetAvatarAction extends MilkyApiAction<{ uri: string }, Record<string, never>> {\n readonly name = \"set_avatar\";\n readonly schema = z.object({ uri: z.string().min(1) });\n\n protected async _handle(payload: { uri: string }): Promise<Record<string, never>> {\n const path = await resolveMediaUri(payload.uri, this.api.mediaDir);\n await this.api.profileApi.setHeader(path);\n return {};\n }\n}\n\n/** set_nickname:设置昵称。 */\nexport class SetNicknameAction extends MilkyApiAction<\n { new_nickname: string },\n Record<string, never>\n> {\n readonly name = \"set_nickname\";\n readonly schema = z.object({ new_nickname: z.string() });\n\n protected async _handle(payload: { new_nickname: string }): Promise<Record<string, never>> {\n await this.api.profileApi.setNickName(payload.new_nickname);\n return {};\n }\n}\n\n/** set_bio:设置个性签名。 */\nexport class SetBioAction extends MilkyApiAction<{ new_bio: string }, Record<string, never>> {\n readonly name = \"set_bio\";\n readonly schema = z.object({ new_bio: z.string() });\n\n protected async _handle(payload: { new_bio: string }): Promise<Record<string, never>> {\n await this.api.profileApi.setLongNick(payload.new_bio);\n return {};\n }\n}\n\n/** get_cookies:获取 cookies(规范输出为 k=v 分号拼接字符串)。 */\nexport class GetCookiesAction extends MilkyApiAction<{ domain: string }, GetCookiesOutput> {\n readonly name = \"get_cookies\";\n readonly schema = z.object({ domain: z.string().min(1) });\n\n protected async _handle(payload: { domain: string }): Promise<GetCookiesOutput> {\n const cookies = await this.api.ticketApi.getCookies(payload.domain, this.api.self.uin);\n return {\n cookies: Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \"),\n };\n }\n}\n\n/** get_csrf_token:bkn(qun.qq.com skey 派生,OB11 get_csrf_token 同口径)。 */\nexport class GetCSRFTokenAction extends MilkyApiAction<Record<string, never>, GetCSRFTokenOutput> {\n readonly name = \"get_csrf_token\";\n readonly schema = z.object({}).strict();\n\n protected async _handle(): Promise<GetCSRFTokenOutput> {\n const cookies = await this.api.ticketApi.getCookies(CSRF_DOMAIN, this.api.self.uin);\n return { csrf_token: TicketApi.getBkn(cookies[\"skey\"] ?? \"\") };\n }\n}\n","/**\n * Milky 社交类动作(P0:get_friend_list / get_group_list;\n * P1 +5:send_profile_like / delete_friend / get_friend_requests /\n * accept_friend_request / reject_friend_request)\n */\n\nimport type { Peer } from \"@napuketto/kernel\";\nimport { kernelError } from \"@napuketto/kernel\";\nimport { z } from \"zod\";\nimport { findBuddyReq, type MilkyApi } from \"../api.js\";\nimport { groupListToEntity, toFriendEntity } from \"../helper/entities.js\";\nimport type {\n FriendRequestEntity,\n GetFriendListOutput,\n GetFriendRequestsOutput,\n GetGroupListOutput,\n GetPeerPinsOutput,\n} from \"../types.js\";\nimport { MilkyApiAction } from \"./base-action.js\";\n\nconst emptySchema = z.object({}).strict();\n\n/** get_friend_list:获取好友列表。 */\nexport class GetFriendListAction extends MilkyApiAction<\n Record<string, never>,\n GetFriendListOutput\n> {\n readonly name = \"get_friend_list\";\n readonly schema = emptySchema;\n\n protected async _handle(): Promise<GetFriendListOutput> {\n const friends = await this.api.friendApi.getFriendList();\n return {\n friends: friends.map((f) => toFriendEntity(f, f.uin, f.nickname)),\n };\n }\n}\n\n/** get_group_list:获取群列表。\n * 实测校准(2026-08-08,OB11 同款):原生 getGroupList 返回值无数据,列表经\n * onGroupListUpdate 事件进 GroupCache——缓存优先,为空触发刷新回填。\n */\nexport class GetGroupListAction extends MilkyApiAction<Record<string, never>, GetGroupListOutput> {\n readonly name = \"get_group_list\";\n readonly schema = emptySchema;\n\n protected async _handle(): Promise<GetGroupListOutput> {\n const groups =\n this.api.groupCache !== undefined\n ? await this.api.groupCache.listGroupsRefreshed()\n : await this.api.groupApi.getGroupList(true);\n return { groups: groups.map(groupListToEntity) };\n }\n}\n\n/** send_profile_like:发送好友赞(count 缺省 1,规范 default 同值)。 */\nexport class SendProfileLikeAction extends MilkyApiAction<\n { user_id: number; count?: number | null | undefined },\n Record<string, never>\n> {\n readonly name = \"send_profile_like\";\n readonly schema = z.object({\n user_id: z.number().int().min(10001),\n count: z.number().int().min(0).nullable().optional(),\n });\n\n protected async _handle(payload: {\n user_id: number;\n count?: number | null | undefined;\n }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n await this.api.profileLikeApi.sendLike(uid, payload.count ?? 1);\n return {};\n }\n}\n\n/** delete_friend:删除好友。 */\nexport class DeleteFriendAction extends MilkyApiAction<{ user_id: number }, Record<string, never>> {\n readonly name = \"delete_friend\";\n readonly schema = z.object({ user_id: z.number().int().min(10001) });\n\n protected async _handle(payload: { user_id: number }): Promise<Record<string, never>> {\n const uid = await this.api.resolveUidFromUin(payload.user_id);\n await this.api.friendApi.deleteFriend(uid);\n return {};\n }\n}\n\n/**\n * get_friend_requests:获取好友请求列表。\n * kernel getBuddyReqList 无过滤/数量参数——is_filtered 入参仅作 schema 兼容\n * (全量返回);state 无源字段恒 pending(真实状态待探测校准)。\n */\nexport class GetFriendRequestsAction extends MilkyApiAction<\n { limit?: number | null | undefined; is_filtered?: boolean | null | undefined },\n GetFriendRequestsOutput\n> {\n readonly name = \"get_friend_requests\";\n readonly schema = z.object({\n limit: z.number().int().min(0).nullable().optional(),\n is_filtered: z.boolean().nullable().optional(),\n });\n\n protected async _handle(payload: {\n limit?: number | null | undefined;\n is_filtered?: boolean | null | undefined;\n }): Promise<GetFriendRequestsOutput> {\n const reqs = await this.api.friendApi.getBuddyReqList();\n // 发起者 uid → uin 批量转换(initiator_id 需要 uin;失败 0 兜底)\n let uidToUin = new Map<string, string>();\n if (reqs.length > 0) {\n uidToUin = await this.api\n .uidToUin(reqs.map((req) => req.friendUid))\n .catch(() => new Map<string, string>());\n }\n const requests: FriendRequestEntity[] = reqs.map((req) => ({\n time: Number(req.reqTime) || 0,\n initiator_id: Number(uidToUin.get(req.friendUid)) || 0,\n initiator_uid: req.friendUid,\n target_user_id: Number(this.api.self.uin),\n target_user_uid: this.api.self.uid ?? \"\",\n state: \"pending\",\n comment: typeof req[\"words\"] === \"string\" ? (req[\"words\"] as string) : \"\",\n via: req.sourceName ?? \"\",\n is_filtered: false,\n }));\n const limit = payload.limit ?? requests.length;\n return { requests: requests.slice(0, limit) };\n }\n}\n\n/**\n * accept/reject_friend_request 公共基类:initiator_uid → 查申请 → 应答。\n * kernel handleFriendRequest 无 reason 参数(拒绝理由无源,入参仅 schema 兼容)。\n */\nabstract class HandleFriendRequestBase extends MilkyApiAction<\n {\n initiator_uid: string;\n is_filtered?: boolean | null | undefined;\n reason?: string | null | undefined;\n },\n Record<string, never>\n> {\n readonly schema = z.object({\n initiator_uid: z.string().min(1),\n is_filtered: z.boolean().nullable().optional(),\n reason: z.string().nullable().optional(),\n });\n\n /** accept=true 同意 / false 拒绝。 */\n protected abstract readonly accept: boolean;\n\n protected async _handle(payload: {\n initiator_uid: string;\n is_filtered?: boolean | null | undefined;\n reason?: string | null | undefined;\n }): Promise<Record<string, never>> {\n const notify = await findBuddyReq(this.api, payload.initiator_uid);\n await this.api.friendApi.handleFriendRequest(notify, this.accept);\n return {};\n }\n}\n\n/** accept_friend_request:同意好友申请。 */\nexport class AcceptFriendRequestAction extends HandleFriendRequestBase {\n readonly name = \"accept_friend_request\";\n protected readonly accept = true;\n}\n\n/** reject_friend_request:拒绝好友申请。 */\nexport class RejectFriendRequestAction extends HandleFriendRequestBase {\n readonly name = \"reject_friend_request\";\n protected readonly accept = false;\n}\n\n/** send_friend_nudge:发送好友戳一戳(is_self=true 戳自己)。 */\nexport class SendFriendNudgeAction extends MilkyApiAction<\n { user_id: number; is_self?: boolean | null | undefined },\n Record<string, never>\n> {\n readonly name = \"send_friend_nudge\";\n readonly schema = z.object({ user_id: z.number().int().min(10001), is_self: optBoolNudge });\n\n protected async _handle(payload: {\n user_id: number;\n is_self?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n const callerUid = requireSelfUid(this.api);\n const receiverUid =\n payload.is_self === true\n ? callerUid\n : await this.api.resolveUidFromUin(payload.user_id);\n const peer = await this.api.resolvePeer(\"friend\", payload.user_id);\n await this.api.msgApi.sendNudge(peer, { receiverUid, callerUid });\n return {};\n }\n}\n\n/** get_peer_pins:获取置顶会话(RecentContactApi isTop 过滤,实体经现有翻译)。 */\nexport class GetPeerPinsAction extends MilkyApiAction<Record<string, never>, GetPeerPinsOutput> {\n readonly name = \"get_peer_pins\";\n readonly schema = z.object({});\n\n protected async _handle(): Promise<GetPeerPinsOutput> {\n const pinned = await this.api.recentContactApi.getPinnedContacts();\n const friendUids = pinned.filter((p) => p.scene === \"friend\").map((p) => p.peerUid);\n const groupCodes = pinned.filter((p) => p.scene === \"group\").map((p) => p.peerUid);\n const friends = await pinnedFriendEntities(this.api, friendUids);\n const groups = await pinnedGroupEntities(this.api, groupCodes);\n return { friends, groups };\n }\n}\n\n/** set_peer_pin:设置/取消会话置顶(is_pinned 缺省 true)。 */\nexport class SetPeerPinAction extends MilkyApiAction<\n {\n message_scene: \"friend\" | \"group\" | \"temp\";\n peer_id: number;\n is_pinned?: boolean | null | undefined;\n },\n Record<string, never>\n> {\n readonly name = \"set_peer_pin\";\n readonly schema = z.object({\n message_scene: z.enum([\"friend\", \"group\", \"temp\"]),\n peer_id: z.number().int().min(10001),\n is_pinned: optBoolNudge,\n });\n\n protected async _handle(payload: {\n message_scene: \"friend\" | \"group\" | \"temp\";\n peer_id: number;\n is_pinned?: boolean | null | undefined;\n }): Promise<Record<string, never>> {\n const peer: Peer = await this.api.resolvePeer(payload.message_scene, payload.peer_id);\n await this.api.msgApi.setContactTop(peer, payload.is_pinned ?? true);\n return {};\n }\n}\n\n/** 置顶好友实体(uid 匹配全量好友列表;未命中跳过)。 */\nasync function pinnedFriendEntities(\n api: MilkyApi,\n uids: string[],\n): Promise<GetPeerPinsOutput[\"friends\"]> {\n if (uids.length === 0) {\n return [];\n }\n const all = await api.friendApi.getFriendList();\n const byUid = new Map(all.map((f) => [f.uid, f]));\n return uids.flatMap((uid) => {\n const f = byUid.get(uid);\n return f !== undefined ? [toFriendEntity(f, f.uin, f.nickname)] : [];\n });\n}\n\n/** 置顶群实体(groupCode 匹配群列表,缓存优先;未命中跳过)。 */\nasync function pinnedGroupEntities(\n api: MilkyApi,\n groupCodes: string[],\n): Promise<GetPeerPinsOutput[\"groups\"]> {\n if (groupCodes.length === 0) {\n return [];\n }\n const groups =\n api.groupCache !== undefined\n ? await api.groupCache.listGroupsRefreshed()\n : await api.groupApi.getGroupList(true);\n const byCode = new Map(groups.map((g) => [g.groupCode, g]));\n return groupCodes.flatMap((code) => {\n const g = byCode.get(code);\n return g !== undefined ? [groupListToEntity(g)] : [];\n });\n}\n\n/** self.uid 必备(nudge 发送的 callerUid)。 */\nfunction requireSelfUid(api: MilkyApi): string {\n const uid = api.self.uid;\n if (uid === undefined || uid === \"\") {\n throw kernelError(\"登录身份缺 uid(无法发起戳一戳)\", \"INVALID_PARAM\");\n }\n return uid;\n}\n\n/** 可选布尔(social.ts 本文件原无 optBool,本地定义避免全局重名)。 */\nconst optBoolNudge = z.boolean().nullable().optional();\n","/**\n * Milky 系统类动作(P0):get_login_info / get_impl_info\n *\n * get_impl_info 是 Milky 的版本协商面(规范 §compatibility):milky_version\n * 固定 \"1.3\"(目标协议版本 1.3.0),qq_protocol_type 固定 windows(自建宿主)。\n */\nimport { z } from \"zod\";\nimport type { GetImplInfoOutput, GetLoginInfoOutput } from \"../types.js\";\nimport { MilkyApiAction } from \"./base-action.js\";\n\n/** Milky 协议版本(docs/protocols/milky.md:目标 1.3.0)。 */\nconst MILKY_VERSION = \"1.3\";\n\nconst emptySchema = z.object({}).strict();\n\n/** get_login_info:获取登录信息。 */\nexport class GetLoginInfoAction extends MilkyApiAction<Record<string, never>, GetLoginInfoOutput> {\n readonly name = \"get_login_info\";\n readonly schema = emptySchema;\n\n protected async _handle(): Promise<GetLoginInfoOutput> {\n return { uin: Number(this.api.self.uin), nickname: this.api.self.nickname };\n }\n}\n\n/** get_impl_info:获取协议端信息(版本协商)。 */\nexport class GetImplInfoAction extends MilkyApiAction<Record<string, never>, GetImplInfoOutput> {\n readonly name = \"get_impl_info\";\n readonly schema = emptySchema;\n\n protected async _handle(): Promise<GetImplInfoOutput> {\n return {\n impl_name: \"napukettoqq\",\n impl_version: this.api.implVersion,\n qq_protocol_version: this.api.qqVersion,\n qq_protocol_type: \"windows\",\n milky_version: MILKY_VERSION,\n };\n }\n}\n","/**\n * Milky 动作注册表(P0 9 + P1 40 + P2 批次二 15 = 64 个)\n *\n * P0/P1 面 = docs/protocols/milky.md §9 清单;批次二 = §0.7(nudge / 公告 /\n * 头衔 / 群头像 / peer_pins / 上传 / download_url / rename_folder / 收藏表情 /\n * resource 反查)。\n */\nimport { ActionRegistry } from \"../../core/index.js\";\nimport type { MilkyApi } from \"../api.js\";\nimport type { MilkyAction } from \"./base-action.js\";\nimport {\n AcceptGroupInvitationAction,\n AcceptGroupRequestAction,\n DeleteGroupAnnouncementAction,\n GetGroupAnnouncementsAction,\n GetGroupEssenceMessagesAction,\n GetGroupInfoAction,\n GetGroupMemberInfoAction,\n GetGroupMemberListAction,\n GetGroupNotificationsAction,\n KickGroupMemberAction,\n QuitGroupAction,\n RejectGroupInvitationAction,\n RejectGroupRequestAction,\n SendGroupAnnouncementAction,\n SendGroupMessageReactionAction,\n SendGroupNudgeAction,\n SetGroupAvatarAction,\n SetGroupEssenceMessageAction,\n SetGroupMemberAdminAction,\n SetGroupMemberCardAction,\n SetGroupMemberMuteAction,\n SetGroupMemberSpecialTitleAction,\n SetGroupNameAction,\n SetGroupWholeMuteAction,\n} from \"./group.js\";\nimport {\n CreateGroupFolderAction,\n DeleteGroupFileAction,\n DeleteGroupFolderAction,\n GetGroupFileDownloadUrlAction,\n GetGroupFilesAction,\n MoveGroupFileAction,\n PersistGroupFileAction,\n RenameGroupFileAction,\n RenameGroupFolderAction,\n UploadGroupFileAction,\n} from \"./group-file.js\";\nimport {\n GetCustomFaceUrlListAction,\n GetForwardedMessagesAction,\n GetHistoryMessagesAction,\n GetMessageAction,\n GetResourceTempUrlAction,\n MarkMessageAsReadAction,\n RecallGroupMessageAction,\n RecallPrivateMessageAction,\n SendGroupMessageAction,\n SendPrivateMessageAction,\n UploadPrivateFileAction,\n} from \"./message.js\";\nimport {\n GetCookiesAction,\n GetCSRFTokenAction,\n GetFriendInfoAction,\n GetUserProfileAction,\n SetAvatarAction,\n SetBioAction,\n SetNicknameAction,\n} from \"./profile.js\";\nimport {\n AcceptFriendRequestAction,\n DeleteFriendAction,\n GetFriendListAction,\n GetFriendRequestsAction,\n GetGroupListAction,\n GetPeerPinsAction,\n RejectFriendRequestAction,\n SendFriendNudgeAction,\n SendProfileLikeAction,\n SetPeerPinAction,\n} from \"./social.js\";\nimport { GetImplInfoAction, GetLoginInfoAction } from \"./system.js\";\n\n/** Milky 动作注册表(P0+P1 49 动作)。 */\nexport function createMilkyActionRegistry(opts: {\n api: MilkyApi;\n}): ActionRegistry<MilkyAction<unknown, unknown>> {\n const registry = new ActionRegistry<MilkyAction<unknown, unknown>>();\n const { api } = opts;\n // P0\n registry.register(new GetLoginInfoAction(api));\n registry.register(new GetImplInfoAction(api));\n registry.register(new SendPrivateMessageAction(api));\n registry.register(new SendGroupMessageAction(api));\n registry.register(new GetMessageAction(api));\n registry.register(new RecallPrivateMessageAction(api));\n registry.register(new RecallGroupMessageAction(api));\n registry.register(new GetFriendListAction(api));\n registry.register(new GetGroupListAction(api));\n // P1 资料/票据\n registry.register(new GetUserProfileAction(api));\n registry.register(new GetFriendInfoAction(api));\n registry.register(new SetAvatarAction(api));\n registry.register(new SetNicknameAction(api));\n registry.register(new SetBioAction(api));\n registry.register(new GetCookiesAction(api));\n registry.register(new GetCSRFTokenAction(api));\n // P1 好友\n registry.register(new SendProfileLikeAction(api));\n registry.register(new DeleteFriendAction(api));\n registry.register(new GetFriendRequestsAction(api));\n registry.register(new AcceptFriendRequestAction(api));\n registry.register(new RejectFriendRequestAction(api));\n // P1 消息\n registry.register(new GetHistoryMessagesAction(api));\n registry.register(new GetForwardedMessagesAction(api));\n registry.register(new MarkMessageAsReadAction(api));\n // P1 群\n registry.register(new GetGroupInfoAction(api));\n registry.register(new GetGroupMemberListAction(api));\n registry.register(new GetGroupMemberInfoAction(api));\n registry.register(new SetGroupNameAction(api));\n registry.register(new SetGroupMemberCardAction(api));\n registry.register(new SetGroupMemberAdminAction(api));\n registry.register(new SetGroupMemberMuteAction(api));\n registry.register(new SetGroupWholeMuteAction(api));\n registry.register(new KickGroupMemberAction(api));\n registry.register(new QuitGroupAction(api));\n registry.register(new GetGroupEssenceMessagesAction(api));\n registry.register(new SetGroupEssenceMessageAction(api));\n registry.register(new SendGroupMessageReactionAction(api));\n registry.register(new GetGroupNotificationsAction(api));\n registry.register(new AcceptGroupRequestAction(api));\n registry.register(new RejectGroupRequestAction(api));\n registry.register(new AcceptGroupInvitationAction(api));\n registry.register(new RejectGroupInvitationAction(api));\n // P1 群文件\n registry.register(new GetGroupFilesAction(api));\n registry.register(new MoveGroupFileAction(api));\n registry.register(new RenameGroupFileAction(api));\n registry.register(new DeleteGroupFileAction(api));\n registry.register(new PersistGroupFileAction(api));\n registry.register(new CreateGroupFolderAction(api));\n registry.register(new DeleteGroupFolderAction(api));\n // P2 批次二(§0.7)\n registry.register(new SendFriendNudgeAction(api));\n registry.register(new GetPeerPinsAction(api));\n registry.register(new SetPeerPinAction(api));\n registry.register(new SendGroupNudgeAction(api));\n registry.register(new GetGroupAnnouncementsAction(api));\n registry.register(new SendGroupAnnouncementAction(api));\n registry.register(new DeleteGroupAnnouncementAction(api));\n registry.register(new SetGroupAvatarAction(api));\n registry.register(new SetGroupMemberSpecialTitleAction(api));\n registry.register(new GetCustomFaceUrlListAction(api));\n registry.register(new GetResourceTempUrlAction(api));\n registry.register(new UploadPrivateFileAction(api));\n registry.register(new UploadGroupFileAction(api));\n registry.register(new GetGroupFileDownloadUrlAction(api));\n registry.register(new RenameGroupFolderAction(api));\n return registry;\n}\n","/**\n * Milky notice 事件翻译(grayTip 系,P1 2026-10-30)\n *\n * NT QQ 中群成员变动/禁言/戳一戳等系统事件通过消息的灰色提示元素(grayTip)\n * 广播。本模块把 RawMessage 里的 grayTip 翻译为 Milky notice 事件(纯函数,\n * ADR-008),判据与 OB11 helper/notice.ts 同源(同一 wrapper 事实):\n * - group_member_increase / group_member_decrease(subType=GROUP + type MEMBER_ADD/QUIT)\n * - group_mute / group_whole_mute(SHUT_UP;member uid 空 = 全员禁言口径)\n * - group_nudge / friend_nudge(aioOpGrayTipElement;形状待真实事件校准,\n * best-effort + raw 校准日志,与 OB11 poke 同口径)\n * - group_name_change / group_disband(GROUP_NAME_MODIFIED / DISBANDED;操作者\n * uid 不可得时不产出事件,避免违反 schema operator_id 下限)\n *\n * user_id / operator_id 都是 uin:接收 uidToUin Map(调用方批量转换后传入)。\n * 未知/未翻译的 grayTip 子类型打 raw JSON 日志(为后续真实事件校准积累数据)。\n */\nimport type { RawMessage } from \"@napuketto/kernel\";\nimport {\n ChatType,\n type GrayTipElement,\n GrayTipSubType,\n type TipGroupElement,\n TipGroupElementType,\n} from \"@napuketto/kernel\";\nimport { firstUntranslatedGrayTip } from \"../../core/gray-tip.js\";\nimport { resolveUin } from \"../../core/uid-uin.js\";\nimport type {\n FriendNudgeData,\n GroupDisbandData,\n GroupMemberDecreaseData,\n GroupMemberIncreaseData,\n GroupMuteData,\n GroupNameChangeData,\n GroupNudgeData,\n GroupWholeMuteData,\n MilkyEvent,\n} from \"../types.js\";\n\n/** 毫秒 → 秒(Unix 时间戳)。 */\nconst MS_TO_SEC = 1000;\n\n/** grayTip 翻译上下文(uid→uin 映射,调用方批量转换)。 */\nexport interface NoticeTranslateContext {\n selfUin: string;\n uidToUin: Map<string, string>;\n /** 校准日志(可选:未知子类型 / aioOp raw JSON;缺省静默)。 */\n logger?: { warn(obj: unknown, msg?: string): void };\n}\n\n/** uid → uin(core 共享解析;ctx 携带映射)。 */\nfunction toUin(uid: string | undefined, ctx: NoticeTranslateContext): number {\n return resolveUin(uid, ctx.uidToUin);\n}\n\n/** 事件信封公共字段。 */\nfunction envelope<T>(\n msg: RawMessage,\n ctx: NoticeTranslateContext,\n eventType: string,\n data: T,\n): MilkyEvent<T> {\n return {\n time: Math.floor(Number(msg.msgTime) / MS_TO_SEC),\n self_id: Number(ctx.selfUin),\n event_type: eventType,\n data,\n };\n}\n\n/** 单个 grayTip → Milky notice 事件(null = 不可翻译)。 */\nfunction translateGrayTip(\n msg: RawMessage,\n g: GrayTipElement,\n ctx: NoticeTranslateContext,\n): MilkyEvent | null {\n // aioOp 优先于子类型判定:群戳一戳载荷挂 GROUP 子类型(归属未实证,\n // 与 OB11 poke 同口径——按元素存在性识别)\n if (g.aioOpGrayTipElement !== undefined) {\n return aioOpToEvent(msg, g, ctx);\n }\n if (g.subElementType === GrayTipSubType.GROUP) {\n return groupElementToEvent(msg, g.groupElement, ctx);\n }\n return null;\n}\n\n/** TipGroupElement → 群成员变动 / 禁言 / 改名 / 解散事件(按类型分发的映射表键)。 */\ninterface GroupChangeCommon {\n groupId: number;\n memberUid: string;\n adminUid: string;\n}\n\n/** 群成员变动类映射器表(键 = TipGroupElementType;缺项 = 不可翻译返回 null)。 */\nconst GROUP_CHANGE_MAPPERS: Partial<\n Record<\n TipGroupElementType,\n (\n msg: RawMessage,\n common: GroupChangeCommon,\n grp: TipGroupElement,\n ctx: NoticeTranslateContext,\n ) => MilkyEvent | null\n >\n> = {\n [TipGroupElementType.MEMBER_ADD]: toMemberIncrease,\n [TipGroupElementType.QUIT]: toMemberDecrease,\n [TipGroupElementType.SHUT_UP]: toShutUpEvent,\n [TipGroupElementType.GROUP_NAME_MODIFIED]: toNameChange,\n [TipGroupElementType.DISBANDED]: toDisband,\n};\n\nfunction groupElementToEvent(\n msg: RawMessage,\n grp: TipGroupElement | undefined,\n ctx: NoticeTranslateContext,\n): MilkyEvent | null {\n if (grp === undefined || grp.type === undefined) {\n return null;\n }\n const mapper = GROUP_CHANGE_MAPPERS[grp.type];\n if (mapper === undefined) {\n return null;\n }\n return mapper(msg, groupChangeCommon(grp, Number(msg.peerUid)), grp, ctx);\n}\n\n/** 禁言载荷优先(shutUp.member/admin 覆盖顶层 memberUid/adminUid)。 */\nfunction groupChangeCommon(grp: TipGroupElement, groupId: number): GroupChangeCommon {\n return {\n groupId,\n memberUid: grp.shutUp?.member?.uid ?? grp.memberUid ?? \"\",\n adminUid: grp.shutUp?.admin?.uid ?? grp.adminUid ?? \"\",\n };\n}\n\n/** 群成员增加(管理员同意 → operator_id;邀请入群 → invitor_id)。 */\nfunction toMemberIncrease(\n msg: RawMessage,\n common: GroupChangeCommon,\n _grp: TipGroupElement,\n ctx: NoticeTranslateContext,\n): MilkyEvent {\n const { groupId, memberUid, adminUid } = common;\n const data: GroupMemberIncreaseData = {\n group_id: groupId,\n user_id: toUin(memberUid, ctx),\n operator_id: adminUid !== \"\" && adminUid === memberUid ? toUin(adminUid, ctx) : null,\n invitor_id: adminUid !== \"\" && adminUid !== memberUid ? toUin(adminUid, ctx) : null,\n };\n return envelope(msg, ctx, \"group_member_increase\", data);\n}\n\n/** 群成员减少(操作者与本人不同 = 被踢;主动退群无操作者)。 */\nfunction toMemberDecrease(\n msg: RawMessage,\n common: GroupChangeCommon,\n _grp: TipGroupElement,\n ctx: NoticeTranslateContext,\n): MilkyEvent {\n const { groupId, memberUid, adminUid } = common;\n const data: GroupMemberDecreaseData = {\n group_id: groupId,\n user_id: toUin(memberUid, ctx),\n operator_id: adminUid !== \"\" && adminUid !== memberUid ? toUin(adminUid, ctx) : null,\n };\n return envelope(msg, ctx, \"group_member_decrease\", data);\n}\n\n/** 禁言(member 空 = 全员禁言口径;is_mute = 是否处于禁言态)。 */\nfunction toShutUpEvent(\n msg: RawMessage,\n common: GroupChangeCommon,\n grp: TipGroupElement,\n ctx: NoticeTranslateContext,\n): MilkyEvent {\n const { groupId, memberUid, adminUid } = common;\n const duration = Number(grp.shutUp?.duration ?? 0);\n if (memberUid === \"\") {\n const data: GroupWholeMuteData = {\n group_id: groupId,\n operator_id: toUin(adminUid, ctx),\n is_mute: duration > 0,\n };\n return envelope(msg, ctx, \"group_whole_mute\", data);\n }\n const data: GroupMuteData = {\n group_id: groupId,\n user_id: toUin(memberUid, ctx),\n operator_id: toUin(adminUid, ctx),\n duration,\n };\n return envelope(msg, ctx, \"group_mute\", data);\n}\n\n/** 改名 / 解散公共守卫:操作者 uid 不可得时不产出(schema operator_id 下限)。 */\nfunction operatorOf(common: GroupChangeCommon): string {\n return common.adminUid !== \"\" ? common.adminUid : common.memberUid;\n}\n\nfunction toNameChange(\n msg: RawMessage,\n common: GroupChangeCommon,\n grp: TipGroupElement,\n ctx: NoticeTranslateContext,\n): MilkyEvent | null {\n const operatorUid = operatorOf(common);\n if (operatorUid === \"\") {\n return null;\n }\n const data: GroupNameChangeData = {\n group_id: common.groupId,\n new_group_name: grp.groupName ?? \"\",\n operator_id: toUin(operatorUid, ctx),\n };\n return envelope(msg, ctx, \"group_name_change\", data);\n}\n\nfunction toDisband(\n msg: RawMessage,\n common: GroupChangeCommon,\n _grp: TipGroupElement,\n ctx: NoticeTranslateContext,\n): MilkyEvent | null {\n const operatorUid = operatorOf(common);\n if (operatorUid === \"\") {\n return null;\n }\n const data: GroupDisbandData = {\n group_id: common.groupId,\n operator_id: toUin(operatorUid, ctx),\n };\n return envelope(msg, ctx, \"group_disband\", data);\n}\n\n/**\n * aioOp → 戳一戳事件(friend_nudge / group_nudge)。\n * aioOp 载荷完整字段形状未经实测(已证字段仅 operateType/peerUid):\n * sender 取消息发送者、receiver 取 aioOp.peerUid(口径与 OB11 poke 一致,待校准);\n * display_* 字段无来源,恒空串;始终打 raw 日志积累校准数据。\n */\nfunction aioOpToEvent(msg: RawMessage, g: GrayTipElement, ctx: NoticeTranslateContext): MilkyEvent {\n const aioOp = g.aioOpGrayTipElement;\n ctx.logger?.warn(\n { raw: JSON.stringify(g)?.slice(0, 2000) },\n \"milky: aioOp grayTip raw(戳一戳待真实事件校准)\",\n );\n if (msg.chatType === ChatType.GROUP) {\n const data: GroupNudgeData = {\n group_id: Number(msg.peerUid),\n sender_id: toUin(msg.senderUid, ctx),\n receiver_id: toUin(aioOp?.peerUid ?? \"\", ctx),\n display_action: \"\",\n display_suffix: \"\",\n display_action_img_url: \"\",\n };\n return envelope(msg, ctx, \"group_nudge\", data);\n }\n const senderUin = toUin(msg.senderUid, ctx);\n const data: FriendNudgeData = {\n user_id: senderUin,\n is_self_send: senderUin === Number(ctx.selfUin),\n is_self_receive: senderUin !== Number(ctx.selfUin),\n display_action: \"\",\n display_suffix: \"\",\n display_action_img_url: \"\",\n };\n return envelope(msg, ctx, \"friend_nudge\", data);\n}\n\n/**\n * RawMessage → Milky notice 事件(无 grayTip / 不可翻译返回 null)。\n * 未知子类型打 raw JSON 日志(JSON/BUDDY/ESSENCE/FILE 等——校准数据积累入口)。\n */\nexport function toMilkyNoticeEvent(\n msg: RawMessage,\n ctx: NoticeTranslateContext,\n): MilkyEvent | null {\n for (const el of msg.elements) {\n const g = el.grayTipElement;\n if (g === undefined) {\n continue;\n }\n const event = translateGrayTip(msg, g, ctx);\n if (event !== null) {\n return event;\n }\n }\n const untranslated = firstUntranslatedGrayTip(msg);\n if (untranslated !== undefined) {\n ctx.logger?.warn(\n {\n subType: untranslated.subElementType,\n raw: JSON.stringify(untranslated)?.slice(0, 2000),\n },\n \"milky: 未翻译的 grayTip 子类型(raw 校准数据)\",\n );\n }\n return null;\n}\n","/**\n * MessageSeqIndex:message_seq ↔ msgId 双向映射(docs/protocols/milky.md §5 方案二)\n *\n * Milky 对外用会话内 message_seq(kernel RawMessage.msgSeq),NT 撤回/取消息入口\n * 是 msgId——两套 ID 空间都要用,这层跳不掉。接收链路 record(双向写入),\n * 动作侧 resolveMsgId 反查;反查不到由动作做历史扫描兜底(fetchMessages 近段匹配)。\n *\n * 容量封顶(FIFO 淘汰,Map 插入序 = 时间序):映射只服务近期消息操作\n * (撤回 2 分钟窗口 / get_message 最近引用),不做全量持久索引。\n */\nimport type { ChatType, RawMessage } from \"@napuketto/kernel\";\n\n/** 单方向最大条目数(测试用例引用容量语义)。 */\nexport const MAX_ENTRIES = 4096;\n\n/** msgId → seq 元信息(collectReplyMeta 回填用)。 */\ninterface SeqMeta {\n seq: number;\n senderUin: string;\n timeSec: number;\n}\n\n/** 合并转发 resId → 定位信息(get_forwarded_messages 取 peer 用)。 */\nexport interface ForwardEntry {\n chatType: ChatType;\n peerUid: string;\n msgId: string;\n}\n\nexport class MessageSeqIndex {\n /** `${chatType}:${peerUid}:${seq}` → msgId。 */\n private readonly seqToMsg = new Map<string, string>();\n /** msgId → seq 元信息。 */\n private readonly msgToMeta = new Map<string, SeqMeta>();\n /** 合并转发 resId → 定位信息(P1:get_forwarded_messages)。 */\n private readonly forwards = new Map<string, ForwardEntry>();\n\n /** 接收链路登记(一条消息双向写入;重复 msgId 覆盖)。 */\n record(msg: RawMessage): void {\n const seq = Number(msg.msgSeq);\n if (!Number.isFinite(seq) || seq < 0) {\n return;\n }\n this.seqToMsg.set(this.key(msg.chatType, msg.peerUid, seq), msg.msgId);\n this.msgToMeta.set(msg.msgId, {\n seq,\n senderUin: msg.senderUin,\n timeSec: Math.floor(Number(msg.msgTime) / 1000),\n });\n this.evict();\n }\n\n /** seq → msgId(反查;未登记返回 undefined)。 */\n resolveMsgId(chatType: ChatType, peerUid: string, seq: number): string | undefined {\n return this.seqToMsg.get(this.key(chatType, peerUid, seq));\n }\n\n /**\n * 批量回填 reply 引用元信息(msgId → Milky reply 段 data 所需三元组)。\n * 未命中的 id 不进表(翻译层按 0 兜底)。\n */\n collectReplyMeta(\n msgIds: string[],\n ): Map<string, { messageSeq: number; senderId: number; time: number }> {\n const out = new Map<string, { messageSeq: number; senderId: number; time: number }>();\n for (const id of msgIds) {\n const m = this.msgToMeta.get(id);\n if (m !== undefined) {\n out.set(id, {\n messageSeq: m.seq,\n senderId: Number(m.senderUin) || 0,\n time: m.timeSec,\n });\n }\n }\n return out;\n }\n\n /** key 规则(chatType 数值 + peerUid + seq;peerUid 群聊=群号,C2C=uid)。 */\n private key(chatType: ChatType, peerUid: string, seq: number): string {\n return `${chatType}:${peerUid}:${seq}`;\n }\n\n /**\n * 登记合并转发(接收链路:消息含 multiForwardMsgElement 时调用)。\n * resId 是 Milky forward_id 的来源;同一 resId 重复覆盖。\n */\n recordForward(resId: string, entry: ForwardEntry): void {\n if (resId === \"\") {\n return;\n }\n this.forwards.set(resId, entry);\n while (this.forwards.size > MAX_ENTRIES) {\n const oldest = this.forwards.keys().next().value;\n if (oldest === undefined) {\n break;\n }\n this.forwards.delete(oldest);\n }\n }\n\n /** resId → 转发定位(get_forwarded_messages;未登记返回 undefined)。 */\n resolveForward(resId: string): ForwardEntry | undefined {\n return this.forwards.get(resId);\n }\n\n /** FIFO 淘汰到容量上限内。 */\n private evict(): void {\n while (this.seqToMsg.size > MAX_ENTRIES) {\n const oldest = this.seqToMsg.keys().next().value;\n if (oldest === undefined) {\n break;\n }\n this.seqToMsg.delete(oldest);\n }\n while (this.msgToMeta.size > MAX_ENTRIES) {\n const oldest = this.msgToMeta.keys().next().value;\n if (oldest === undefined) {\n break;\n }\n this.msgToMeta.delete(oldest);\n }\n }\n}\n","/**\n * Milky 传输装配(单端口 HTTP:POST /api/:api + GET /event SSE + /event WS 升级\n * + WebHook 主动推送,docs/protocols/milky.md §4)\n *\n * - HTTP API:HttpServer onPathRequest 分发 → 动作注册表 → 规范响应信封\n * (200 ok / 200 failed(-400/-403/自定) / 401 鉴权 / 404 API 不存在(空 body)/\n * 415 Content-Type)。\n * - /event:onRawRequest 承接 SSE(createSseResponse,event: milky_event);\n * onUpgrade 承接同端口 WS 升级(网络原语 2026-10-28 下沉 network)。\n * - WebHook:HttpClient(fire-and-forget POST,Authorization 头带 token)。\n *\n * 事件推送统一经 MilkyEventHub(注册到 EventBroadcaster,send → SSE/WS 客户端)。\n */\nimport type {\n AuthorizeHook,\n EventBroadcaster,\n HttpRouteContext,\n RequestContext,\n Respond,\n TransportAdapter,\n} from \"@napuketto/network\";\nimport { createSseResponse, HttpClient, HttpServer } from \"@napuketto/network\";\nimport { WebSocket } from \"ws\";\nimport type { ActionRegistry } from \"../core/index.js\";\nimport type { MilkyAction } from \"./action/base-action.js\";\nimport type { MilkyConfig } from \"./config.js\";\n\n/** /event 路径(规范固定)。 */\nconst EVENT_PATH = \"/event\";\n/** /api/ 前缀 + 动作名(小写字母开头,小写/数字/下划线)。 */\nconst API_PATH_RE = /^\\/api\\/([a-z][a-z0-9_]*)$/;\n/** Bearer 前缀。 */\nconst BEARER_PREFIX = \"Bearer \";\n\n/** 校准 logger 最小面(webhook 失败 / 配置异常提示;缺省静默)。 */\nexport interface MilkyLoggerLike {\n warn(obj: unknown, msg?: string): void;\n info(obj: unknown, msg?: string): void;\n}\n\n/** 传输装配结果。 */\nexport interface MilkyTransportSet {\n /** 已注册 broadcaster 的传输(HTTP server + webhook clients + 事件枢纽)。 */\n adapters: TransportAdapter[];\n /** 停止:关闭传输 + 注销广播(幂等)。 */\n close: () => Promise<void>;\n}\n\n/**\n * Milky 事件枢纽:SSE 客户端 + WS 客户端集合,send 即广播。\n * 传输适配器面(open/close/send,EventBroadcaster 多态派发)——生命周期随\n * HttpServer。连接注册经 attachTo 挂到 HttpServer 注入点(本类内部闭环);\n * WS 入帧忽略(规范:/event 为纯事件推送通道)。\n */\nclass MilkyEventHub implements TransportAdapter {\n private readonly sseClients = new Set<SseClientHandle>();\n private readonly sockets = new Set<WebSocket>();\n\n /** 把 /event 的 SSE(onRawRequest)与 WS 升级(onUpgrade)挂到 HTTP server。 */\n attachTo(server: HttpServer, config: MilkyConfig): void {\n server.onRawRequest = (ctx) => {\n if (ctx.path !== EVENT_PATH || ctx.method !== \"GET\") {\n return undefined;\n }\n if (!config.eventModes.includes(\"sse\")) {\n return new Response(\"event mode sse disabled\", { status: 404 });\n }\n return createSseResponse((client) => {\n this.sseClients.add(client);\n return () => {\n this.sseClients.delete(client);\n };\n });\n };\n server.onUpgrade = (req, accept, reject) => {\n if (pathnameOf(req.url) !== EVENT_PATH) {\n return;\n }\n if (!config.eventModes.includes(\"ws\")) {\n reject(404, \"event mode ws disabled\");\n return;\n }\n if (config.token !== \"\" && !tokenMatches(req, config.token)) {\n reject(401, \"unauthorized\");\n return;\n }\n accept((socket) => {\n this.sockets.add(socket);\n const remove = (): void => {\n this.sockets.delete(socket);\n };\n socket.on(\"close\", remove);\n socket.on(\"error\", remove);\n });\n };\n }\n\n /** 广播事件(EventBroadcaster emit 入口)。 */\n send<T>(event: T): void {\n const json = JSON.stringify(event);\n for (const client of this.sseClients) {\n client.send(json, \"milky_event\");\n }\n for (const socket of this.sockets) {\n if (socket.readyState === WebSocket.OPEN) {\n socket.send(json);\n }\n }\n }\n\n open(): void {\n // 生命周期随 HttpServer\n }\n\n async close(): Promise<void> {\n for (const client of this.sseClients) {\n client.close();\n }\n this.sseClients.clear();\n for (const socket of this.sockets) {\n socket.close(1001, \"server shutdown\");\n }\n this.sockets.clear();\n }\n\n onRequest?: (req: unknown, respond: Respond) => void;\n}\n\n/** SSE 客户端句柄(network SseClient + 显式关闭)。 */\ninterface SseClientHandle {\n send(data: string, event?: string): void;\n close(): void;\n}\n\n/** 按配置装配 Milky 传输。 */\nexport function assembleMilkyTransports(opts: {\n config: MilkyConfig;\n broadcaster: EventBroadcaster;\n registry: ActionRegistry<MilkyAction<unknown, unknown>>;\n logger?: MilkyLoggerLike;\n}): MilkyTransportSet {\n const { config, broadcaster, registry, logger } = opts;\n const hub = new MilkyEventHub();\n const token = config.token;\n const authorize = token !== \"\" ? makeMilkyAuthorize(token) : undefined;\n\n const server = new HttpServer({\n host: config.host,\n port: config.port,\n ...(authorize !== undefined ? { authorize } : {}),\n });\n hub.attachTo(server, config);\n server.onPathRequest = (ctx, req, respond) => {\n handleMilkyHttpRequest(ctx, req, respond, registry);\n };\n\n const adapters: TransportAdapter[] = [server, hub];\n for (const url of config.webhooks) {\n const client = new HttpClient({\n url,\n ...(token !== \"\" ? { headers: { authorization: `${BEARER_PREFIX}${token}` } } : {}),\n timeoutMs: 5000,\n onError: (err: unknown) => {\n logger?.warn({ url, err: String(err) }, \"milky: webhook 推送失败\");\n },\n });\n adapters.push(client);\n }\n\n for (const adapter of adapters) {\n broadcaster.register(adapter);\n }\n return {\n adapters,\n close: async () => {\n await server.close();\n await hub.close();\n for (const adapter of adapters) {\n broadcaster.unregister(adapter);\n }\n },\n };\n}\n\n/** HTTP /api 分发(规范信封 + 404/415 语义)。 */\nfunction handleMilkyHttpRequest(\n ctx: HttpRouteContext,\n req: unknown,\n respond: Respond,\n registry: ActionRegistry<MilkyAction<unknown, unknown>>,\n): void {\n if (ctx.method !== \"POST\") {\n respond(undefined, 404);\n return;\n }\n const match = API_PATH_RE.exec(ctx.path);\n if (match === null) {\n respond(undefined, 404);\n return;\n }\n const contentType = ctx.headers?.[\"content-type\"];\n if (contentType !== undefined && !contentType.toLowerCase().includes(\"application/json\")) {\n respond(undefined, 415);\n return;\n }\n const action = registry.get(match[1] ?? \"\");\n if (action === undefined) {\n // API 不存在:HTTP 404 + 空 body(规范)\n respond(undefined, 404);\n return;\n }\n action\n .handle(req)\n .then((result) => {\n if (result.status === \"ok\") {\n respond({ status: \"ok\", retcode: 0, data: result.data ?? {} });\n } else {\n respond({\n status: \"failed\",\n retcode: result.retcode,\n data: null,\n message: result.message,\n });\n }\n })\n .catch(() => {\n respond({ status: \"failed\", retcode: -500, data: null, message: \"internal error\" });\n });\n}\n\n/** 鉴权钩子:Bearer 头或 access_token 查询参数(规范允许 SSE/WS 查询参数兜底)。 */\nfunction makeMilkyAuthorize(token: string): AuthorizeHook {\n return (ctx) => tokenMatches(ctx, token);\n}\n\n/** 请求凭据匹配(头优先,查询参数兜底)。 */\nfunction tokenMatches(ctx: RequestContext, token: string): boolean {\n const auth = ctx.headers[\"authorization\"] ?? ctx.headers[\"Authorization\"];\n if (auth?.startsWith(BEARER_PREFIX)) {\n return auth.slice(BEARER_PREFIX.length) === token;\n }\n try {\n const url = new URL(ctx.url, \"http://localhost\");\n return url.searchParams.get(\"access_token\") === token;\n } catch {\n return false;\n }\n}\n\n/** URL 路径部分(无 scheme 相对 url 容错)。 */\nfunction pathnameOf(url: string): string {\n try {\n return new URL(url, \"http://localhost\").pathname;\n } catch {\n return url.split(\"?\")[0] ?? \"\";\n }\n}\n","/**\n * NapukettoMilkyAdapter:Milky 协议适配器(P0 2026-10-28,P1 2026-10-30)\n *\n * 第四个协议适配器(与 OB11/Satori/KuroBot 并行):单端口 HTTP(/api + /event)\n * + WebHook。收链路三源(P1):\n * - 消息通道(Msg/onRecvMsg):seq 登记 → grayTip→notice / 文件消息→group_file_upload\n * (群场景)/ 普通→message_receive(自消息不上报);\n * - 群通知通道(Group/onGroupNotifiesUpdated):入群请求 / 成员邀请 / 邀请自身;\n * - 好友请求通道(Buddy/onBuddyReqChange):friend_request(防御收窄)。\n * 发链路 /api 动作 → kernel apis。\n *\n * 生命周期走 BaseProtocolAdapter 骨架;config.enabled=false 时空转(不订阅、\n * 不起传输)。翻译为纯函数(ADR-008):实体回填 / ID 转换在广播路径异步取得\n * 后经 ctx 注入。\n */\nimport type {\n BuddyEventChannel,\n CanonicalElement,\n GroupEventChannel,\n GroupNotify,\n MsgEventChannel,\n RawMessage,\n} from \"@napuketto/kernel\";\nimport { ChatType, toCanonicalElements } from \"@napuketto/kernel\";\nimport type { EventBroadcaster } from \"@napuketto/network\";\nimport { narrowBuddyReqs } from \"../core/buddy-req.js\";\nimport { collectGrayTipUids } from \"../core/gray-tip.js\";\nimport { BaseProtocolAdapter, type ProtocolConfig, type ProtocolHooks } from \"../core/index.js\";\nimport { subscribeRawMessages } from \"../core/raw-message.js\";\nimport type { RequestTranslateContext } from \"../core/uid-uin.js\";\nimport { createMilkyActionRegistry } from \"./action/index.js\";\nimport { MilkyApi, type MilkyApiOptions } from \"./api.js\";\nimport type { MilkyConfig } from \"./config.js\";\nimport { toGroupEntity, toGroupMemberEntity } from \"./helper/entities.js\";\nimport { type NoticeTranslateContext, toMilkyNoticeEvent } from \"./helper/notice.js\";\nimport { collectNotifyUids, toFriendRequestEvent, toGroupRequestEvent } from \"./helper/request.js\";\nimport { incomingForwardSegment } from \"./helper/segments.js\";\nimport { MessageSeqIndex } from \"./helper/seq-index.js\";\nimport {\n type ReceiveTranslateContext,\n toGroupFileUploadEvent,\n toMessageRecallEvent,\n toMessageReceiveEvent,\n} from \"./helper/translate.js\";\nimport { assembleMilkyTransports, type MilkyLoggerLike } from \"./transport.js\";\n\n/** 适配器构造参数(api 相关字段继承 MilkyApiOptions)。 */\nexport interface MilkyAdapterOptions extends MilkyApiOptions {\n config: ProtocolConfig<MilkyConfig>;\n broadcaster: EventBroadcaster;\n /** kernel 消息事件通道(收链路入口)。 */\n msgChannel: MsgEventChannel;\n /** kernel 群事件通道(P1:群请求/邀请推送;缺省不订阅)。 */\n groupChannel?: GroupEventChannel;\n /** kernel 好友事件通道(P1:好友申请推送;缺省不订阅)。 */\n buddyChannel?: BuddyEventChannel;\n /** 校准日志(webhook 失败 / 启停提示 / 未知事件形状;IPC 模式传 loader pino 实例)。 */\n logger?: MilkyLoggerLike;\n}\n\nexport class NapukettoMilkyAdapter extends BaseProtocolAdapter<MilkyConfig> {\n readonly protocol = \"milky\";\n\n private readonly msgChannel: MsgEventChannel;\n private readonly groupChannel: GroupEventChannel | undefined;\n private readonly buddyChannel: BuddyEventChannel | undefined;\n private readonly calibLogger: MilkyLoggerLike | undefined;\n private readonly api: MilkyApi;\n private readonly seqIndex = new MessageSeqIndex();\n /** 动作注册表(公共只读:装配方/测试枚举)。 */\n readonly registry: ReturnType<typeof createMilkyActionRegistry>;\n private unsubscribes: Array<() => void> = [];\n private stopTransports: (() => Promise<void>) | null = null;\n\n constructor(opts: MilkyAdapterOptions) {\n const hooks: ProtocolHooks = {\n onStart: (config) => this.startTransports(config as MilkyConfig),\n onStop: () => this.stopAll(),\n onReload: (config) => this.reloadTransports(config as MilkyConfig),\n };\n super({\n config: opts.config,\n broadcaster: opts.broadcaster,\n hooks,\n });\n this.msgChannel = opts.msgChannel;\n this.groupChannel = opts.groupChannel;\n this.buddyChannel = opts.buddyChannel;\n this.calibLogger = opts.logger;\n this.api = new MilkyApi(opts, this.seqIndex);\n this.registry = createMilkyActionRegistry({ api: this.api });\n }\n\n /** 启动传输 + 订阅(enabled=false 空转:不订阅不起传输)。 */\n private async startTransports(config: MilkyConfig): Promise<void> {\n if (!config.enabled) {\n this.calibLogger?.info({}, \"milky: 未启用(enabled=false),跳过装配\");\n return;\n }\n const broadcaster = this.getBroadcaster();\n if (broadcaster !== undefined) {\n const set = assembleMilkyTransports({\n config,\n broadcaster,\n registry: this.registry,\n ...(this.calibLogger !== undefined ? { logger: this.calibLogger } : {}),\n });\n this.stopTransports = set.close;\n }\n this.subscribe();\n this.calibLogger?.info(\n { host: config.host, port: config.port, modes: config.eventModes },\n \"milky: adapter started\",\n );\n }\n\n /** 热更新:停止重建(enabled 切换生效)。 */\n private async reloadTransports(config: MilkyConfig): Promise<void> {\n await this.stopAll();\n await this.startTransports(config);\n }\n\n /** 停止:退订 + 关传输。 */\n private async stopAll(): Promise<void> {\n this.unsubscribeAll();\n if (this.stopTransports !== null) {\n await this.stopTransports();\n this.stopTransports = null;\n }\n }\n\n /** 订阅 kernel 事件(消息 + 群通知 + 好友请求,幂等)。 */\n private subscribe(): void {\n if (this.unsubscribes.length > 0) {\n return;\n }\n this.unsubscribes.push(\n subscribeRawMessages(this.msgChannel, (msg) => {\n void this.handleIncoming(msg);\n }),\n );\n if (this.groupChannel !== undefined) {\n const groupChannel = this.groupChannel;\n this.unsubscribes.push(\n groupChannel.on(\"Group/onGroupNotifiesUpdated\", (doubt, notifies) => {\n void this.handleGroupNotifies(doubt, notifies);\n }),\n );\n }\n if (this.buddyChannel !== undefined) {\n const buddyChannel = this.buddyChannel;\n this.unsubscribes.push(\n buddyChannel.on(\"Buddy/onBuddyReqChange\", (arg) => {\n this.handleBuddyReqs(arg);\n }),\n );\n }\n }\n\n /** 退订(幂等)。 */\n private unsubscribeAll(): void {\n for (const off of this.unsubscribes) {\n off();\n }\n this.unsubscribes = [];\n }\n\n /** 单条消息:seq 登记 → grayTip→notice / 群文件上传 / message_receive(自消息不上报)。 */\n private async handleIncoming(msg: RawMessage): Promise<void> {\n // seq 双向登记(含自消息:本账号发出的消息也要可反查);转发 resId 登记索引\n this.seqIndex.record(msg);\n this.recordForward(msg);\n if (hasGrayTip(msg)) {\n await this.broadcastNotice(msg);\n return;\n }\n // 群文件上传:群场景文件消息 → group_file_upload 事件(Milky 语义,\n // 场景守卫在翻译函数内)\n const upload = toGroupFileUploadEvent(msg, this.api.self.uin);\n if (upload !== null) {\n this.broadcastEvent(upload);\n return;\n }\n // 自消息不上报(与 OB11 默认一致)\n if (String(msg.senderUin) === this.api.self.uin) {\n return;\n }\n this.broadcastEvent(await this.buildMessageReceiveEvent(msg));\n }\n\n /** grayTip → notice 事件广播(REVOKE 走 message_recall,其余走 notice 翻译)。 */\n private async broadcastNotice(msg: RawMessage): Promise<void> {\n const uidToUin = await this.resolveUidToUin(collectGrayTipUids(msg));\n const event =\n findRevokeElement(msg) !== undefined\n ? toMessageRecallEvent(msg, {\n selfUin: this.api.self.uin,\n ...(uidToUin !== undefined ? { uidToUin } : {}),\n })\n : toMilkyNoticeEvent(msg, this.noticeCtx(uidToUin));\n if (event !== null) {\n this.broadcastEvent(event);\n }\n }\n\n /** notice 翻译上下文(uidToUin 缺省空 Map;logger 透传校准日志)。 */\n private noticeCtx(uidToUin: Map<string, string> | undefined): NoticeTranslateContext {\n return {\n selfUin: this.api.self.uin,\n ...(uidToUin !== undefined ? { uidToUin } : { uidToUin: new Map() }),\n ...(this.calibLogger !== undefined ? { logger: this.calibLogger } : {}),\n };\n }\n\n /** 群通知通道:入群请求 / 成员邀请 / 邀请自身(uid→uin 批量后翻译)。 */\n private async handleGroupNotifies(doubt: boolean, notifies: GroupNotify[]): Promise<void> {\n const ctx = await this.requestCtx(collectNotifyUids(notifies));\n for (const notify of notifies) {\n const event = toGroupRequestEvent(notify, doubt, ctx);\n if (event !== null) {\n this.broadcastEvent(event);\n }\n }\n }\n\n /** 好友请求通道:Buddy/onBuddyReqChange(防御收窄,未知形状 raw 日志)。 */\n private handleBuddyReqs(arg: unknown): void {\n const reqs = narrowBuddyReqs(arg);\n if (reqs === null) {\n this.calibLogger?.warn(\n { raw: truncate(JSON.stringify(arg)) },\n \"milky: onBuddyReqChange 未知参数形状\",\n );\n return;\n }\n void (async () => {\n const ctx = await this.requestCtx(reqs.map((req) => req.friendUid));\n for (const req of reqs) {\n this.broadcastEvent(toFriendRequestEvent(req, ctx));\n }\n })();\n }\n\n /** request 翻译上下文(uid→uin 批量转换)。 */\n private async requestCtx(uids: string[]): Promise<RequestTranslateContext> {\n const uidToUin = await this.resolveUidToUin(uids);\n return {\n selfUin: this.api.self.uin,\n ...(uidToUin !== undefined ? { uidToUin } : { uidToUin: new Map() }),\n };\n }\n\n /** message_receive 组装:at uid→uin + reply 回填 + 群实体回填 + 转发段(全部 fail-soft)。 */\n private async buildMessageReceiveEvent(msg: RawMessage): Promise<unknown> {\n const elements = toCanonicalElements(msg);\n const ctx: ReceiveTranslateContext = { selfUin: this.api.self.uin };\n await this.fillMentionUids(elements, ctx);\n this.fillReplyMeta(elements, ctx);\n await this.fillGroupEntities(msg, ctx);\n const forward = msg.elements.find(\n (el) => el.multiForwardMsgElement !== undefined,\n )?.multiForwardMsgElement;\n if (forward !== undefined) {\n ctx.forwardSegments = [incomingForwardSegment(forward.resId, forward.fileName)];\n }\n return toMessageReceiveEvent(msg, ctx);\n }\n\n /** at uid → uin 批量转换(mention.user_id 用;失败 mention 段跳过)。 */\n private async fillMentionUids(\n elements: CanonicalElement[],\n ctx: ReceiveTranslateContext,\n ): Promise<void> {\n const atUids = elements\n .filter((el) => el.type === \"at\" && el.target !== \"all\")\n .map((el) => (el as { target: string }).target);\n if (atUids.length === 0) {\n return;\n }\n try {\n ctx.uidToUin = await this.api.uidToUin(atUids);\n } catch {\n // 转换失败:mention 段跳过\n }\n }\n\n /** reply 引用元信息回填(seqIndex 命中即用;未命中不强查)。 */\n private fillReplyMeta(elements: CanonicalElement[], ctx: ReceiveTranslateContext): void {\n const replyIds = elements\n .filter((el) => el.type === \"reply\")\n .map((el) => (el as { messageId: string }).messageId);\n const meta = this.seqIndex.collectReplyMeta(replyIds);\n if (meta.size > 0) {\n ctx.replyMeta = meta;\n }\n }\n\n /** 群场景实体回填(GroupCache 缓存优先,失败最小实体兜底)。 */\n private async fillGroupEntities(msg: RawMessage, ctx: ReceiveTranslateContext): Promise<void> {\n if (msg.chatType !== ChatType.GROUP || this.api.groupCache === undefined) {\n return;\n }\n const [detail, member] = await Promise.all([\n this.api.groupCache.getGroupDetail(msg.peerUid).catch(() => undefined),\n this.api.groupCache.getMember(msg.peerUid, msg.senderUid).catch(() => undefined),\n ]);\n ctx.groupEntity = toGroupEntity(detail, msg.peerUid);\n ctx.groupMemberEntity = toGroupMemberEntity(member, msg.peerUid, msg.senderUin);\n }\n\n /** 转发 resId → 定位登记(get_forwarded_messages 反查用)。 */\n private recordForward(msg: RawMessage): void {\n const forward = msg.elements.find(\n (el) => el.multiForwardMsgElement !== undefined,\n )?.multiForwardMsgElement;\n if (forward !== undefined && forward.resId !== \"\") {\n this.seqIndex.recordForward(forward.resId, {\n chatType: msg.chatType,\n peerUid: msg.peerUid,\n msgId: msg.msgId,\n });\n }\n }\n\n /** uid 批量 → uin(空集/失败返回 undefined 语义:调用方用空 Map)。 */\n private resolveUidToUin(uids: string[]): Promise<Map<string, string> | undefined> {\n const unique = [...new Set(uids.filter((uid) => uid !== \"\"))];\n if (unique.length === 0) {\n return Promise.resolve(undefined);\n }\n return this.api.uidToUin(unique).catch(() => undefined);\n }\n}\n\n/** 是否含 grayTip 元素(与 OB11 收链路同判据)。 */\nfunction hasGrayTip(msg: RawMessage): boolean {\n return msg.elements.some((el) => el.grayTipElement !== undefined);\n}\n\n/** 撤回 grayTip 元素(非撤回消息返回 undefined)。 */\nfunction findRevokeElement(msg: RawMessage) {\n return msg.elements.find((el) => el.grayTipElement?.revokeElement !== undefined)?.grayTipElement\n ?.revokeElement;\n}\n\n/** 字符串截断(raw 日志防刷屏)。 */\nfunction truncate(raw: string | undefined): string {\n return raw === undefined ? \"\" : raw.slice(0, 2000);\n}\n","/**\n * Milky 协议配置(zod schema,归属本包,ADR-012)\n *\n * 单一 TOML 的 `[accounts.milky]` 账号段(docs/protocols/milky.md §4):\n * 单端口 HTTP 模型(/api + /event 同端口),`enabled` 缺省 false = 不启用。\n */\nimport { z } from \"zod\";\n\n/** Milky 配置 schema。 */\nexport const milkyConfigSchema = z.object({\n /** 启用开关(缺省 false:账号段存在但 enabled 未开 = 装配为空转)。 */\n enabled: z.boolean().default(false),\n /** HTTP 监听地址。 */\n host: z.string().min(1).default(\"127.0.0.1\"),\n /** HTTP 监听端口(/api 与 /event 同端口)。 */\n port: z.number().int().min(0).max(65535).default(3001),\n /** access_token(空 = 不校验,仅限内网)。 */\n token: z.string().default(\"\"),\n /** /event 允许的连接形态(缺省两者都开)。 */\n eventModes: z.array(z.enum([\"sse\", \"ws\"])).default([\"sse\", \"ws\"]),\n /** 额外事件推送地址(WebHook,可多个;协议端在请求头发 Bearer token)。 */\n webhooks: z.array(z.string().min(1)).default([]),\n /** 发送媒体 http(s) URI 下载缓存目录(缺省不下载 = http(s) 发送媒体不可用)。 */\n cacheDir: z.string().optional(),\n});\n\n/** Milky 配置类型(由 schema 推导)。 */\nexport type MilkyConfig = z.infer<typeof milkyConfigSchema>;\n"],"mappings":"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"}