@napuketto/adapter 0.6.0 → 0.7.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.
@@ -42,6 +42,51 @@ declare class MessageSeqIndex {
42
42
  private evict;
43
43
  }
44
44
  //#endregion
45
+ //#region src/milky/action/error-map.d.ts
46
+ /** KernelErrorCode → Milky retcode 映射表(-400/-403 规范语义,其余自定负数)。 */
47
+ type MilkyErrorCodeMap = Record<KernelErrorCode, number>;
48
+ //#endregion
49
+ //#region src/milky/action/base-action.d.ts
50
+ /** Milky 动作结果(retcode 为规范负数族;transport 原样组装信封)。 */
51
+ interface MilkyActionResult<T> {
52
+ status: "ok" | "failed";
53
+ retcode: number;
54
+ data: T | null;
55
+ message: string;
56
+ }
57
+ declare abstract class MilkyAction<TPayload, TReturn> {
58
+ abstract readonly name: string;
59
+ abstract readonly schema: ZodType<TPayload>;
60
+ protected abstract readonly errorCodeMap: MilkyErrorCodeMap;
61
+ protected abstract _handle(payload: TPayload): Promise<TReturn>;
62
+ /** 校验并执行(HTTP /api 入口;WS /event 不承载动作)。 */
63
+ handle(payload: unknown): Promise<MilkyActionResult<TReturn>>;
64
+ }
65
+ //#endregion
66
+ //#region src/milky/config.d.ts
67
+ /** Milky 配置 schema。 */
68
+ declare const milkyConfigSchema: z.ZodObject<{
69
+ enabled: z.ZodDefault<z.ZodBoolean>;
70
+ host: z.ZodDefault<z.ZodString>;
71
+ port: z.ZodDefault<z.ZodNumber>;
72
+ token: z.ZodDefault<z.ZodString>;
73
+ eventModes: z.ZodDefault<z.ZodArray<z.ZodEnum<{
74
+ sse: "sse";
75
+ ws: "ws";
76
+ }>>>;
77
+ webhooks: z.ZodDefault<z.ZodArray<z.ZodString>>;
78
+ cacheDir: z.ZodOptional<z.ZodString>;
79
+ }, z.core.$strip>;
80
+ /** Milky 配置类型(由 schema 推导)。 */
81
+ type MilkyConfig = z.infer<typeof milkyConfigSchema>;
82
+ //#endregion
83
+ //#region src/milky/transport.d.ts
84
+ /** 校准 logger 最小面(webhook 失败 / 配置异常提示;缺省静默)。 */
85
+ interface MilkyLoggerLike {
86
+ warn(obj: unknown, msg?: string): void;
87
+ info(obj: unknown, msg?: string): void;
88
+ }
89
+ //#endregion
45
90
  //#region src/milky/api.d.ts
46
91
  /** MilkyApi 构造参数。 */
47
92
  interface MilkyApiOptions {
@@ -69,6 +114,8 @@ interface MilkyApiOptions {
69
114
  implVersion: string;
70
115
  /** 发送媒体 http(s)/base64 URI 下载缓存目录(缺省 = 远程媒体发送不可用)。 */
71
116
  mediaDir?: string;
117
+ /** 动作层可观测出口(P2 批次一:forward 临时消息撤回失败 warn;缺省静默)。 */
118
+ logger?: MilkyLoggerLike;
72
119
  }
73
120
  declare class MilkyApi {
74
121
  readonly msgApi: MsgApi;
@@ -89,6 +136,8 @@ declare class MilkyApi {
89
136
  readonly qqVersion: string;
90
137
  readonly implVersion: string;
91
138
  readonly mediaDir: string | undefined;
139
+ /** 动作层可观测出口(缺省静默)。 */
140
+ readonly logger: MilkyLoggerLike | undefined;
92
141
  /** message_seq ↔ msgId 双向映射(接收链路 record,动作侧反查)。 */
93
142
  readonly seqIndex: MessageSeqIndex;
94
143
  constructor(opts: MilkyApiOptions, seqIndex: MessageSeqIndex);
@@ -118,57 +167,12 @@ declare class MilkyApi {
118
167
  }>;
119
168
  }
120
169
  //#endregion
121
- //#region src/milky/action/error-map.d.ts
122
- /** KernelErrorCode → Milky retcode 映射表(-400/-403 规范语义,其余自定负数)。 */
123
- type MilkyErrorCodeMap = Record<KernelErrorCode, number>;
124
- //#endregion
125
- //#region src/milky/action/base-action.d.ts
126
- /** Milky 动作结果(retcode 为规范负数族;transport 原样组装信封)。 */
127
- interface MilkyActionResult<T> {
128
- status: "ok" | "failed";
129
- retcode: number;
130
- data: T | null;
131
- message: string;
132
- }
133
- declare abstract class MilkyAction<TPayload, TReturn> {
134
- abstract readonly name: string;
135
- abstract readonly schema: ZodType<TPayload>;
136
- protected abstract readonly errorCodeMap: MilkyErrorCodeMap;
137
- protected abstract _handle(payload: TPayload): Promise<TReturn>;
138
- /** 校验并执行(HTTP /api 入口;WS /event 不承载动作)。 */
139
- handle(payload: unknown): Promise<MilkyActionResult<TReturn>>;
140
- }
141
- //#endregion
142
170
  //#region src/milky/action/index.d.ts
143
171
  /** Milky 动作注册表(P0+P1 49 动作)。 */
144
172
  declare function createMilkyActionRegistry(opts: {
145
173
  api: MilkyApi;
146
174
  }): ActionRegistry<MilkyAction<unknown, unknown>>;
147
175
  //#endregion
148
- //#region src/milky/config.d.ts
149
- /** Milky 配置 schema。 */
150
- declare const milkyConfigSchema: z.ZodObject<{
151
- enabled: z.ZodDefault<z.ZodBoolean>;
152
- host: z.ZodDefault<z.ZodString>;
153
- port: z.ZodDefault<z.ZodNumber>;
154
- token: z.ZodDefault<z.ZodString>;
155
- eventModes: z.ZodDefault<z.ZodArray<z.ZodEnum<{
156
- sse: "sse";
157
- ws: "ws";
158
- }>>>;
159
- webhooks: z.ZodDefault<z.ZodArray<z.ZodString>>;
160
- cacheDir: z.ZodOptional<z.ZodString>;
161
- }, z.core.$strip>;
162
- /** Milky 配置类型(由 schema 推导)。 */
163
- type MilkyConfig = z.infer<typeof milkyConfigSchema>;
164
- //#endregion
165
- //#region src/milky/transport.d.ts
166
- /** 校准 logger 最小面(webhook 失败 / 配置异常提示;缺省静默)。 */
167
- interface MilkyLoggerLike {
168
- warn(obj: unknown, msg?: string): void;
169
- info(obj: unknown, msg?: string): void;
170
- }
171
- //#endregion
172
176
  //#region src/milky/adapter.d.ts
173
177
  /** 适配器构造参数(api 相关字段继承 MilkyApiOptions)。 */
174
178
  interface MilkyAdapterOptions extends MilkyApiOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/milky/helper/seq-index.ts","../../src/milky/api.ts","../../src/milky/action/error-map.ts","../../src/milky/action/base-action.ts","../../src/milky/action/index.ts","../../src/milky/config.ts","../../src/milky/transport.ts","../../src/milky/adapter.ts"],"mappings":";;;;;;UAuBiB;EACb,UAAU;EACV;EACA;;cAGS;;mBAEQ;;mBAEA;;mBAEA;;EAGjB,OAAO,KAAK;;EAeZ,aAAa,UAAU,UAAU,iBAAiB;;;;;EAQlD,iBACI,mBACD;IAAc;IAAoB;IAAkB;;;UAgB/C;;;;;EAQR,cAAc,eAAe,OAAO;;EAepC,eAAe,gBAAgB;;UAKvB;;;;;UCjFK;EACb,QAAQ;EACR,UAAU;EACV,WAAW;EACX,YAAY;;EAEZ,gBAAgB;EAChB,WAAW;EACX,QAAQ;EACR,gBAAgB;EAChB,cAAc;;EAEd;IAAQ;IAAa;IAAkB;;;EAEvC,aAAa;;EAEb;;EAEA;;EAEA;;cAGS;WACA,QAAQ;WACR,UAAU;WACV,WAAW;WACX,YAAY;WACZ,gBAAgB;WAChB,WAAW;WACX,QAAQ;WACR,gBAAgB;WAChB,cAAc;WACd;IAAQ;IAAa;IAAkB;;WACvC,YAAY;WACZ;WACA;WACA;;WAEA,UAAU;EAEnB,YAAY,MAAM,iBAAiB,UAAU;;EAmB7C,SAAS,iBAAiB,QAAQ;;EAKlC,SAAS,iBAAiB,QAAQ;;;;;EAQ5B,kBAAkB,uBAAuB;;;;;EAiBzC,YAAY,oCAAoC,aAAa,QAAQ;;;;;EAqBrE,kBACF,MAAM,MACN,aACA,UAAU,mBACX;;EAeG,kBACF,MAAM,MACN,gBACD;IAAU;IAAqB;;;;;;KCtJ1B,oBAAoB,OAAO;;;;UCItB,kBAAkB;EAC/B;EACA;EACA,MAAM;EACN;;uBAYkB,YAAY,UAAU;oBACtB;oBACA,QAAQ,QAAQ;8BACN,cAAc;qBAEvB,QAAQ,SAAS,WAAW,QAAQ;;EAGjD,OAAO,mBAAmB,QAAQ,kBAAkB;;;;;iBCiC9C,0BAA0B;EACtC,KAAK;IACL,eAAe;;;;cC/DN,mBAAiB,EAAA;;;;;;;;;;;GAe5B,EAAA,KAAA;;KAGU,cAAc,EAAE,aAAa;;;;UCQxB;EACb,KAAK,cAAc;EACnB,KAAK,cAAc;;;;;UCUN,4BAA4B;EACzC,QAAQ,eAAe;EACvB,aAAa;;EAEb,YAAY;;EAEZ,eAAe;;EAEf,eAAe;;EAEf,SAAS;;cAGA,8BAA8B,oBAAoB;WAClD;mBAEQ;mBACA;mBACA;mBACA;mBACA;mBACA;;WAER,UAAU,kBAAkB;UAC7B;UACA;EAER,YAAY,MAAM;;UAoBJ;;UAuBA;;UAMA;;UASN;;UA4BA;;UAQM;;UAuBA;;UAeN;;UASM;;UAWN;;UAkBM;;UASA;;UAgBA;;UAkBN;;UAWM;;UAaN;;UAcA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/milky/helper/seq-index.ts","../../src/milky/action/error-map.ts","../../src/milky/action/base-action.ts","../../src/milky/config.ts","../../src/milky/transport.ts","../../src/milky/api.ts","../../src/milky/action/index.ts","../../src/milky/adapter.ts"],"mappings":";;;;;;UAuBiB;EACb,UAAU;EACV;EACA;;cAGS;;mBAEQ;;mBAEA;;mBAEA;;EAGjB,OAAO,KAAK;;EAeZ,aAAa,UAAU,UAAU,iBAAiB;;;;;EAQlD,iBACI,mBACD;IAAc;IAAoB;IAAkB;;;UAgB/C;;;;;EAQR,cAAc,eAAe,OAAO;;EAepC,eAAe,gBAAgB;;UAKvB;;;;;KClGA,oBAAoB,OAAO;;;;UCItB,kBAAkB;EAC/B;EACA;EACA,MAAM;EACN;;uBAYkB,YAAY,UAAU;oBACtB;oBACA,QAAQ,QAAQ;8BACN,cAAc;qBAEvB,QAAQ,SAAS,WAAW,QAAQ;;EAGjD,OAAO,mBAAmB,QAAQ,kBAAkB;;;;;cC5BjD,mBAAiB,EAAA;;;;;;;;;;;GAe5B,EAAA,KAAA;;KAGU,cAAc,EAAE,aAAa;;;;UCQxB;EACb,KAAK,cAAc;EACnB,KAAK,cAAc;;;;;UCVN;EACb,QAAQ;EACR,UAAU;EACV,WAAW;EACX,YAAY;;EAEZ,gBAAgB;EAChB,WAAW;EACX,QAAQ;EACR,gBAAgB;EAChB,cAAc;;EAEd;IAAQ;IAAa;IAAkB;;;EAEvC,aAAa;;EAEb;;EAEA;;EAEA;;EAEA,SAAS;;cAGA;WACA,QAAQ;WACR,UAAU;WACV,WAAW;WACX,YAAY;WACZ,gBAAgB;WAChB,WAAW;WACX,QAAQ;WACR,gBAAgB;WAChB,cAAc;WACd;IAAQ;IAAa;IAAkB;;WACvC,YAAY;WACZ;WACA;WACA;;WAEA,QAAQ;;WAER,UAAU;EAEnB,YAAY,MAAM,iBAAiB,UAAU;;EAoB7C,SAAS,iBAAiB,QAAQ;;EAKlC,SAAS,iBAAiB,QAAQ;;;;;EAQ5B,kBAAkB,uBAAuB;;;;;EAiBzC,YAAY,oCAAoC,aAAa,QAAQ;;;;;EAqBrE,kBACF,MAAM,MACN,aACA,UAAU,mBACX;;EAeG,kBACF,MAAM,MACN,gBACD;IAAU;IAAqB;;;;;;iBC/FtB,0BAA0B;EACtC,KAAK;IACL,eAAe;;;;UCzBF,4BAA4B;EACzC,QAAQ,eAAe;EACvB,aAAa;;EAEb,YAAY;;EAEZ,eAAe;;EAEf,eAAe;;EAEf,SAAS;;cAGA,8BAA8B,oBAAoB;WAClD;mBAEQ;mBACA;mBACA;mBACA;mBACA;mBACA;;WAER,UAAU,kBAAkB;UAC7B;UACA;EAER,YAAY,MAAM;;UAoBJ;;UAuBA;;UAMA;;UASN;;UA4BA;;UAQM;;UAuBA;;UAeN;;UASM;;UAWN;;UAkBM;;UASA;;UAgBA;;UAkBN;;UAWM;;UAaN;;UAcA"}
@@ -27,6 +27,8 @@ var MilkyApi = class {
27
27
  qqVersion;
28
28
  implVersion;
29
29
  mediaDir;
30
+ /** 动作层可观测出口(缺省静默)。 */
31
+ logger;
30
32
  /** message_seq ↔ msgId 双向映射(接收链路 record,动作侧反查)。 */
31
33
  seqIndex;
32
34
  constructor(opts, seqIndex) {
@@ -44,6 +46,7 @@ var MilkyApi = class {
44
46
  this.qqVersion = opts.qqVersion;
45
47
  this.implVersion = opts.implVersion;
46
48
  this.mediaDir = opts.mediaDir;
49
+ this.logger = opts.logger;
47
50
  this.seqIndex = seqIndex;
48
51
  }
49
52
  /** uin → uid(私聊目标 / at 段发送转换 / 群管动作的 uid 入参)。 */
@@ -939,8 +942,8 @@ async function writeBase64(payload, mediaDir) {
939
942
  * 跳过——规范兼容性要求「数组中未知项跳过」)。forward 接收段不经 canonical:
940
943
  * kernel 无 MULTI_FORWARD 分支,adapter 从 RawMessage 提取 resId 后经
941
944
  * incomingForwardSegment + ctx 注入。
942
- * 发送方向:OutgoingSegment → canonical(10 种中映射 9 种;forward 发送需要
943
- * kernel 组装任意内容的新转发(未探测),显式报错不静默跳过)。
945
+ * 发送方向:OutgoingSegment → canonical(10 种全映射;forward 顶层段不走本转换器,
946
+ * 由 sendMilkyMessage 分流到组装链——本转换器内 forward 报错只拦截混发/嵌套)。
944
947
  */
945
948
  /** uin 字符串 → Milky user_id(非有限正数 = 转换失败)。 */
946
949
  function toUserId(uin) {
@@ -1114,7 +1117,9 @@ function rawToPayload(raw) {
1114
1117
  /**
1115
1118
  * OutgoingSegment 数组 → canonical 元素(同步映射;媒体 URI 解析与 at uin→uid
1116
1119
  * 由调用方在返回值上继续处理)。
1117
- * forward 显式报错(发送走 kernel 专用链路,P1 接)。
1120
+ * forward 在此报错:顶层 forward 已由 sendMilkyMessage 分流到组装链(message.ts,
1121
+ * P2 批次一),命中本分支 = forward 与其他段混发漏网或嵌套 forward(组装链内逐项
1122
+ * 转换经过此处)——均显式拒绝。
1118
1123
  */
1119
1124
  function outgoingSegmentsToCanonical(segments) {
1120
1125
  const elements = [];
@@ -1179,7 +1184,7 @@ function outgoingSegmentsToCanonical(segments) {
1179
1184
  raw: seg.data.json_payload
1180
1185
  });
1181
1186
  break;
1182
- case "forward": throw kernelError("forward 段发送暂未支持(需 kernel 组装任意内容的新转发,P2 探测)", "INVALID_PARAM");
1187
+ case "forward": throw kernelError("forward 段不可与其他消息段混发或嵌套(顶层 forward 须单独发送)", "INVALID_PARAM");
1183
1188
  }
1184
1189
  return {
1185
1190
  elements,
@@ -1399,14 +1404,70 @@ async function recallBySeq(peer, seq, api) {
1399
1404
  if (msgId === void 0) throw kernelError(`消息 ${seq} 不存在`, "NOT_FOUND");
1400
1405
  await api.msgApi.recallMessage(peer, [msgId]);
1401
1406
  }
1402
- /** 发送核心:segments → canonical(URI/ID 转换)→ sendMessage → 回查输出。 */
1407
+ /** 发送核心:segments → canonical(URI/ID 转换)→ sendMessage → 回查输出。
1408
+ * forward 段分流到组装链(P2 批次一,临时消息法)。 */
1403
1409
  async function sendMilkyMessage(peer, segments, api) {
1410
+ if (segments.some((s) => s.type === "forward")) return await sendForwardComposition(peer, segments, api);
1404
1411
  const { elements, atUins } = outgoingSegmentsToCanonical(segments);
1405
1412
  const resolved = await resolveElements(elements, atUins, api);
1406
1413
  if (resolved.length === 0) throw kernelError("消息内容为空(全部消息段不可用)", "INVALID_PARAM");
1407
1414
  const { msgId } = await api.msgApi.sendMessage(peer, resolved);
1408
1415
  return await api.resolveSentOutput(peer, msgId);
1409
1416
  }
1417
+ /**
1418
+ * forward 段组装链(P2 批次一,milky.md §0.6):仅支持单 forward 单独发。
1419
+ * 临时消息法:逐条发送 messages[i].segments → sendForwardMessage(buildMultiForwardMsg
1420
+ * 以目标 peer 的真实消息组装 → sendMsg)→ best-effort 撤回临时消息 → 回查输出。
1421
+ *
1422
+ * 已知差异(规范语义 vs kernel 出口,待实机联调):节点发送者恒为机器人自己
1423
+ * (user_id / sender_name / time 不参与组装);title / preview / summary / prompt 忽略。
1424
+ */
1425
+ async function sendForwardComposition(peer, segments, api) {
1426
+ if (segments.length !== 1) throw kernelError("forward 段必须单独发送(不支持与其他消息段混发)", "INVALID_PARAM");
1427
+ const [forward] = segments;
1428
+ if (forward === void 0 || forward.type !== "forward") throw kernelError("forward 组装链收到非 forward 段", "UNKNOWN");
1429
+ const messages = narrowForwardMessages(forward);
1430
+ const srcMsgIds = [];
1431
+ for (const [i, item] of messages.entries()) {
1432
+ const { elements, atUins } = outgoingSegmentsToCanonical(item.segments);
1433
+ const resolved = await resolveElements(elements, atUins, api);
1434
+ if (resolved.length === 0) throw kernelError(`forward 第 ${i + 1} 条消息无可用内容段`, "INVALID_PARAM");
1435
+ const { msgId } = await api.msgApi.sendMessage(peer, resolved);
1436
+ srcMsgIds.push(msgId);
1437
+ }
1438
+ const { msgId } = await api.msgApi.sendForwardMessage(peer, peer, srcMsgIds);
1439
+ await recallTempMessages(peer, srcMsgIds, api);
1440
+ return await api.resolveSentOutput(peer, msgId);
1441
+ }
1442
+ /**
1443
+ * forward 段载荷收窄(入口 schema 只保证 data 为 record):messages 非空数组,
1444
+ * 项内 segments 非空数组。user_id / sender_name / time 不参与组装不校验
1445
+ * (丢弃字段不设门槛);title / preview / summary / prompt 忽略。
1446
+ */
1447
+ function narrowForwardMessages(forward) {
1448
+ const raw = forward.data.messages;
1449
+ if (!Array.isArray(raw) || raw.length === 0) throw kernelError("forward 段 messages 必须是非空数组", "INVALID_PARAM");
1450
+ const out = [];
1451
+ for (const item of raw) {
1452
+ if (typeof item !== "object" || item === null) throw kernelError("forward 段 messages 项必须是对象", "INVALID_PARAM");
1453
+ const segments = item.segments;
1454
+ if (!Array.isArray(segments) || segments.length === 0) throw kernelError("forward 段 messages 项的 segments 必须是非空数组", "INVALID_PARAM");
1455
+ out.push(item);
1456
+ }
1457
+ return out;
1458
+ }
1459
+ /** 临时消息清理(best-effort:失败只留可见垃圾,转发已发出——warn 可观测不抛)。 */
1460
+ async function recallTempMessages(peer, msgIds, api) {
1461
+ try {
1462
+ await api.msgApi.recallMessage(peer, msgIds);
1463
+ } catch (e) {
1464
+ api.logger?.warn({
1465
+ peer: peer.peerUid,
1466
+ count: msgIds.length,
1467
+ error: e instanceof Error ? e.message : String(e)
1468
+ }, "milky: forward 临时消息撤回失败(转发已发出)");
1469
+ }
1470
+ }
1410
1471
  /** 元素二次解析:at uin→uid + 远程媒体 URI 落盘(reply seq 已在映射层兜底原样)。 */
1411
1472
  async function resolveElements(elements, atUins, api) {
1412
1473
  const uinToUid = await resolveAtUins(atUins, api);