cortico-world-bili-watch 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/describe.json +2 -2
- package/package.json +1 -1
- package/src/social/service.ts +31 -9
- package/src/tools.ts +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,35 @@
|
|
|
3
3
|
桌宠的市场按本文件的 `## <版本号>` 分段显示更新说明,
|
|
4
4
|
标题里的版本号必须和 `package.json` 的 `version` 一致。
|
|
5
5
|
|
|
6
|
+
## 0.2.7
|
|
7
|
+
|
|
8
|
+
修「bili_publish 明明传了 target、oid、root、parent、type=1,还是报『评论类型仅支持
|
|
9
|
+
视频(1)、动态(11/17)』;补上 retryRejected 又变成『新评论必须提供固定 requestId』;
|
|
10
|
+
最后自己编了个 requestId 才发出去」。
|
|
11
|
+
|
|
12
|
+
**根因:publish 不会从凭据里取目标。** `bili_prepare` 返回的 brief 里明明存着
|
|
13
|
+
target,但 publish 是先 `normalizeTarget(input.target)`、后读 brief —— 于是
|
|
14
|
+
「只传 briefId」必然被判成缺 target;补上 target 又卡在 requestId 上;模型只好
|
|
15
|
+
自己编一个(这次编的是 `reply-323189507152-20261107`),四层防重直接失效。
|
|
16
|
+
|
|
17
|
+
连带发现(鱼自己也看出来了:「带 briefId 的回复被当成新评论处理」):kind 判定
|
|
18
|
+
只看 `inboxId`,凭据接楼(`parent≠0`)一律记成 `proactive`。今早 13:51 那条回复
|
|
19
|
+
就是这么落库的 —— 扣的是「主动发言」额度、单人每日上限没生效、记录页还显示成
|
|
20
|
+
主动评论。
|
|
21
|
+
|
|
22
|
+
- **target 来源**:`input.target ?? brief.target`;两个都没有时给明确提示
|
|
23
|
+
「缺少发送目标:给 briefId 或完整 target」,而不是误导性的类型错误。
|
|
24
|
+
- **requestId 自动派生**:有 briefId 就用 `brief:<briefId>`,同一个凭据重试必然
|
|
25
|
+
复用同一键;显式传 target + requestId 的旧用法原样保留。
|
|
26
|
+
- **kind 按目标判定**:接楼(`parent≠0`)记 `reply`,新评论记 `proactive`,
|
|
27
|
+
推荐仍记 `recommend`。
|
|
28
|
+
- 工具描述同步:有 briefId 就不必再传 target / requestId。
|
|
29
|
+
|
|
30
|
+
离线验证 5/5(真实 state 副本 + 假网络,不真的发出去,脚本在 `test/publish-brief.mts`):
|
|
31
|
+
① 只给 briefId 的接楼 → `kind=reply`、`req=brief:71f211fc…`、真正 POST 到 reply/add;
|
|
32
|
+
② 只给 briefId 的新评论 → `kind=proactive`;③ 什么都不给 → 「缺少发送目标」;
|
|
33
|
+
④ 显式 target + requestId 的旧用法仍然 `sent`;⑤ 同一 brief 重发 → `reused`、零重复提交。
|
|
34
|
+
|
|
6
35
|
## 0.2.6
|
|
7
36
|
|
|
8
37
|
修「评论永远发不出去:发送前的网页会话初始化未完成,第五次了」(鱼的今早反馈,
|
package/describe.json
CHANGED
|
@@ -580,7 +580,7 @@
|
|
|
580
580
|
},
|
|
581
581
|
{
|
|
582
582
|
"name": "bili_publish",
|
|
583
|
-
"description": "Publish a PUBLIC comment. Preparation binds platform, account, target and draft; never reuse\na brief across destinations. A changed draft returns a renewed needs_review brief without sending.\n\nFor a notification supply `inboxId
|
|
583
|
+
"description": "Publish a PUBLIC comment. Preparation binds platform, account, target and draft; never reuse\na brief across destinations. A changed draft returns a renewed needs_review brief without sending.\n\nFor a notification supply `inboxId`. For a prepared reply just pass `briefId` — the target\nand a stable requestId are derived from the brief, so do **not** re-supply them.\nOnly a bare new comment (no preparation) needs a full `target` plus a **stable requestId**.\nReuse the same requestId when checking a retry. An unknown result is pending confirmation,\nnot a definite failure - do not bypass it by changing text or requestId at the same target.\n\n`sent` means accepted, not verified public visibility. Check `delivery`: public is guest-list\nverified, self-only is platform restricted, unconfirmed is inconclusive.\n**Never repost self-only or unconfirmed receipts automatically.**",
|
|
584
584
|
"parameters": {
|
|
585
585
|
"type": "object",
|
|
586
586
|
"additionalProperties": false,
|
|
@@ -629,7 +629,7 @@
|
|
|
629
629
|
"requestId": {
|
|
630
630
|
"type": "string",
|
|
631
631
|
"maxLength": 180,
|
|
632
|
-
"description": "Stable idempotency key for a new top-level comment or an unsolicited thread reply."
|
|
632
|
+
"description": "Stable idempotency key for a new top-level comment or an unsolicited thread reply. Omit it when `briefId` is given (derived from the brief)."
|
|
633
633
|
},
|
|
634
634
|
"text": {
|
|
635
635
|
"type": "string",
|
package/package.json
CHANGED
package/src/social/service.ts
CHANGED
|
@@ -656,6 +656,19 @@ export class BiliService {
|
|
|
656
656
|
|
|
657
657
|
const acc = this.account ?? (await this.connect(signal));
|
|
658
658
|
|
|
659
|
+
// ── 凭据(briefId):先读,它本身就是 target 与 requestId 的来源 ────
|
|
660
|
+
//
|
|
661
|
+
// 模型只需要 `bili_prepare` → `bili_publish({ briefId, text })`。凭据里已经
|
|
662
|
+
// 绑定了平台/账号/目标,还要它自己再抄一遍 target,只会抄错 —— 实测:
|
|
663
|
+
// 漏传 target 被报「评论类型仅支持视频(1)」,补上 target 又要自己编
|
|
664
|
+
// requestId,编出来的还是新键(防重直接失效)。
|
|
665
|
+
const brief = input.preparation?.briefId
|
|
666
|
+
? this.d.store.brief(input.preparation.briefId)
|
|
667
|
+
: undefined;
|
|
668
|
+
if (input.preparation?.briefId && !brief) {
|
|
669
|
+
throw new BiliError('找不到这份接话凭据(可能已过期),请重新 bili_prepare。', 'rejected');
|
|
670
|
+
}
|
|
671
|
+
|
|
659
672
|
// ── 定位目标与账本 ───────────────────────────────────────────────
|
|
660
673
|
let target: CommentTarget;
|
|
661
674
|
let kind: SendRecord['kind'] = input.recommend ? 'recommend' : 'proactive';
|
|
@@ -671,7 +684,18 @@ export class BiliService {
|
|
|
671
684
|
kind = inboxItem.focusOwnerId ? 'focus' : 'reply';
|
|
672
685
|
recipientId = inboxItem.authorId || undefined;
|
|
673
686
|
} else {
|
|
674
|
-
|
|
687
|
+
const raw = input.target ?? brief?.target;
|
|
688
|
+
if (!raw) {
|
|
689
|
+
throw new BiliError(
|
|
690
|
+
'缺少发送目标:给 briefId(bili_prepare 拿到的)或完整 target(oid/type/root/parent)。',
|
|
691
|
+
'invalid',
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
target = normalizeTarget(raw);
|
|
695
|
+
// 接楼就是回复,用回复账本(每人每日上限才算得对)。
|
|
696
|
+
// 以前只有 inboxId 才记 reply,凭据接楼一律记成 proactive —— 主动发言
|
|
697
|
+
// 额度被扣、单人上限没生效、记录页还显示成"主动评论"。
|
|
698
|
+
if (!input.recommend) kind = target.parent !== '0' ? 'reply' : 'proactive';
|
|
675
699
|
}
|
|
676
700
|
|
|
677
701
|
// 接楼必须有 recipientId:拿不到就不发,绝不绕过单人上限
|
|
@@ -684,7 +708,11 @@ export class BiliService {
|
|
|
684
708
|
}
|
|
685
709
|
}
|
|
686
710
|
|
|
687
|
-
|
|
711
|
+
// 凭据本身就是幂等键:同一个 brief 重试沿用同一个 requestId,
|
|
712
|
+
// 模型不用编、也不该编(编新的会让四层防重失效)。
|
|
713
|
+
const requestId = input.inboxId
|
|
714
|
+
? `reply:${input.inboxId}`
|
|
715
|
+
: (input.requestId ?? (brief ? `brief:${brief.id}` : undefined));
|
|
688
716
|
if (!requestId || (!input.inboxId && requestId.length > 180) || /[\r\n]/.test(requestId)) {
|
|
689
717
|
throw new BiliError('新评论必须提供固定的 requestId;重试要沿用原值。', 'invalid');
|
|
690
718
|
}
|
|
@@ -729,13 +757,7 @@ export class BiliService {
|
|
|
729
757
|
};
|
|
730
758
|
}
|
|
731
759
|
|
|
732
|
-
// ──
|
|
733
|
-
const brief = input.preparation?.briefId
|
|
734
|
-
? this.d.store.brief(input.preparation.briefId)
|
|
735
|
-
: undefined;
|
|
736
|
-
if (input.preparation?.briefId && !brief) {
|
|
737
|
-
throw new BiliError('找不到这份接话凭据(可能已过期),请重新 bili_prepare。', 'rejected');
|
|
738
|
-
}
|
|
760
|
+
// ── 凭据绑定的账号/目标/草稿必须对得上 ───────────────────────────
|
|
739
761
|
if (brief) {
|
|
740
762
|
if (brief.accountId !== acc.id) {
|
|
741
763
|
throw new BiliError('凭据属于另一个账号,未提交。', 'rejected');
|
package/src/tools.ts
CHANGED
|
@@ -424,7 +424,9 @@ const socialTools = [
|
|
|
424
424
|
'Publish a PUBLIC comment. Preparation binds platform, account, target and draft; never reuse',
|
|
425
425
|
'a brief across destinations. A changed draft returns a renewed needs_review brief without sending.',
|
|
426
426
|
'',
|
|
427
|
-
'For a notification supply `inboxId
|
|
427
|
+
'For a notification supply `inboxId`. For a prepared reply just pass `briefId` — the target',
|
|
428
|
+
'and a stable requestId are derived from the brief, so do **not** re-supply them.',
|
|
429
|
+
'Only a bare new comment (no preparation) needs a full `target` plus a **stable requestId**.',
|
|
428
430
|
'Reuse the same requestId when checking a retry. An unknown result is pending confirmation,',
|
|
429
431
|
'not a definite failure - do not bypass it by changing text or requestId at the same target.',
|
|
430
432
|
'',
|
|
@@ -446,7 +448,8 @@ const socialTools = [
|
|
|
446
448
|
requestId: {
|
|
447
449
|
type: 'string',
|
|
448
450
|
maxLength: 180,
|
|
449
|
-
description:
|
|
451
|
+
description:
|
|
452
|
+
'Stable idempotency key for a new top-level comment or an unsolicited thread reply. Omit it when `briefId` is given (derived from the brief).',
|
|
450
453
|
},
|
|
451
454
|
text: { type: 'string', minLength: 1, maxLength: 1000 },
|
|
452
455
|
mentionFocus: {
|