@zhin.js/plugin-reminder 1.0.4 → 1.0.6

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 (79) hide show
  1. package/README.md +12 -2
  2. package/commands/remind/after/index.js +6 -5
  3. package/commands/remind/after/index.ts +6 -5
  4. package/commands/remind/at/index.js +8 -7
  5. package/commands/remind/at/index.ts +6 -5
  6. package/commands/remind/cancel/index.js +5 -4
  7. package/commands/remind/cancel/index.ts +5 -4
  8. package/commands/remind/create/index.js +3 -3
  9. package/commands/remind/create/index.ts +3 -3
  10. package/commands/remind/every/index.js +6 -5
  11. package/commands/remind/every/index.ts +6 -5
  12. package/commands/remind/list/index.js +5 -4
  13. package/commands/remind/list/index.ts +5 -4
  14. package/lib/admin-i18n.d.ts +155 -0
  15. package/lib/admin-i18n.d.ts.map +1 -0
  16. package/lib/admin-i18n.js +152 -0
  17. package/lib/admin-i18n.js.map +1 -0
  18. package/lib/admin-tasks.d.ts +35 -5
  19. package/lib/admin-tasks.d.ts.map +1 -1
  20. package/lib/admin-tasks.js +77 -57
  21. package/lib/admin-tasks.js.map +1 -1
  22. package/lib/caller.d.ts +2 -1
  23. package/lib/caller.d.ts.map +1 -1
  24. package/lib/caller.js +5 -3
  25. package/lib/caller.js.map +1 -1
  26. package/lib/config.js +6 -6
  27. package/lib/config.js.map +1 -1
  28. package/lib/create-reminder.d.ts.map +1 -1
  29. package/lib/create-reminder.js +31 -25
  30. package/lib/create-reminder.js.map +1 -1
  31. package/lib/duration.d.ts +2 -1
  32. package/lib/duration.d.ts.map +1 -1
  33. package/lib/duration.js +4 -3
  34. package/lib/duration.js.map +1 -1
  35. package/lib/i18n.d.ts +2 -0
  36. package/lib/i18n.d.ts.map +1 -0
  37. package/lib/i18n.js +336 -0
  38. package/lib/i18n.js.map +1 -0
  39. package/lib/natural-time.d.ts +5 -1
  40. package/lib/natural-time.d.ts.map +1 -1
  41. package/lib/natural-time.js +71 -57
  42. package/lib/natural-time.js.map +1 -1
  43. package/lib/service.d.ts +8 -2
  44. package/lib/service.d.ts.map +1 -1
  45. package/lib/service.js +47 -36
  46. package/lib/service.js.map +1 -1
  47. package/lib/storage.d.ts +4 -0
  48. package/lib/storage.d.ts.map +1 -0
  49. package/lib/storage.js +51 -0
  50. package/lib/storage.js.map +1 -0
  51. package/lib/timing.d.ts +2 -1
  52. package/lib/timing.d.ts.map +1 -1
  53. package/lib/timing.js +5 -4
  54. package/lib/timing.js.map +1 -1
  55. package/lib/tool-actor.d.ts +2 -0
  56. package/lib/tool-actor.d.ts.map +1 -1
  57. package/lib/tool-actor.js +14 -4
  58. package/lib/tool-actor.js.map +1 -1
  59. package/package.json +9 -9
  60. package/plugin.js +12 -4
  61. package/schema.json +30 -0
  62. package/skills/reminder/tools/reminder_cancel/index.js +3 -2
  63. package/skills/reminder/tools/reminder_cancel/index.ts +3 -2
  64. package/skills/reminder/tools/reminder_create/index.js +7 -6
  65. package/skills/reminder/tools/reminder_create/index.ts +7 -6
  66. package/skills/reminder/tools/reminder_list/index.js +3 -2
  67. package/skills/reminder/tools/reminder_list/index.ts +3 -2
  68. package/src/admin-i18n.ts +154 -0
  69. package/src/admin-tasks.ts +79 -53
  70. package/src/caller.ts +5 -3
  71. package/src/config.ts +6 -6
  72. package/src/create-reminder.ts +33 -25
  73. package/src/duration.ts +5 -3
  74. package/src/i18n.ts +336 -0
  75. package/src/natural-time.ts +40 -30
  76. package/src/service.ts +51 -38
  77. package/src/storage.ts +54 -0
  78. package/src/timing.ts +6 -4
  79. package/src/tool-actor.ts +15 -4
package/lib/storage.js ADDED
@@ -0,0 +1,51 @@
1
+ import { createRelationalStateStore, TASK_TARGET_COLUMNS, TASK_RECEIPT_COLUMNS, encodeTaskTarget, decodeTaskTarget, encodeTaskReceipts, decodeTaskReceipts, encodeStorageIdentity, decodeStorageIdentity } from 'zhin.js/plugin-runtime';
2
+ import { REMINDER_STATE_KEY } from './service.js';
3
+ import { ADMIN_REMINDER_STATE_KEY } from './admin-tasks.js';
4
+ const taskColumns = {
5
+ id: { type: 'text', length: 36, primary: true }, position: { type: 'integer', nullable: false },
6
+ ...TASK_TARGET_COLUMNS, sender_id: { type: 'text', nullable: true }, creation: { type: 'text', nullable: true },
7
+ locale: { type: 'text', length: 16, nullable: true },
8
+ content: { type: 'text', nullable: false }, state: { type: 'text', length: 24, nullable: false },
9
+ created_at: { type: 'bigint', nullable: false }, next_run_at: { type: 'bigint', nullable: false },
10
+ interval_ms: { type: 'bigint', nullable: true }, claim_id: { type: 'text', nullable: true },
11
+ last_run_at: { type: 'bigint', nullable: true }, detail: { type: 'text', nullable: false }, detail_key: { type: 'text', length: 40, nullable: true }, failure_code: { type: 'text', length: 64, nullable: true },
12
+ };
13
+ function codec(admin) {
14
+ const table = admin ? 'admin_reminder_tasks' : 'reminder_tasks';
15
+ const receipts = 'admin_reminder_receipts';
16
+ return {
17
+ key: admin ? ADMIN_REMINDER_STATE_KEY : REMINDER_STATE_KEY,
18
+ header: { table: `${table}_book`, definition: {
19
+ version: { type: 'integer', nullable: true }, revision: { type: 'text', nullable: true },
20
+ } },
21
+ addColumns: { [table]: ['locale', 'detail_key', 'failure_code'] },
22
+ tables: { [table]: taskColumns, ...(admin ? { [receipts]: TASK_RECEIPT_COLUMNS } : {}) },
23
+ encode(value) {
24
+ const book = value;
25
+ if (book.version !== 1 || !Array.isArray(book.tasks))
26
+ throw new Error('Unsupported reminder book; original state was preserved');
27
+ return { header: { version: book.version, revision: 'revision' in book ? book.revision : null }, rows: {
28
+ [table]: book.tasks.map((task, position) => ({ id: task.id, position, ...encodeTaskTarget(task.target),
29
+ sender_id: 'senderId' in task ? encodeStorageIdentity(task.senderId) : null,
30
+ locale: task.locale ?? 'zh-CN', creation: 'creation' in task ? task.creation : null, content: encodeStorageIdentity(task.text),
31
+ state: 'status' in task ? task.status : task.state, created_at: task.createdAt, next_run_at: task.nextRunAt,
32
+ interval_ms: task.intervalMs, claim_id: task.claimId, last_run_at: task.lastRunAt, detail: encodeStorageIdentity(task.detail), detail_key: task.detailKey ?? null, failure_code: 'failureCode' in task ? task.failureCode ?? null : null })),
33
+ ...(admin ? { [receipts]: encodeTaskReceipts(book.receipts) } : {}),
34
+ } };
35
+ },
36
+ decode(header, rows) {
37
+ return { version: Number(header.version), ...(admin ? { revision: String(header.revision) } : {}),
38
+ tasks: rows[table].map(row => ({ id: String(row.id), target: decodeTaskTarget(row), text: decodeStorageIdentity(row.content), locale: row.locale == null ? 'zh-CN' : String(row.locale),
39
+ createdAt: Number(row.created_at), nextRunAt: Number(row.next_run_at), intervalMs: row.interval_ms == null ? null : Number(row.interval_ms),
40
+ claimId: row.claim_id == null ? null : String(row.claim_id), lastRunAt: row.last_run_at == null ? null : Number(row.last_run_at), detail: decodeStorageIdentity(row.detail), ...(row.detail_key == null ? {} : { detailKey: String(row.detail_key) }), ...(row.failure_code == null ? {} : { failureCode: String(row.failure_code) }),
41
+ ...(admin ? { creation: String(row.creation), state: String(row.state) } : { senderId: decodeStorageIdentity(row.sender_id), status: String(row.state) }),
42
+ })), ...(admin ? { receipts: decodeTaskReceipts(rows[receipts]) } : {}),
43
+ };
44
+ },
45
+ };
46
+ }
47
+ /** Both pools keep their existing CAS API but persist independent rows atomically. */
48
+ export function createReminderState(database) {
49
+ return createRelationalStateStore(database, [codec(false), codec(true)]);
50
+ }
51
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
package/lib/timing.d.ts CHANGED
@@ -1,4 +1,5 @@
1
+ import type { Locale } from 'zhin.js/i18n';
1
2
  export declare const MAX_DELAY_SECONDS: number;
2
- export declare function parseReminderInstant(value: string): number;
3
+ export declare function parseReminderInstant(value: string, locale?: Locale): number;
3
4
  export declare function nextPeriodicTime(from: number, interval: number, now: number): number;
4
5
  //# sourceMappingURL=timing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../src/timing.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,QAAqB,CAAC;AAEpD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAU1D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpF"}
1
+ {"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../src/timing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,eAAO,MAAM,iBAAiB,QAAqB,CAAC;AAEpD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAU3E;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpF"}
package/lib/timing.js CHANGED
@@ -1,16 +1,17 @@
1
+ import { reminderMessages as t } from './i18n.js';
1
2
  export const MAX_DELAY_SECONDS = 365 * 24 * 60 * 60;
2
- export function parseReminderInstant(value) {
3
+ export function parseReminderInstant(value, locale) {
3
4
  if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,3})?)?(?:Z|[+-]\d{2}:\d{2})$/u.test(value))
4
- throw new TypeError('绝对时间须为带 Z 或 ±hh:mm 的 ISO 时间,例如 2026-10-14T09:00:00+08:00');
5
+ throw new TypeError(t(locale, 'absoluteFormat'));
5
6
  const [year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0] = value.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?/u).slice(1).map(item => Number(item ?? 0));
6
7
  const calendar = new Date(0);
7
8
  calendar.setUTCFullYear(year, month, 0);
8
9
  const daysInMonth = calendar.getUTCDate();
9
10
  if (month < 1 || month > 12 || day < 1 || day > daysInMonth || hour > 23 || minute > 59 || second > 59)
10
- throw new TypeError('提醒时间无效');
11
+ throw new TypeError(t(locale, 'instantInvalid'));
11
12
  const time = Date.parse(value);
12
13
  if (!Number.isSafeInteger(time))
13
- throw new TypeError('提醒时间无效');
14
+ throw new TypeError(t(locale, 'instantInvalid'));
14
15
  return time;
15
16
  }
16
17
  export function nextPeriodicTime(from, interval, now) {
package/lib/timing.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"timing.js","sourceRoot":"","sources":["../src/timing.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAEpD,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,IAAI,CAAC,gFAAgF,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,0DAA0D,CAAC,CAAC;IACnL,MAAM,CAAC,IAAI,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,wDAAwD,CAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IACxL,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7B,QAAQ,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC;IAC1C,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,WAAW,IAAI,IAAI,GAAG,EAAE,IAAI,MAAM,GAAG,EAAE,IAAI,MAAM,GAAG,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,QAAQ,CAAC,CAAC;IACtI,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC/D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,QAAgB,EAAE,GAAW;IAC1E,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;AACrE,CAAC"}
1
+ {"version":3,"file":"timing.js","sourceRoot":"","sources":["../src/timing.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,IAAI,CAAC,EAAE,MAAM,WAAW,CAAC;AAClD,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAEpD,MAAM,UAAU,oBAAoB,CAAC,KAAa,EAAE,MAAe;IACjE,IAAI,CAAC,gFAAgF,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACpJ,MAAM,CAAC,IAAI,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,wDAAwD,CAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IACxL,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7B,QAAQ,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC;IAC1C,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,WAAW,IAAI,IAAI,GAAG,EAAE,IAAI,MAAM,GAAG,EAAE,IAAI,MAAM,GAAG,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACzJ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAClF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,QAAgB,EAAE,GAAW;IAC1E,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;AACrE,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { type Locale } from 'zhin.js/i18n';
1
2
  /**
2
3
  * Resolve a ReminderActor from an Agent Tool invocation (IM origin only).
3
4
  */
@@ -7,6 +8,7 @@ import type { ToolInvocationOrigin } from "@zhin.js/tool";
7
8
  import { type ReminderActor } from "./service.js";
8
9
  export interface ToolActorContext {
9
10
  readonly origin: ToolInvocationOrigin;
11
+ readonly locale?: Locale;
10
12
  readonly principal: Readonly<{
11
13
  subjectId: string;
12
14
  roles: readonly string[];
@@ -1 +1 @@
1
- {"version":3,"file":"tool-actor.d.ts","sourceRoot":"","sources":["../src/tool-actor.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAqB,MAAM,iBAAiB,CAAC;AACtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAEtE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAC9E,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,gBAAgB,GAAG,CAAC,CAAC;CACjD;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,cAAc,CA2B5E;AAED,6EAA6E;AAC7E,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,gBAAgB,GACxB,aAAa,CAIf"}
1
+ {"version":3,"file":"tool-actor.d.ts","sourceRoot":"","sources":["../src/tool-actor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE1D;;GAEG;AACH,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAqB,MAAM,iBAAiB,CAAC;AACtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAEtE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAC9E,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,gBAAgB,GAAG,CAAC,CAAC;CACjD;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,cAAc,CAmC5E;AAED,6EAA6E;AAC7E,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,gBAAgB,GACxB,aAAa,CAIf"}
package/lib/tool-actor.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { resolveLocale } from 'zhin.js/i18n';
2
+ import { reminderMessages as t } from './i18n.js';
1
3
  /**
2
4
  * Resolve a ReminderActor from an Agent Tool invocation (IM origin only).
3
5
  */
@@ -8,7 +10,7 @@ import { ReminderInputError } from "./service.js";
8
10
  export function toolDeliveryTarget(context) {
9
11
  const origin = context.origin;
10
12
  if (origin.kind !== "im") {
11
- throw new ReminderInputError("提醒工具只能在聊天会话中使用(不能用于 http/schedule 等来源)");
13
+ throw new ReminderInputError(t(context.locale, 'toolOrigin'));
12
14
  }
13
15
  const index = context.project(adapterFeatureId);
14
16
  const matches = index
@@ -17,7 +19,15 @@ export function toolDeliveryTarget(context) {
17
19
  endpoint.name === origin.endpoint) &&
18
20
  index.clientAdapter(endpoint.id) === origin.platform);
19
21
  if (matches.length !== 1) {
20
- throw new ReminderInputError("无法确定当前会话所属的机器人账号");
22
+ throw new ReminderInputError(t(context.locale, 'toolEndpoint'));
23
+ }
24
+ if (origin.conversation) {
25
+ const canonical = createDeliveryTarget({ conversation: origin.conversation });
26
+ if (canonical.endpoint.id !== String(matches[0].id) || canonical.endpoint.adapter !== origin.platform
27
+ || canonical.kind !== origin.scope || canonical.id !== origin.sceneId || canonical.threadId !== origin.threadId) {
28
+ throw new ReminderInputError(t(context.locale, 'toolEndpoint'));
29
+ }
30
+ return canonical;
21
31
  }
22
32
  return createDeliveryTarget({
23
33
  conversation: {
@@ -32,7 +42,7 @@ export function toolDeliveryTarget(context) {
32
42
  export function reminderActorFromTool(context) {
33
43
  const senderId = context.principal.subjectId?.trim();
34
44
  if (!senderId)
35
- throw new ReminderInputError("提醒工具需要真实发送者");
36
- return { senderId, target: toolDeliveryTarget(context) };
45
+ throw new ReminderInputError(t(context.locale, 'toolSender'));
46
+ return { senderId, target: toolDeliveryTarget(context), locale: resolveLocale(context.locale) };
37
47
  }
38
48
  //# sourceMappingURL=tool-actor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tool-actor.js","sourceRoot":"","sources":["../src/tool-actor.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,oBAAoB,EAAuB,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAqB,MAAM,iBAAiB,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAsB,MAAM,cAAc,CAAC;AAQtE,6EAA6E;AAC7E,MAAM,UAAU,kBAAkB,CAAC,OAAyB;IAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QACzB,MAAM,IAAI,kBAAkB,CAC1B,wCAAwC,CACzC,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAe,gBAAgB,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,KAAK;SAClB,QAAQ,EAAE;SACV,MAAM,CACL,CAAC,QAAQ,EAAE,EAAE,CACX,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,QAAQ;QACtC,QAAQ,CAAC,IAAI,KAAK,MAAM,CAAC,QAAQ,CAAC;QACpC,KAAK,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,QAAQ,CACvD,CAAC;IACJ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,oBAAoB,CAAC;QAC1B,YAAY,EAAE;YACZ,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE;YAClE,IAAI,EAAE,MAAM,CAAC,KAAK;YAClB,EAAE,EAAE,MAAM,CAAC,OAAO;YAClB,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxE;KACF,CAAC,CAAC;AACL,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,qBAAqB,CACnC,OAAyB;IAEzB,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC;IACrD,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,kBAAkB,CAAC,aAAa,CAAC,CAAC;IAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;AAC3D,CAAC"}
1
+ {"version":3,"file":"tool-actor.js","sourceRoot":"","sources":["../src/tool-actor.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/plugin-reminder",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Persistent personal reminders for Zhin Plugin Runtime",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -22,15 +22,15 @@
22
22
  "schema.json"
23
23
  ],
24
24
  "dependencies": {
25
- "@zhin.js/im-contract": "1.1.5",
26
- "@zhin.js/skill": "1.1.8",
27
- "@zhin.js/tool": "1.1.8"
25
+ "@zhin.js/skill": "1.1.10",
26
+ "@zhin.js/tool": "1.1.10",
27
+ "@zhin.js/im-contract": "1.1.7"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "zod": "^4.0.0",
31
- "zhin.js": "^1.1.13",
32
- "@zhin.js/command": "^1.1.9",
33
- "@zhin.js/schedule-feature": "^1.1.7"
31
+ "zhin.js": "^1.1.16",
32
+ "@zhin.js/command": "^1.1.11",
33
+ "@zhin.js/schedule-feature": "^1.1.9"
34
34
  },
35
35
  "peerDependenciesMeta": {
36
36
  "@zhin.js/command": {
@@ -47,8 +47,8 @@
47
47
  "typescript": "^6.0.3",
48
48
  "vitest": "^4.1.10",
49
49
  "zod": "^4.4.3",
50
- "zhin.js": "1.1.13",
51
- "@zhin.js/schedule-feature": "1.1.7"
50
+ "zhin.js": "1.1.16",
51
+ "@zhin.js/schedule-feature": "1.1.9"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=22.19.0"
package/plugin.js CHANGED
@@ -1,8 +1,10 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { projectLocaleToken } from 'zhin.js/i18n';
2
3
  import { databaseHostToken, definePlugin, outboundHostToken } from 'zhin.js';
3
4
  import { pluginVerificationToken, pluginTaskProviderToken } from 'zhin.js/plugin-runtime';
4
5
  import { randomUUID } from 'node:crypto';
5
6
  import { assertReminderTimezone } from "./lib/config.js";
7
+ import { createReminderState } from "./lib/storage.js";
6
8
  import { ReminderService } from "./lib/service.js";
7
9
  import { reminderServiceToken } from "./lib/runtime.js";
8
10
  export default definePlugin({
@@ -12,15 +14,19 @@ export default definePlugin({
12
14
  setup(context) {
13
15
  const config = context.config.get();
14
16
  assertReminderTimezone(config.timezone);
15
- const state = context.resources.use(databaseHostToken).state;
17
+ const database = context.resources.use(databaseHostToken);
18
+ const state = database.state;
19
+ const taskState = createReminderState(database);
16
20
  const outbound = context.resources.use(outboundHostToken);
17
21
  if (!outbound.sendTarget)
18
22
  throw new Error('提醒需要支持精确 DeliveryTarget 的 Outbound Host');
19
- const service = new ReminderService(state, outbound, config);
23
+ const service = new ReminderService(taskState, outbound, config, context.resources.use(projectLocaleToken));
20
24
  context.resources.provide(reminderServiceToken, service);
21
25
  context.resources.provide(pluginTaskProviderToken, service.administratorTasks);
22
26
  context.resources.provide(pluginVerificationToken, {
23
- checks: () => [{ id: 'local-state', title: '持久状态读写检查', scope: 'local', effects: ['写入、读取并删除一个独立探针键;不创建提醒、不发送消息'] }],
27
+ checks: () => [{ id: 'local-state', title: '持久状态读写检查', titleI18n: { en: 'Persistent state read/write check' }, scope: 'local',
28
+ effects: ['写入、读取并删除一个独立探针键;不创建提醒、不发送消息'],
29
+ effectsI18n: { en: ['Write, read and delete an isolated probe key; no reminders are created and no messages are sent'] } }],
24
30
  async run(checkId) {
25
31
  if (checkId !== 'local-state')
26
32
  throw new Error('Unknown reminder verification check');
@@ -30,7 +36,9 @@ export default definePlugin({
30
36
  const value = await state.get(key);
31
37
  if (value?.probe !== true)
32
38
  throw new Error('持久状态读写结果不一致');
33
- return { status: 'passed', summary: '本地持久状态读写通过', evidence: ['独立探针写入并成功读回;清理后删除', '仅验证当前 owner 的数据库状态;不证明调度或平台投递健康'] };
39
+ return { status: 'passed', summary: '本地持久状态读写通过', summaryI18n: { en: 'Local persistent state read/write check passed' },
40
+ evidence: ['独立探针写入并成功读回;清理后删除', '仅验证当前 owner 的数据库状态;不证明调度或平台投递健康'],
41
+ evidenceI18n: { en: ['An isolated probe was written, read back and deleted during cleanup', 'Checks only this owner’s database state; does not verify scheduling or platform delivery'] } };
34
42
  }
35
43
  finally {
36
44
  await state.delete(key);
package/schema.json CHANGED
@@ -5,6 +5,11 @@
5
5
  "timezone": {
6
6
  "type": "string",
7
7
  "description": "解释 create 自然时间并显示提醒的 IANA 时区;ISO 绝对时间仍须显式 offset",
8
+ "x-i18n": {
9
+ "en": {
10
+ "description": "IANA timezone for natural reminder times and display. Absolute ISO times still require an explicit offset."
11
+ }
12
+ },
8
13
  "default": "UTC",
9
14
  "x-zhin-config": {
10
15
  "effect": "reload"
@@ -13,6 +18,11 @@
13
18
  "maxTasks": {
14
19
  "type": "number",
15
20
  "description": "每实例聊天个人提醒池的活跃任务上限;与管理员池独立,降低上限不删除既有任务",
21
+ "x-i18n": {
22
+ "en": {
23
+ "description": "Maximum active personal chat reminders per instance, separate from administrator tasks. Lowering the limit does not delete existing tasks."
24
+ }
25
+ },
16
26
  "default": 20,
17
27
  "minimum": 1,
18
28
  "maximum": 32,
@@ -24,6 +34,11 @@
24
34
  "adminMaxTasks": {
25
35
  "type": "number",
26
36
  "description": "每实例管理员提醒池的活跃任务上限(待执行、暂停或未确认);与聊天池独立,两池总量可达上限之和",
37
+ "x-i18n": {
38
+ "en": {
39
+ "description": "Maximum active administrator reminders (scheduled, paused or unconfirmed) per instance. Separate from chat tasks; the two quotas are additive."
40
+ }
41
+ },
27
42
  "default": 20,
28
43
  "minimum": 1,
29
44
  "maximum": 32,
@@ -35,6 +50,11 @@
35
50
  "maxTasksPerSender": {
36
51
  "type": "number",
37
52
  "description": "同一发送者在同一会话的任务上限",
53
+ "x-i18n": {
54
+ "en": {
55
+ "description": "Maximum tasks per sender in the same conversation."
56
+ }
57
+ },
38
58
  "default": 10,
39
59
  "minimum": 1,
40
60
  "maximum": 10,
@@ -46,6 +66,11 @@
46
66
  "batchSize": {
47
67
  "type": "number",
48
68
  "description": "每次扫描最多投递的任务数",
69
+ "x-i18n": {
70
+ "en": {
71
+ "description": "Maximum tasks delivered in each scan."
72
+ }
73
+ },
49
74
  "default": 5,
50
75
  "minimum": 1,
51
76
  "maximum": 5,
@@ -57,6 +82,11 @@
57
82
  "missedGraceSeconds": {
58
83
  "type": "number",
59
84
  "description": "周期轮次超过此延迟后跳过;停机期间不补历史轮次",
85
+ "x-i18n": {
86
+ "en": {
87
+ "description": "Skip recurring runs delayed beyond this many seconds. Missed runs during downtime are not backfilled."
88
+ }
89
+ },
60
90
  "default": 15,
61
91
  "minimum": 5,
62
92
  "maximum": 60,
@@ -1,4 +1,5 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { reminderMessages as t } from "../../../../lib/i18n.js";
2
3
  import { defineAgentTool } from "@zhin.js/tool";
3
4
  import { z } from "zod";
4
5
  import { replyReminder } from "../../../../lib/caller.js";
@@ -17,8 +18,8 @@ export default defineAgentTool({
17
18
  const service = context.use(reminderServiceToken);
18
19
  const ok = await service.cancel(reminderActorFromTool(context), id);
19
20
  return ok
20
- ? `已取消提醒 ${id}`
21
- : `找不到提醒 ${id}(或不属于你在当前会话的任务)`;
21
+ ? t(context.locale, 'toolCancelled', { id })
22
+ : t(context.locale, 'toolNotFound', { id });
22
23
  });
23
24
  },
24
25
  });
@@ -1,3 +1,4 @@
1
+ import { reminderMessages as t } from '../../../../src/i18n.js';
1
2
  import { defineAgentTool } from "@zhin.js/tool";
2
3
  import { z } from "zod";
3
4
  import { replyReminder } from "../../../../src/caller.js";
@@ -18,8 +19,8 @@ export default defineAgentTool({
18
19
  const service = context.use(reminderServiceToken);
19
20
  const ok = await service.cancel(reminderActorFromTool(context), id);
20
21
  return ok
21
- ? `已取消提醒 ${id}`
22
- : `找不到提醒 ${id}(或不属于你在当前会话的任务)`;
22
+ ? t(context.locale, 'toolCancelled', { id })
23
+ : t(context.locale, 'toolNotFound', { id });
23
24
  });
24
25
  },
25
26
  });
@@ -1,4 +1,5 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { reminderMessages as t } from "../../../../lib/i18n.js";
2
3
  import { defineAgentTool } from "@zhin.js/tool";
3
4
  import { z } from "zod";
4
5
  import { replyReminder } from "../../../../lib/caller.js";
@@ -36,22 +37,22 @@ export default defineAgentTool({
36
37
  every_seconds !== undefined ? "every" : undefined,
37
38
  ].filter(Boolean);
38
39
  if (modes.length !== 1) {
39
- throw new ReminderInputError("请在 after / at / every_seconds 中只选一种时间表达");
40
+ throw new ReminderInputError(t(context.locale, 'toolMode'));
40
41
  }
41
42
  const service = context.use(reminderServiceToken);
42
43
  const actor = reminderActorFromTool(context);
43
44
  if (every_seconds !== undefined) {
44
45
  const intervalMs = every_seconds * 1000;
45
46
  const task = await service.add(actor, text, Date.now() + intervalMs, intervalMs);
46
- return `已创建周期提醒\n${service.describe(task)}`;
47
+ return `${t(context.locale, 'createdPeriodic')}\n${service.describe(task, context.locale)}`;
47
48
  }
48
49
  if (after) {
49
- const delayMs = parseRelativeDelayMs(after);
50
+ const delayMs = parseRelativeDelayMs(after, context.locale);
50
51
  const task = await service.add(actor, text, Date.now() + delayMs, null);
51
- return `已创建提醒\n${service.describe(task)}`;
52
+ return `${t(context.locale, 'created')}\n${service.describe(task, context.locale)}`;
52
53
  }
53
- const task = await service.add(actor, text, parseReminderInstant(at), null);
54
- return `已创建提醒\n${service.describe(task)}`;
54
+ const task = await service.add(actor, text, parseReminderInstant(at, context.locale), null);
55
+ return `${t(context.locale, 'created')}\n${service.describe(task, context.locale)}`;
55
56
  });
56
57
  },
57
58
  });
@@ -1,3 +1,4 @@
1
+ import { reminderMessages as t } from '../../../../src/i18n.js';
1
2
  import { defineAgentTool } from "@zhin.js/tool";
2
3
  import { z } from "zod";
3
4
  import { replyReminder } from "../../../../src/caller.js";
@@ -45,7 +46,7 @@ export default defineAgentTool({
45
46
  ].filter(Boolean);
46
47
  if (modes.length !== 1) {
47
48
  throw new ReminderInputError(
48
- "请在 after / at / every_seconds 中只选一种时间表达"
49
+ t(context.locale, 'toolMode')
49
50
  );
50
51
  }
51
52
  const service = context.use(reminderServiceToken);
@@ -58,20 +59,20 @@ export default defineAgentTool({
58
59
  Date.now() + intervalMs,
59
60
  intervalMs
60
61
  );
61
- return `已创建周期提醒\n${service.describe(task)}`;
62
+ return `${t(context.locale, 'createdPeriodic')}\n${service.describe(task, context.locale)}`;
62
63
  }
63
64
  if (after) {
64
- const delayMs = parseRelativeDelayMs(after);
65
+ const delayMs = parseRelativeDelayMs(after, context.locale);
65
66
  const task = await service.add(actor, text, Date.now() + delayMs, null);
66
- return `已创建提醒\n${service.describe(task)}`;
67
+ return `${t(context.locale, 'created')}\n${service.describe(task, context.locale)}`;
67
68
  }
68
69
  const task = await service.add(
69
70
  actor,
70
71
  text,
71
- parseReminderInstant(at!),
72
+ parseReminderInstant(at!, context.locale),
72
73
  null
73
74
  );
74
- return `已创建提醒\n${service.describe(task)}`;
75
+ return `${t(context.locale, 'created')}\n${service.describe(task, context.locale)}`;
75
76
  });
76
77
  },
77
78
  });
@@ -1,4 +1,5 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { reminderMessages as t } from "../../../../lib/i18n.js";
2
3
  import { defineAgentTool } from "@zhin.js/tool";
3
4
  import { z } from "zod";
4
5
  import { replyReminder } from "../../../../lib/caller.js";
@@ -15,8 +16,8 @@ export default defineAgentTool({
15
16
  const service = context.use(reminderServiceToken);
16
17
  const tasks = await service.list(reminderActorFromTool(context));
17
18
  if (tasks.length === 0)
18
- return "当前会话没有提醒";
19
- return tasks.map((task) => service.describe(task)).join("\n---\n");
19
+ return t(context.locale, 'toolEmpty');
20
+ return tasks.map((task) => service.describe(task, context.locale)).join("\n---\n");
20
21
  });
21
22
  },
22
23
  });
@@ -1,3 +1,4 @@
1
+ import { reminderMessages as t } from '../../../../src/i18n.js';
1
2
  import { defineAgentTool } from "@zhin.js/tool";
2
3
  import { z } from "zod";
3
4
  import { replyReminder } from "../../../../src/caller.js";
@@ -15,8 +16,8 @@ export default defineAgentTool({
15
16
  return replyReminder(async () => {
16
17
  const service = context.use(reminderServiceToken);
17
18
  const tasks = await service.list(reminderActorFromTool(context));
18
- if (tasks.length === 0) return "当前会话没有提醒";
19
- return tasks.map((task) => service.describe(task)).join("\n---\n");
19
+ if (tasks.length === 0) return t(context.locale, 'toolEmpty');
20
+ return tasks.map((task) => service.describe(task, context.locale)).join("\n---\n");
20
21
  });
21
22
  },
22
23
  });