cursor-feedback 2.0.1 → 2.0.3

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 CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [2.0.3](https://github.com/jianger666/cursor-feedback-extension/compare/v2.0.2...v2.0.3) (2026-06-22)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * **feishu:** 配置指引「找不到」——补打包 docs + stat 校验兜底在线 ([9eebf3c](https://github.com/jianger666/cursor-feedback-extension/commit/9eebf3cd9238f93bc0de9f1c918fd776c1885a4e))
11
+
12
+ ### [2.0.2](https://github.com/jianger666/cursor-feedback-extension/compare/v2.0.1...v2.0.2) (2026-06-20)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * **feishu:** 消息没送到时引用回复提示,去除虚假「已收到」回执 ([52b107d](https://github.com/jianger666/cursor-feedback-extension/commit/52b107d27ee146dcc10ba1a3aa77d18f3f51bb3c))
18
+
5
19
  ### [2.0.1](https://github.com/jianger666/cursor-feedback-extension/compare/v2.0.0...v2.0.1) (2026-06-20)
6
20
 
7
21
 
package/dist/extension.js CHANGED
@@ -897,17 +897,18 @@ class FeedbackViewProvider {
897
897
  * 打开「如何配置飞书机器人」指引
898
898
  */
899
899
  async _handleOpenFeishuGuide() {
900
+ const onlineUrl = 'https://github.com/jianger666/cursor-feedback-extension/blob/main/docs/feishu-setup.md';
900
901
  const guideUri = vscode.Uri.joinPath(this._extensionUri, 'docs', 'feishu-setup.md');
901
902
  try {
903
+ // 先 stat 确认打进包的本地文档在、再站内预览。
904
+ // markdown.showPreview 对缺失文件不报错、只渲染「找不到 feishu-setup.md」、catch 也不触发——
905
+ // 所以必须自己先校验存在、否则一旦打包又漏了 docs 就退回原 bug。
906
+ await vscode.workspace.fs.stat(guideUri);
902
907
  await vscode.commands.executeCommand('markdown.showPreview', guideUri);
903
908
  }
904
909
  catch {
905
- try {
906
- await vscode.env.openExternal(guideUri);
907
- }
908
- catch {
909
- // ignore
910
- }
910
+ // 本地没有(打包漏了 / 环境异常)→ 兜底开 GitHub 在线文档、绝不让用户再撞「找不到」
911
+ await vscode.env.openExternal(vscode.Uri.parse(onlineUrl));
911
912
  }
912
913
  }
913
914
  /**
package/dist/feishu.js CHANGED
@@ -583,6 +583,27 @@ class FeishuBridge {
583
583
  flog('飞书回执失败: ' + e);
584
584
  }
585
585
  }
586
+ /**
587
+ * 回复(引用)某条消息:用飞书 reply 接口让回执挂在原消息下,用户一眼看出是哪条。
588
+ * messageId 缺失或调用失败时回退普通发送,保证提示一定送达。
589
+ */
590
+ async replyToMessage(messageId, chatId, text) {
591
+ if (!this.client || !chatId)
592
+ return;
593
+ if (messageId) {
594
+ try {
595
+ await this.client.im.v1.message.reply({
596
+ path: { message_id: messageId },
597
+ data: { content: JSON.stringify({ text }), msg_type: 'text' },
598
+ });
599
+ return;
600
+ }
601
+ catch (e) {
602
+ flog('飞书回复消息失败,回退普通发送: ' + e);
603
+ }
604
+ }
605
+ await this.replyText(chatId, text);
606
+ }
586
607
  /**
587
608
  * 给某条消息加 Get 表情作为「轻回执」:不产生新消息、不产生未读。
588
609
  * 失败(如该消息类型不支持表情)时回退文字回执,保证用户知道已收到。
@@ -90,6 +90,8 @@ class McpFeedbackServer {
90
90
  * 暂存后等下一轮 pending 一注册立即兑现,避免回复石沉大海(修复用户反馈的竞态 bug)。
91
91
  */
92
92
  this.stashedInbound = null;
93
+ /** 暂存过期提示定时器:到点仍未被认领则「回复」那条消息告知没送到,避免静默丢弃 */
94
+ this.stashExpiryTimer = null;
93
95
  // 最近一次被飞书回复 resolve 的请求:供插件端精确区分「飞书回复」与「超时」,
94
96
  // 避免超时续期(request 也会短暂为 null)被误判成飞书回复而错误重置面板。
95
97
  this.lastFeishuResolved = null;
@@ -403,9 +405,11 @@ class McpFeedbackServer {
403
405
  if (globalCount === 0) {
404
406
  // 抢跑兜底:此刻全局无人等待,但很可能 AI 正要发起下一轮(卡片还没注册)。
405
407
  // 暂存到收到消息的本实例,等下一轮 pending 注册时立即兑现。
408
+ // 关键:此刻没有任何 AI 在等待,绝不能给「✅ 已收到」回执——那是虚假承诺,会让用户
409
+ // 误以为消息已被接收(实则 AI 这轮可能已结束、永远不会来认领,消息石沉大海)。
410
+ // 回执只在「真正送达某个等待中的请求」时给(见 tryConsumeStash → submitFromFeishu)。
406
411
  this.stashedInbound = { text, chatId, images, files, at: Date.now(), messageId };
407
- // 轻回执:先给消息加 ✅ 表情(无未读);兑现到具体任务时不再重复回执
408
- this.feishu.reactDone(messageId || undefined, chatId);
412
+ this.armStashExpiryNotice();
409
413
  }
410
414
  else if (globalCount === 1) {
411
415
  if (localPending.length === 1) {
@@ -565,6 +569,27 @@ class McpFeedbackServer {
565
569
  this.tryConsumeStash(requestId);
566
570
  });
567
571
  }
572
+ /**
573
+ * 暂存「无主消息」后,启动过期提示定时器:到 STASH_TTL_MS 仍没被 AI 认领,就「回复」
574
+ * 那条消息明确告知没送到、引导重发(不再静默丢弃,也不给虚假回执)。
575
+ * 每来一条无主消息都重置,避免连发时多个定时器并存。
576
+ */
577
+ armStashExpiryNotice() {
578
+ if (this.stashExpiryTimer)
579
+ clearTimeout(this.stashExpiryTimer);
580
+ this.stashExpiryTimer = setTimeout(() => {
581
+ this.stashExpiryTimer = null;
582
+ const stash = this.stashedInbound;
583
+ if (!stash)
584
+ return; // 已被 tryConsumeStash 兑现
585
+ this.stashedInbound = null;
586
+ // 引用回复(锚定到最近这条,方便定位)。文案不带「这条/都/重复」等数量词——
587
+ // 单条已断、多条全丢、第一条已送达后续丢,三种场景下数量词总有一种会误导。
588
+ // 且引导「待 AI 回复后再重发」:AI 只有重新调起 feedback(即回复)时才会等待接收,
589
+ // 此刻立即重发仍会落空。
590
+ this.feishu.replyToMessage(stash.messageId, stash.chatId, '⚠️ 消息未能送达 AI(它可能正忙于上一轮任务,或这轮对话已结束)。需要的话请待 AI 回复后重新发送一次。');
591
+ }, McpFeedbackServer.STASH_TTL_MS);
592
+ }
568
593
  /**
569
594
  * 抢跑暂存兑现:若存在近期「无主」飞书消息,立即作为指定请求的回复提交。
570
595
  * 超过 STASH_TTL_MS 的暂存视为与当前任务无关,直接丢弃。
@@ -574,12 +599,19 @@ class McpFeedbackServer {
574
599
  if (!stash)
575
600
  return;
576
601
  this.stashedInbound = null;
602
+ // 已被 AI 认领,取消「没送到」提示定时器
603
+ if (this.stashExpiryTimer) {
604
+ clearTimeout(this.stashExpiryTimer);
605
+ this.stashExpiryTimer = null;
606
+ }
577
607
  if (Date.now() - stash.at > McpFeedbackServer.STASH_TTL_MS) {
578
608
  debugLog('Stashed inbound expired, dropped');
579
609
  return;
580
610
  }
581
611
  debugLog(`Consuming stashed inbound for request: ${requestId}`);
582
- this.submitFromFeishu(requestId, stash.text, stash.chatId, stash.images, stash.files);
612
+ // 真正送达某个等待中的请求时,才给「✅ 送达回执」(传 messageId 触发 reactDone)。
613
+ // 暂存阶段不再预先回执,避免「没人接却假装已收到」误导用户。
614
+ this.submitFromFeishu(requestId, stash.text, stash.chatId, stash.images, stash.files, stash.messageId);
583
615
  }
584
616
  /**
585
617
  * 处理获取系统信息请求
@@ -1118,8 +1150,9 @@ class McpFeedbackServer {
1118
1150
  }
1119
1151
  }
1120
1152
  McpFeedbackServer.PORT_SCAN_RANGE = 20; // 与插件端扫描范围保持一致
1121
- /** 抢跑暂存有效期:超过则视为与当前任务无关,丢弃 */
1122
- McpFeedbackServer.STASH_TTL_MS = 8000;
1153
+ /** 抢跑暂存有效期:覆盖「AI 刚结束、正要调下一轮 feedback」的竞态间隙(通常 1-3s)。
1154
+ * 取 5s——太长会把已脱离语境的旧消息硬塞进很久后才出现的新一轮,造成上下文错乱(像答非所问)。 */
1155
+ McpFeedbackServer.STASH_TTL_MS = 5000;
1123
1156
  /**
1124
1157
  * 「我的窗口」判定为已关闭的空闲阈值:本实例曾被自己窗口插件轮询,但超过此时长没再收到
1125
1158
  *(只剩别的窗口在扫端口)→ 视为我的窗口已关、本实例是僵尸:不再上报 pending,避免污染全局计数。
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "cursor-feedback",
3
3
  "displayName": "Cursor Feedback",
4
4
  "description": "One Cursor conversation, unlimited AI interactions - Save your monthly request quota! Interactive feedback loop for AI chat via MCP",
5
- "version": "2.0.1",
5
+ "version": "2.0.3",
6
6
  "icon": "icon.png",
7
7
  "author": "jianger666",
8
8
  "license": "MIT",