@wowyuarm/dsh-agent-team 0.1.11 → 0.1.12

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 (83) hide show
  1. package/README.md +4 -4
  2. package/README.zh.md +4 -4
  3. package/package.json +3 -2
  4. package/packages/agent-team/README.md +2 -2
  5. package/packages/agent-team/README.zh.md +2 -2
  6. package/packages/agent-team/lib/context-projection.js +5 -1
  7. package/packages/agent-team/lib/index.js +11 -44
  8. package/packages/agent-team/lib/ledger.js +251 -142
  9. package/packages/agent-team/lib/member-runtime.js +47 -9
  10. package/packages/agent-team/lib/mentions.js +56 -0
  11. package/packages/agent-team/lib/spec.js +1 -0
  12. package/packages/agent-team/lib/typert.host.js +80 -31
  13. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  14. package/packages/agent-team/lib/typert.remote-client.js +71 -26
  15. package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -1
  16. package/packages/agent-team/lib/types/index.d.ts +1 -7
  17. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  18. package/packages/agent-team/lib/types/ledger.d.ts +75 -17
  19. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  20. package/packages/agent-team/lib/types/member-runtime.d.ts +2 -1
  21. package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
  22. package/packages/agent-team/lib/types/mentions.d.ts +34 -0
  23. package/packages/agent-team/lib/types/mentions.d.ts.map +1 -0
  24. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  25. package/packages/agent-team/lib/types/types/entities.d.ts +0 -18
  26. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
  27. package/packages/agent-team/lib/types/types/requests-results.d.ts +57 -15
  28. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
  29. package/packages/agent-team/preset/team-member/agent.cordis.yml +48 -8
  30. package/packages/client-agent-team/lib/client.js +1366 -909
  31. package/packages/client-agent-team/lib/client.js.map +1 -1
  32. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  33. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +3 -3
  34. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts +18 -0
  35. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts.map +1 -0
  36. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.js +22 -0
  37. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +3 -1
  38. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  39. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +125 -13
  40. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
  41. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +10 -3
  42. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
  43. package/packages/client-agent-team/lib/types/client/TeamComposer.js +11 -17
  44. package/packages/client-agent-team/lib/types/client/TeamConversation.js +1 -1
  45. package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts +20 -0
  46. package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts.map +1 -0
  47. package/packages/client-agent-team/lib/types/client/TeamCountBadge.js +25 -0
  48. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +9 -5
  49. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -1
  50. package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +82 -14
  51. package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts +43 -0
  52. package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts.map +1 -0
  53. package/packages/client-agent-team/lib/types/client/TeamMemberRow.js +27 -0
  54. package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts +2 -2
  55. package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts.map +1 -1
  56. package/packages/client-agent-team/lib/types/client/TeamMembersAction.js +2 -2
  57. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  58. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +6 -2
  59. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  60. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +28 -10
  61. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  62. package/packages/client-agent-team/lib/types/client/index.js +3 -4
  63. package/packages/client-agent-team/lib/types/client/locales.d.ts +36 -16
  64. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  65. package/packages/client-agent-team/lib/types/client/locales.js +36 -16
  66. package/packages/client-agent-team/lib/types/client/slots.d.ts +0 -1
  67. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  68. package/packages/client-agent-team/lib/types/client/team-changes.d.ts +7 -1
  69. package/packages/client-agent-team/lib/types/client/team-changes.d.ts.map +1 -1
  70. package/packages/client-agent-team/lib/types/client/team-changes.js +62 -31
  71. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +38 -5
  72. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  73. package/packages/client-agent-team/lib/types/client/team-formatters.js +54 -7
  74. package/packages/tool-agent-team/README.md +2 -2
  75. package/packages/tool-agent-team/README.zh.md +2 -2
  76. package/packages/tool-agent-team/lib/index.js +29 -16
  77. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
  78. package/packages/agent-team/lib/progress-nudge.js +0 -328
  79. package/packages/agent-team/lib/types/progress-nudge.d.ts +0 -136
  80. package/packages/agent-team/lib/types/progress-nudge.d.ts.map +0 -1
  81. package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts +0 -3
  82. package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts.map +0 -1
  83. package/packages/client-agent-team/lib/types/client/TeamSettings.js +0 -5
@@ -27,14 +27,20 @@ export const zh = {
27
27
  statusError: '错误',
28
28
  statusUnavailable: '不可用',
29
29
  addChannel: '新建频道',
30
- mentionsOfMe: '提到我',
31
- mentionsOfMeWithCount: '提到我,{count} 条未读提及',
32
- loadingInbox: '正在加载提到我…',
33
- inboxEmptyTitle: '还没有人提到你',
34
- inboxEmptyHint: '需要你知道或做决定时,成员会提到你',
35
- inboxTimeToday: '今天',
30
+ inboxTitle: '收件箱',
31
+ inboxTitleWithCount: '收件箱,{count} 条未读',
32
+ loadingInbox: '正在加载收件箱…',
33
+ inboxEmptyTitle: '收件箱是空的',
34
+ inboxEmptyHint: '你参与的 Thread 有新活动、或有人提到你时,会出现在这里',
36
35
  inboxTimeYesterday: '昨天',
37
- inboxHeaderMeta: '共 {threads} 个 Thread · {mentions} 条提及,按最新提及排序',
36
+ inboxHeaderThreads: '{count} 个 Thread',
37
+ inboxHeaderUnread: '{count} 条未读',
38
+ inboxHeaderMentions: '{count} 条提及',
39
+ inboxRowUnread: '{count} 条未读',
40
+ inboxRowUnreadMentions: '{count} 条未读,其中 {mentions} 条提及',
41
+ inboxRowActor: '最新来自 {name}',
42
+ inboxSectionNeedsMe: '需要我',
43
+ inboxSectionRecent: '最近活跃',
38
44
  channelName: '名称',
39
45
  channelDescription: '说明',
40
46
  initialMembers: '初始成员',
@@ -100,12 +106,16 @@ export const zh = {
100
106
  taskStatusInReview: '待验收',
101
107
  taskStatusDone: '已完成',
102
108
  taskStatusClosed: '已关闭',
103
- taskMessageCount: '{count} 条消息',
104
109
  taskLabel: 'Task #{number}',
105
110
  taskPending: 'Task …',
106
111
  openTask: '打开 Task #{number}',
107
112
  openThread: '打开讨论',
113
+ openTaskUnread: '打开 Task #{number}({count} 条新动态)',
114
+ openThreadUnread: '打开讨论({count} 条新动态)',
108
115
  threadLabel: '讨论',
116
+ recentActivity: '最近活动 {time}',
117
+ replyAction: '回复',
118
+ claimers: '由 {names} 处理',
109
119
  asTask: '作为任务',
110
120
  promoteToTask: '转为 Task',
111
121
  promotingTask: '正在转为 Task…',
@@ -184,14 +194,20 @@ export const en = {
184
194
  statusError: 'Error',
185
195
  statusUnavailable: 'Unavailable',
186
196
  addChannel: 'New Channel',
187
- mentionsOfMe: 'Mentions of me',
188
- mentionsOfMeWithCount: 'Mentions of me, {count} unread mention(s)',
189
- loadingInbox: 'Loading mentions…',
190
- inboxEmptyTitle: 'Nobody has mentioned you yet',
191
- inboxEmptyHint: 'Members will mention you when you must know or decide',
192
- inboxTimeToday: 'Today',
197
+ inboxTitle: 'Inbox',
198
+ inboxTitleWithCount: 'Inbox, {count} unread',
199
+ loadingInbox: 'Loading Inbox…',
200
+ inboxEmptyTitle: 'Your Inbox is empty',
201
+ inboxEmptyHint: 'Threads you take part in appear here when they have new activity or mention you',
193
202
  inboxTimeYesterday: 'Yesterday',
194
- inboxHeaderMeta: '{threads} Thread(s) · {mentions} mention(s), newest first',
203
+ inboxHeaderThreads: '{count} Thread(s)',
204
+ inboxHeaderUnread: '{count} unread',
205
+ inboxHeaderMentions: '{count} mention(s)',
206
+ inboxRowUnread: '{count} unread',
207
+ inboxRowUnreadMentions: '{count} unread, {mentions} mention(s)',
208
+ inboxRowActor: 'Latest from {name}',
209
+ inboxSectionNeedsMe: 'Needs me',
210
+ inboxSectionRecent: 'Recently active',
195
211
  channelName: 'Name',
196
212
  channelDescription: 'Description',
197
213
  initialMembers: 'Initial members',
@@ -257,12 +273,16 @@ export const en = {
257
273
  taskStatusInReview: 'In review',
258
274
  taskStatusDone: 'Done',
259
275
  taskStatusClosed: 'Closed',
260
- taskMessageCount: '{count} messages',
261
276
  taskLabel: 'Task #{number}',
262
277
  taskPending: 'Task …',
263
278
  openTask: 'Open Task #{number}',
264
279
  openThread: 'Open thread',
280
+ openTaskUnread: 'Open Task #{number} ({count} new updates)',
281
+ openThreadUnread: 'Open thread ({count} new updates)',
265
282
  threadLabel: 'Thread',
283
+ recentActivity: 'Last activity {time}',
284
+ replyAction: 'Reply',
285
+ claimers: 'Handled by {names}',
266
286
  asTask: 'As task',
267
287
  promoteToTask: 'Convert to Task',
268
288
  promotingTask: 'Converting to Task…',
@@ -102,6 +102,5 @@ export interface TeamMemberGroup {
102
102
  }
103
103
  export type TeamFooterProps = PropsRuntime<'sidebar.footer.action'> & PropsLocale<'team'> & TeamNavigationActions & {
104
104
  navigation: TeamNavigationSource;
105
- loadMemberGroups: () => Promise<readonly TeamMemberGroup[]>;
106
105
  };
107
106
  //# sourceMappingURL=slots.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../../src/client/slots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACjF,OAAO,KAAK,EACV,yBAAyB,EACzB,8BAA8B,EAC9B,6BAA6B,EAC7B,6BAA6B,EAC7B,4BAA4B,EAC5B,mBAAmB,EACnB,2BAA2B,EAC3B,kCAAkC,EAClC,iCAAiC,EACjC,6BAA6B,EAC7B,4BAA4B,EAC5B,cAAc,EACd,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,EAC1B,6BAA6B,EAC7B,4BAA4B,EAC5B,6BAA6B,EAC7B,4BAA4B,EAC5B,qBAAqB,EACrB,6BAA6B,EAC7B,4BAA4B,EAC5B,uBAAuB,EACvB,mCAAmC,EACnC,kCAAkC,EAClC,qBAAqB,EACrB,+BAA+B,EAC/B,8BAA8B,EAC9B,oBAAoB,EACpB,6BAA6B,EAC7B,sBAAsB,EACtB,6BAA6B,EAC7B,2BAA2B,EAC3B,kCAAkC,EAClC,0BAA0B,EAC1B,yBAAyB,EACzB,6BAA6B,EAC7B,4BAA4B,EAC5B,oBAAoB,EACpB,mBAAmB,EACnB,2BAA2B,EAC3B,0BAA0B,EAC1B,6BAA6B,EAC7B,4BAA4B,EAC5B,4BAA4B,EAC5B,aAAa,EACb,oBAAoB,EACrB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACpF,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAC5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,sBAAsB,CAAA;IACzC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;CAChD;AAED,gGAAgG;AAChG,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,kBAAkB,KAAK,MAAM,IAAI,CAAA;AAEvG,wEAAwE;AACxE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,8EAA8E;AAC9E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE;QACnB,QAAQ,CAAC,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAA;KACnD,CAAA;CACF;AAED,2EAA2E;AAC3E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;CAC5C;AAED,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,SAAS,sBAAsB,EAAE,CAAA;IAClD,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CACvG;AAED,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC,oBAAoB,CAAC,GAC7D,WAAW,CAAC,MAAM,CAAC,GACnB,qBAAqB,GACrB;IACA,UAAU,EAAE,oBAAoB,CAAA;IAChC,WAAW,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,YAAY,CAAC,SAAS,2BAA2B,EAAE,CAAC,CAAC,CAAA;IAChH,oFAAoF;IACpF,SAAS,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC,CAAA;IACpF,+GAA+G;IAC/G,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;IACpD,gBAAgB,EAAE,oBAAoB,CAAA;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,yBAAyB,KAAK,OAAO,CAAC,YAAY,CAAC,qBAAqB,CAAC,CAAC,CAAA;IAC/F,YAAY,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAA;IACrF,aAAa,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,OAAO,CAAC,YAAY,CAAC,4BAA4B,CAAC,CAAC,CAAA;IAC9G,aAAa,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,OAAO,CAAC,YAAY,CAAC,4BAA4B,CAAC,CAAC,CAAA;IAC9G,cAAc,EAAE,CAAC,OAAO,EAAE,8BAA8B,KAAK,OAAO,CAAC,YAAY,CAAC,6BAA6B,CAAC,CAAC,CAAA;IACjH,YAAY,EAAE,CAAC,OAAO,EAAE,4BAA4B,KAAK,OAAO,CAAC,YAAY,CAAC,qBAAqB,CAAC,CAAC,CAAA;IACrG,aAAa,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,OAAO,CAAC,YAAY,CAAC,4BAA4B,CAAC,CAAC,CAAA;IAC9G;;;;OAIG;IACH,kBAAkB,EAAE,CAAC,OAAO,EAAE,kCAAkC,KAAK,OAAO,CAAC,YAAY,CAAC,iCAAiC,CAAC,CAAC,CAAA;IAC7H,aAAa,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,OAAO,CAAC,YAAY,CAAC,4BAA4B,CAAC,CAAC,CAAA;IAC9G,WAAW,EAAE,CAAC,OAAO,EAAE,2BAA2B,KAAK,OAAO,CAAC,YAAY,CAAC,0BAA0B,CAAC,CAAC,CAAA;IACxG,mBAAmB,EAAE,CAAC,OAAO,EAAE,mCAAmC,KAAK,OAAO,CAAC,YAAY,CAAC,kCAAkC,CAAC,CAAC,CAAA;IAChI,mFAAmF;IACnF,UAAU,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAA;IACzD,6EAA6E;IAC7E,iBAAiB,EAAE,CAAC,SAAS,EAAE,2BAA2B,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,KAAK,IAAI,CAAA;IAC1F,kBAAkB,CAAC,EAAE,mBAAmB,CAAA;CACzC,CAAA;AAEH,MAAM,MAAM,qBAAqB,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,GAAG,qBAAqB,GAAG;IACvG,UAAU,EAAE,oBAAoB,CAAA;IAChC,gEAAgE;IAChE,MAAM,EAAE,cAAc,CAAA;IACtB,YAAY,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAA;IACrF,UAAU,EAAE,CAAC,OAAO,EAAE,0BAA0B,KAAK,OAAO,CAAC,YAAY,CAAC,yBAAyB,CAAC,CAAC,CAAA;IACrG,iBAAiB,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,OAAO,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAC,CAAA;IAC5G,gBAAgB,EAAE,oBAAoB,CAAA;IACtC,aAAa,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,OAAO,CAAC,YAAY,CAAC,4BAA4B,CAAC,CAAC,CAAA;IAC9G,aAAa,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,OAAO,CAAC,YAAY,CAAC,4BAA4B,CAAC,CAAC,CAAA;IAC9G,WAAW,EAAE,CAAC,OAAO,EAAE,2BAA2B,KAAK,OAAO,CAAC,YAAY,CAAC,0BAA0B,CAAC,CAAC,CAAA;IACxG,WAAW,EAAE,CAAC,OAAO,EAAE,2BAA2B,KAAK,OAAO,CAAC,YAAY,CAAC,0BAA0B,CAAC,CAAC,CAAA;IACxG,mBAAmB,EAAE,CAAC,OAAO,EAAE,mCAAmC,KAAK,OAAO,CAAC,YAAY,CAAC,kCAAkC,CAAC,CAAC,CAAA;IAChI,KAAK,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,YAAY,CAAC,oBAAoB,GAAG,6BAA6B,CAAC,CAAC,CAAA;IACtH,UAAU,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,YAAY,CAAC,mBAAmB,CAAC,CAAC,CAAA;IACzF,aAAa,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,OAAO,CAAC,YAAY,CAAC,4BAA4B,CAAC,CAAC,CAAA;IAC9G,eAAe,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,OAAO,CAAC,YAAY,CAAC,8BAA8B,CAAC,CAAC,CAAA;IACpH,WAAW,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,YAAY,CAAC,SAAS,2BAA2B,EAAE,CAAC,CAAC,CAAA;IAChH,2FAA2F;IAC3F,SAAS,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC,CAAA;IACpF,wGAAwG;IACxG,kBAAkB,EAAE,CAAC,OAAO,EAAE,kCAAkC,KAAK,OAAO,CAAC,YAAY,CAAC,2BAA2B,CAAC,CAAC,CAAA;CACxH,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,YAAY,CAAC,kBAAkB,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,GAAG;IACvF,gBAAgB,EAAE,MAAM,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAAA;CAC5D,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,2BAA2B,EAAE,CAAA;CACzD;AAED,MAAM,MAAM,eAAe,GAAG,YAAY,CAAC,uBAAuB,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,GAAG,qBAAqB,GAAG;IAClH,UAAU,EAAE,oBAAoB,CAAA;IAChC,gBAAgB,EAAE,MAAM,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAAA;CAC5D,CAAA"}
1
+ {"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../../src/client/slots.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,13 @@ type ChangesFn = (request: AgentTeamChangesRequest, signal?: AbortSignal) => Pro
17
17
  * and pages never open parallel `changes` requests for the same scope, and
18
18
  * the poll is aborted as soon as the last subscriber leaves.
19
19
  *
20
+ * A failed call reports the outage to every listener once and then keeps
21
+ * retrying with backoff. The transport recovers on its own terms — a Host
22
+ * restart, a sleep/wake, a dropped proxy — and a surface that stayed mounted
23
+ * has to resume from that recovery rather than stay silent until it remounts,
24
+ * so the first answered call after an outage wakes every listener once even
25
+ * when the cursor did not move.
26
+ *
20
27
  * Each poll keeps its own cursor, and a cursor only means something inside the
21
28
  * scope it was issued for: the Host answers a presence scope from a
22
29
  * process-local wake epoch and every other scope from a durable ledger
@@ -34,7 +41,6 @@ export declare class TeamChangeStream {
34
41
  constructor(changes: ChangesFn);
35
42
  subscribe(scope: TeamChangeScope, listener: TeamChangeListener): () => void;
36
43
  private run;
37
- private fail;
38
44
  }
39
45
  /**
40
46
  * The Host's `changes` stream never wakes on a Thread read — a read advances
@@ -1 +1 @@
1
- {"version":3,"file":"team-changes.d.ts","sourceRoot":"","sources":["../../../src/client/team-changes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAA;AAE3H,mFAAmF;AACnF,MAAM,MAAM,eAAe,GAAG,oBAAoB,GAAG,SAAS,CAAA;AAE9D,2EAA2E;AAC3E,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAA;AAEnE,KAAK,SAAS,GAAG,CAAC,OAAO,EAAE,uBAAuB,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAC,CAAA;AAiB1H;;;;;;;;;GASG;AACH,qBAAa,gBAAgB;IASf,OAAO,CAAC,QAAQ,CAAC,OAAO;IARpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IACrD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;gBAExB,OAAO,EAAE,SAAS;IAE/C,SAAS,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI;YAmB7D,GAAG;IA2CjB,OAAO,CAAC,IAAI;CAKb;AAED;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAI;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAElD,IAAI,IAAI,IAAI;IAKZ,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;CAI5C"}
1
+ {"version":3,"file":"team-changes.d.ts","sourceRoot":"","sources":["../../../src/client/team-changes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAA;AAE3H,mFAAmF;AACnF,MAAM,MAAM,eAAe,GAAG,oBAAoB,GAAG,SAAS,CAAA;AAE9D,2EAA2E;AAC3E,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAA;AAEnE,KAAK,SAAS,GAAG,CAAC,OAAO,EAAE,uBAAuB,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAC,CAAA;AA8B1H;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,gBAAgB;IASf,OAAO,CAAC,QAAQ,CAAC,OAAO;IARpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IACrD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;gBAExB,OAAO,EAAE,SAAS;IAE/C,SAAS,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI;YAmB7D,GAAG;CA6DlB;AAED;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAI;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAElD,IAAI,IAAI,IAAI;IAKZ,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;CAI5C"}
@@ -1,3 +1,14 @@
1
+ /** First retry delay after a failed call, doubling up to the cap. */
2
+ const RETRY_BASE_MS = 1_000;
3
+ const RETRY_MAX_MS = 30_000;
4
+ /** Abortable delay: the poll's subscription ending must not wait out a backoff. */
5
+ function sleep(ms, signal) {
6
+ return new Promise(resolve => {
7
+ const done = () => { clearTimeout(timer); signal.removeEventListener('abort', done); resolve(); };
8
+ const timer = setTimeout(done, ms);
9
+ signal.addEventListener('abort', done, { once: true });
10
+ });
11
+ }
1
12
  function scopeKey(scope) {
2
13
  return scope === undefined ? 'all'
3
14
  : scope.kind === 'workspace' ? `workspace:${scope.workspaceId}`
@@ -10,6 +21,13 @@ function scopeKey(scope) {
10
21
  * and pages never open parallel `changes` requests for the same scope, and
11
22
  * the poll is aborted as soon as the last subscriber leaves.
12
23
  *
24
+ * A failed call reports the outage to every listener once and then keeps
25
+ * retrying with backoff. The transport recovers on its own terms — a Host
26
+ * restart, a sleep/wake, a dropped proxy — and a surface that stayed mounted
27
+ * has to resume from that recovery rather than stay silent until it remounts,
28
+ * so the first answered call after an outage wakes every listener once even
29
+ * when the cursor did not move.
30
+ *
13
31
  * Each poll keeps its own cursor, and a cursor only means something inside the
14
32
  * scope it was issued for: the Host answers a presence scope from a
15
33
  * process-local wake epoch and every other scope from a durable ledger
@@ -49,32 +67,52 @@ export class TeamChangeStream {
49
67
  async run(key, scope, poll) {
50
68
  const { signal } = poll.controller;
51
69
  const request = (afterVersion) => ({ afterVersion, ...(scope === undefined ? {} : { scope }) });
70
+ // No cursor yet means the opening sample still has to be taken. A failed
71
+ // call is reported once per outage and then retried, so a recovered
72
+ // transport resumes every mounted surface without a remount.
52
73
  let version = poll.resumeFrom;
53
- if (version === undefined) {
54
- // Nothing has been observed for this scope yet, so there is no cursor to
55
- // resume from: sample the current version silently, because the
56
- // subscribers just fetched their initial projection and an immediate wake
57
- // would double-fetch. This leaves one named gap — a commit landing between
58
- // that initial fetch being processed and this sample being answered is
59
- // missed until the next commit in the scope — which resuming from a known
60
- // version closes for every later subscription.
61
- const probe = await this.changes(request(0), signal);
62
- if (signal.aborted)
63
- return;
64
- if (!probe.ok) {
65
- this.fail(key, poll, probe.error.message);
66
- return;
67
- }
68
- version = probe.value.version;
69
- this.observed.set(key, version);
70
- }
74
+ let retryDelay = RETRY_BASE_MS;
75
+ let reported = false;
71
76
  while (!signal.aborted) {
72
- const result = await this.changes(request(version), signal);
73
- if (signal.aborted)
77
+ const result = await this.changes(request(version ?? 0), signal);
78
+ if (signal.aborted || this.polls.get(key) !== poll)
74
79
  return;
75
80
  if (!result.ok) {
76
- this.fail(key, poll, result.error.message);
77
- return;
81
+ if (!reported) {
82
+ reported = true;
83
+ for (const listener of poll.listeners)
84
+ listener({ type: 'failed', message: result.error.message });
85
+ }
86
+ await sleep(retryDelay, signal);
87
+ retryDelay = Math.min(retryDelay * 2, RETRY_MAX_MS);
88
+ continue;
89
+ }
90
+ retryDelay = RETRY_BASE_MS;
91
+ if (reported) {
92
+ // The first answered call after an outage is what recovery looks like
93
+ // from here: the Host's parked wait answers on its own deadline even
94
+ // when nothing committed, and while the transport was gone each
95
+ // surface's own reads failed too. An unchanged cursor is still news to
96
+ // them, so the recovery re-anchors every listener once instead of
97
+ // waiting for the next unrelated commit.
98
+ reported = false;
99
+ version = result.value.version;
100
+ this.observed.set(key, version);
101
+ for (const listener of poll.listeners)
102
+ listener({ type: 'changed', version });
103
+ continue;
104
+ }
105
+ if (version === undefined) {
106
+ // Nothing has been observed for this scope yet, so there is no cursor to
107
+ // resume from: sample the current version silently, because the
108
+ // subscribers just fetched their initial projection and an immediate wake
109
+ // would double-fetch. This leaves one named gap — a commit landing between
110
+ // that initial fetch being processed and this sample being answered is
111
+ // missed until the next commit in the scope — which resuming from a known
112
+ // version closes for every later subscription.
113
+ version = result.value.version;
114
+ this.observed.set(key, version);
115
+ continue;
78
116
  }
79
117
  this.observed.set(key, result.value.version);
80
118
  // Any difference is a resolution in this scope's own cursor domain —
@@ -82,8 +120,8 @@ export class TeamChangeStream {
82
120
  // scopes count different things) or from an earlier Host lifetime can sit
83
121
  // ahead of the domain value. Re-anchoring on difference instead of only
84
122
  // on growth keeps such a subscription observable rather than silently
85
- // parked, and the Host never answers a request whose cursor already
86
- // equals the domain value, so this cannot spin.
123
+ // parked. The Host answers an equal cursor only on its keep-alive
124
+ // deadline, so this stays one comparison per answered call, never a spin.
87
125
  if (result.value.version !== version) {
88
126
  version = result.value.version;
89
127
  for (const listener of poll.listeners)
@@ -91,13 +129,6 @@ export class TeamChangeStream {
91
129
  }
92
130
  }
93
131
  }
94
- fail(key, poll, message) {
95
- // A dead poll must not stay registered: the next subscriber restarts it.
96
- if (this.polls.get(key) === poll)
97
- this.polls.delete(key);
98
- for (const listener of poll.listeners)
99
- listener({ type: 'failed', message });
100
- }
101
132
  }
102
133
  /**
103
134
  * The Host's `changes` stream never wakes on a Thread read — a read advances
@@ -1,4 +1,4 @@
1
- import type { AgentTeamActivity, AgentTeamClaim, AgentTeamMemberId, AgentTeamTask, AgentTeamTaskRef } from '@wowyuarm/dsh-agent-team/types';
1
+ import type { AgentTeamActivity, AgentTeamClaim, AgentTeamClientMemberStatus, AgentTeamMemberId, AgentTeamTask, AgentTeamTaskRef } from '@wowyuarm/dsh-agent-team/types';
2
2
  import type { TeamConversationProps } from './slots.ts';
3
3
  import type { TeamStateDotState } from './TeamStateDot.tsx';
4
4
  export declare function formatTaskStatus(status: AgentTeamTask['status'], t: TeamConversationProps['t']): string;
@@ -52,6 +52,36 @@ export declare function splitMentionNames(text: string, names: readonly string[]
52
52
  segments: MentionSegment[];
53
53
  unmatched: readonly string[];
54
54
  };
55
+ /**
56
+ * Whether one draft spells a handle as an authored `@mention`: a literal `@`
57
+ * before the handle, case-insensitively, on Unicode word boundaries. The Host
58
+ * resolves delivery from the same text with its own scanner, so this is the
59
+ * Client's single answer to "did the author call this name" — the composer
60
+ * prunes picked recipients with it and previews the draft's notifications with
61
+ * it.
62
+ */
63
+ export declare function containsMention(body: string, handle: string): boolean;
64
+ /** Whether one draft carries the `@all` marker the mention menu expands. */
65
+ export declare function containsAllMention(body: string): boolean;
66
+ /**
67
+ * Every Member the mention menu's `@all` row stands for: the roster this
68
+ * composer was handed minus Members who cannot take a Message right now — the
69
+ * same filter the per-handle rows apply, so the expansion and the menu agree.
70
+ */
71
+ export declare function allMentionMembers(members: readonly AgentTeamClientMemberStatus[]): readonly AgentTeamClientMemberStatus[];
72
+ /**
73
+ * Member ids one draft asks to notify by text alone: the Client's preview of
74
+ * the Host's own body mention resolution, so a hand-typed `@Handle` reports
75
+ * exactly like a pick from the mention menu. `@all` stands for the menu's
76
+ * expansion; a written handle counts whenever its Member can still take a
77
+ * Message — state decides, not presence, because an offline Member is notified
78
+ * and reads it later.
79
+ *
80
+ * The result is preview-only. Only picked recipients travel as explicit
81
+ * recipients, where a name the Channel cannot reach would be a rejected target
82
+ * rather than the prose the Host reads.
83
+ */
84
+ export declare function mentionedMemberIds(body: string, members: readonly AgentTeamClientMemberStatus[]): readonly AgentTeamMemberId[];
55
85
  /** Canonical chip handles for one Message's structured mention refs. */
56
86
  export declare function mentionNamesOf(mentions: readonly AgentTeamMemberId[], handles: ReadonlyMap<AgentTeamMemberId, string>): string[];
57
87
  /**
@@ -70,10 +100,13 @@ export declare function formatAbsoluteTime(occurredAt: string): string;
70
100
  */
71
101
  export declare function formatMessageTime(occurredAt: string, now?: Date): string;
72
102
  /**
73
- * Queue label for one Inbox row's newest mention. The mention queue scans by
74
- * recency, so the two days a reader reasons about by name are named ("今天" /
75
- * "昨天") while everything older keeps the Message date form, so the row and
76
- * the Thread it opens agree about the same instant.
103
+ * Recency label for one Inbox row's newest fact, shared with the Channel feed's
104
+ * entry line so the two agree about the same instant. Today is a bare clock time
105
+ * — the reader is in today, and 「今天」 printed down every row spends the label's
106
+ * first word on the one segment that never varies, while `HH:mm` alone still
107
+ * reads as a clock because it is exactly one. The first day that is not today is
108
+ * the fact the reader has to be told, so it keeps its word; everything older
109
+ * keeps the Message date form, so the row and the Thread it opens agree.
77
110
  */
78
111
  export declare function formatInboxTime(occurredAt: string, t: TeamConversationProps['t'], now?: Date): string;
79
112
  export declare function formatActivity(activity: AgentTeamActivity, options: {
@@ -1 +1 @@
1
- {"version":3,"file":"team-formatters.d.ts","sourceRoot":"","sources":["../../../src/client/team-formatters.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"team-formatters.d.ts","sourceRoot":"","sources":["../../../src/client/team-formatters.ts"],"names":[],"mappings":"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"}
@@ -117,6 +117,49 @@ export function splitMentionNames(text, names) {
117
117
  segments.push({ text: text.slice(cursor), mention: false });
118
118
  return { segments, unmatched: names.filter(name => !matched.has(name.toLowerCase())) };
119
119
  }
120
+ /**
121
+ * Whether one draft spells a handle as an authored `@mention`: a literal `@`
122
+ * before the handle, case-insensitively, on Unicode word boundaries. The Host
123
+ * resolves delivery from the same text with its own scanner, so this is the
124
+ * Client's single answer to "did the author call this name" — the composer
125
+ * prunes picked recipients with it and previews the draft's notifications with
126
+ * it.
127
+ */
128
+ export function containsMention(body, handle) {
129
+ return new RegExp(`(?:^|[^\\p{L}\\p{N}_])@${escapeRegExp(handle)}(?=$|[^\\p{L}\\p{N}_])`, 'iu').test(body);
130
+ }
131
+ /** Whether one draft carries the `@all` marker the mention menu expands. */
132
+ export function containsAllMention(body) {
133
+ return /(?<![\p{L}\p{N}_@])@all(?=$|[^\p{L}\p{N}_])/u.test(body);
134
+ }
135
+ /**
136
+ * Every Member the mention menu's `@all` row stands for: the roster this
137
+ * composer was handed minus Members who cannot take a Message right now — the
138
+ * same filter the per-handle rows apply, so the expansion and the menu agree.
139
+ */
140
+ export function allMentionMembers(members) {
141
+ return members.filter(status => status.presence !== 'unavailable' && status.member.state !== 'inactive' && status.member.state !== 'archived');
142
+ }
143
+ /**
144
+ * Member ids one draft asks to notify by text alone: the Client's preview of
145
+ * the Host's own body mention resolution, so a hand-typed `@Handle` reports
146
+ * exactly like a pick from the mention menu. `@all` stands for the menu's
147
+ * expansion; a written handle counts whenever its Member can still take a
148
+ * Message — state decides, not presence, because an offline Member is notified
149
+ * and reads it later.
150
+ *
151
+ * The result is preview-only. Only picked recipients travel as explicit
152
+ * recipients, where a name the Channel cannot reach would be a rejected target
153
+ * rather than the prose the Host reads.
154
+ */
155
+ export function mentionedMemberIds(body, members) {
156
+ if (containsAllMention(body))
157
+ return allMentionMembers(members).map(status => status.member.memberId);
158
+ return members
159
+ .filter(status => status.member.state !== 'inactive' && status.member.state !== 'archived')
160
+ .filter(status => containsMention(body, status.member.handle))
161
+ .map(status => status.member.memberId);
162
+ }
120
163
  /** Canonical chip handles for one Message's structured mention refs. */
121
164
  export function mentionNamesOf(mentions, handles) {
122
165
  return mentions
@@ -168,19 +211,23 @@ function calendarDayDelta(at, now) {
168
211
  return Math.round((midnight(now) - midnight(at)) / 86_400_000);
169
212
  }
170
213
  /**
171
- * Queue label for one Inbox row's newest mention. The mention queue scans by
172
- * recency, so the two days a reader reasons about by name are named ("今天" /
173
- * "昨天") while everything older keeps the Message date form, so the row and
174
- * the Thread it opens agree about the same instant.
214
+ * Recency label for one Inbox row's newest fact, shared with the Channel feed's
215
+ * entry line so the two agree about the same instant. Today is a bare clock time
216
+ * — the reader is in today, and 「今天」 printed down every row spends the label's
217
+ * first word on the one segment that never varies, while `HH:mm` alone still
218
+ * reads as a clock because it is exactly one. The first day that is not today is
219
+ * the fact the reader has to be told, so it keeps its word; everything older
220
+ * keeps the Message date form, so the row and the Thread it opens agree.
175
221
  */
176
222
  export function formatInboxTime(occurredAt, t, now = new Date()) {
177
223
  const at = new Date(occurredAt);
178
224
  if (Number.isNaN(at.getTime()))
179
225
  return '';
180
226
  const days = calendarDayDelta(at, now);
181
- if (days === 0 || days === 1) {
182
- return `${t(days === 0 ? 'inboxTimeToday' : 'inboxTimeYesterday')} ${pad(at.getHours())}:${pad(at.getMinutes())}`;
183
- }
227
+ if (days === 0)
228
+ return `${pad(at.getHours())}:${pad(at.getMinutes())}`;
229
+ if (days === 1)
230
+ return `${t('inboxTimeYesterday')} ${pad(at.getHours())}:${pad(at.getMinutes())}`;
184
231
  return formatMessageTime(occurredAt, now);
185
232
  }
186
233
  export function formatActivity(activity, options) {
@@ -7,7 +7,7 @@ Model-facing tools for Agent Team Members. The package registers tools in the ca
7
7
  ## Tools
8
8
 
9
9
  - `team_inbox` lists bounded unread Thread summaries for the calling Member, ordered by direct work and then recency; Task standing appears only where the Thread has a real Task overlay. The header states total unread/direct counts and the number of Threads shown (with a truncation conclusion when unread work lies beyond the bounded list); each item shows its exact unread/direct counts, Channel ref, and Task standing. The footer routes reading to `team_thread read`; the render carries no revision and no write token.
10
- - `team_thread` reads a Thread, pages history, follows, or unfollows. `threadRef` is primary; a `taskRef` is a Host alias only for released task-only Clients. The five actions render separately: `status`/`follow`/`unfollow` answer only the Attention question in one line; `read` renders outcome, Thread identity, orientation (full anchor when Host-supplied background is present, bounded anchor subject otherwise, never a duplicate of an in-facts anchor), active Claims only, the chronological facts with inline unread/direct markers, and a read-through/remaining-unread footer; `history` renders a historical page with the full anchor on a first page and the bounded subject on continuation pages, never current Claims or advice. `read` advances the durable watermark and is the only read-side source of a next-write token — rendered only when no unread remains; your own committed public mutations hand off a fresh token as well. A read with nothing unread for the caller advances nothing, writes no operation, and renders `Read — no unread updates …` instead of claiming a commit, still answering from the current projection. Activity facts render structured — actor, Task ref, and the Claim refs each activity claimed, completed, accepted, or released. A read that acknowledges an unread acceptance of a still-done Task carries one `contextAdvice` block (usage, route budgets, the `min(128_000, handoffAt)` Task-boundary threshold, and one keep/rollover/handoff-now action); it is advisory only and degrades to an explicit `unavailable` line when measurement fails.
10
+ - `team_thread` reads a Thread, pages history, follows, or unfollows. `threadRef` is primary; a `taskRef` is a Host alias only for released task-only Clients. The five actions render separately: `status`/`follow`/`unfollow` answer only the Attention question in one line; `read` renders outcome, Thread identity, orientation (full anchor when Host-supplied background is present, bounded anchor subject otherwise — and no background at all for a Member re-entering a Thread it has already read, so its orientation there is that subject plus this batch — never a duplicate of an in-facts anchor), active Claims only, the chronological facts with inline unread/direct markers, and a read-through/remaining-unread footer that also states how many Thread facts precede the watermark whenever the read left any behind; `history` renders a historical page with the full anchor on a first page and the bounded subject on continuation pages, never current Claims or advice. `read` advances the durable watermark and is the only read-side source of a next-write token — rendered only when no unread remains; your own committed public mutations hand off a fresh token as well. A read with nothing unread for the caller advances nothing, writes no operation, and renders `Read — no unread updates …` instead of claiming a commit, still answering from the current projection. Activity facts render structured — actor, Task ref, and the Claim refs each activity claimed, completed, accepted, or released. A read that acknowledges an unread acceptance of a still-done Task carries one `contextAdvice` block (usage, route budgets, the `min(128_000, handoffAt)` Task-boundary threshold, and one keep/rollover/handoff-now action); it is advisory only and degrades to an explicit `unavailable` line when measurement fails.
11
11
  - `team_message` starts a top-level Thread, replies to an existing Thread, or sends a DM. It defaults to a taskless Thread; pass `asTask: true` for atomic Task creation. A committed start/reply renders one committed-verb outcome (Thread created / reply added) with the Message, Thread, and optional Task refs, and exactly one next-write token hand-off. Replies reject unread work before checking token freshness. Typed rejections begin `Not committed`, keep the structured refs and counts needed to reread and retry, and render no numeric revision or write token — recovery is read-and-reconsider. DMs distinguish `Delivered` from `Recorded, not delivered` (with the delivery note and a no-blind-duplicate warning).
12
12
  - `team_claim` lists or mutates the calling Member's Direction Claims through `list`, `claim`, `done`, and `release`; it applies only to real Tasks. `list` renders the Task/Thread identity with active Claims only (the collision surface) and no write token. A committed mutation names its action (Claim created/completed/released), renders the authoritative affected Claim first, and hands off one next-write token. Rejections share the message rejection form. Direction exclusion uses Unicode NFKC normalization, trim, whitespace compression, and deterministic case folding.
13
13
  - `team_view` is the address book: bounded, membership-authorized Channel, top-level Thread, and Member summaries — current addresses, not a work queue. Threads are the sole paginated catalog: newest-first rows carrying threadRef, Channel ref, a bounded anchor subject, and Task standing inline (never a second Task index, never revision or message count). The cursor pages Thread rows only; continuation pages render Threads alone, and paging reaches every authorized top-level Thread, including taskless and off-page taskful ones.
@@ -15,7 +15,7 @@ Model-facing tools for Agent Team Members. The package registers tools in the ca
15
15
  - `context_checkpoint` records one named checkpoint of the calling Member's current context. The durable checkpoint is the successful `tool/call`+`tool/result` pair the Session projection folds; the returned ref is deterministic from the Member Session identity plus the tool call id. It performs no lifecycle side effect in the tool body and concludes the turn: a checkpoint resolves at its containing turn's end, so the model records it as its final action of a completed unit of work.
16
16
  - `context_timeline` returns one bounded structural view of the Member's context generations across the current Session and its archived ancestor lineage: recorded checkpoints and handoff/Team/compaction boundaries, with restorability reasons where a return cannot be proven safe. Structural only — no transcript content. A fresh `context_rollover` never requires consulting the timeline first.
17
17
 
18
- An Agent cannot silently enroll an unfollowed Agent through a mention; the Host returns `member_not_following`. Human confirmation is a separate Host/Client flow. Closed Tasks reject replies, Claims, and new Attention until a Human reopens them; taskless Threads have no Claim or Task-resolution mutation path.
18
+ Mentions are authored in the Message body, as `@Handle` (the `@` is required, matching ignores case, and `@all` reaches the Channel); there is no recipient parameter. An Agent cannot silently enroll an uninvited Member: naming one this Thread has never carried commits the Message, delivers nothing to that Member, and reports them as undelivered. Human confirmation is a separate Host/Client flow. Closed Tasks reject replies, Claims, and new Attention until a Human reopens them; taskless Threads have no Claim or Task-resolution mutation path.
19
19
 
20
20
  Every agent-facing render carries absolute event instants in the fixed Team coordination zone UTC+8 with an explicit offset (`2026-09-08T17:00:00+08:00`): `team_thread` fact lines and anchors stamp each fact with its committing operation's instant, `team_inbox` rows carry `newestOccurredAt`, `team_view` Thread rows carry `lastActivityAt`, notifications state `Occurred at:`, and committed mutations render `Committed at:` from the receipt. The same stored instant renders byte-identically on every reread path; only absolute timestamps are rendered, never relative text, and sequence and revision — not wall-clock time — remain the ordering authority.
21
21
 
@@ -7,7 +7,7 @@
7
7
  ## 工具
8
8
 
9
9
  - `team_inbox` 列出调用方 Member 的有界未读 Thread 摘要,先按 direct work、再按最近活动排序;只有 Thread 存在真实 Task overlay 时才出现 Task standing。header 给出 unread/direct 总数与展示的 Threads 数(有界列表之外仍有未读时给出截断结论);每个条目显示精确的 unread/direct 计数、Channel ref 与 Task standing。页脚把阅读指向 `team_thread read`;渲染不携带 revision 与写令牌。
10
- - `team_thread` 读取 Thread、分页历史、follow 或 unfollow。`threadRef` 是主身份;`taskRef` 只对 released task-only Client 是 Host alias。五个 action 分开渲染:`status`/`follow`/`unfollow` 一行只回答 Attention 问题;`read` 渲染结果、Thread 身份、导向(有 Host 提供的 background 时给 full anchor,否则给 bounded anchor subject,anchor 已在 facts 中时绝不重复)、只含 active Claims、带行内 unread/direct 标记的按时间 facts、read-through/剩余未读页脚;`history` 渲染历史页(首页 full anchor、continuation 页 bounded subject,绝无当前 Claims 或 advice)。`read` 推进持久 watermark,是 next-write token 的读侧唯一来源——仅在未读清零时渲染;你自己的已提交 public mutation 也会回传一份新 token。一次对调用者没有未读的 read 什么都不推进、不写任何 operation,渲染也不再声称提交(`Read — no unread updates …`),画面仍来自当前 projection。Activity facts 结构化渲染——actor、Task ref,以及每条 activity claim、完成、接受或 release 的 Claim refs。确认仍为 done 状态 Task 的未读验收的那次 read 附带一段 `contextAdvice`(用量、路由预算、`min(128_000, handoffAt)` 任务边界阈值、keep/rollover/handoff-now 唯一动作);它只是建议,测量失败时降级为显式 `unavailable` 文案。
10
+ - `team_thread` 读取 Thread、分页历史、follow 或 unfollow。`threadRef` 是主身份;`taskRef` 只对 released task-only Client 是 Host alias。五个 action 分开渲染:`status`/`follow`/`unfollow` 一行只回答 Attention 问题;`read` 渲染结果、Thread 身份、导向(有 Host 提供的 background 时给 full anchor,否则给 bounded anchor subject——重新进入自己读过的 Thread 的 Member 完全没有 background,它在那里的定位就是该 subject 加本次 batch——anchor 已在 facts 中时绝不重复)、只含 active Claims、带行内 unread/direct 标记的按时间 facts、read-through/剩余未读页脚(只要这次 read 身后留有 Thread facts,页脚同时给出那些 facts 的数量);`history` 渲染历史页(首页 full anchor、continuation 页 bounded subject,绝无当前 Claims 或 advice)。`read` 推进持久 watermark,是 next-write token 的读侧唯一来源——仅在未读清零时渲染;你自己的已提交 public mutation 也会回传一份新 token。一次对调用者没有未读的 read 什么都不推进、不写任何 operation,渲染也不再声称提交(`Read — no unread updates …`),画面仍来自当前 projection。Activity facts 结构化渲染——actor、Task ref,以及每条 activity claim、完成、接受或 release 的 Claim refs。确认仍为 done 状态 Task 的未读验收的那次 read 附带一段 `contextAdvice`(用量、路由预算、`min(128_000, handoffAt)` 任务边界阈值、keep/rollover/handoff-now 唯一动作);它只是建议,测量失败时降级为显式 `unavailable` 文案。
11
11
  - `team_message` 创建顶层 Thread、回复既有 Thread 或发送 DM。默认创建 taskless Thread;传入 `asTask: true` 才原子创建 Task。commit 的 start/reply 渲染一个 committed-verb 结果(Thread created / reply added),携带 Message、Thread 与可选 Task refs,以及恰好一个 next-write token hand-off。Reply 在检查令牌新鲜度前先拒绝未读工作。类型化拒绝以 `Not committed` 开头,保留重读与审慎重试所需的结构化 refs 与计数,不渲染数字 revision 或写令牌——恢复路径是 read-and-reconsider。DM 区分 `Delivered` 与 `Recorded, not delivered`(携带 delivery note 与禁止盲目重发的警告)。
12
12
  - `team_claim` 通过 `list`、`claim`、`done`、`release` 读取或修改调用方 Member 的 Direction Claim;它只适用于真实 Task。`list` 渲染 Task/Thread 身份与只有 active Claims 的 collision surface,且无写令牌。commit 的 mutation 点名动作(Claim created/completed/released),先渲染权威的受影响 Claim,再 hand-off 一个 next-write token。拒绝与 message 拒绝共享同一形式。Direction 互斥键执行 Unicode NFKC normalization、trim、空白压缩和确定性大小写折叠。
13
13
  - `team_view` 是 address book:有界、按 membership 授权的 Channel、顶层 Thread 与 Member 摘要——是当前的地址簿,不是工作队列。Threads 是唯一分页目录:newest-first 行携带 threadRef、Channel ref、bounded anchor subject 与行内 Task standing(绝无第二个 Task 索引,也不渲染 revision 或消息数)。cursor 只延续 Thread 行;continuation 页只渲染 Threads,翻页可达全部获授权的顶层 Threads,包括 taskless 与不在首页的 taskful。
@@ -15,7 +15,7 @@
15
15
  - `context_checkpoint` 为调用的 Member 记录一个命名的当前上下文 checkpoint。durable checkpoint 就是 Session projection 折叠的成功 `tool/call`+`tool/result` 对;返回的 ref 由 Member Session 身份加 tool call id 确定性派生。工具体不做 lifecycle 副作用,但会结束 turn:checkpoint 在其所属 turn 结束时 resolve,因此模型把它作为一个完整工作单元的最后动作来记录。
16
16
  - `context_timeline` 返回该 Member 跨当前 Session 与已归档祖先 lineage 的上下文代际有界结构视图:已记录的 checkpoints 与 handoff/Team/compaction 边界,无法证明可安全回返的条目携带拒绝原因。仅结构信息——不含任何 transcript 正文。fresh 的 `context_rollover` 从不需要先查 timeline。
17
17
 
18
- Agent 不能通过 mention 静默把另一个 unfollowed Agent 加入 Thread;Host 返回 `member_not_following`。Human confirmation 属于单独的 Host/Client 流程。Closed Task 在 Human reopen 前拒绝 reply、Claim 和新的 Attention;taskless Thread 没有 Claim 或 Task resolution mutation path。
18
+ mention 在 Message 正文里撰写,形如 `@Handle`(`@` 必需、大小写不敏感,`@all` 触达整个 Channel);不存在收件人参数。Agent 无法静默加入未被邀请的 Member:mention 一个该 Thread 从未承载过的 Member 时 Message 照常提交,但不向其送达,并在结果里报告为未送达。Human confirmation 属于单独的 Host/Client 流程。Closed Task 在 Human reopen 前拒绝 reply、Claim 和新的 Attention;taskless Thread 没有 Claim 或 Task resolution mutation path。
19
19
 
20
20
  所有 agent-facing 渲染都在固定的 Team 协调时区 UTC+8 下携带带显式偏移的绝对事件时刻(`2026-09-08T17:00:00+08:00`):`team_thread` 的 fact 行与 anchor 为每条 fact 标注其提交 operation 的时刻,`team_inbox` 行携带 `newestOccurredAt`,`team_view` 的 Thread 行携带 `lastActivityAt`,通知给出 `Occurred at:`,已提交变更从 receipt 渲染 `Committed at:`。同一存储时刻在任何重读路径中渲染完全一致;只渲染绝对 timestamp,绝不出现相对时间文案,且 sequence 与 revision——而非 wall-clock 时间——仍是顺序 authority。
21
21