aws-runtime-bridge 1.9.40 → 1.9.41

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.
Files changed (110) hide show
  1. package/dist/adapter/AcodeSdkAdapter.d.ts +31 -4
  2. package/dist/adapter/AcodeSdkAdapter.d.ts.map +1 -1
  3. package/dist/adapter/AcodeSdkAdapter.js +382 -57
  4. package/dist/adapter/ClaudeSdkAdapter.d.ts.map +1 -1
  5. package/dist/adapter/ClaudeSdkAdapter.js +1 -0
  6. package/dist/adapter/OpencodeSdkAdapter.d.ts +19 -0
  7. package/dist/adapter/OpencodeSdkAdapter.d.ts.map +1 -1
  8. package/dist/adapter/OpencodeSdkAdapter.js +62 -0
  9. package/dist/adapter/types.d.ts +21 -6
  10. package/dist/adapter/types.d.ts.map +1 -1
  11. package/dist/adapter/types.js +10 -1
  12. package/dist/index.js +11 -0
  13. package/dist/routes/ai-sources.js +4 -1
  14. package/dist/routes/dashboard.d.ts.map +1 -1
  15. package/dist/routes/dashboard.js +1 -1
  16. package/dist/routes/runtime-binding.d.ts.map +1 -1
  17. package/dist/routes/runtime-binding.js +6 -3
  18. package/dist/routes/sessions.js +89 -4
  19. package/dist/routes/sub-agents.js +15 -1
  20. package/dist/routes/terminal.d.ts +3 -0
  21. package/dist/routes/terminal.d.ts.map +1 -1
  22. package/dist/routes/terminal.js +122 -5
  23. package/dist/services/acode-package.d.ts +8 -1
  24. package/dist/services/acode-package.d.ts.map +1 -1
  25. package/dist/services/acode-package.js +33 -4
  26. package/dist/services/aws-client-agent-mcp.d.ts.map +1 -1
  27. package/dist/services/aws-client-agent-mcp.js +11 -4
  28. package/dist/services/fileSnapshotStore.js +1 -1
  29. package/dist/services/legacy-path-migration.d.ts +3 -0
  30. package/dist/services/legacy-path-migration.d.ts.map +1 -0
  31. package/dist/services/legacy-path-migration.js +66 -0
  32. package/dist/services/lifecycle-state.d.ts.map +1 -1
  33. package/dist/services/lifecycle-state.js +1 -1
  34. package/dist/services/runtime-binding.d.ts +5 -0
  35. package/dist/services/runtime-binding.d.ts.map +1 -1
  36. package/dist/services/runtime-binding.js +33 -1
  37. package/dist/services/session-output.d.ts +7 -1
  38. package/dist/services/session-output.d.ts.map +1 -1
  39. package/dist/services/session-output.js +16 -2
  40. package/package/acode/dist/built-in-file-tools.d.ts.map +1 -1
  41. package/package/acode/dist/built-in-file-tools.js +504 -3
  42. package/package/acode/dist/compaction.d.ts +43 -7
  43. package/package/acode/dist/compaction.d.ts.map +1 -1
  44. package/package/acode/dist/compaction.js +286 -31
  45. package/package/acode/dist/runtime.d.ts +120 -0
  46. package/package/acode/dist/runtime.d.ts.map +1 -1
  47. package/package/acode/dist/runtime.js +921 -71
  48. package/package/acode/dist/sub-agent-manager.d.ts +96 -1
  49. package/package/acode/dist/sub-agent-manager.d.ts.map +1 -1
  50. package/package/acode/dist/sub-agent-manager.js +293 -3
  51. package/package/acode/dist/sub-agent-store.d.ts +8 -1
  52. package/package/acode/dist/sub-agent-store.d.ts.map +1 -1
  53. package/package/acode/dist/sub-agent-store.js +55 -0
  54. package/package/acode/dist/sub-agent-types.d.ts +4 -0
  55. package/package/acode/dist/sub-agent-types.d.ts.map +1 -1
  56. package/package/acode/dist/types.d.ts +19 -0
  57. package/package/acode/dist/types.d.ts.map +1 -1
  58. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +9 -0
  59. package/package/aws-client-agent-mcp/dist/agent-client.d.ts.map +1 -1
  60. package/package/aws-client-agent-mcp/dist/agent-client.js +69 -10
  61. package/package/aws-client-agent-mcp/dist/agent-client.js.map +1 -1
  62. package/package/aws-client-agent-mcp/dist/config.d.ts.map +1 -1
  63. package/package/aws-client-agent-mcp/dist/config.js +4 -0
  64. package/package/aws-client-agent-mcp/dist/config.js.map +1 -1
  65. package/package/aws-client-agent-mcp/dist/constants.d.ts +2 -0
  66. package/package/aws-client-agent-mcp/dist/constants.d.ts.map +1 -1
  67. package/package/aws-client-agent-mcp/dist/constants.js +3 -1
  68. package/package/aws-client-agent-mcp/dist/constants.js.map +1 -1
  69. package/package/aws-client-agent-mcp/dist/context-manager.d.ts +4 -1
  70. package/package/aws-client-agent-mcp/dist/context-manager.d.ts.map +1 -1
  71. package/package/aws-client-agent-mcp/dist/context-manager.js +6 -2
  72. package/package/aws-client-agent-mcp/dist/context-manager.js.map +1 -1
  73. package/package/aws-client-agent-mcp/dist/context-manager.test.js +5 -0
  74. package/package/aws-client-agent-mcp/dist/context-manager.test.js.map +1 -1
  75. package/package/aws-client-agent-mcp/dist/http-client.d.ts +5 -0
  76. package/package/aws-client-agent-mcp/dist/http-client.d.ts.map +1 -1
  77. package/package/aws-client-agent-mcp/dist/http-client.js +15 -1
  78. package/package/aws-client-agent-mcp/dist/http-client.js.map +1 -1
  79. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +92 -34
  80. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
  81. package/package/aws-client-agent-mcp/dist/mcp-server.js +606 -208
  82. package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
  83. package/package/aws-client-agent-mcp/dist/mcp-server.test.js +151 -51
  84. package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -1
  85. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +7 -0
  86. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts.map +1 -1
  87. package/package/aws-client-agent-mcp/dist/mcp-tools.js +18 -0
  88. package/package/aws-client-agent-mcp/dist/mcp-tools.js.map +1 -1
  89. package/package/aws-client-agent-mcp/dist/memory-store.d.ts +32 -9
  90. package/package/aws-client-agent-mcp/dist/memory-store.d.ts.map +1 -1
  91. package/package/aws-client-agent-mcp/dist/memory-store.js +58 -19
  92. package/package/aws-client-agent-mcp/dist/memory-store.js.map +1 -1
  93. package/package/aws-client-agent-mcp/dist/memory-tools.js +3 -3
  94. package/package/aws-client-agent-mcp/dist/memory-tools.js.map +1 -1
  95. package/package/aws-client-agent-mcp/dist/message-buffer.d.ts +13 -0
  96. package/package/aws-client-agent-mcp/dist/message-buffer.d.ts.map +1 -1
  97. package/package/aws-client-agent-mcp/dist/message-buffer.js +23 -0
  98. package/package/aws-client-agent-mcp/dist/message-buffer.js.map +1 -1
  99. package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts +13 -0
  100. package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts.map +1 -1
  101. package/package/aws-client-agent-mcp/dist/server-memory-store.js +18 -0
  102. package/package/aws-client-agent-mcp/dist/server-memory-store.js.map +1 -1
  103. package/package/aws-client-agent-mcp/dist/types.d.ts +9 -0
  104. package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
  105. package/package/aws-client-agent-mcp/dist/types.js.map +1 -1
  106. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts +34 -1
  107. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +1 -1
  108. package/package/aws-client-agent-mcp/dist/websocket-client.js +146 -18
  109. package/package/aws-client-agent-mcp/dist/websocket-client.js.map +1 -1
  110. package/package.json +1 -1
@@ -183,7 +183,7 @@ describe("McpServer unread backlog hydration", () => {
183
183
  // The message must arrive via the local buffer (WebSocket push), not a second blocking fetch.
184
184
  assert.equal(fetchOptions.length, 1);
185
185
  assert.equal(fetchOptions[0].blockIfEmpty, false);
186
- assert.equal(fetchOptions[0].includePipelineTasks, false);
186
+ assert.equal(fetchOptions[0].includePipelineTasks, true);
187
187
  });
188
188
  it("poll_message should handle hydration error gracefully and receive WebSocket messages", async () => {
189
189
  const directMessage = {
@@ -436,7 +436,7 @@ describe("McpServer unread backlog hydration", () => {
436
436
  assert.equal(result.fromBuffer, true);
437
437
  assert.equal(fetchOptions.length, 1);
438
438
  assert.equal(fetchOptions[0]?.blockIfEmpty, false);
439
- assert.equal(fetchOptions[0]?.includePipelineTasks, false);
439
+ assert.equal(fetchOptions[0]?.includePipelineTasks, true);
440
440
  assert.equal(fetchOptions[0]?.blockTimeoutMs, undefined);
441
441
  });
442
442
  it("poll_message should merge existing local cache with newly claimed task notification", async () => {
@@ -478,7 +478,7 @@ describe("McpServer unread backlog hydration", () => {
478
478
  assert.equal(result.fromBuffer, true);
479
479
  assert.equal(fetchOptions.length, 1);
480
480
  assert.equal(fetchOptions[0]?.blockIfEmpty, false);
481
- assert.equal(fetchOptions[0]?.includePipelineTasks, false);
481
+ assert.equal(fetchOptions[0]?.includePipelineTasks, true);
482
482
  });
483
483
  it("poll_message should wait for WebSocket messages when backend long polling returns empty", async () => {
484
484
  const delayedMessage = {
@@ -667,6 +667,93 @@ describe("McpServer unread backlog hydration", () => {
667
667
  "thinking",
668
668
  ]);
669
669
  });
670
+ it("poll_message should skip reportToolResult when only _acodeAutoDelegate messages are returned", async () => {
671
+ const statusEvents = [];
672
+ const reportedResults = [];
673
+ const delegateMessage = {
674
+ msgId: "memory-update-pending-1",
675
+ senderId: "MCP-System",
676
+ senderName: "系统",
677
+ receiverId: "agent-self",
678
+ content: "您有以下 Memory 正处于更新中状态",
679
+ requireReply: false,
680
+ timestamp: new Date().toISOString(),
681
+ _acodeAutoDelegate: {
682
+ type: "memory_file_change",
683
+ uris: ["architecture://relay/core-routing"],
684
+ },
685
+ };
686
+ const server = createServerWithUnread({
687
+ directMessages: [delegateMessage],
688
+ groupMessages: [],
689
+ }, {
690
+ getStatusReporter: () => ({
691
+ reportToolUse: () => statusEvents.push("tool_using"),
692
+ reportToolResult: (r) => {
693
+ statusEvents.push("tool_result");
694
+ reportedResults.push(r);
695
+ },
696
+ reportThinking: () => statusEvents.push("thinking"),
697
+ reportWaitingInput: () => statusEvents.push("waiting_input"),
698
+ reportError: () => statusEvents.push("error"),
699
+ reportToolError: () => statusEvents.push("tool_error"),
700
+ }),
701
+ });
702
+ const handleToolCall = getHandleToolCall(server);
703
+ const result = (await handleToolCall.call(server, "poll_message", {}));
704
+ assert.equal(result.directMessages.length, 1);
705
+ assert.deepEqual(statusEvents, ["tool_using", "thinking"]);
706
+ assert.equal(reportedResults.length, 0);
707
+ });
708
+ it("poll_message should filter _acodeAutoDelegate from reportToolResult but keep normal messages", async () => {
709
+ const statusEvents = [];
710
+ const reportedResults = [];
711
+ const delegateMessage = {
712
+ msgId: "memory-update-pending-2",
713
+ senderId: "MCP-System",
714
+ senderName: "系统",
715
+ receiverId: "agent-self",
716
+ content: "请继续完成更新工作",
717
+ requireReply: false,
718
+ timestamp: new Date().toISOString(),
719
+ _acodeAutoDelegate: {
720
+ type: "memory_file_change",
721
+ uris: ["architecture://overview/system-architecture"],
722
+ },
723
+ };
724
+ const normalMessage = {
725
+ msgId: "dm-normal-work",
726
+ senderId: "agent-colleague",
727
+ senderName: "Colleague",
728
+ content: "请帮忙看一下这个接口",
729
+ requireReply: false,
730
+ timestamp: new Date().toISOString(),
731
+ };
732
+ const server = createServerWithUnread({
733
+ directMessages: [delegateMessage, normalMessage],
734
+ groupMessages: [],
735
+ }, {
736
+ getStatusReporter: () => ({
737
+ reportToolUse: () => statusEvents.push("tool_using"),
738
+ reportToolResult: (r) => {
739
+ statusEvents.push("tool_result");
740
+ reportedResults.push(r);
741
+ },
742
+ reportThinking: () => statusEvents.push("thinking"),
743
+ reportWaitingInput: () => statusEvents.push("waiting_input"),
744
+ reportError: () => statusEvents.push("error"),
745
+ reportToolError: () => statusEvents.push("tool_error"),
746
+ }),
747
+ });
748
+ const handleToolCall = getHandleToolCall(server);
749
+ const result = (await handleToolCall.call(server, "poll_message", {}));
750
+ assert.equal(result.directMessages.length, 2);
751
+ assert.deepEqual(statusEvents, ["tool_using", "tool_result", "thinking"]);
752
+ assert.equal(reportedResults.length, 1);
753
+ const reported = reportedResults[0];
754
+ assert.equal(reported.directMessages.length, 1);
755
+ assert.equal(reported.directMessages[0].msgId, "dm-normal-work");
756
+ });
670
757
  });
671
758
  describe("McpServer memory store paths", () => {
672
759
  it("uses project permanent memory directory by default", async () => {
@@ -930,17 +1017,9 @@ describe("McpServer memory tools", () => {
930
1017
  assert.equal(memoryStats.by_type.project_memory?.by_domain.core?.count, 1);
931
1018
  });
932
1019
  });
933
- it("poll_message injects a cleanup notice when listable memory exceeds soft limits", async () => {
1020
+ it("poll_message returns cleanup notice as a while-type when no unread messages", async () => {
934
1021
  await withMemoryServer(async (server) => {
935
1022
  const handleToolCall = getHandleToolCall(server);
936
- const directMessage = {
937
- msgId: "dm-trigger-cleanup",
938
- senderId: "agent-trigger",
939
- senderName: "Trigger Agent",
940
- content: "trigger cleanup notice",
941
- requireReply: false,
942
- timestamp: new Date().toISOString(),
943
- };
944
1023
  Reflect.set(server, "agentClient", {
945
1024
  fetchUnreadMessages: async () => ({
946
1025
  directMessages: [],
@@ -956,27 +1035,29 @@ describe("McpServer memory tools", () => {
956
1035
  content: `recent ${index}`,
957
1036
  });
958
1037
  }
959
- // poll_message blocks until a real message arrives; cleanup notice is prepended.
1038
+ // Override poll to resolve immediately with empty (simulating timeout without waiting 30s)
960
1039
  const buffer = Reflect.get(server, "messageBuffer");
961
- setTimeout(() => {
962
- buffer.push(directMessage);
963
- }, 50);
1040
+ const originalPoll = buffer.poll.bind(buffer);
1041
+ let pollCallCount = 0;
1042
+ buffer.poll = ((_timeoutMs) => {
1043
+ pollCallCount++;
1044
+ return Promise.resolve({ directMessages: [], groupMessages: [] });
1045
+ });
964
1046
  const result = (await handleToolCall.call(server, "poll_message", {}));
965
1047
  assert.equal(result.groupMessages.length, 0);
966
- // cleanup notice prepended before the real message
967
- assert.equal(result.directMessages.length, 2);
1048
+ // cleanup notice returned as a while-type (no unread messages)
1049
+ assert.equal(result.directMessages.length, 1);
968
1050
  assert.match(result.directMessages[0]?.msgId, /^memory-cleanup-/);
969
1051
  assert.equal(result.directMessages[0]?.senderId, "MCP-System");
970
1052
  assert.equal(result.directMessages[0]?.receiverId, "agent-self");
971
1053
  assert.match(result.directMessages[0]?.content ?? "", /本地 memory 已超过建议容量/);
972
- assert.match(result.directMessages[0]?.content ?? "", /agent_memory\/recent 类型下当前 33 条 memory/);
973
1054
  assert.match(result.directMessages[0]?.content ?? "", /get_memory_stats/);
974
1055
  assert.match(result.directMessages[0]?.prompt ?? "", /无需持久化/);
975
- // real message follows the cleanup notice
976
- assert.equal(result.directMessages[1]?.msgId, directMessage.msgId);
1056
+ // 非紧急类在初始路径直接返回,不进入 while 循环
1057
+ assert.equal(pollCallCount, 0);
977
1058
  });
978
1059
  });
979
- it("poll_message should claim backend tasks before returning a cleanup notice", async () => {
1060
+ it("poll_message returns task notification without cleanup notice (while-type not stacked)", async () => {
980
1061
  await withMemoryServer(async (server) => {
981
1062
  const handleToolCall = getHandleToolCall(server);
982
1063
  const taskNotification = {
@@ -1008,13 +1089,11 @@ describe("McpServer memory tools", () => {
1008
1089
  });
1009
1090
  }
1010
1091
  const result = (await handleToolCall.call(server, "poll_message", {}));
1011
- assert.equal(fetchOptions.length, 1);
1012
- assert.equal(fetchOptions[0]?.blockIfEmpty, false);
1013
- assert.equal(fetchOptions[0]?.includePipelineTasks, false);
1092
+ // Task notification is returned as an unread message; cleanup is a while-type
1093
+ // that is only checked when there are no unread messages - not stacked with messages.
1014
1094
  assert.equal(result.groupMessages.length, 0);
1015
- assert.equal(result.directMessages.length, 2);
1016
- assert.match(result.directMessages[0]?.msgId, /^memory-cleanup-/);
1017
- assert.equal(result.directMessages[1]?.msgId, taskNotification.msgId);
1095
+ assert.equal(result.directMessages.length, 1);
1096
+ assert.equal(result.directMessages[0]?.msgId, taskNotification.msgId);
1018
1097
  });
1019
1098
  });
1020
1099
  it("get_message injects a cleanup notice when listable memory exceeds soft limits", async () => {
@@ -1164,7 +1243,7 @@ describe("McpServer memory tools", () => {
1164
1243
  assert.deepEqual(missingDelete, { deleted: false });
1165
1244
  });
1166
1245
  });
1167
- it("rejects empty append-only updates as no-op", async () => {
1246
+ it("allows no-content update for status-only refresh (empty append)", async () => {
1168
1247
  await withMemoryServer(async (server) => {
1169
1248
  const handleToolCall = getHandleToolCall(server);
1170
1249
  await handleToolCall.call(server, "create_memory", {
@@ -1172,10 +1251,12 @@ describe("McpServer memory tools", () => {
1172
1251
  uri: "core://agent/noop",
1173
1252
  content: "original",
1174
1253
  });
1175
- await assert.rejects(() => handleToolCall.call(server, "update_memory", {
1254
+ // append 不再报错,而是执行无内容更新(仅刷新状态/MD5)
1255
+ const result = await handleToolCall.call(server, "update_memory", {
1176
1256
  uri: "core://agent/noop",
1177
1257
  append: "",
1178
- }), /Provide either old_string\/new_string or append/);
1258
+ });
1259
+ assert.ok(result, "no-content update should succeed");
1179
1260
  });
1180
1261
  });
1181
1262
  it("rejects create_memory when bound_files contain non-existent paths", async () => {
@@ -1800,7 +1881,7 @@ describe("McpServer todo reminder on poll_message", () => {
1800
1881
  timestamp: new Date().toISOString(),
1801
1882
  };
1802
1883
  }
1803
- it("injects todo reminder when incomplete todos exist", async () => {
1884
+ it("returns todo alone when incomplete todos exist and no unread messages", async () => {
1804
1885
  await writeTodoFile([
1805
1886
  { content: "任务A", status: "pending", priority: "high" },
1806
1887
  { content: "任务B", status: "completed", priority: "low" },
@@ -1809,11 +1890,33 @@ describe("McpServer todo reminder on poll_message", () => {
1809
1890
  const server = createServerForTodo();
1810
1891
  const handleToolCall = getHandleToolCall(server);
1811
1892
  const result = (await handleToolCall.call(server, "poll_message", {}));
1893
+ // 无未读消息时,todo 单独返回(组合2)
1812
1894
  assert.equal(result.directMessages.length, 1);
1813
- const notice = result.directMessages[0];
1814
- assert.equal(notice.senderId, "MCP-System");
1815
- assert.equal(notice.senderName, "系统");
1816
- assert.match(notice.content, /Todo 列表存在 1 项未完成/);
1895
+ assert.equal(result.directMessages[0].senderId, "MCP-System");
1896
+ assert.equal(result.directMessages[0].senderName, "系统");
1897
+ assert.match(result.directMessages[0].content, /Todo 列表存在 1 项未完成/);
1898
+ }
1899
+ finally {
1900
+ await cleanupTodoFile();
1901
+ }
1902
+ });
1903
+ it("returns messages + todo when both unread messages and incomplete todos exist", async () => {
1904
+ await writeTodoFile([
1905
+ { content: "任务A", status: "pending", priority: "high" },
1906
+ ]);
1907
+ try {
1908
+ const server = createServerForTodo();
1909
+ // 先把消息放入 buffer,模拟已有未读消息
1910
+ const buffer = Reflect.get(server, "messageBuffer");
1911
+ const msg = makeDirectMessage("msg-before-poll");
1912
+ buffer.push(msg);
1913
+ const handleToolCall = getHandleToolCall(server);
1914
+ const result = (await handleToolCall.call(server, "poll_message", {}));
1915
+ // 有未读消息 + todo -> 组合4: 未读消息 + todo
1916
+ assert.equal(result.directMessages.length, 2);
1917
+ assert.equal(result.directMessages[0].senderId, "MCP-System");
1918
+ assert.match(result.directMessages[0].content, /Todo 列表存在 1 项未完成/);
1919
+ assert.equal(result.directMessages[1].msgId, "msg-before-poll");
1817
1920
  }
1818
1921
  finally {
1819
1922
  await cleanupTodoFile();
@@ -1830,7 +1933,7 @@ describe("McpServer todo reminder on poll_message", () => {
1830
1933
  setTimeout(() => buffer.push(wake), 50);
1831
1934
  const handleToolCall = getHandleToolCall(server);
1832
1935
  const result = (await handleToolCall.call(server, "poll_message", {}));
1833
- // 全完成时不应注入 todo 通知,仅返回 push 的唤醒消息
1936
+ // 全完成时无 todo,进入 while 循环等待消息后返回
1834
1937
  assert.equal(result.directMessages.length, 1);
1835
1938
  assert.equal(result.directMessages[0].msgId, "wake-completed");
1836
1939
  }
@@ -1838,46 +1941,43 @@ describe("McpServer todo reminder on poll_message", () => {
1838
1941
  await cleanupTodoFile();
1839
1942
  }
1840
1943
  });
1841
- it("does not repeat todo reminder when fingerprint unchanged", async () => {
1944
+ it("returns todo alone on every poll_message when incomplete todos exist", async () => {
1842
1945
  await writeTodoFile([
1843
1946
  { content: "任务A", status: "pending", priority: "high" },
1844
1947
  ]);
1845
1948
  try {
1846
1949
  const server = createServerForTodo();
1847
1950
  const handleToolCall = getHandleToolCall(server);
1848
- // 第一次:应返回 todo 通知
1951
+ // 第一次 poll:无未读消息 -> todo 单独返回(组合2)
1849
1952
  const result1 = (await handleToolCall.call(server, "poll_message", {}));
1850
1953
  assert.equal(result1.directMessages.length, 1);
1851
- assert.match(result1.directMessages[0].content, /Todo 列表存在/);
1852
- // 第二次:指纹未变,应进入阻塞等待。push 一条消息让 poll 返回
1853
- const buffer = Reflect.get(server, "messageBuffer");
1854
- const wake = makeDirectMessage("wake-unchanged");
1855
- setTimeout(() => buffer.push(wake), 50);
1954
+ assert.match(result1.directMessages[0].content, /Todo 列表存在 1 项未完成/);
1955
+ // 第二次 poll(待办未变):仍返回 todo
1856
1956
  const result2 = (await handleToolCall.call(server, "poll_message", {}));
1857
- // 第二次不应再注入 todo 通知,仅返回 push 的唤醒消息
1858
1957
  assert.equal(result2.directMessages.length, 1);
1859
- assert.equal(result2.directMessages[0].msgId, "wake-unchanged");
1958
+ assert.match(result2.directMessages[0].content, /Todo 列表存在 1 项未完成/);
1860
1959
  }
1861
1960
  finally {
1862
1961
  await cleanupTodoFile();
1863
1962
  }
1864
1963
  });
1865
- it("re-injects todo reminder when todos change after being notified", async () => {
1964
+ it("returns todo with updated count when todo file changes", async () => {
1866
1965
  await writeTodoFile([
1867
1966
  { content: "任务A", status: "pending", priority: "high" },
1868
1967
  ]);
1869
1968
  try {
1870
1969
  const server = createServerForTodo();
1871
1970
  const handleToolCall = getHandleToolCall(server);
1872
- // 第一次:返回 todo 通知(1 项未完成)
1971
+ // 第一次 poll:1 项未完成
1873
1972
  const result1 = (await handleToolCall.call(server, "poll_message", {}));
1973
+ assert.equal(result1.directMessages.length, 1);
1874
1974
  assert.match(result1.directMessages[0].content, /Todo 列表存在 1 项未完成/);
1875
- // 修改 todo:新增一项未完成(指纹变化)
1975
+ // 修改 todo:新增一项
1876
1976
  await writeTodoFile([
1877
1977
  { content: "任务A", status: "pending", priority: "high" },
1878
1978
  { content: "任务B", status: "in_progress", priority: "medium" },
1879
1979
  ]);
1880
- // 第二次:指纹变化,应再次返回 todo 通知(2 项未完成)
1980
+ // 第二次 poll:2 项未完成
1881
1981
  const result2 = (await handleToolCall.call(server, "poll_message", {}));
1882
1982
  assert.equal(result2.directMessages.length, 1);
1883
1983
  assert.match(result2.directMessages[0].content, /Todo 列表存在 2 项未完成/);
@@ -1895,7 +1995,7 @@ describe("McpServer todo reminder on poll_message", () => {
1895
1995
  setTimeout(() => buffer.push(wake), 50);
1896
1996
  const handleToolCall = getHandleToolCall(server);
1897
1997
  const result = (await handleToolCall.call(server, "poll_message", {}));
1898
- // 无 todo 文件不应注入通知,仅返回 push 的唤醒消息
1998
+ // 无 todo 文件 -> 进入 while 循环等待消息后返回
1899
1999
  assert.equal(result.directMessages.length, 1);
1900
2000
  assert.equal(result.directMessages[0].msgId, "wake-no-file");
1901
2001
  });