@napuketto/adapter 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/kurobot/schema.ts","../../src/kurobot/connection.ts","../../src/kurobot/translate.ts","../../src/kurobot/adapter.ts","../../src/kurobot/config.ts"],"sourcesContent":["/**\n * kurobridge-ws 协议 schema(镜像实现,任务书 KUROBOT-PROMPT §1.2 决策一)\n *\n * **SSOT: KuroBridge bridge/protocol**(`C:\\Dev\\MC-Ecosystem\\KuroAdapter\\bridge\\protocol\\src\\`),\n * 镜像基线 **0.4.x**(KuroAdapter ADR-030 品牌改名:kurobot-ws.v1 → kurobridge-ws.v1,\n * PROTOCOL_VERSION 0.4.0;帧形状与 0.3.1 逐字段一致,仅品牌字符串与版本号变更)。\n * `@kuro-bridge/protocol` 已发 npm,本仓暂维持镜像(golden 帧对表测试锁漂移:\n * connection.test.ts / schema.test.ts),将来可切换为真依赖。\n *\n * 只镜像 WS 对端可见的消息集(meta / frame / messages/ws);IPC 侧消息\n * (ready/broadcast/execute_command 等,Java↔Node 内部通道)不镜像。\n * 帧格式:`{header: {type, id?}, body}`(单行 JSON 文本帧);事件帧无 id,\n * 请求/响应帧 id 必填(UUID 关联);解析后 transform 为扁平消息 `{type, id?, body}`。\n */\nimport { z } from \"zod\";\n\n// ---- 协议元信息(镜像 meta.ts)----\n\nexport const PROTOCOL_NAME = \"kurobridge-ws\" as const;\n\n/** 语义化版本(主版本相同即兼容,ADR-026:0.2.x/0.3.0 服务端均接受 0.3.1 hello)。 */\nexport const PROTOCOL_VERSION = \"0.4.0\" as const;\n\n/** WS 子协议(握手期校验,服务端 handleProtocols 不带即拒连)。 */\nexport const WS_SUBPROTOCOL = \"kurobridge-ws.v1\" as const;\n\nconst VERSION_PATTERN = /^(\\d+)\\.(\\d+)\\.(\\d+)$/;\n\nfunction parseMajor(version: string): number | null {\n const match = VERSION_PATTERN.exec(version);\n if (match === null) {\n return null;\n }\n const major = Number.parseInt(match[1] as string, 10);\n return Number.isNaN(major) ? null : major;\n}\n\n/** 协议版本兼容判定(镜像 meta.ts 同名函数):主版本号相同即兼容。 */\nexport function isProtocolVersionCompatible(peerVersion: string, serverVersion: string): boolean {\n const peer = parseMajor(peerVersion);\n const server = parseMajor(serverVersion);\n return peer !== null && server !== null && peer === server;\n}\n\n// ---- 帧格式(镜像 frame.ts)----\n\nconst TYPE_PATTERN = /^[a-z][a-z0-9_]*$/;\n\nexport const frameHeaderSchema = z.object({\n type: z.string().regex(TYPE_PATTERN),\n id: z.uuid().optional(),\n});\n\nexport type FrameHeader = z.infer<typeof frameHeaderSchema>;\n\n/**\n * 通用线格式帧(两段式解析的第一段):只约束帧骨架(type 受 snake_case、\n * id 存在时须 UUID、body 任意),供收帧侧「先取 type、再分发到具体 schema」。\n */\nexport const wireFrameSchema = z.object({\n header: frameHeaderSchema,\n body: z.unknown(),\n});\n\nexport type WireFrame = z.infer<typeof wireFrameSchema>;\n\n/** 扁平事件消息 */\nexport interface EventMessage<T extends string, B> {\n type: T;\n body: B;\n}\n\n/** 扁平请求/响应消息(UUID 关联) */\nexport interface RequestMessage<T extends string, B> {\n type: T;\n id: string;\n body: B;\n}\n\n/** 事件帧(单向通知,携带 id 即校验失败) */\nexport function eventFrameSchema<const T extends string, B extends z.ZodType>(type: T, body: B) {\n return z\n .object({\n header: z.strictObject({ type: z.literal(type) }),\n body,\n })\n .transform((frame) => {\n // zod v4 对泛型成员的对象输出推断不足(body 键丢失),此处用结构断言收拢\n const wire = frame as { header: { type: T }; body: z.output<B> };\n return { type: wire.header.type, body: wire.body } satisfies EventMessage<\n T,\n z.output<B>\n >;\n });\n}\n\n/** 请求/响应帧(id 必填) */\nexport function requestFrameSchema<const T extends string, B extends z.ZodType>(type: T, body: B) {\n return z\n .object({\n header: frameHeaderSchema.extend({ type: z.literal(type), id: z.uuid() }),\n body,\n })\n .transform((frame) => {\n const wire = frame as { header: { type: T; id: string }; body: z.output<B> };\n return {\n type: wire.header.type,\n id: wire.header.id,\n body: wire.body,\n } satisfies RequestMessage<T, z.output<B>>;\n });\n}\n\n/** 出帧:扁平消息 → 线格式 JSON 文本(单行,可直接走 WS 文本帧) */\nexport function encodeFrame(message: { type: string; body: unknown; id?: string }): string {\n const header: { type: string; id?: string } = { type: message.type };\n if (message.id !== undefined) {\n header.id = message.id;\n }\n return JSON.stringify({ header, body: message.body });\n}\n\n/** 请求-响应的通用结果体 */\nexport const resultBodySchema = z.union([\n z.object({ ok: z.literal(true) }),\n z.object({ ok: z.literal(false), error: z.string().min(1) }),\n]);\n\nexport type ResultBody = z.infer<typeof resultBodySchema>;\n\n/** 请求-响应的命令结果体(ok 分支可选 `output`:命令输出行;与 query/命令链共用)。 */\nexport const commandResultBodySchema = z.union([\n z.object({ ok: z.literal(true), output: z.array(z.string()).optional() }),\n z.object({ ok: z.literal(false), error: z.string().min(1) }),\n]);\n\nexport type CommandResultBody = z.infer<typeof commandResultBodySchema>;\n\n// ---- Peer → Server(镜像 messages/ws.ts)----\n\nconst helloBodySchema = z.object({\n peerId: z.string().min(1),\n platform: z.string().min(1),\n version: z.string().min(1),\n protocolVersion: z.string().regex(/^\\d+\\.\\d+\\.\\d+$/),\n /** 鉴权 token(服务端配置非空 token 时未带/带错 → hello_ack ok:false + close 1008)。 */\n token: z.string().optional(),\n /** 对端自报身份(0.3.1,MVP-3:建议 `名称/版本`,服务端仅日志辨识)。 */\n client: z.string().optional(),\n});\n\n/** 对端注册(请求,服务端必须回同 id 的 hello_ack)。 */\nexport const helloFrame = requestFrameSchema(\"hello\", helloBodySchema);\nexport type HelloBody = z.infer<typeof helloBodySchema>;\nexport type HelloFrame = z.infer<typeof helloFrame>;\n\nconst pingBodySchema = z.object({\n timestamp: z.number().int().nonnegative(),\n});\n\n/** 心跳请求(应用层帧——服务端空闲检测只认应用层入帧,WS 层 ping 无效)。 */\nexport const pingFrame = requestFrameSchema(\"ping\", pingBodySchema);\nexport type PingBody = z.infer<typeof pingBodySchema>;\nexport type PingFrame = z.infer<typeof pingFrame>;\n\nconst platformChatBodySchema = z.object({\n /** 消息来源频道(QQ 群号字符串) */\n channel: z.string().min(1),\n sender: z.string().min(1),\n content: z.string().min(1),\n});\n\n/** 平台 → 游戏聊天(事件;服务端按绑定表过滤未绑定频道)。 */\nexport const platformChatFrame = eventFrameSchema(\"chat\", platformChatBodySchema);\nexport type PlatformChatBody = z.infer<typeof platformChatBodySchema>;\nexport type PlatformChatFrame = z.infer<typeof platformChatFrame>;\n\nconst commandSourceSchema = z.object({\n /** 消息来源频道(QQ 群号字符串) */\n channel: z.string().min(1),\n /** 发送者 QQ 号(协议端负责从群消息提取;管理员判定在服务端) */\n userId: z.string().min(1),\n});\n\nconst commandBodySchema = z.object({\n /** 待执行的命令行(不含前导斜杠,如 \"whitelist list\") */\n command: z.string().min(1),\n source: commandSourceSchema,\n});\n\n/** 群指令 → 执行游戏命令(请求;响应为同 id command_result)。 */\nexport const commandFrame = requestFrameSchema(\"command\", commandBodySchema);\nexport type CommandBody = z.infer<typeof commandBodySchema>;\nexport type CommandSource = z.infer<typeof commandSourceSchema>;\nexport type CommandFrame = z.infer<typeof commandFrame>;\n\nconst queryBodySchema = z.object({\n /** 查询类别:status = 最近一帧服务器状态快照;bindings = 当前绑定频道列表 */\n kind: z.union([z.literal(\"status\"), z.literal(\"bindings\")]),\n});\n\n/** 状态/绑定查询(请求;响应为同 id query_result)。 */\nexport const queryFrame = requestFrameSchema(\"query\", queryBodySchema);\nexport type QueryBody = z.infer<typeof queryBodySchema>;\nexport type QueryFrame = z.infer<typeof queryFrame>;\n\n// ---- Server → Peer(镜像 messages/ws.ts)----\n\nconst helloAckOkBodySchema = z.object({\n ok: z.literal(true),\n serverId: z.string().min(1),\n version: z.string().min(1),\n protocolVersion: z.string().regex(/^\\d+\\.\\d+\\.\\d+$/),\n /** 服务端绑定表快照(空数组合法 = 全部不发)。 */\n channelBindings: z.array(z.string().min(1)),\n});\n\nconst helloAckErrorBodySchema = z.object({\n ok: z.literal(false),\n reason: z.string().min(1),\n});\n\n/** 握手结果(响应,同 id)。 */\nexport const helloAckFrame = z.union([\n requestFrameSchema(\"hello_ack\", helloAckOkBodySchema),\n requestFrameSchema(\"hello_ack\", helloAckErrorBodySchema),\n]);\nexport type HelloAckOkBody = z.infer<typeof helloAckOkBodySchema>;\nexport type HelloAckErrorBody = z.infer<typeof helloAckErrorBodySchema>;\nexport type HelloAckBody = HelloAckOkBody | HelloAckErrorBody;\nexport type HelloAckFrame = z.infer<typeof helloAckFrame>;\n\nconst pongBodySchema = z.object({\n timestamp: z.number().int().nonnegative(),\n});\n\n/** 心跳响应(不需要处理:收不到就等服务端 1001 关闭走重连)。 */\nexport const pongFrame = requestFrameSchema(\"pong\", pongBodySchema);\nexport type PongBody = z.infer<typeof pongBodySchema>;\nexport type PongFrame = z.infer<typeof pongFrame>;\n\nconst gameChatBodySchema = z.object({\n /** 目标频道(服务端按绑定表逐频道 fan-out,每频道一帧) */\n channel: z.string().min(1),\n playerName: z.string().min(1),\n content: z.string().min(1),\n});\n\n/** 游戏 → 平台聊天(事件)。 */\nexport const gameChatFrame = eventFrameSchema(\"chat\", gameChatBodySchema);\nexport type GameChatBody = z.infer<typeof gameChatBodySchema>;\nexport type GameChatFrame = z.infer<typeof gameChatFrame>;\n\nconst joinBodySchema = z.object({\n channel: z.string().min(1),\n playerName: z.string().min(1),\n});\n\n/** 玩家进服(事件,按绑定频道 fan-out)。 */\nexport const joinFrame = eventFrameSchema(\"join\", joinBodySchema);\nexport type JoinBody = z.infer<typeof joinBodySchema>;\nexport type JoinFrame = z.infer<typeof joinFrame>;\n\nconst leaveBodySchema = z.object({\n channel: z.string().min(1),\n playerName: z.string().min(1),\n});\n\n/** 玩家退服(事件,按绑定频道 fan-out)。 */\nexport const leaveFrame = eventFrameSchema(\"leave\", leaveBodySchema);\nexport type LeaveBody = z.infer<typeof leaveBodySchema>;\nexport type LeaveFrame = z.infer<typeof leaveFrame>;\n\nconst statusBodySchema = z.object({\n /** 1 分钟 TPS 均值(Paper getTPS()[0]) */\n tps: z.number().nonnegative(),\n onlinePlayers: z.number().int().nonnegative(),\n uptimeSeconds: z.number().int().nonnegative(),\n});\n\n/** 服务器状态(事件;无 channel——全服状态而非频道消息)。 */\nexport const statusFrame = eventFrameSchema(\"status\", statusBodySchema);\nexport type StatusBody = z.infer<typeof statusBodySchema>;\nexport type StatusFrame = z.infer<typeof statusFrame>;\n\nconst bindingsUpdatedBodySchema = z.object({\n /** 变更后的完整绑定列表(非增量;空数组合法 = 全部不发)。 */\n channelBindings: z.array(z.string().min(1)),\n});\n\n/** 绑定表变更推送(事件)。 */\nexport const bindingsUpdatedFrame = eventFrameSchema(\"bindings_updated\", bindingsUpdatedBodySchema);\nexport type BindingsUpdatedBody = z.infer<typeof bindingsUpdatedBodySchema>;\nexport type BindingsUpdatedFrame = z.infer<typeof bindingsUpdatedFrame>;\n\n/** 群指令的执行结果(响应,同 id)。 */\nexport const commandResultFrame = requestFrameSchema(\"command_result\", commandResultBodySchema);\nexport type CommandResultFrame = z.infer<typeof commandResultFrame>;\n\nconst queryResultBodySchema = z.union([\n z.object({\n ok: z.literal(true),\n /** data 形状由请求 kind 决定:status → StatusBody 同构;bindings → string[]。 */\n data: z.unknown(),\n }),\n z.object({ ok: z.literal(false), error: z.string().min(1) }),\n]);\n\n/** 查询结果(响应,同 id)。 */\nexport const queryResultFrame = requestFrameSchema(\"query_result\", queryResultBodySchema);\nexport type QueryResultBody = z.infer<typeof queryResultBodySchema>;\nexport type QueryResultFrame = z.infer<typeof queryResultFrame>;\n\nconst deathBodySchema = z.object({\n /** 目标频道(服务端按绑定表逐频道 fan-out,每频道一帧) */\n channel: z.string().min(1),\n /** 死亡玩家名(SSOT 原文命名 `player`——与 join/leave 的 playerName 不一致,照抄不「修正」) */\n player: z.string().min(1),\n /** 死亡消息文本(Bukkit deathMessage 可为 null → 服务端以空串兜底,故允许空串) */\n message: z.string(),\n});\n\n/** 玩家死亡(事件,按绑定频道 fan-out 对齐 join/leave)。 */\nexport const deathFrame = eventFrameSchema(\"death\", deathBodySchema);\nexport type DeathBody = z.infer<typeof deathBodySchema>;\nexport type DeathFrame = z.infer<typeof deathFrame>;\n\n/** 服务端 → 对端已知帧 type 清单(收帧分发用;不在表内走未知帧容忍)。 */\nexport const SERVER_TO_PEER_TYPES: readonly string[] = [\n \"hello_ack\",\n \"pong\",\n \"chat\",\n \"join\",\n \"leave\",\n \"death\",\n \"status\",\n \"bindings_updated\",\n \"command_result\",\n \"query_result\",\n];\n","/**\n * KurobotConnection:kurobridge-ws 客户端连接层(任务书 KUROBOT-PROMPT §1.2 决策二)\n *\n * 自建而不复用 network.WsClient 的四个协议语义理由(均已核实 WsClient 现状):\n * ① 服务端 handleProtocols 校验子协议 `kurobridge-ws.v1`,不带直接拒连——WsClient\n * 不支持 Sec-WebSocket-Protocol;\n * ② 服务端空闲检测(30s)只认**应用层入帧**,WS 层 ws.ping() 不重置计时——必须发\n * 应用层 ping 帧;\n * ③ 每次连接(含重连)成功后必须立即重发 hello——WsClient 无 onOpen 回调;\n * ④ 重连需感知 close code(1002/1008 停止重连)——WsClient 是固定延迟重连。\n * 这四项都是 kurobridge-ws 协议语义,塞进协议无关的 network 违反其定位(红线:不改 network)。\n *\n * 状态机:connecting → establishing(hello 已发,等 ack)→ established(应用层 ping)\n * ↔ backoff(指数退避 1s/2s/…/60s 封顶);hello_ack ok:false / close 1002 / 1008 →\n * 永久停止(等版本升级或配置修正,error 日志)。未 established 时发送直接丢弃(不积压)。\n */\nimport { randomUUID } from \"node:crypto\";\nimport { WebSocket } from \"ws\";\nimport {\n type BindingsUpdatedBody,\n bindingsUpdatedFrame,\n type CommandResultBody,\n commandResultFrame,\n type DeathBody,\n deathFrame,\n encodeFrame,\n type GameChatBody,\n gameChatFrame,\n type HelloAckOkBody,\n helloAckFrame,\n isProtocolVersionCompatible,\n type JoinBody,\n joinFrame,\n type LeaveBody,\n leaveFrame,\n type PongBody,\n pongFrame,\n type QueryResultBody,\n queryResultFrame,\n type StatusBody,\n statusFrame,\n WS_SUBPROTOCOL,\n wireFrameSchema,\n} from \"./schema.js\";\n\n/** 连接层日志最小面(装配方传 pino 实例;缺省静默)。 */\nexport interface KurobotLogger {\n debug(obj: unknown, msg: string): void;\n info(obj: unknown, msg: string): void;\n warn(obj: unknown, msg: string): void;\n error(obj: unknown, msg: string): void;\n}\n\n/** 服务端 → 对端的已知业务帧(扁平消息;hello_ack 由连接层内部消费不经此回调)。 */\nexport type ServerEventMessage =\n | { type: \"pong\"; id: string; body: PongBody }\n | { type: \"chat\"; body: GameChatBody }\n | { type: \"join\"; body: JoinBody }\n | { type: \"leave\"; body: LeaveBody }\n | { type: \"death\"; body: DeathBody }\n | { type: \"status\"; body: StatusBody }\n | { type: \"bindings_updated\"; body: BindingsUpdatedBody }\n | { type: \"command_result\"; id: string; body: CommandResultBody }\n | { type: \"query_result\"; id: string; body: QueryResultBody };\n\n/** 连接终止原因(onEnded 只在永久停止时触发一次;用户 stop() 不触发)。 */\nexport interface ConnectionEndedReason {\n /** true = 不可恢复(版本不符 / token 错 / hello_ack 拒绝)。 */\n permanent: boolean;\n /** WS close code(可得时)。 */\n code?: number;\n /** 人读描述。 */\n detail: string;\n}\n\n/** hello body(protocolVersion 固定 0.3.1;peerId/platform/version/client 由适配器解析)。 */\nexport interface KurobotHello {\n peerId: string;\n platform: string;\n version: string;\n protocolVersion: string;\n token?: string;\n client?: string;\n}\n\n/** 连接层参数(重连节奏等可注入测试快值;生产用缺省)。 */\nexport interface KurobotConnectionOptions {\n /** KuroBot 服务端完整地址(ws:// / wss://)。 */\n url: string;\n hello: KurobotHello;\n /** 应用层心跳间隔毫秒(须显著小于服务端 30s 空闲阈值;0 = 关闭)。 */\n pingIntervalMs: number;\n /** 建立(hello → ack)超时毫秒。 */\n helloTimeoutMs: number;\n /** 重连退避基数毫秒(指数 2^attempt)。 */\n retryBaseDelayMs: number;\n /** 重连退避上限毫秒。 */\n retryMaxDelayMs: number;\n /** 握手成功(ack ok,含绑定快照)。 */\n onEstablished: (ack: HelloAckOkBody) => void;\n /** 服务端业务帧(hello_ack 内部消费不回调;pong 透传由消费方忽略)。 */\n onFrame: (msg: ServerEventMessage) => void;\n /** 连接永久停止(1002/1008/hello_ack 拒绝);用户 stop() 不触发。 */\n onEnded: (reason: ConnectionEndedReason) => void;\n /** 日志(缺省静默)。 */\n logger?: KurobotLogger;\n}\n\n/** 连接层内部状态。 */\ntype ConnectionState =\n | \"idle\"\n | \"connecting\"\n | \"establishing\"\n | \"established\"\n | \"backoff\"\n | \"stopped\";\n\n/**\n * 已知 type → 具体 schema 校验(返回扁平消息;body 非法返回 null 由调用方统一 warn)。\n * 与 schema.ts 的 Server→Peer 消息集一一对应;hello_ack 在连接层单独处理,不在此表。\n */\nconst SERVER_FRAME_PARSERS: Record<string, (json: unknown) => ServerEventMessage | null> = {\n pong: (json) => {\n const ok = pongFrame.safeParse(json);\n return ok.success ? { type: \"pong\", id: ok.data.id, body: ok.data.body } : null;\n },\n chat: (json) => {\n const ok = gameChatFrame.safeParse(json);\n return ok.success ? { type: \"chat\", body: ok.data.body } : null;\n },\n join: (json) => {\n const ok = joinFrame.safeParse(json);\n return ok.success ? { type: \"join\", body: ok.data.body } : null;\n },\n leave: (json) => {\n const ok = leaveFrame.safeParse(json);\n return ok.success ? { type: \"leave\", body: ok.data.body } : null;\n },\n death: (json) => {\n const ok = deathFrame.safeParse(json);\n return ok.success ? { type: \"death\", body: ok.data.body } : null;\n },\n status: (json) => {\n const ok = statusFrame.safeParse(json);\n return ok.success ? { type: \"status\", body: ok.data.body } : null;\n },\n bindings_updated: (json) => {\n const ok = bindingsUpdatedFrame.safeParse(json);\n return ok.success ? { type: \"bindings_updated\", body: ok.data.body } : null;\n },\n command_result: (json) => {\n const ok = commandResultFrame.safeParse(json);\n return ok.success ? { type: \"command_result\", id: ok.data.id, body: ok.data.body } : null;\n },\n query_result: (json) => {\n const ok = queryResultFrame.safeParse(json);\n return ok.success ? { type: \"query_result\", id: ok.data.id, body: ok.data.body } : null;\n },\n};\n\n/** kurobridge-ws 客户端连接(子协议 + hello + 应用层 ping + 感知 close code 的指数退避)。 */\nexport class KurobotConnection {\n private readonly opts: KurobotConnectionOptions;\n private readonly log: KurobotLogger;\n private state: ConnectionState = \"idle\";\n private ws: WebSocket | null = null;\n /** 用户主动 stop(其后一切 close 都不再重连、不上报 onEnded)。 */\n private userStopped = false;\n /** 已判定永久拒绝(版本/token),不再重连。 */\n private rejected = false;\n private pendingHelloId: string | null = null;\n private helloTimer: NodeJS.Timeout | null = null;\n private pingTimer: NodeJS.Timeout | null = null;\n private retryTimer: NodeJS.Timeout | null = null;\n /** 连续失败计数(established 成功后清零)。 */\n private attempt = 0;\n\n constructor(opts: KurobotConnectionOptions) {\n this.opts = opts;\n this.log = opts.logger ?? SILENT_LOGGER;\n }\n\n /** 当前是否已建立(ack ok)。 */\n isEstablished(): boolean {\n return this.state === \"established\";\n }\n\n /** 启动:发起首次连接(异步,结果经回调上报;重复调用幂等)。 */\n start(): void {\n if (this.state !== \"idle\") {\n return;\n }\n this.connect();\n }\n\n /** 停止:关闭连接、清定时器、不再重连(幂等;不触发 onEnded)。 */\n stop(): void {\n if (this.state === \"stopped\") {\n return;\n }\n this.userStopped = true;\n this.clearTimers();\n this.state = \"stopped\";\n const ws = this.ws;\n this.ws = null;\n ws?.close(1000, \"client stop\");\n }\n\n /** 发送出站帧(chat/command/query 等扁平消息);未 established 丢弃 + debug。 */\n send(message: { type: string; body: unknown; id?: string }): boolean {\n const ws = this.ws;\n if (this.state !== \"established\" || ws === null || ws.readyState !== WebSocket.OPEN) {\n this.log.debug({ type: message.type }, \"kurobot: 未建立连接,丢弃出站帧\");\n return false;\n }\n ws.send(encodeFrame(message));\n return true;\n }\n\n /** 发起一次连接。 */\n private connect(): void {\n if (this.userStopped || this.rejected) {\n return;\n }\n this.state = \"connecting\";\n const ws = new WebSocket(this.opts.url, WS_SUBPROTOCOL);\n this.ws = ws;\n ws.on(\"open\", () => {\n this.onOpen();\n });\n ws.on(\"message\", (data: unknown) => {\n this.onText(String(data));\n });\n ws.on(\"close\", (code: number, reason: Buffer) => {\n this.onClose(code, reason.toString());\n });\n ws.on(\"error\", (err: Error) => {\n // close 总会跟随 error 到达(连接失败 / 中途断开),状态迁移统一在 onClose\n this.log.warn({ err: err.message }, \"kurobot: 连接错误\");\n });\n }\n\n /** 连接建立:立即发 hello(每次连接都重发——服务端按连接会话握手)。 */\n private onOpen(): void {\n if (this.ws === null || this.userStopped || this.rejected) {\n return;\n }\n this.state = \"establishing\";\n this.pendingHelloId = randomUUID();\n this.ws.send(\n encodeFrame({ type: \"hello\", id: this.pendingHelloId, body: this.opts.hello }),\n );\n // 握手超时兜底(服务端也有 10s hello 超时,双保险)\n this.helloTimer = setTimeout(() => {\n this.helloTimer = null;\n if (this.state === \"establishing\") {\n this.log.warn({}, \"kurobot: 等待 hello_ack 超时,关闭重试\");\n this.ws?.close();\n }\n }, this.opts.helloTimeoutMs);\n }\n\n /** 收到文本帧:两段式解析(wire 取 type → 分发具体 schema)+ 未知帧容忍。 */\n private onText(text: string): void {\n let json: unknown;\n try {\n json = JSON.parse(text) as unknown;\n } catch {\n this.log.warn({ text: text.slice(0, 200) }, \"kurobot: 非法 JSON 帧,忽略\");\n return;\n }\n const wire = wireFrameSchema.safeParse(json);\n if (!wire.success) {\n this.log.warn({ text: text.slice(0, 200) }, \"kurobot: 帧骨架非法,忽略\");\n return;\n }\n const { type } = wire.data.header;\n if (type === \"hello\") {\n this.log.warn({}, \"kurobot: 收到非预期的 hello 帧,忽略\");\n return;\n }\n if (type === \"hello_ack\") {\n this.handleHelloAck(json);\n return;\n }\n const msg = this.parseServerFrame(type, json);\n if (msg !== null) {\n this.opts.onFrame(msg);\n }\n }\n\n /** 已知 type 的具体 schema 校验(未知 type 走容忍;body 非法 warn 丢弃)。 */\n private parseServerFrame(type: string, json: unknown): ServerEventMessage | null {\n const parser = SERVER_FRAME_PARSERS[type];\n if (parser === undefined) {\n this.handleUnknownFrame(type, headerId(json));\n return null;\n }\n const msg = parser(json);\n if (msg === null) {\n this.log.warn({ type }, \"kurobot: 已知帧 body 校验失败,丢弃\");\n }\n return msg;\n }\n\n /** 未知帧容忍(对齐 ADR-026 服务端策略):事件帧忽略;请求帧回 `<type>_result` 失败回执;`_result` 结尾不回执(防乒乓)。 */\n private handleUnknownFrame(type: string, id: string | undefined): void {\n if (id === undefined) {\n this.log.debug({ type }, \"kurobot: 未知事件帧,忽略\");\n return;\n }\n if (type.endsWith(\"_result\")) {\n this.log.debug({ type }, \"kurobot: 未知响应帧,忽略(不回执防乒乓)\");\n return;\n }\n this.log.debug({ type }, \"kurobot: 未知请求帧,回执 unknown frame type\");\n this.send({ type: `${type}_result`, id, body: { ok: false, error: \"unknown frame type\" } });\n }\n\n /** hello_ack 处理:ok → 建立;ok:false → 永久停止(版本/鉴权问题不可自愈)。 */\n private handleHelloAck(json: unknown): void {\n const parsed = helloAckFrame.safeParse(json);\n if (!parsed.success) {\n this.log.warn({ type: \"hello_ack\" }, \"kurobot: 已知帧 body 校验失败,丢弃\");\n return;\n }\n if (parsed.data.id !== this.pendingHelloId) {\n this.log.warn({}, \"kurobot: hello_ack id 与请求不匹配,忽略\");\n return;\n }\n if (!parsed.data.body.ok) {\n this.log.error({ reason: parsed.data.body.reason }, \"kurobot: 握手被拒,停止重连\");\n this.reject(`hello_ack: ${parsed.data.body.reason}`);\n return;\n }\n const ack = parsed.data.body;\n if (!isProtocolVersionCompatible(this.opts.hello.protocolVersion, ack.protocolVersion)) {\n // 主版本协商在服务端(已接受才会回 ok),此处仅告警异常不一致\n this.log.warn(\n { peer: ack.protocolVersion, self: this.opts.hello.protocolVersion },\n \"kurobot: hello_ack 版本与本地声明主版本不一致\",\n );\n }\n if (this.helloTimer !== null) {\n clearTimeout(this.helloTimer);\n this.helloTimer = null;\n }\n this.attempt = 0;\n this.state = \"established\";\n this.startPing();\n this.log.info(\n { serverId: ack.serverId, version: ack.version, protocolVersion: ack.protocolVersion },\n \"kurobot: 握手成功\",\n );\n this.opts.onEstablished(ack);\n }\n\n /** 应用层心跳:每 pingIntervalMs 发 ping 帧(服务端任何入帧重置 30s 空闲计时)。 */\n private startPing(): void {\n this.stopPing();\n if (this.opts.pingIntervalMs <= 0) {\n return;\n }\n this.pingTimer = setInterval(() => {\n if (this.state === \"established\") {\n this.send({ type: \"ping\", id: randomUUID(), body: { timestamp: Date.now() } });\n }\n }, this.opts.pingIntervalMs);\n }\n\n private stopPing(): void {\n if (this.pingTimer !== null) {\n clearInterval(this.pingTimer);\n this.pingTimer = null;\n }\n }\n\n private clearTimers(): void {\n if (this.helloTimer !== null) {\n clearTimeout(this.helloTimer);\n this.helloTimer = null;\n }\n this.stopPing();\n if (this.retryTimer !== null) {\n clearTimeout(this.retryTimer);\n this.retryTimer = null;\n }\n this.pendingHelloId = null;\n }\n\n /** 永久拒绝:关闭连接,不再重连,上报 onEnded。 */\n private reject(detail: string, code?: number): void {\n this.rejected = true;\n this.clearTimers();\n this.state = \"stopped\";\n const ws = this.ws;\n this.ws = null;\n ws?.close();\n const reason: ConnectionEndedReason = { permanent: true, detail };\n if (code !== undefined) {\n reason.code = code;\n }\n this.opts.onEnded(reason);\n }\n\n /** close:区分用户停止 / 永久拒绝(1002/1008)/ 可重连断开。 */\n private onClose(code: number, reason: string): void {\n if (this.helloTimer !== null) {\n clearTimeout(this.helloTimer);\n this.helloTimer = null;\n }\n this.stopPing();\n const wasEstablished = this.state === \"established\";\n this.ws = null;\n if (this.userStopped || this.rejected) {\n this.state = \"stopped\";\n return;\n }\n this.state = \"idle\";\n // 1002 协议错误(版本不匹配)/ 1008 策略违规(token 错):等待版本升级/配置修正\n if (code === 1002 || code === 1008) {\n this.log.error({ code, reason }, \"kurobot: 连接被拒(不可重试错误),停止重连\");\n this.rejected = true;\n this.state = \"stopped\";\n this.opts.onEnded({ permanent: true, code, detail: reason || `closed ${code}` });\n return;\n }\n if (wasEstablished) {\n this.log.warn({ code, reason }, \"kurobot: 连接断开,准备重连\");\n }\n this.scheduleRetry();\n }\n\n /** 指数退避重连:base * 2^attempt 封顶 retryMaxDelayMs;established 成功清零。 */\n private scheduleRetry(): void {\n if (this.userStopped || this.rejected || this.retryTimer !== null) {\n return;\n }\n this.state = \"backoff\";\n const delay = Math.min(\n this.opts.retryBaseDelayMs * 2 ** this.attempt,\n this.opts.retryMaxDelayMs,\n );\n this.attempt += 1;\n this.log.debug({ delay, attempt: this.attempt }, \"kurobot: 退避后重连\");\n this.retryTimer = setTimeout(() => {\n this.retryTimer = null;\n this.connect();\n }, delay);\n }\n}\n\n/** 从已解析的原始帧 JSON 取 header.id(容忍缺失)。 */\nfunction headerId(json: unknown): string | undefined {\n if (typeof json !== \"object\" || json === null) {\n return undefined;\n }\n const header = (json as { header?: unknown }).header;\n if (typeof header !== \"object\" || header === null) {\n return undefined;\n }\n const id = (header as { id?: unknown }).id;\n return typeof id === \"string\" ? id : undefined;\n}\n\n/** 静默日志(缺省)。 */\nconst SILENT_LOGGER: KurobotLogger = {\n debug: () => undefined,\n info: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n};\n","/**\n * 消息映射纯函数(任务书 KUROBOT-PROMPT §1.2 QQ↔MC 映射;翻译层无副作用,ADR-008)\n *\n * QQ → MC:canonical elements 富文本降级为单行文本(无法表达的类型静默跳过,\n * 对齐 OB11 收向「无法表达静默跳过」惯例)。\n * MC → QQ:渲染模板占位符替换({player}/{content}/{message},MVP 纯文本)+\n * 1500 字符截断。\n */\nimport { type CanonicalElement, type RawMessage, toCanonicalElements } from \"@napuketto/kernel\";\nimport type { CommandResultBody } from \"./schema.js\";\n\n/** 发往 QQ 文本的总长上限(超出截断追加 …(截断);任务书对 command_result 规定,统一套用)。 */\nexport const MAX_GROUP_TEXT_LENGTH = 1500;\n\n/** 截断追加的省略标记。 */\nconst TRUNCATE_SUFFIX = \"…(截断)\";\n\n/** 超长截断(按 UTF-16 码元计,超限部分丢弃)。 */\nexport function truncateForGroup(text: string): string {\n if (text.length <= MAX_GROUP_TEXT_LENGTH) {\n return text;\n }\n return `${text.slice(0, MAX_GROUP_TEXT_LENGTH)}${TRUNCATE_SUFFIX}`;\n}\n\n/** QQ 群消息发送者显示名:sendMemberName ?? sendNickName(双空兜底 senderUin,schema min(1))。 */\nexport function resolveSenderName(msg: RawMessage): string {\n const member = msg.sendMemberName;\n if (typeof member === \"string\" && member !== \"\") {\n return member;\n }\n const nick = msg.sendNickName;\n if (typeof nick === \"string\" && nick !== \"\") {\n return nick;\n }\n return String(msg.senderUin);\n}\n\n/** at 元素 → 文本占位(@全体成员 / @{display ?? uid})。 */\nfunction atToText(el: { target: string; display?: string }): string {\n if (el.target === \"all\") {\n return \"@全体成员\";\n }\n return `@${el.display ?? el.target}`;\n}\n\n/** canonical 元素序列 → 降级文本(text 原文、@、图片/表情/回复占位;空白返回 null = 不发)。 */\nexport function degradeElements(elements: CanonicalElement[]): string | null {\n const parts: string[] = [];\n for (const el of elements) {\n switch (el.type) {\n case \"text\":\n parts.push(el.text);\n break;\n case \"at\":\n parts.push(atToText(el));\n break;\n case \"image\":\n parts.push(\"[图片]\");\n break;\n case \"face\":\n parts.push(\"[表情]\");\n break;\n case \"reply\":\n parts.push(\"[回复]\");\n break;\n default:\n // voice/video/file/forward/json/xml/unknown:无法表达,静默跳过\n break;\n }\n }\n const text = parts.join(\"\").trim();\n return text === \"\" ? null : text;\n}\n\n/** RawMessage → 降级文本(便捷封装;null = 空消息不发)。 */\nexport function degradeMessage(msg: RawMessage): string | null {\n return degradeElements(toCanonicalElements(msg));\n}\n\n/** 渲染模板变量(player 必有;content = 聊天内容;message = 死亡消息)。 */\nexport interface TemplateVars {\n player: string;\n content?: string;\n message?: string;\n}\n\n/** 渲染模板:替换 {player}/{content}/{message} 占位符(未知占位符原样保留)。 */\nexport function renderTemplate(template: string, vars: TemplateVars): string {\n return template\n .replaceAll(\"{player}\", vars.player)\n .replaceAll(\"{content}\", vars.content ?? \"\")\n .replaceAll(\"{message}\", vars.message ?? \"\");\n}\n\n/** death 事件 → 群文本(message 空串时以「死亡了」代入:Bukkit deathMessage null 兜底)。 */\nexport function renderDeathText(template: string, player: string, message: string): string {\n return renderTemplate(template, { player, message: message === \"\" ? \"死亡了\" : message });\n}\n\n/** command_result body → 群文本(ok 合并 output;error → 命令失败:{error})。 */\nexport function renderCommandResult(body: CommandResultBody): string {\n if (!body.ok) {\n return `命令失败:${body.error}`;\n }\n const output = body.output ?? [];\n if (output.length === 0) {\n return \"(命令执行成功,无输出)\";\n }\n return output.join(\"\\n\");\n}\n","/**\n * NapukettoKurobotAdapter:kurobridge-ws 协议适配器(KuroBot MVP-3,2026-09-13)\n *\n * - 出链路:订阅 kernel 消息事件通道 → 仅群聊 → 富文本降级 → 出站绑定过滤 →\n * kurobridge-ws chat 帧;命令前缀消息 → command 帧(source 由本侧提取)。\n * - 入链路:KurobotConnection 收服务端帧 → chat/join/leave/death 渲染模板 →\n * kernel 群消息 API 纯文本发送;status 仅缓存;command_result 经 pending 表\n * 关联回发群(帧无 channel 字段,靠请求 UUID 关联)。\n *\n * 生命周期走 BaseProtocolAdapter 骨架(start 校验配置 → onStart 建连接 + 订阅 →\n * onStop 清理);连接层状态机见 connection.ts。不发协议事件给 network 广播器\n * (kurobot 是纯客户端出向协议,无第三方接入门面)。\n */\nimport { randomUUID } from \"node:crypto\";\nimport { createRequire } from \"node:module\";\nimport type { CanonicalElement, MsgEventChannel, Peer, RawMessage } from \"@napuketto/kernel\";\nimport { ChatType } from \"@napuketto/kernel\";\nimport { BaseProtocolAdapter, type ProtocolConfig } from \"../core/index.js\";\nimport { forEachRawMessage } from \"../core/raw-message.js\";\nimport type { KurobotConfig } from \"./config.js\";\nimport type {\n ConnectionEndedReason,\n KurobotConnectionOptions,\n ServerEventMessage,\n} from \"./connection.js\";\nimport { KurobotConnection } from \"./connection.js\";\nimport { type HelloAckOkBody, PROTOCOL_VERSION, type StatusBody } from \"./schema.js\";\nimport {\n degradeMessage,\n renderCommandResult,\n renderDeathText,\n renderTemplate,\n resolveSenderName,\n truncateForGroup,\n} from \"./translate.js\";\n\n/** 发群消息最小面(kernel MsgApi.sendMessage 的结构子集,便于测试桩替换)。 */\nexport interface KurobotMsgApi {\n sendMessage(target: Peer, elements: CanonicalElement[]): Promise<{ msgId: string }>;\n}\n\n/** 适配器构造参数。 */\nexport interface KurobotAdapterOptions {\n /** 协议配置(zod 校验 + seed 装配)。 */\n config: ProtocolConfig<KurobotConfig>;\n /** kernel 消息事件通道(QQ 消息收链路入口)。 */\n msgChannel: MsgEventChannel;\n /** kernel 消息 API(MC → QQ 群文本发送)。 */\n msgApi: KurobotMsgApi;\n /** 当前登录账号(自消息过滤 + hello peerId)。 */\n self: { uin: string; nickname: string };\n /** 日志(缺省静默)。 */\n logger?: KurobotLoggerAlias;\n}\n\n/** 适配器日志面(复用连接层最小面)。 */\ntype KurobotLoggerAlias = KurobotConnectionOptions[\"logger\"];\n\n/** kurobot 协议适配器。 */\nexport class NapukettoKurobotAdapter extends BaseProtocolAdapter<KurobotConfig> {\n readonly protocol = \"kurobot\";\n\n private readonly msgChannel: MsgEventChannel;\n private readonly msgApi: KurobotMsgApi;\n private readonly selfUin: string;\n private readonly log: KurobotLoggerAlias;\n private connection: KurobotConnection | null = null;\n private unsubscribe: (() => void) | null = null;\n /** 当前生效配置(收链路取 commandPrefix 等;onStart/onReload 刷新)。 */\n private currentConfig: KurobotConfig | null = null;\n /** 出站绑定集(hello_ack 快照 + bindings_updated 全量替换;空集 = 全部不发)。 */\n private bindings = new Set<string>();\n /** command 请求 UUID → 回发群号(command_result 帧无 channel,靠 id 关联)。 */\n private pendingCommands = new Map<string, string>();\n /** query 请求 UUID → 查询类别。 */\n private pendingQueries = new Map<string, \"status\" | \"bindings\">();\n /** 最近一帧 status 快照(仅缓存不发群,M-04 决策同构)。 */\n private lastStatus: StatusBody | null = null;\n\n constructor(opts: KurobotAdapterOptions) {\n super({\n config: opts.config,\n hooks: {\n onStart: (config) => this.startKurobot(config as KurobotConfig),\n onStop: () => this.stopAll(),\n onReload: (config) => this.reloadKurobot(config as KurobotConfig),\n },\n });\n this.msgChannel = opts.msgChannel;\n this.msgApi = opts.msgApi;\n this.selfUin = String(opts.self.uin);\n this.log = opts.logger;\n }\n\n /** 最近一帧 status 快照(仅缓存;无帧时 null)。 */\n getLastStatus(): StatusBody | null {\n return this.lastStatus;\n }\n\n /** 连接是否已建立(hello_ack ok 后为 true)。 */\n isConnected(): boolean {\n return this.connection?.isEstablished() ?? false;\n }\n\n /** 发起 query 请求(status/bindings)。MVP 未接 QQ 触发面——预留能力(见 design.md §8)。 */\n query(kind: \"status\" | \"bindings\"): boolean {\n const conn = this.connection;\n if (conn === null || !conn.isEstablished()) {\n return false;\n }\n const id = randomUUID();\n this.pendingQueries.set(id, kind);\n return conn.send({ type: \"query\", id, body: { kind } });\n }\n\n /** 启动:建连接(异步握手,日志可见)+ 订阅 kernel 消息。 */\n private async startKurobot(config: KurobotConfig): Promise<void> {\n this.currentConfig = config;\n this.bindings = new Set();\n this.pendingCommands.clear();\n this.pendingQueries.clear();\n this.lastStatus = null;\n const hello: KurobotConnectionOptions[\"hello\"] = {\n peerId: this.selfUin,\n platform: \"qq\",\n version: resolveAdapterVersion(),\n protocolVersion: PROTOCOL_VERSION,\n client: config.client ?? resolveDefaultClient(),\n };\n if (config.token !== \"\") {\n hello.token = config.token;\n }\n const connOptions: KurobotConnectionOptions = {\n url: config.url,\n hello,\n pingIntervalMs: config.pingIntervalMs,\n helloTimeoutMs: 10_000,\n retryBaseDelayMs: 1_000,\n retryMaxDelayMs: 60_000,\n onEstablished: (ack) => this.onEstablished(ack),\n onFrame: (msg) => this.onServerFrame(msg),\n onEnded: (reason) => this.onEnded(reason),\n };\n if (this.log !== undefined) {\n connOptions.logger = this.log;\n }\n this.connection = new KurobotConnection(connOptions);\n this.connection.start();\n this.subscribe();\n }\n\n /** 配置热更新:停旧连接/退订 → 按新配置重建(对齐 satori reloadTransports)。 */\n private async reloadKurobot(config: KurobotConfig): Promise<void> {\n await this.stopAll();\n await this.startKurobot(config);\n }\n\n /** 停止:退订 + 关连接 + 清 pending 表。 */\n private async stopAll(): Promise<void> {\n this.unsubscribeAll();\n this.connection?.stop();\n this.connection = null;\n this.pendingCommands.clear();\n this.pendingQueries.clear();\n }\n\n /** 握手成功:绑定集整体替换为服务端快照 + 清上一连接的 pending 表。 */\n private onEstablished(ack: HelloAckOkBody): void {\n this.pendingCommands.clear();\n this.pendingQueries.clear();\n this.bindings = new Set(ack.channelBindings);\n }\n\n /** 连接永久停止(1002/1008/hello_ack 拒绝):清 pending(绑定集留给下次握手覆盖)。 */\n private onEnded(reason: ConnectionEndedReason): void {\n this.pendingCommands.clear();\n this.pendingQueries.clear();\n this.log?.error({ reason }, \"kurobot: 连接终止\");\n }\n\n /** 服务端帧分发(渲染回群 / 缓存 / 绑定集维护 / 命令结果关联回发)。 */\n private onServerFrame(msg: ServerEventMessage): void {\n switch (msg.type) {\n case \"pong\":\n // 心跳响应不需要处理(任务书 §1.2:收不到就等服务端 1001 关闭走重连)\n return;\n case \"chat\":\n this.sendToGroup(\n msg.body.channel,\n renderTemplate(this.requireConfig().chatTemplate, {\n player: msg.body.playerName,\n content: msg.body.content,\n }),\n );\n return;\n case \"join\":\n this.sendToGroup(\n msg.body.channel,\n renderTemplate(this.requireConfig().joinTemplate, {\n player: msg.body.playerName,\n }),\n );\n return;\n case \"leave\":\n this.sendToGroup(\n msg.body.channel,\n renderTemplate(this.requireConfig().leaveTemplate, {\n player: msg.body.playerName,\n }),\n );\n return;\n case \"death\":\n this.sendToGroup(\n msg.body.channel,\n truncateForGroup(\n renderDeathText(\n this.requireConfig().deathTemplate,\n msg.body.player,\n msg.body.message,\n ),\n ),\n );\n return;\n case \"status\":\n // 仅缓存不发群(防刷屏)\n this.lastStatus = msg.body;\n this.log?.debug({ status: msg.body }, \"kurobot: status 已缓存\");\n return;\n case \"bindings_updated\":\n this.bindings = new Set(msg.body.channelBindings);\n this.log?.info({ bindings: msg.body.channelBindings }, \"kurobot: 绑定表已更新\");\n return;\n case \"command_result\": {\n const channel = this.pendingCommands.get(msg.id);\n if (channel === undefined) {\n this.log?.warn({ id: msg.id }, \"kurobot: command_result 无对应请求,丢弃\");\n return;\n }\n this.pendingCommands.delete(msg.id);\n this.sendToGroup(channel, truncateForGroup(renderCommandResult(msg.body)));\n return;\n }\n case \"query_result\": {\n this.onQueryResult(msg.id, msg.body);\n return;\n }\n }\n }\n\n /** query_result 处理:bindings 刷新绑定集(防御性收窄);status 缓存。 */\n private onQueryResult(\n id: string,\n body: { ok: true; data?: unknown } | { ok: false; error: string },\n ): void {\n const kind = this.pendingQueries.get(id);\n if (kind === undefined) {\n this.log?.warn({ id }, \"kurobot: query_result 无对应请求,丢弃\");\n return;\n }\n this.pendingQueries.delete(id);\n if (!body.ok) {\n this.log?.warn({ kind, error: body.error }, \"kurobot: 查询失败\");\n return;\n }\n if (kind === \"bindings\" && isStringArray(body.data)) {\n this.bindings = new Set(body.data);\n return;\n }\n this.log?.debug({ kind, data: body.data }, \"kurobot: 查询结果已记录\");\n }\n\n /** kernel 群消息 → kurobot 出站(仅群聊 + 自消息过滤 + 命令分流 + 绑定过滤)。 */\n private handleIncomingMessage(msg: RawMessage): void {\n const config = this.currentConfig;\n if (config === null) {\n return;\n }\n if (msg.chatType !== ChatType.GROUP) {\n return;\n }\n // 过滤自己发的消息防回环(本账号其它端发送同样过滤)\n if (String(msg.senderUin) === this.selfUin) {\n return;\n }\n const channel = msg.peerUid;\n if (channel === \"\") {\n return;\n }\n const text = degradeMessage(msg);\n if (text === null) {\n return;\n }\n // 命令前缀 → command 帧(管理员判定在服务端;不做绑定过滤,语义对齐服务端 dispatchCommand)\n if (text.startsWith(config.commandPrefix)) {\n const command = text.slice(config.commandPrefix.length).trim();\n if (command === \"\") {\n return; // 空命令(只有前缀)忽略\n }\n this.sendCommand(channel, command, String(msg.senderUin));\n return;\n }\n // 出站绑定过滤:空快照 = 全部不发(对齐服务端空绑定丢弃语义)\n if (this.bindings.size === 0 || !this.bindings.has(channel)) {\n this.log?.debug({ channel }, \"kurobot: 非绑定群,跳过 chat 帧\");\n return;\n }\n this.sendChat(channel, resolveSenderName(msg), text);\n }\n\n /** 发 chat 事件帧(无 id)。 */\n private sendChat(channel: string, sender: string, content: string): void {\n this.connection?.send({ type: \"chat\", body: { channel, sender, content } });\n }\n\n /** 发 command 请求帧(登记 pending 表供 command_result 关联)。 */\n private sendCommand(channel: string, command: string, userId: string): void {\n const id = randomUUID();\n this.pendingCommands.set(id, channel);\n const sent = this.connection?.send({\n type: \"command\",\n id,\n body: { command, source: { channel, userId } },\n });\n if (sent !== true) {\n this.pendingCommands.delete(id);\n }\n }\n\n /** 群文本发送(失败 error 日志不抛出——不影响连接与收链路)。 */\n private sendToGroup(channel: string, text: string): void {\n this.msgApi\n .sendMessage({ chatType: ChatType.GROUP, peerUid: channel }, [{ type: \"text\", text }])\n .then(() => {\n this.log?.debug({ channel }, \"kurobot: 群消息已发送\");\n })\n .catch((err: unknown) => {\n this.log?.error(\n { channel, err: err instanceof Error ? err.message : String(err) },\n \"kurobot: 群消息发送失败\",\n );\n });\n }\n\n /** 当前生效配置(收链路保证已 start)。 */\n private requireConfig(): KurobotConfig {\n const config = this.currentConfig;\n if (config === null) {\n throw new Error(\"kurobot: 配置未初始化(适配器未启动)\");\n }\n return config;\n }\n\n /** 订阅 kernel 消息事件(幂等)。 */\n private subscribe(): void {\n if (this.unsubscribe !== null) {\n return;\n }\n this.unsubscribe = this.msgChannel.on(\"Msg/onRecvMsg\", (msgs) => {\n forEachRawMessage(msgs, (msg) => {\n this.handleIncomingMessage(msg);\n });\n });\n }\n\n /** 退订(幂等)。 */\n private unsubscribeAll(): void {\n this.unsubscribe?.();\n this.unsubscribe = null;\n }\n}\n\n/** string[] 防御性收窄(query_result bindings data)。 */\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((item) => typeof item === \"string\");\n}\n\n/** best-effort 读取 adapter 包版本(dist 与 src 双布局相对包根一致)。 */\nfunction resolvePackageVersion(): string | null {\n try {\n const require = createRequire(import.meta.url);\n const pkg = require(\"../../package.json\") as { version?: unknown };\n if (typeof pkg.version === \"string\" && pkg.version !== \"\") {\n return pkg.version;\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/** hello.version:adapter 包版本(取不到用 unknown)。 */\nfunction resolveAdapterVersion(): string {\n return resolvePackageVersion() ?? \"unknown\";\n}\n\n/** hello.client 缺省身份:napukettoqq/<版本>(取不到版本则 napukettoqq)。 */\nfunction resolveDefaultClient(): string {\n const version = resolvePackageVersion();\n return version === null ? \"napukettoqq\" : `napukettoqq/${version}`;\n}\n","/**\n * kurobot 协议配置(zod schema,归属本包,ADR-012;任务书 KUROBOT-PROMPT §1.2)\n *\n * 单一 TOML 的 `[accounts.kurobot]` 账号段(段存在即启用、不写不启用),\n * seed 注入对齐 onebot11/satori 的 ConfigBase 模式。\n */\nimport { z } from \"zod\";\n\n/** 群消息渲染模板占位符(MVP 纯文本:{player} / {content} / {message})。 */\nexport const TEMPLATE_PLACEHOLDERS = [\"player\", \"content\", \"message\"] as const;\n\n/** kurobot 配置 schema。 */\nexport const kurobotConfigSchema = z.object({\n /** KuroBot 服务端完整地址(必填,ws:// 或 wss://)。 */\n url: z.url().refine((u) => u.startsWith(\"ws://\") || u.startsWith(\"wss://\"), {\n message: \"url 必须是 ws:// 或 wss:// 地址\",\n }),\n /** 鉴权 token(缺省空 = 不带;服务端配置了非空 token 则必须一致,否则 close 1008)。 */\n token: z.string().default(\"\"),\n /** 自报身份(缺省 napukettoqq,能取到 adapter 包版本则 napukettoqq/<版本>)。 */\n client: z.string().min(1).optional(),\n /** 群命令前缀(前缀开头 → command 帧,不再作为 chat 发送)。 */\n commandPrefix: z.string().min(1).default(\"/\"),\n /** 应用层心跳间隔毫秒(服务端空闲阈值 30s,任何入帧重置;须显著小于 30000)。 */\n pingIntervalMs: z.number().int().positive().default(15000),\n /** MC 聊天渲染模板。 */\n chatTemplate: z.string().min(1).default(\"[{player}] {content}\"),\n /** 玩家进服渲染模板。 */\n joinTemplate: z.string().min(1).default(\"{player} 加入了服务器\"),\n /** 玩家退服渲染模板。 */\n leaveTemplate: z.string().min(1).default(\"{player} 离开了服务器\"),\n /** 玩家死亡渲染模板(message 为空串时以「死亡了」代入)。 */\n deathTemplate: z.string().min(1).default(\"{player} {message}\"),\n});\n\n/** kurobot 配置类型(由 schema 推导)。 */\nexport type KurobotConfig = z.infer<typeof kurobotConfigSchema>;\n\n/**\n * ConfigBase 必填的 defaults 形参兜底值(url 必填 → 无法 `parse({})`)。\n * 装配走 seed 模式(段存在才装配,seed 已校验),defaults 不参与生效值;\n * 仅在「无 seed 且配置文件缺失」的直连场景被落盘——端口 0 地址连接会失败退避,\n * 不会静默假在线。\n */\nexport function kurobotConfigDefaults(): KurobotConfig {\n return kurobotConfigSchema.parse({ url: \"ws://127.0.0.1:0\" });\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { i as ProtocolConfig, n as BaseProtocolAdapter, s as ActionRegistry, u as ErrorCodeMap } from "../index-CDKj-jus.mjs";
2
- import "../gray-tip-CcpfI1Og.mjs";
3
- import { BuddyCacheEventChannel, BuddyEventChannel, CanonicalElement, ChatType, FriendApi, GroupApi, GroupCache, GroupEventChannel, GroupNotifyApi, MsgApi, MsgEventChannel, Peer, ProfileApi, ProfileLikeApi, RichMediaApi, TicketApi, WebApi } from "@napuketto/kernel";
2
+ import "../gray-tip-8zPh4d9W.mjs";
3
+ import { BuddyCacheEventChannel, BuddyEventChannel, CanonicalElement, ChatType, FriendApi, GroupApi, GroupCache, GroupEventChannel, GroupNotifyApi, MsgApi, MsgEventChannel, Peer, ProfileApi, ProfileLikeApi, RawMessage, RichMediaApi, TicketApi, WebApi } from "@napuketto/kernel";
4
4
  import { z } from "zod";
5
5
  import { EventBroadcaster, TransportAdapter } from "@napuketto/network";
6
6
  //#region src/onebot11/helper/message-unique.d.ts
@@ -1,5 +1,6 @@
1
1
  import { i as BaseAction, o as ActionRegistry, r as BaseProtocolAdapter, t as ensureSilk } from "../core-of7sLiQX.mjs";
2
- import { i as createWsServerSchema, n as collectGrayTipUids, r as createHttpServerSchema, t as forEachRawMessage } from "../raw-message-Bx18pIQS.mjs";
2
+ import { n as createHttpServerSchema, r as createWsServerSchema, t as collectGrayTipUids } from "../gray-tip-B80z9KR4.mjs";
3
+ import { t as forEachRawMessage } from "../raw-message-6KdlG8kR.mjs";
3
4
  import { ChatType, GrayTipSubType, GroupApi, GroupNotifyMsgStatus, GroupNotifyMsgType, NTGroupMemberRole, NTGroupRequestOperateTypes, TicketApi, TipGroupElementType, WebHonorType, kernelError, toCanonicalElements } from "@napuketto/kernel";
4
5
  import { downloadUrl, inferExtension } from "@napuketto/media";
5
6
  import { z } from "zod";