@zhushanwen/pi-pending-notifications 0.7.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhushanwen/pi-pending-notifications",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Cross-extension async operation registration/query mechanism for Pi.",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -384,6 +384,53 @@ describe("pendingNotificationsExtension factory", () => {
384
384
  );
385
385
  expect(stateChangeCalls).toHaveLength(0);
386
386
  });
387
+
388
+ it("U7b: reason → status 词表映射(表驱动——防新枚举值漏映射静默落兜底,cancelled 同族事故先例)", () => {
389
+ fireSessionStart(setup);
390
+ const cases: Array<[string, string]> = [
391
+ ["completed", "completed"],
392
+ ["failed", "failed"],
393
+ ["cancelled", "cancelled"],
394
+ ["expired", "expired"],
395
+ ["time_limited", "time_limited"],
396
+ ["budget_limited", "failed"],
397
+ ["aborted", "aborted"],
398
+ // U5 新词表:subagent-core stopReason 展示值经注销 reason 通道到达
399
+ ["interrupted", "aborted"],
400
+ ["interrupted-by-restart", "aborted"],
401
+ ["interrupted-by-parent", "aborted"],
402
+ ["reopened", "completed"],
403
+ ];
404
+ for (const [i] of cases.entries()) {
405
+ setup.handlers.pendingRegister!({ id: `w-map-${i}`, type: "workflow", name: `op-${i}` });
406
+ }
407
+ setup.appendEntryMock.mockClear();
408
+ for (const [i, [reason]] of cases.entries()) {
409
+ setup.handlers.pendingUnregister!({ id: `w-map-${i}`, reason });
410
+ }
411
+
412
+ const unregisterCalls = setup.appendEntryMock.mock.calls.filter((c) => c[0] === "pending:unregister");
413
+ expect(unregisterCalls).toHaveLength(cases.length);
414
+ for (const [i, [reason, expected]] of cases.entries()) {
415
+ expect(unregisterCalls).toContainEqual([
416
+ "pending:unregister",
417
+ expect.objectContaining({ id: `w-map-${i}`, reason, status: expected }),
418
+ ]);
419
+ }
420
+ });
421
+
422
+ it("U7c: 未知 reason 落 default 兜底 completed(兜底语义的显式登记——未来若改兜底口径,此用例同步更新)", () => {
423
+ fireSessionStart(setup);
424
+ setup.handlers.pendingRegister!({ id: "w-unknown", type: "workflow", name: "op" });
425
+ setup.appendEntryMock.mockClear();
426
+
427
+ setup.handlers.pendingUnregister!({ id: "w-unknown", reason: "some-future-reason" });
428
+
429
+ expect(setup.appendEntryMock).toHaveBeenCalledWith(
430
+ "pending:unregister",
431
+ expect.objectContaining({ id: "w-unknown", reason: "some-future-reason", status: "completed" }),
432
+ );
433
+ });
387
434
  });
388
435
 
389
436
  describe("tool count/list (U9-U10)", () => {
package/src/index.ts CHANGED
@@ -277,7 +277,11 @@ function parseUnregisterEvent(data: unknown): ParsedUnregister | null {
277
277
  };
278
278
  }
279
279
 
280
- /** 将事件 reason 映射为 pending:unregister entry 的 status 字段(落盘契约组成部分) */
280
+ /** 将事件 reason 映射为 pending:unregister entry 的 status 字段(落盘契约组成部分)。
281
+ * [U5 / 永久会话模型 §3.2.5 通知词表对齐] subagent-core 新 stopReason 展示值经注销
282
+ * reason 通道到达(interrupted/interrupted-by-restart/interrupted-by-parent → aborted、
283
+ * reopened → completed)——防新词落 default 被记为 completed 的误标(cancelled 同族
284
+ * 事故先例:新枚举值漏映射静默落兜底)。 */
281
285
  function mapReasonToStatus(reason: string): PendingStatus {
282
286
  switch (reason) {
283
287
  case "completed": return "completed";
@@ -287,6 +291,12 @@ function mapReasonToStatus(reason: string): PendingStatus {
287
291
  case "time_limited": return "time_limited";
288
292
  case "budget_limited": return "failed";
289
293
  case "aborted": return "aborted";
294
+ case "interrupted":
295
+ case "interrupted-by-restart":
296
+ case "interrupted-by-parent":
297
+ return "aborted";
298
+ case "reopened":
299
+ return "completed";
290
300
  default: return "completed";
291
301
  }
292
302
  }