@wowyuarm/dsh-agent-team 0.1.10 → 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 (135) hide show
  1. package/README.md +17 -4
  2. package/README.zh.md +17 -4
  3. package/package.json +53 -47
  4. package/packages/agent-team/README.md +6 -4
  5. package/packages/agent-team/README.zh.md +6 -4
  6. package/packages/agent-team/lib/context-management.js +40 -50
  7. package/packages/agent-team/lib/context-projection.js +15 -1
  8. package/packages/agent-team/lib/index.js +244 -154
  9. package/packages/agent-team/lib/invariant.js +38 -4
  10. package/packages/agent-team/lib/ledger.js +775 -383
  11. package/packages/agent-team/lib/member-context.js +6 -2
  12. package/packages/agent-team/lib/member-runtime.js +47 -9
  13. package/packages/agent-team/lib/member-time-context.js +20 -5
  14. package/packages/agent-team/lib/mentions.js +56 -0
  15. package/packages/agent-team/lib/pressure-policy.js +33 -9
  16. package/packages/agent-team/lib/session-event-cursor.js +116 -0
  17. package/packages/agent-team/lib/session-remediation.js +38 -26
  18. package/packages/agent-team/lib/spec.js +47 -34
  19. package/packages/agent-team/lib/stored-session-reader.js +138 -0
  20. package/packages/agent-team/lib/typert.host.js +157 -41
  21. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  22. package/packages/agent-team/lib/typert.remote-client.js +129 -32
  23. package/packages/agent-team/lib/types/context-management.d.ts +7 -0
  24. package/packages/agent-team/lib/types/context-management.d.ts.map +1 -1
  25. package/packages/agent-team/lib/types/context-projection.d.ts +8 -0
  26. package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -1
  27. package/packages/agent-team/lib/types/index.d.ts +77 -7
  28. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  29. package/packages/agent-team/lib/types/invariant.d.ts.map +1 -1
  30. package/packages/agent-team/lib/types/ledger.d.ts +251 -20
  31. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  32. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  33. package/packages/agent-team/lib/types/member-runtime.d.ts +2 -1
  34. package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
  35. package/packages/agent-team/lib/types/member-time-context.d.ts.map +1 -1
  36. package/packages/agent-team/lib/types/mentions.d.ts +34 -0
  37. package/packages/agent-team/lib/types/mentions.d.ts.map +1 -0
  38. package/packages/agent-team/lib/types/pressure-policy.d.ts +18 -0
  39. package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -1
  40. package/packages/agent-team/lib/types/session-event-cursor.d.ts +119 -0
  41. package/packages/agent-team/lib/types/session-event-cursor.d.ts.map +1 -0
  42. package/packages/agent-team/lib/types/session-remediation.d.ts +23 -0
  43. package/packages/agent-team/lib/types/session-remediation.d.ts.map +1 -1
  44. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  45. package/packages/agent-team/lib/types/stored-session-reader.d.ts +92 -0
  46. package/packages/agent-team/lib/types/stored-session-reader.d.ts.map +1 -0
  47. package/packages/agent-team/lib/types/types/entities.d.ts +28 -20
  48. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
  49. package/packages/agent-team/lib/types/types/operations.d.ts +45 -19
  50. package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
  51. package/packages/agent-team/lib/types/types/requests-results.d.ts +87 -4
  52. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
  53. package/packages/agent-team/preset/team-member/agent.cordis.yml +49 -7
  54. package/packages/client-agent-team/README.md +1 -1
  55. package/packages/client-agent-team/README.zh.md +1 -1
  56. package/packages/client-agent-team/lib/client.js +2357 -1207
  57. package/packages/client-agent-team/lib/client.js.map +1 -1
  58. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  59. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +27 -7
  60. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts +18 -0
  61. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts.map +1 -0
  62. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.js +22 -0
  63. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +3 -1
  64. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  65. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +167 -35
  66. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
  67. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +23 -27
  68. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts +11 -5
  69. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
  70. package/packages/client-agent-team/lib/types/client/TeamComposer.js +26 -26
  71. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
  72. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
  73. package/packages/client-agent-team/lib/types/client/TeamConversation.js +9 -2
  74. package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts +20 -0
  75. package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts.map +1 -0
  76. package/packages/client-agent-team/lib/types/client/TeamCountBadge.js +25 -0
  77. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +25 -0
  78. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -0
  79. package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +139 -0
  80. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -1
  81. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +8 -24
  82. package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts +43 -0
  83. package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts.map +1 -0
  84. package/packages/client-agent-team/lib/types/client/TeamMemberRow.js +27 -0
  85. package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts +2 -2
  86. package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts.map +1 -1
  87. package/packages/client-agent-team/lib/types/client/TeamMembersAction.js +2 -2
  88. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts +9 -2
  89. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
  90. package/packages/client-agent-team/lib/types/client/TeamMessage.js +11 -4
  91. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +8 -0
  92. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
  93. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.js +21 -1
  94. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  95. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +108 -30
  96. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  97. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  98. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +68 -7
  99. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  100. package/packages/client-agent-team/lib/types/client/index.js +19 -9
  101. package/packages/client-agent-team/lib/types/client/locales.d.ts +40 -2
  102. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  103. package/packages/client-agent-team/lib/types/client/locales.js +40 -2
  104. package/packages/client-agent-team/lib/types/client/navigation.d.ts +10 -0
  105. package/packages/client-agent-team/lib/types/client/navigation.d.ts.map +1 -1
  106. package/packages/client-agent-team/lib/types/client/navigation.js +18 -7
  107. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts +41 -0
  108. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts.map +1 -0
  109. package/packages/client-agent-team/lib/types/client/scope-coverage.js +64 -0
  110. package/packages/client-agent-team/lib/types/client/slots.d.ts +7 -2
  111. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  112. package/packages/client-agent-team/lib/types/client/team-changes.d.ts +33 -2
  113. package/packages/client-agent-team/lib/types/client/team-changes.d.ts.map +1 -1
  114. package/packages/client-agent-team/lib/types/client/team-changes.js +107 -25
  115. package/packages/client-agent-team/lib/types/client/team-dialog-save.d.ts +20 -0
  116. package/packages/client-agent-team/lib/types/client/team-dialog-save.d.ts.map +1 -0
  117. package/packages/client-agent-team/lib/types/client/team-dialog-save.js +36 -0
  118. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +43 -1
  119. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  120. package/packages/client-agent-team/lib/types/client/team-formatters.js +81 -6
  121. package/packages/tool-agent-team/README.md +2 -2
  122. package/packages/tool-agent-team/README.zh.md +2 -2
  123. package/packages/tool-agent-team/lib/context-tools.js +18 -14
  124. package/packages/tool-agent-team/lib/host-access.js +20 -0
  125. package/packages/tool-agent-team/lib/index.js +44 -32
  126. package/packages/tool-agent-team/lib/types/context-tools.d.ts.map +1 -1
  127. package/packages/tool-agent-team/lib/types/host-access.d.ts +14 -0
  128. package/packages/tool-agent-team/lib/types/host-access.d.ts.map +1 -0
  129. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
  130. package/packages/agent-team/lib/progress-nudge.js +0 -328
  131. package/packages/agent-team/lib/types/progress-nudge.d.ts +0 -136
  132. package/packages/agent-team/lib/types/progress-nudge.d.ts.map +0 -1
  133. package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts +0 -3
  134. package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts.map +0 -1
  135. package/packages/client-agent-team/lib/types/client/TeamSettings.js +0 -5
@@ -4143,7 +4143,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4143
4143
  literal("working"),
4144
4144
  literal("error")
4145
4145
  ]).readonly(),
4146
- "diagnostic": string().readonly().optional(),
4146
+ "diagnostic": object({
4147
+ "class": union([
4148
+ literal("session-refused"),
4149
+ literal("session-unreadable"),
4150
+ literal("preset-composition"),
4151
+ literal("rollover"),
4152
+ literal("runtime"),
4153
+ literal("activation")
4154
+ ]).readonly(),
4155
+ "detail": string().readonly(),
4156
+ "location": object({
4157
+ "kind": string().readonly(),
4158
+ "path": string().readonly()
4159
+ }).readonly().optional(),
4160
+ "sessionId": intersection(string(), unknown()).readonly().optional(),
4161
+ "remediable": boolean().readonly().optional()
4162
+ }).readonly().optional(),
4147
4163
  "capabilityWarnings": union([_undefined(), array(object({
4148
4164
  "name": string().readonly(),
4149
4165
  "knownNames": array(string()).readonly()
@@ -4294,6 +4310,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4294
4310
  object({
4295
4311
  "kind": literal("thread").readonly(),
4296
4312
  "threadRef": intersection(string(), unknown()).readonly()
4313
+ }),
4314
+ object({
4315
+ "kind": literal("presence").readonly(),
4316
+ "workspaceId": intersection(string(), unknown()).readonly()
4297
4317
  })
4298
4318
  ]).readonly().optional()
4299
4319
  });
@@ -4436,7 +4456,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4436
4456
  literal("working"),
4437
4457
  literal("error")
4438
4458
  ]).readonly(),
4439
- "diagnostic": string().readonly().optional(),
4459
+ "diagnostic": object({
4460
+ "class": union([
4461
+ literal("session-refused"),
4462
+ literal("session-unreadable"),
4463
+ literal("preset-composition"),
4464
+ literal("rollover"),
4465
+ literal("runtime"),
4466
+ literal("activation")
4467
+ ]).readonly(),
4468
+ "detail": string().readonly(),
4469
+ "location": object({
4470
+ "kind": string().readonly(),
4471
+ "path": string().readonly()
4472
+ }).readonly().optional(),
4473
+ "sessionId": intersection(string(), unknown()).readonly().optional(),
4474
+ "remediable": boolean().readonly().optional()
4475
+ }).readonly().optional(),
4440
4476
  "capabilityWarnings": union([_undefined(), array(object({
4441
4477
  "name": string().readonly(),
4442
4478
  "knownNames": array(string()).readonly()
@@ -4481,6 +4517,53 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4481
4517
  const _wowyuarm_dsh_agent_team_agentTeam_inbox_result$schema = object({
4482
4518
  "items": array(object({
4483
4519
  "channelRef": intersection(string(), unknown()).readonly(),
4520
+ "channelName": string().readonly().optional(),
4521
+ "task": object({
4522
+ "taskRef": intersection(string(), unknown()).readonly(),
4523
+ "channelRef": intersection(string(), unknown()).readonly(),
4524
+ "threadRef": intersection(string(), unknown()).readonly(),
4525
+ "status": union([
4526
+ literal("done"),
4527
+ literal("todo"),
4528
+ literal("in_progress"),
4529
+ literal("in_review"),
4530
+ literal("closed")
4531
+ ]).readonly(),
4532
+ "resolution": union([
4533
+ literal("closed"),
4534
+ literal("open"),
4535
+ literal("accepted")
4536
+ ]).readonly()
4537
+ }).readonly().optional(),
4538
+ "taskNumber": number().readonly().optional(),
4539
+ "thread": object({
4540
+ "threadRef": intersection(string(), unknown()).readonly(),
4541
+ "taskRef": intersection(string(), unknown()).readonly().optional(),
4542
+ "revision": number().readonly()
4543
+ }).readonly(),
4544
+ "unreadCount": number().readonly(),
4545
+ "directCount": number().readonly(),
4546
+ "previewText": string().readonly().optional(),
4547
+ "newestSequence": number().readonly(),
4548
+ "newestOccurredAt": string().readonly(),
4549
+ "newestActor": object({
4550
+ "memberId": intersection(string(), unknown()).readonly(),
4551
+ "name": string().readonly()
4552
+ }).readonly(),
4553
+ "claimOwners": array(object({
4554
+ "memberId": intersection(string(), unknown()).readonly(),
4555
+ "name": string().readonly()
4556
+ })).readonly(),
4557
+ "attention": object({
4558
+ "memberId": intersection(string(), unknown()).readonly(),
4559
+ "threadRef": intersection(string(), unknown()).readonly(),
4560
+ "startSequence": number().readonly(),
4561
+ "readThroughSequence": number().readonly()
4562
+ }).readonly().optional()
4563
+ })).readonly(),
4564
+ "recent": array(object({
4565
+ "channelRef": intersection(string(), unknown()).readonly(),
4566
+ "channelName": string().readonly().optional(),
4484
4567
  "task": object({
4485
4568
  "taskRef": intersection(string(), unknown()).readonly(),
4486
4569
  "channelRef": intersection(string(), unknown()).readonly(),
@@ -4498,6 +4581,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4498
4581
  literal("accepted")
4499
4582
  ]).readonly()
4500
4583
  }).readonly().optional(),
4584
+ "taskNumber": number().readonly().optional(),
4501
4585
  "thread": object({
4502
4586
  "threadRef": intersection(string(), unknown()).readonly(),
4503
4587
  "taskRef": intersection(string(), unknown()).readonly().optional(),
@@ -4505,8 +4589,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4505
4589
  }).readonly(),
4506
4590
  "unreadCount": number().readonly(),
4507
4591
  "directCount": number().readonly(),
4592
+ "previewText": string().readonly().optional(),
4508
4593
  "newestSequence": number().readonly(),
4509
4594
  "newestOccurredAt": string().readonly(),
4595
+ "newestActor": object({
4596
+ "memberId": intersection(string(), unknown()).readonly(),
4597
+ "name": string().readonly()
4598
+ }).readonly(),
4599
+ "claimOwners": array(object({
4600
+ "memberId": intersection(string(), unknown()).readonly(),
4601
+ "name": string().readonly()
4602
+ })).readonly(),
4510
4603
  "attention": object({
4511
4604
  "memberId": intersection(string(), unknown()).readonly(),
4512
4605
  "threadRef": intersection(string(), unknown()).readonly(),
@@ -4571,7 +4664,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4571
4664
  literal("working"),
4572
4665
  literal("error")
4573
4666
  ]).readonly(),
4574
- "diagnostic": string().readonly().optional(),
4667
+ "diagnostic": object({
4668
+ "class": union([
4669
+ literal("session-refused"),
4670
+ literal("session-unreadable"),
4671
+ literal("preset-composition"),
4672
+ literal("rollover"),
4673
+ literal("runtime"),
4674
+ literal("activation")
4675
+ ]).readonly(),
4676
+ "detail": string().readonly(),
4677
+ "location": object({
4678
+ "kind": string().readonly(),
4679
+ "path": string().readonly()
4680
+ }).readonly().optional(),
4681
+ "sessionId": intersection(string(), unknown()).readonly().optional(),
4682
+ "remediable": boolean().readonly().optional()
4683
+ }).readonly().optional(),
4575
4684
  "capabilityWarnings": union([_undefined(), array(object({
4576
4685
  "name": string().readonly(),
4577
4686
  "knownNames": array(string()).readonly()
@@ -4673,7 +4782,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4673
4782
  "requestId": intersection(string(), unknown()).readonly(),
4674
4783
  "sequence": number().readonly(),
4675
4784
  "occurredAt": string().readonly()
4676
- }).readonly(),
4785
+ }).readonly().optional(),
4677
4786
  "task": object({
4678
4787
  "taskRef": intersection(string(), unknown()).readonly(),
4679
4788
  "channelRef": intersection(string(), unknown()).readonly(),
@@ -4800,6 +4909,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4800
4909
  })).readonly(),
4801
4910
  "readThroughSequence": number().readonly(),
4802
4911
  "remainingUnreadCount": number().readonly(),
4912
+ "earlierFactCount": number().readonly().optional(),
4803
4913
  "attention": object({
4804
4914
  "memberId": intersection(string(), unknown()).readonly(),
4805
4915
  "threadRef": intersection(string(), unknown()).readonly(),
@@ -4819,8 +4929,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4819
4929
  "hardLimit": union([_undefined(), number()]).readonly().optional(),
4820
4930
  "action": union([
4821
4931
  literal("unavailable"),
4822
- literal("keep"),
4823
4932
  literal("rollover"),
4933
+ literal("keep"),
4824
4934
  literal("handoff-now")
4825
4935
  ]).readonly(),
4826
4936
  "guidance": string().readonly()
@@ -4869,7 +4979,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4869
4979
  literal("working"),
4870
4980
  literal("error")
4871
4981
  ]).readonly(),
4872
- "diagnostic": string().readonly().optional(),
4982
+ "diagnostic": object({
4983
+ "class": union([
4984
+ literal("session-refused"),
4985
+ literal("session-unreadable"),
4986
+ literal("preset-composition"),
4987
+ literal("rollover"),
4988
+ literal("runtime"),
4989
+ literal("activation")
4990
+ ]).readonly(),
4991
+ "detail": string().readonly(),
4992
+ "location": object({
4993
+ "kind": string().readonly(),
4994
+ "path": string().readonly()
4995
+ }).readonly().optional(),
4996
+ "sessionId": intersection(string(), unknown()).readonly().optional(),
4997
+ "remediable": boolean().readonly().optional()
4998
+ }).readonly().optional(),
4873
4999
  "capabilityWarnings": union([_undefined(), array(object({
4874
5000
  "name": string().readonly(),
4875
5001
  "knownNames": array(string()).readonly()
@@ -5013,7 +5139,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5013
5139
  "threadRef": intersection(string(), unknown()).readonly(),
5014
5140
  "messageRef": intersection(string(), unknown()).readonly(),
5015
5141
  "sequence": number().readonly()
5016
- })).readonly()
5142
+ })).readonly(),
5143
+ "undeliveredMentions": array(intersection(string(), unknown())).readonly().optional()
5017
5144
  })
5018
5145
  ]);
5019
5146
  const _wowyuarm_dsh_agent_team_agentTeam_resolveTaskRefs_parameter_0$schema = object({
@@ -5348,7 +5475,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5348
5475
  literal("working"),
5349
5476
  literal("error")
5350
5477
  ]).readonly(),
5351
- "diagnostic": string().readonly().optional(),
5478
+ "diagnostic": object({
5479
+ "class": union([
5480
+ literal("session-refused"),
5481
+ literal("session-unreadable"),
5482
+ literal("preset-composition"),
5483
+ literal("rollover"),
5484
+ literal("runtime"),
5485
+ literal("activation")
5486
+ ]).readonly(),
5487
+ "detail": string().readonly(),
5488
+ "location": object({
5489
+ "kind": string().readonly(),
5490
+ "path": string().readonly()
5491
+ }).readonly().optional(),
5492
+ "sessionId": intersection(string(), unknown()).readonly().optional(),
5493
+ "remediable": boolean().readonly().optional()
5494
+ }).readonly().optional(),
5352
5495
  "capabilityWarnings": union([_undefined(), array(object({
5353
5496
  "name": string().readonly(),
5354
5497
  "knownNames": array(string()).readonly()
@@ -5532,7 +5675,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5532
5675
  },
5533
5676
  sourceLocation: {
5534
5677
  "file": "packages/agent-team/src/index.ts",
5535
- "line": 653,
5678
+ "line": 699,
5536
5679
  "column": 9
5537
5680
  }
5538
5681
  },
@@ -5559,7 +5702,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5559
5702
  },
5560
5703
  sourceLocation: {
5561
5704
  "file": "packages/agent-team/src/index.ts",
5562
- "line": 643,
5705
+ "line": 689,
5563
5706
  "column": 9
5564
5707
  }
5565
5708
  },
@@ -5586,7 +5729,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5586
5729
  },
5587
5730
  sourceLocation: {
5588
5731
  "file": "packages/agent-team/src/index.ts",
5589
- "line": 1024,
5732
+ "line": 1080,
5590
5733
  "column": 9
5591
5734
  }
5592
5735
  },
@@ -5613,7 +5756,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5613
5756
  },
5614
5757
  sourceLocation: {
5615
5758
  "file": "packages/agent-team/src/index.ts",
5616
- "line": 1146,
5759
+ "line": 1202,
5617
5760
  "column": 9
5618
5761
  }
5619
5762
  },
@@ -5641,7 +5784,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5641
5784
  },
5642
5785
  sourceLocation: {
5643
5786
  "file": "packages/agent-team/src/index.ts",
5644
- "line": 575,
5787
+ "line": 620,
5645
5788
  "column": 9
5646
5789
  }
5647
5790
  },
@@ -5668,7 +5811,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5668
5811
  },
5669
5812
  sourceLocation: {
5670
5813
  "file": "packages/agent-team/src/index.ts",
5671
- "line": 1036,
5814
+ "line": 1092,
5672
5815
  "column": 9
5673
5816
  }
5674
5817
  },
@@ -5695,7 +5838,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5695
5838
  },
5696
5839
  sourceLocation: {
5697
5840
  "file": "packages/agent-team/src/index.ts",
5698
- "line": 752,
5841
+ "line": 814,
5699
5842
  "column": 9
5700
5843
  }
5701
5844
  },
@@ -5722,7 +5865,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5722
5865
  },
5723
5866
  sourceLocation: {
5724
5867
  "file": "packages/agent-team/src/index.ts",
5725
- "line": 616,
5868
+ "line": 662,
5726
5869
  "column": 9
5727
5870
  }
5728
5871
  },
@@ -5749,7 +5892,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5749
5892
  },
5750
5893
  sourceLocation: {
5751
5894
  "file": "packages/agent-team/src/index.ts",
5752
- "line": 1132,
5895
+ "line": 1188,
5753
5896
  "column": 9
5754
5897
  }
5755
5898
  },
@@ -5776,7 +5919,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5776
5919
  },
5777
5920
  sourceLocation: {
5778
5921
  "file": "packages/agent-team/src/index.ts",
5779
- "line": 1155,
5922
+ "line": 1211,
5780
5923
  "column": 3
5781
5924
  }
5782
5925
  },
@@ -5803,7 +5946,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5803
5946
  },
5804
5947
  sourceLocation: {
5805
5948
  "file": "packages/agent-team/src/index.ts",
5806
- "line": 1056,
5949
+ "line": 1112,
5807
5950
  "column": 9
5808
5951
  }
5809
5952
  },
@@ -5831,7 +5974,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5831
5974
  },
5832
5975
  sourceLocation: {
5833
5976
  "file": "packages/agent-team/src/index.ts",
5834
- "line": 566,
5977
+ "line": 611,
5835
5978
  "column": 3
5836
5979
  }
5837
5980
  },
@@ -5858,7 +6001,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5858
6001
  },
5859
6002
  sourceLocation: {
5860
6003
  "file": "packages/agent-team/src/index.ts",
5861
- "line": 1046,
6004
+ "line": 1102,
5862
6005
  "column": 9
5863
6006
  }
5864
6007
  },
@@ -5885,7 +6028,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5885
6028
  },
5886
6029
  sourceLocation: {
5887
6030
  "file": "packages/agent-team/src/index.ts",
5888
- "line": 1119,
6031
+ "line": 1175,
5889
6032
  "column": 9
5890
6033
  }
5891
6034
  },
@@ -5912,7 +6055,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5912
6055
  },
5913
6056
  sourceLocation: {
5914
6057
  "file": "packages/agent-team/src/index.ts",
5915
- "line": 1162,
6058
+ "line": 1218,
5916
6059
  "column": 9
5917
6060
  }
5918
6061
  },
@@ -5939,7 +6082,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5939
6082
  },
5940
6083
  sourceLocation: {
5941
6084
  "file": "packages/agent-team/src/index.ts",
5942
- "line": 713,
6085
+ "line": 759,
5943
6086
  "column": 9
5944
6087
  }
5945
6088
  },
@@ -5966,7 +6109,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5966
6109
  },
5967
6110
  sourceLocation: {
5968
6111
  "file": "packages/agent-team/src/index.ts",
5969
- "line": 1067,
6112
+ "line": 1123,
5970
6113
  "column": 9
5971
6114
  }
5972
6115
  },
@@ -5993,7 +6136,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5993
6136
  },
5994
6137
  sourceLocation: {
5995
6138
  "file": "packages/agent-team/src/index.ts",
5996
- "line": 1140,
6139
+ "line": 1196,
5997
6140
  "column": 9
5998
6141
  }
5999
6142
  },
@@ -6020,7 +6163,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6020
6163
  },
6021
6164
  sourceLocation: {
6022
6165
  "file": "packages/agent-team/src/index.ts",
6023
- "line": 553,
6166
+ "line": 598,
6024
6167
  "column": 3
6025
6168
  }
6026
6169
  },
@@ -6047,7 +6190,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6047
6190
  },
6048
6191
  sourceLocation: {
6049
6192
  "file": "packages/agent-team/src/index.ts",
6050
- "line": 1076,
6193
+ "line": 1132,
6051
6194
  "column": 9
6052
6195
  }
6053
6196
  },
@@ -6074,7 +6217,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6074
6217
  },
6075
6218
  sourceLocation: {
6076
6219
  "file": "packages/agent-team/src/index.ts",
6077
- "line": 1178,
6220
+ "line": 1236,
6078
6221
  "column": 3
6079
6222
  }
6080
6223
  },
@@ -6101,7 +6244,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6101
6244
  },
6102
6245
  sourceLocation: {
6103
6246
  "file": "packages/agent-team/src/index.ts",
6104
- "line": 1171,
6247
+ "line": 1229,
6105
6248
  "column": 3
6106
6249
  }
6107
6250
  },
@@ -6128,7 +6271,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6128
6271
  },
6129
6272
  sourceLocation: {
6130
6273
  "file": "packages/agent-team/src/index.ts",
6131
- "line": 628,
6274
+ "line": 674,
6132
6275
  "column": 9
6133
6276
  }
6134
6277
  },
@@ -6155,7 +6298,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6155
6298
  },
6156
6299
  sourceLocation: {
6157
6300
  "file": "packages/agent-team/src/index.ts",
6158
- "line": 964,
6301
+ "line": 1020,
6159
6302
  "column": 9
6160
6303
  }
6161
6304
  },
@@ -6182,7 +6325,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6182
6325
  },
6183
6326
  sourceLocation: {
6184
6327
  "file": "packages/agent-team/src/index.ts",
6185
- "line": 1185,
6328
+ "line": 1243,
6186
6329
  "column": 3
6187
6330
  }
6188
6331
  }
@@ -6200,6 +6343,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6200
6343
  mode: parsed.mode === "team" ? "team" : "conversation",
6201
6344
  ...typeof parsed.workspaceId === "string" ? { workspaceId: parsed.workspaceId } : {},
6202
6345
  ...typeof parsed.channelRef === "string" ? { channelRef: parsed.channelRef } : {},
6346
+ ...parsed.inbox === true ? { inbox: true } : {},
6203
6347
  ...hasThread ? {
6204
6348
  threadRef: parsed.threadRef,
6205
6349
  ...typeof parsed.taskRef === "string" ? { taskRef: parsed.taskRef } : {},
@@ -6213,11 +6357,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6213
6357
  function persistSnapshot(snapshot) {
6214
6358
  if (typeof localStorage === "undefined") return;
6215
6359
  try {
6216
- const { mode, workspaceId, channelRef, taskRef, threadRef, taskNumber } = snapshot;
6360
+ const { mode, workspaceId, channelRef, taskRef, threadRef, taskNumber, inbox } = snapshot;
6217
6361
  localStorage.setItem(STORAGE_KEY$3, JSON.stringify({
6218
6362
  mode,
6219
6363
  ...workspaceId === void 0 ? {} : { workspaceId },
6220
6364
  ...channelRef === void 0 ? {} : { channelRef },
6365
+ ...inbox === true ? { inbox: true } : {},
6221
6366
  ...taskRef === void 0 ? {} : { taskRef },
6222
6367
  ...threadRef === void 0 ? {} : { threadRef },
6223
6368
  ...taskNumber === void 0 ? {} : { taskNumber }
@@ -6256,6 +6401,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6256
6401
  this.clearMemberSession();
6257
6402
  this.setThread(threadRef, channelRef, taskRef, taskNumber);
6258
6403
  },
6404
+ selectInbox: () => {
6405
+ this.clearMemberSession();
6406
+ this.setInbox();
6407
+ },
6259
6408
  backToWorkspace: () => {
6260
6409
  this.clearMemberSession();
6261
6410
  this.setThread(void 0);
@@ -6302,8 +6451,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6302
6451
  this.commit();
6303
6452
  }
6304
6453
  setWorkspace(workspaceId) {
6305
- if (this.snapshot.workspaceId === workspaceId) return;
6306
- const { channelRef: _channelRef, taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, ...base } = this.snapshot;
6454
+ if (this.snapshot.workspaceId === workspaceId && this.snapshot.inbox !== true) return;
6455
+ const { channelRef: _channelRef, taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, inbox: _inbox, ...base } = this.snapshot;
6307
6456
  this.snapshot = {
6308
6457
  ...base,
6309
6458
  workspaceId
@@ -6311,14 +6460,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6311
6460
  this.commit();
6312
6461
  }
6313
6462
  setChannel(channelRef) {
6314
- if (this.snapshot.channelRef === channelRef && this.snapshot.threadRef === void 0) return;
6315
- const { taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, ...base } = this.snapshot;
6463
+ if (this.snapshot.channelRef === channelRef && this.snapshot.threadRef === void 0 && this.snapshot.inbox !== true) return;
6464
+ const { taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, inbox: _inbox, ...base } = this.snapshot;
6316
6465
  this.snapshot = {
6317
6466
  ...base,
6318
6467
  channelRef
6319
6468
  };
6320
6469
  this.commit();
6321
6470
  }
6471
+ /** The Inbox is a face, not workspace content: selecting a Workspace leaves it. */
6472
+ setInbox() {
6473
+ if (this.snapshot.inbox === true && this.snapshot.channelRef === void 0 && this.snapshot.threadRef === void 0) return;
6474
+ const { channelRef: _channelRef, taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, ...base } = this.snapshot;
6475
+ this.snapshot = {
6476
+ ...base,
6477
+ inbox: true
6478
+ };
6479
+ this.commit();
6480
+ }
6322
6481
  clearChannel() {
6323
6482
  const { channelRef: _channelRef, ...base } = this.snapshot;
6324
6483
  if (this.snapshot.channelRef === void 0) return;
@@ -6326,12 +6485,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6326
6485
  this.commit();
6327
6486
  }
6328
6487
  setThread(threadRef, channelRef, taskRef, taskNumber) {
6329
- if (this.snapshot.threadRef === threadRef && this.snapshot.taskRef === taskRef && this.snapshot.channelRef === channelRef && this.snapshot.taskNumber === taskNumber) return;
6488
+ if (this.snapshot.threadRef === threadRef && this.snapshot.taskRef === taskRef && this.snapshot.channelRef === channelRef && this.snapshot.taskNumber === taskNumber && this.snapshot.inbox !== true) return;
6330
6489
  if (threadRef === void 0) {
6331
6490
  const { taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, ...base } = this.snapshot;
6332
6491
  this.snapshot = base;
6333
6492
  } else {
6334
- const { channelRef: _channelRef, taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, ...base } = this.snapshot;
6493
+ const { channelRef: _channelRef, taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, inbox: _inbox, ...base } = this.snapshot;
6335
6494
  this.snapshot = {
6336
6495
  ...base,
6337
6496
  threadRef,
@@ -6349,17 +6508,50 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6349
6508
  };
6350
6509
  //#endregion
6351
6510
  //#region src/client/team-changes.ts
6511
+ /** First retry delay after a failed call, doubling up to the cap. */
6512
+ const RETRY_BASE_MS = 1e3;
6513
+ const RETRY_MAX_MS = 3e4;
6514
+ /** Abortable delay: the poll's subscription ending must not wait out a backoff. */
6515
+ function sleep(ms, signal) {
6516
+ return new Promise((resolve) => {
6517
+ const done = () => {
6518
+ clearTimeout(timer);
6519
+ signal.removeEventListener("abort", done);
6520
+ resolve();
6521
+ };
6522
+ const timer = setTimeout(done, ms);
6523
+ signal.addEventListener("abort", done, { once: true });
6524
+ });
6525
+ }
6352
6526
  function scopeKey(scope) {
6353
- return scope.kind === "workspace" ? `workspace:${scope.workspaceId}` : scope.kind === "channel" ? `channel:${scope.channelRef}` : `thread:${scope.threadRef}`;
6527
+ return scope === void 0 ? "all" : scope.kind === "workspace" ? `workspace:${scope.workspaceId}` : scope.kind === "channel" ? `channel:${scope.channelRef}` : scope.kind === "presence" ? `presence:${scope.workspaceId}` : `thread:${scope.threadRef}`;
6354
6528
  }
6355
6529
  /**
6356
6530
  * One long-poll per change scope, shared by every listening surface: panels
6357
6531
  * and pages never open parallel `changes` requests for the same scope, and
6358
6532
  * the poll is aborted as soon as the last subscriber leaves.
6533
+ *
6534
+ * A failed call reports the outage to every listener once and then keeps
6535
+ * retrying with backoff. The transport recovers on its own terms — a Host
6536
+ * restart, a sleep/wake, a dropped proxy — and a surface that stayed mounted
6537
+ * has to resume from that recovery rather than stay silent until it remounts,
6538
+ * so the first answered call after an outage wakes every listener once even
6539
+ * when the cursor did not move.
6540
+ *
6541
+ * Each poll keeps its own cursor, and a cursor only means something inside the
6542
+ * scope it was issued for: the Host answers a presence scope from a
6543
+ * process-local wake epoch and every other scope from a durable ledger
6544
+ * position.
6359
6545
  */
6360
6546
  var TeamChangeStream = class {
6361
6547
  changes;
6362
6548
  polls = /* @__PURE__ */ new Map();
6549
+ /**
6550
+ * The last version each scope key answered with, kept after that scope's poll
6551
+ * is torn down: a commit landing while no poll exists is otherwise folded into
6552
+ * the replacement poll's opening sample, which reports nothing.
6553
+ */
6554
+ observed = /* @__PURE__ */ new Map();
6363
6555
  constructor(changes) {
6364
6556
  this.changes = changes;
6365
6557
  }
@@ -6369,7 +6561,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6369
6561
  if (poll === void 0) {
6370
6562
  poll = {
6371
6563
  controller: new AbortController(),
6372
- listeners: /* @__PURE__ */ new Set()
6564
+ listeners: /* @__PURE__ */ new Set(),
6565
+ resumeFrom: this.observed.get(key)
6373
6566
  };
6374
6567
  this.polls.set(key, poll);
6375
6568
  this.run(key, scope, poll);
@@ -6386,27 +6579,46 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6386
6579
  }
6387
6580
  async run(key, scope, poll) {
6388
6581
  const { signal } = poll.controller;
6389
- const probe = await this.changes({
6390
- afterVersion: 0,
6391
- scope
6392
- }, signal);
6393
- if (signal.aborted) return;
6394
- if (!probe.ok) {
6395
- this.fail(key, poll, probe.error.message);
6396
- return;
6397
- }
6398
- let version = probe.value.version;
6582
+ const request = (afterVersion) => ({
6583
+ afterVersion,
6584
+ ...scope === void 0 ? {} : { scope }
6585
+ });
6586
+ let version = poll.resumeFrom;
6587
+ let retryDelay = RETRY_BASE_MS;
6588
+ let reported = false;
6399
6589
  while (!signal.aborted) {
6400
- const result = await this.changes({
6401
- afterVersion: version,
6402
- scope
6403
- }, signal);
6404
- if (signal.aborted) return;
6590
+ const result = await this.changes(request(version ?? 0), signal);
6591
+ if (signal.aborted || this.polls.get(key) !== poll) return;
6405
6592
  if (!result.ok) {
6406
- this.fail(key, poll, result.error.message);
6407
- return;
6593
+ if (!reported) {
6594
+ reported = true;
6595
+ for (const listener of poll.listeners) listener({
6596
+ type: "failed",
6597
+ message: result.error.message
6598
+ });
6599
+ }
6600
+ await sleep(retryDelay, signal);
6601
+ retryDelay = Math.min(retryDelay * 2, RETRY_MAX_MS);
6602
+ continue;
6603
+ }
6604
+ retryDelay = RETRY_BASE_MS;
6605
+ if (reported) {
6606
+ reported = false;
6607
+ version = result.value.version;
6608
+ this.observed.set(key, version);
6609
+ for (const listener of poll.listeners) listener({
6610
+ type: "changed",
6611
+ version
6612
+ });
6613
+ continue;
6614
+ }
6615
+ if (version === void 0) {
6616
+ version = result.value.version;
6617
+ this.observed.set(key, version);
6618
+ continue;
6408
6619
  }
6409
- if (result.value.version > version) {
6620
+ this.observed.set(key, result.value.version);
6621
+ if (result.value.version !== version) {
6410
6622
  version = result.value.version;
6411
6623
  for (const listener of poll.listeners) listener({
6412
6624
  type: "changed",
@@ -6415,12 +6627,26 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6415
6627
  }
6416
6628
  }
6417
6629
  }
6418
- fail(key, poll, message) {
6419
- if (this.polls.get(key) === poll) this.polls.delete(key);
6420
- for (const listener of poll.listeners) listener({
6421
- type: "failed",
6422
- message
6423
- });
6630
+ };
6631
+ /**
6632
+ * The Host's `changes` stream never wakes on a Thread read — a read advances
6633
+ * only the reader's private watermark, so no shared projection changes. A
6634
+ * durable read does consume the reader's own mention markers, so the Human's
6635
+ * badge and Inbox page refresh from the completed read itself instead of
6636
+ * waiting for the next unrelated commit.
6637
+ */
6638
+ var TeamReadStream = class {
6639
+ version = 0;
6640
+ listeners = /* @__PURE__ */ new Set();
6641
+ bump() {
6642
+ this.version += 1;
6643
+ for (const listener of this.listeners) listener();
6644
+ }
6645
+ subscribe(listener) {
6646
+ this.listeners.add(listener);
6647
+ return () => {
6648
+ this.listeners.delete(listener);
6649
+ };
6424
6650
  }
6425
6651
  };
6426
6652
  //#endregion
@@ -6555,13 +6781,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6555
6781
  };
6556
6782
  //#endregion
6557
6783
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/team.module.css.mjs
6558
- const css$9 = ".YvAbSa_footerStack{flex:none;width:100%;height:42px;margin:8px 0 0;display:flex}.YvAbSa_footerAction,.YvAbSa_settingsAction{box-sizing:border-box;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:8px;width:calc(100% + 4px);height:42px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.YvAbSa_footerAction{margin:0 -2px}.YvAbSa_settingsAction{margin:4px -2px}.YvAbSa_footerAction:hover,.YvAbSa_footerAction:focus-visible,.YvAbSa_settingsAction:hover,.YvAbSa_settingsAction:focus-visible{background:var(--dsw-alias-interactive-bg-hover);outline:none}.YvAbSa_footerAction.YvAbSa_rail,.YvAbSa_settingsAction.YvAbSa_rail{border-radius:50%;justify-content:center;width:36px;height:36px;padding:0}.YvAbSa_footerAction.YvAbSa_rail{margin:0}.YvAbSa_settingsAction.YvAbSa_rail{margin:8px 0 10px}.YvAbSa_railStack{align-items:center;width:36px;height:36px;margin:0}";
6559
- const tagId$9 = "@wowyuarm/dsh-agent-team/team.module.css";
6560
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$9) + "]") === null) {
6784
+ const css$13 = ".YvAbSa_footerStack{flex:none;width:100%;height:42px;margin:8px 0 0;display:flex}.YvAbSa_footerAction,.YvAbSa_settingsAction{box-sizing:border-box;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:8px;width:calc(100% + 4px);height:42px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.YvAbSa_footerAction{margin:0 -2px}.YvAbSa_settingsAction{margin:4px -2px}.YvAbSa_footerAction:hover,.YvAbSa_footerAction:focus-visible,.YvAbSa_settingsAction:hover,.YvAbSa_settingsAction:focus-visible{background:var(--dsw-alias-interactive-bg-hover)}.YvAbSa_footerAction:focus-visible,.YvAbSa_settingsAction:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:-2px}.YvAbSa_footerAction.YvAbSa_rail,.YvAbSa_settingsAction.YvAbSa_rail{corner-shape:round;border-radius:50%;justify-content:center;width:36px;height:36px;padding:0}.YvAbSa_footerAction.YvAbSa_rail{margin:0}.YvAbSa_settingsAction.YvAbSa_rail{margin:8px 0 10px}.YvAbSa_railStack{align-items:center;width:36px;height:36px;margin:0}";
6785
+ const tagId$13 = "@wowyuarm/dsh-agent-team/team.module.css";
6786
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$13) + "]") === null) {
6561
6787
  const tag = document.createElement("style");
6562
6788
  tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
6563
- tag.dataset.pluginCss = tagId$9;
6564
- tag.textContent = css$9;
6789
+ tag.dataset.pluginCss = tagId$13;
6790
+ tag.textContent = css$13;
6565
6791
  document.head.appendChild(tag);
6566
6792
  }
6567
6793
  var team_module_css_default = {
@@ -6604,303 +6830,769 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6604
6830
  }) });
6605
6831
  }
6606
6832
  //#endregion
6607
- //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/state-dot.module.css.mjs
6608
- const css$8 = ".DalNWW_quiet{border-radius:50%;flex:none;display:inline-block;position:relative}.DalNWW_quiet[data-variant=todo]{border:1px solid var(--dsw-alias-label-tertiary)}.DalNWW_quiet[data-variant=quiet]{color:var(--dsw-alias-label-tertiary)}.DalNWW_quiet[data-variant=quiet]:before{content:\"\";opacity:.1;background:currentColor;border-radius:50%;position:absolute;inset:0}.DalNWW_quiet[data-variant=quiet]:after{content:\"\";background:currentColor;border-radius:50%;position:absolute;inset:20%}";
6609
- const tagId$8 = "@wowyuarm/dsh-agent-team/state-dot.module.css";
6610
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$8) + "]") === null) {
6611
- const tag = document.createElement("style");
6612
- tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
6613
- tag.dataset.pluginCss = tagId$8;
6614
- tag.textContent = css$8;
6615
- document.head.appendChild(tag);
6833
+ //#region src/client/team-formatters.ts
6834
+ function formatTaskStatus(status, t) {
6835
+ return t({
6836
+ todo: "taskStatusTodo",
6837
+ in_progress: "taskStatusInProgress",
6838
+ in_review: "taskStatusInReview",
6839
+ done: "taskStatusDone",
6840
+ closed: "taskStatusClosed"
6841
+ }[status]);
6842
+ }
6843
+ function formatClaimState(state, t) {
6844
+ return t({
6845
+ active: "claimStateActive",
6846
+ done: "claimStateDone",
6847
+ released: "claimStateReleased"
6848
+ }[state]);
6616
6849
  }
6617
- var state_dot_module_css_default = { "quiet": "DalNWW_quiet" };
6618
- //#endregion
6619
- //#region src/client/TeamStateDot.tsx
6620
6850
  /**
6621
- * Render the one shared Team status indicator. Native StateDot states pass
6622
- * through; the quiet statuses mirror StateDot geometry locally so every
6623
- * surface renders the same shape — todo a hollow ring (not started), quiet a
6624
- * solid tertiary dot with the same 10% halo (closed, unavailable).
6851
+ * Status indicator for a Task status, the dot every Task surface renders.
6852
+ * Active states map to StateDot variants; every status renders a dot so they
6853
+ * share one shape language — todo is a hollow ring (not started), closed a
6854
+ * quiet gray dot (archived).
6625
6855
  */
6626
- function TeamStateDot({ state, size = 10 }) {
6627
- if (state === "todo" || state === "quiet") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6628
- className: state_dot_module_css_default.quiet,
6629
- "data-variant": state,
6630
- style: {
6631
- width: size,
6632
- height: size
6633
- },
6634
- "aria-hidden": "true"
6635
- });
6636
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
6637
- state,
6638
- size
6639
- });
6856
+ function taskStatusDot(status) {
6857
+ return {
6858
+ todo: "todo",
6859
+ in_progress: "ongoing",
6860
+ in_review: "warning",
6861
+ done: "done",
6862
+ closed: "quiet"
6863
+ }[status];
6640
6864
  }
6641
- //#endregion
6642
- //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/presence.module.css.mjs
6643
- const css$7 = ".-\\36 lQ-q_target{flex:0 0 14px;justify-content:center;align-items:center;display:inline-flex}";
6644
- const tagId$7 = "@wowyuarm/dsh-agent-team/presence.module.css";
6645
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$7) + "]") === null) {
6646
- const tag = document.createElement("style");
6647
- tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
6648
- tag.dataset.pluginCss = tagId$7;
6649
- tag.textContent = css$7;
6650
- document.head.appendChild(tag);
6865
+ /** One-line title snippet derived from the Task's root Message body. */
6866
+ function formatTaskTitle(body) {
6867
+ const firstLine = body.split("\n", 1)[0]?.trim() ?? "";
6868
+ return firstLine.length > 120 ? `${firstLine.slice(0, 119)}…` : firstLine;
6651
6869
  }
6652
- var presence_module_css_default = { "target": "-6lQ-q_target" };
6653
- //#endregion
6654
- //#region src/client/TeamPresenceDot.tsx
6655
- function presenceLabel(status, t) {
6656
- const label = status.presence === "available" ? t("statusAvailable") : status.presence === "working" ? t("statusWorking") : status.presence === "error" ? t("statusError") : t("statusUnavailable");
6657
- return status.diagnostic === void 0 ? label : `${label}: ${status.diagnostic}`;
6870
+ /** Deterministic avatar hue for one Member identity; stable across sessions and themes. */
6871
+ function memberHue(memberId) {
6872
+ let hash = 0;
6873
+ for (let index = 0; index < memberId.length; index += 1) hash = (hash * 31 + memberId.charCodeAt(index)) % 360;
6874
+ return hash;
6658
6875
  }
6659
- /** Shared presence → indicator mapping for dots and avatar badges. */
6660
- function presenceDotState(presence) {
6661
- return presence === "available" ? "done" : presence === "working" ? "ongoing" : presence === "error" ? "error" : "quiet";
6876
+ const BRANDED_REF_PATTERN = /\b(task|channel|thread):{1,2}[0-9a-f]{6,}(?:-[0-9a-f]{1,})*\b/gi;
6877
+ /**
6878
+ * Canonical form of one matched ref: models occasionally double the colon or
6879
+ * uppercase the UUID when citing a ref in prose, while Host lookups and
6880
+ * navigation only accept the lowercase single-colon ref the ledger mints.
6881
+ */
6882
+ function canonicalBrandedRef(match) {
6883
+ return match.replace("::", ":").toLowerCase();
6662
6884
  }
6663
- function TeamPresenceDot({ status, t }) {
6664
- const label = presenceLabel(status, t);
6665
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
6666
- label,
6667
- delayMs: 300,
6668
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6669
- className: presence_module_css_default.target,
6670
- role: "img",
6671
- "aria-label": label,
6672
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamStateDot, { state: presenceDotState(status.presence) })
6673
- })
6674
- });
6885
+ /**
6886
+ * Split a literal text run into plain and branded-ref segments. The pattern
6887
+ * anchors on the fixed ref prefixes plus a UUID shape (full or abbreviated),
6888
+ * so ordinary prose containing a colon never linkifies; a doubled colon from
6889
+ * model output is tolerated. Segment refs are always canonical, so resolution
6890
+ * and navigation work regardless of how the ref was spelled; text without any
6891
+ * ref comes back as one untouched segment.
6892
+ */
6893
+ function splitBrandedRefs(text) {
6894
+ const segments = [];
6895
+ let cursor = 0;
6896
+ for (const match of text.matchAll(BRANDED_REF_PATTERN)) {
6897
+ const start = match.index ?? 0;
6898
+ if (start > cursor) segments.push({ text: text.slice(cursor, start) });
6899
+ segments.push({
6900
+ text: match[0],
6901
+ ref: canonicalBrandedRef(match[0])
6902
+ });
6903
+ cursor = start + match[0].length;
6904
+ }
6905
+ if (cursor < text.length) segments.push({ text: text.slice(cursor) });
6906
+ return segments;
6675
6907
  }
6676
- //#endregion
6677
- //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/members.module.css.mjs
6678
- const css$6 = ".UkovOW_body{max-height:min(65vh,560px);overflow-y:auto}.UkovOW_content{outline:none;gap:12px;display:grid}.UkovOW_group{gap:3px;display:grid}.UkovOW_group+.UkovOW_group{border-top:1px solid var(--dsw-alias-border-l2);padding-top:10px}.UkovOW_group h3{color:var(--dsw-alias-label-secondary);margin:0 0 3px;font-size:12px;font-weight:600;line-height:18px}.UkovOW_member{border-radius:6px;grid-template-columns:14px minmax(0,1fr);align-items:center;gap:0 8px;min-height:36px;padding:4px 6px;display:grid}.UkovOW_member:hover{background:var(--dsw-alias-interactive-bg-hover)}.UkovOW_copy{min-width:0;display:grid}.UkovOW_copy strong{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:500;line-height:18px;overflow:hidden}.UkovOW_copy small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:14px;overflow:hidden}.UkovOW_state,.UkovOW_error{margin:0;padding:6px 0;font-size:12px;line-height:18px}.UkovOW_state{color:var(--dsw-alias-label-tertiary)}.UkovOW_error{color:var(--dsw-alias-state-error-primary)}@media (width<=600px){.UkovOW_body{max-height:calc(100vh - 160px)}}";
6679
- const tagId$6 = "@wowyuarm/dsh-agent-team/members.module.css";
6680
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
6681
- const tag = document.createElement("style");
6682
- tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
6683
- tag.dataset.pluginCss = tagId$6;
6684
- tag.textContent = css$6;
6685
- document.head.appendChild(tag);
6908
+ /**
6909
+ * Whether one string's whole content is exactly one branded ref. A code span
6910
+ * like this is the model styling a ref as an identifier, not publishing code,
6911
+ * so the Markdown pass may linkify it; anything larger stays literal.
6912
+ */
6913
+ function isSingleBrandedRef(text) {
6914
+ const trimmed = text.trim();
6915
+ if (trimmed === "") return false;
6916
+ const matches = [...trimmed.matchAll(BRANDED_REF_PATTERN)];
6917
+ return matches.length === 1 && matches[0][0] === trimmed;
6686
6918
  }
6687
- var members_module_css_default = {
6688
- "body": "UkovOW_body",
6689
- "content": "UkovOW_content",
6690
- "copy": "UkovOW_copy",
6691
- "error": "UkovOW_error",
6692
- "group": "UkovOW_group",
6693
- "member": "UkovOW_member",
6694
- "state": "UkovOW_state"
6695
- };
6696
- //#endregion
6697
- //#region src/client/TeamMembersAction.tsx
6698
- function TeamMembersAction({ wide, loadMemberGroups, t }) {
6699
- const [panelOpen, setPanelOpen] = (0, react.useState)(false);
6700
- const [groups, setGroups] = (0, react.useState)([]);
6701
- const [loading, setLoading] = (0, react.useState)(false);
6702
- const [error, setError] = (0, react.useState)();
6703
- const triggerRef = (0, react.useRef)(null);
6704
- const contentRef = (0, react.useRef)(null);
6705
- (0, react.useEffect)(() => {
6706
- if (!panelOpen) return;
6707
- queueMicrotask(() => {
6708
- contentRef.current?.focus();
6709
- });
6710
- }, [panelOpen]);
6711
- const openMembers = () => {
6712
- setPanelOpen(true);
6713
- setLoading(true);
6714
- setError(void 0);
6715
- loadMemberGroups().then(setGroups).catch((cause) => {
6716
- setError(cause instanceof Error ? cause.message : String(cause));
6717
- }).finally(() => {
6718
- setLoading(false);
6719
- });
6919
+ function escapeRegExp(value) {
6920
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6921
+ }
6922
+ /**
6923
+ * Locate one Message's structured mention names inside its literal body. A
6924
+ * name matches case-insensitively with an optional leading '@' on Unicode word
6925
+ * boundaries, and longer names win at the same position. Mention segments
6926
+ * render the canonical `@Handle`; names absent from the body come back
6927
+ * unmatched so the consumer can append them as a fallback chip row.
6928
+ */
6929
+ function splitMentionNames(text, names) {
6930
+ if (names.length === 0) return {
6931
+ segments: [{
6932
+ text,
6933
+ mention: false
6934
+ }],
6935
+ unmatched: []
6720
6936
  };
6721
- const closeMembers = () => {
6722
- setPanelOpen(false);
6723
- queueMicrotask(() => {
6724
- triggerRef.current?.focus();
6937
+ const ordered = [...names].sort((left, right) => right.length - left.length);
6938
+ const pattern = new RegExp(`(?<![\\p{L}\\p{N}_@])@?(?:${ordered.map((name) => `(${escapeRegExp(name)})`).join("|")})(?=$|[^\\p{L}\\p{N}_])`, "giu");
6939
+ const segments = [];
6940
+ const matched = /* @__PURE__ */ new Set();
6941
+ let cursor = 0;
6942
+ for (const match of text.matchAll(pattern)) {
6943
+ const groupIndex = match.findIndex((group, index) => index >= 1 && group !== void 0);
6944
+ if (groupIndex < 1) continue;
6945
+ if (match.index > cursor) segments.push({
6946
+ text: text.slice(cursor, match.index),
6947
+ mention: false
6948
+ });
6949
+ const name = ordered[groupIndex - 1];
6950
+ segments.push({
6951
+ text: `@${name}`,
6952
+ mention: true,
6953
+ name
6725
6954
  });
6955
+ matched.add(name.toLowerCase());
6956
+ cursor = match.index + match[0].length;
6957
+ }
6958
+ if (cursor < text.length) segments.push({
6959
+ text: text.slice(cursor),
6960
+ mention: false
6961
+ });
6962
+ return {
6963
+ segments,
6964
+ unmatched: names.filter((name) => !matched.has(name.toLowerCase()))
6726
6965
  };
6727
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
6728
- label: t("members"),
6729
- delayMs: 500,
6730
- disabled: wide,
6731
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
6732
- ref: triggerRef,
6733
- type: "button",
6734
- className: wide ? team_module_css_default.settingsAction : `${team_module_css_default.settingsAction} ${team_module_css_default.rail}`,
6735
- "aria-label": t("members"),
6736
- "aria-haspopup": "dialog",
6737
- onClick: openMembers,
6738
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconUserOutline16, { size: wide ? 16 : 18 }), wide && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("members") })]
6739
- })
6740
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
6741
- open: panelOpen,
6742
- onClose: closeMembers,
6743
- title: t("members"),
6744
- closeLabel: t("close"),
6745
- contentClassName: members_module_css_default.body,
6746
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6747
- ref: contentRef,
6748
- className: members_module_css_default.content,
6749
- tabIndex: -1,
6750
- children: [
6751
- loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6752
- className: members_module_css_default.state,
6753
- role: "status",
6754
- children: t("loadingAgents")
6755
- }),
6756
- !loading && groups.length === 0 && error === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6757
- className: members_module_css_default.state,
6758
- children: t("emptyAgents")
6759
- }),
6760
- !loading && groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
6761
- className: members_module_css_default.group,
6762
- "aria-labelledby": `team-members-${group.workspaceId}`,
6763
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
6764
- id: `team-members-${group.workspaceId}`,
6765
- children: group.workspaceTitle
6766
- }), group.members.map((status) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6767
- className: members_module_css_default.member,
6768
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamPresenceDot, {
6769
- status,
6770
- t
6771
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6772
- className: members_module_css_default.copy,
6773
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: ["@", status.member.handle] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: status.member.description })]
6774
- })]
6775
- }, status.member.memberId))]
6776
- }, group.workspaceId)),
6777
- error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6778
- className: members_module_css_default.error,
6779
- role: "alert",
6780
- children: error
6781
- })
6782
- ]
6783
- })
6784
- })] });
6785
6966
  }
6786
- //#endregion
6787
- //#region src/client/TeamSettings.tsx
6788
- function TeamSettings({ wide, loadMemberGroups, t }) {
6789
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMembersAction, {
6790
- wide,
6791
- loadMemberGroups,
6792
- t
6793
- });
6967
+ /**
6968
+ * Whether one draft spells a handle as an authored `@mention`: a literal `@`
6969
+ * before the handle, case-insensitively, on Unicode word boundaries. The Host
6970
+ * resolves delivery from the same text with its own scanner, so this is the
6971
+ * Client's single answer to "did the author call this name" — the composer
6972
+ * prunes picked recipients with it and previews the draft's notifications with
6973
+ * it.
6974
+ */
6975
+ function containsMention(body, handle) {
6976
+ return new RegExp(`(?:^|[^\\p{L}\\p{N}_])@${escapeRegExp(handle)}(?=$|[^\\p{L}\\p{N}_])`, "iu").test(body);
6794
6977
  }
6795
- //#endregion
6796
- //#region src/client/attachment-preview.ts
6797
- /** Base64 one file payload in chunks so large uploads stay off the call-stack limit. */
6798
- function bytesToBase64(bytes) {
6799
- let binary = "";
6800
- const chunk = 32768;
6801
- for (let start = 0; start < bytes.length; start += chunk) binary += String.fromCharCode(...bytes.subarray(start, start + chunk));
6802
- return btoa(binary);
6978
+ /** Whether one draft carries the `@all` marker the mention menu expands. */
6979
+ function containsAllMention(body) {
6980
+ return /(?<![\p{L}\p{N}_@])@all(?=$|[^\p{L}\p{N}_])/u.test(body);
6803
6981
  }
6804
6982
  /**
6805
- * Thumbnail data URLs live in one session-wide cache: message lists re-render
6806
- * often, and each miss costs a Host round-trip plus a base64 decode. Failed
6807
- * loads (bytes already GC'd) are cached as `null` so the chip fallback is stable.
6983
+ * Every Member the mention menu's `@all` row stands for: the roster this
6984
+ * composer was handed minus Members who cannot take a Message right now — the
6985
+ * same filter the per-handle rows apply, so the expansion and the menu agree.
6808
6986
  */
6809
- const dataUrlCache = /* @__PURE__ */ new Map();
6810
- function cachedAttachmentDataUrl(attachmentId) {
6811
- return dataUrlCache.get(attachmentId);
6987
+ function allMentionMembers(members) {
6988
+ return members.filter((status) => status.presence !== "unavailable" && status.member.state !== "inactive" && status.member.state !== "archived");
6812
6989
  }
6813
- async function loadAttachmentDataUrl(getAttachment, attachment) {
6814
- const cached = dataUrlCache.get(attachment.attachmentId);
6815
- if (cached !== void 0) return cached;
6816
- const result = await getAttachment({ attachmentId: attachment.attachmentId });
6817
- const url = result.ok && attachment.mediaType.startsWith("image/") ? `data:${attachment.mediaType};base64,${result.value.bytesBase64}` : null;
6818
- dataUrlCache.set(attachment.attachmentId, url);
6819
- return url;
6990
+ /**
6991
+ * Member ids one draft asks to notify by text alone: the Client's preview of
6992
+ * the Host's own body mention resolution, so a hand-typed `@Handle` reports
6993
+ * exactly like a pick from the mention menu. `@all` stands for the menu's
6994
+ * expansion; a written handle counts whenever its Member can still take a
6995
+ * Message — state decides, not presence, because an offline Member is notified
6996
+ * and reads it later.
6997
+ *
6998
+ * The result is preview-only. Only picked recipients travel as explicit
6999
+ * recipients, where a name the Channel cannot reach would be a rejected target
7000
+ * rather than the prose the Host reads.
7001
+ */
7002
+ function mentionedMemberIds(body, members) {
7003
+ if (containsAllMention(body)) return allMentionMembers(members).map((status) => status.member.memberId);
7004
+ return members.filter((status) => status.member.state !== "inactive" && status.member.state !== "archived").filter((status) => containsMention(body, status.member.handle)).map((status) => status.member.memberId);
6820
7005
  }
6821
- /** Human-readable byte size for attachment chips. */
6822
- function formatByteSize(byteSize) {
6823
- if (byteSize < 1024) return `${byteSize} B`;
6824
- if (byteSize < 1024 * 1024) return `${(byteSize / 1024).toFixed(0)} KB`;
6825
- return `${(byteSize / (1024 * 1024)).toFixed(1)} MB`;
7006
+ /** Canonical chip handles for one Message's structured mention refs. */
7007
+ function mentionNamesOf(mentions, handles) {
7008
+ return mentions.map((memberId) => memberId === "member:human" ? "human" : handles.get(memberId)).filter((name) => name !== void 0);
6826
7009
  }
6827
- //#endregion
6828
- //#region src/client/requests.ts
6829
- /** Fresh idempotency identity for one Client-initiated durable request. */
6830
- const mintRequestId = () => crypto.randomUUID();
6831
- //#endregion
6832
- //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/composer.module.css.mjs
6833
- const css$5 = ".x9jGQq_root{padding:0 var(--dsh-composer-side-clearance,16px) 8px;flex-direction:column;align-items:center;display:flex}.x9jGQq_card{box-sizing:border-box;width:100%;max-width:var(--dsh-composer-card-max-width,780px);border:1px solid var(--dsw-alias-border-l2-darkmode-thin);background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1));box-shadow:var(--dsw-shadow-lv2);border-radius:22px;flex-direction:column;gap:6px;padding:10px 0 0;display:flex;position:relative}.x9jGQq_inputArea{min-height:28px;position:relative}.x9jGQq_inputArea textarea{box-sizing:border-box;resize:none;width:100%;min-height:28px;max-height:336px;color:var(--dsw-alias-label-primary,var(--dsw-alias-label-primary));font:inherit;white-space:pre-wrap;overflow-wrap:anywhere;background:0 0;border:0;outline:0;padding:4px 12px 0 16px;font-size:15px;line-height:24px;display:block;overflow-y:auto}.x9jGQq_inputArea textarea::placeholder{color:var(--dsw-alias-label-caption,var(--dsw-alias-label-tertiary))}.x9jGQq_inputArea textarea:disabled{cursor:not-allowed;opacity:.55}.x9jGQq_mentionMenu{z-index:10;border:1px solid var(--dsw-alias-border-inverted);background:var(--dsw-specific-menu);max-height:min(320px,40vh);box-shadow:var(--dsw-shadow-lv3);border-radius:12px;padding:4px;position:absolute;bottom:calc(100% + 12px);left:0;right:0;overflow-y:auto}.x9jGQq_mentionOption{width:100%;min-height:40px;color:var(--dsw-alias-label-primary,var(--dsw-alias-label-primary));cursor:pointer;text-align:left;background:0 0;border:0;border-radius:10px;grid-template-columns:16px minmax(0,auto) minmax(0,1fr);align-items:center;gap:8px;padding:8px 10px;font-size:14px;line-height:22px;display:grid}.x9jGQq_mentionOption:hover,.x9jGQq_mentionOption[aria-selected=true]{background:var(--dsw-alias-interactive-bg-hover)}.x9jGQq_mentionName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.x9jGQq_mentionAllDot{background:var(--dsw-alias-label-primary);border-radius:50%;justify-self:center;width:8px;height:8px}.x9jGQq_mentionDescription{min-width:0;color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-tertiary));text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.x9jGQq_toolbar{justify-content:flex-end;align-items:center;gap:6px;min-height:34px;padding:2px 8px 6px;display:flex}.x9jGQq_asTaskOn[aria-pressed=true],.x9jGQq_asTaskOn[aria-pressed=true]:hover:not(:disabled){background:var(--dsw-alias-button-primary-fill);border-color:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.x9jGQq_attachButton{background:var(--dsw-specific-selector);color:var(--dsw-alias-label-primary);cursor:pointer;border:0;border-radius:999px;flex:none;place-items:center;width:28px;height:28px;margin-right:auto;display:grid}.x9jGQq_attachButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.x9jGQq_attachButton:disabled{cursor:default;opacity:.5}.x9jGQq_attachButton:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,var(--dsw-specific-selector));outline-offset:1px}.x9jGQq_fileInput{display:none}.x9jGQq_fileChips{flex-wrap:wrap;gap:4px;margin:0;padding:4px 8px 0;list-style:none;display:flex}.x9jGQq_fileChip{background:var(--dsw-alias-interactive-bg-hover);border-radius:6px;align-items:center;gap:4px;max-width:100%;padding:2px 4px 2px 8px;display:inline-flex}.x9jGQq_fileChipSize{color:var(--dsw-alias-label-tertiary);margin-left:6px}.x9jGQq_imageChip{align-items:center;display:flex}.x9jGQq_imageChipPreview{border:1px solid var(--dsw-alias-border-l2);object-fit:cover;border-radius:4px;width:56px;height:40px}.x9jGQq_fileChipName{text-overflow:ellipsis;white-space:nowrap;max-width:220px;font-size:11px;line-height:16px;overflow:hidden}.x9jGQq_fileChipRemove{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;justify-content:center;align-items:center;width:16px;height:16px;padding:0;font-size:12px;display:inline-flex}.x9jGQq_fileChipRemove:hover,.x9jGQq_fileChipRemove:focus-visible{color:var(--dsw-alias-label-primary);outline:none}.x9jGQq_sendButton{background:var(--dsw-alias-button-info-fill,var(--dsw-alias-button-primary-fill));color:#fff;cursor:pointer;border:0;border-radius:50%;justify-content:center;align-items:center;width:34px;height:34px;padding:0;transition:background-color .1s,opacity .1s;display:inline-flex}.x9jGQq_sendButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover,var(--dsw-alias-button-primary-hover))}.x9jGQq_sendButton:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.x9jGQq_sendButton:disabled{cursor:not-allowed;opacity:.4}.x9jGQq_confirmation{color:var(--dsw-alias-label-tertiary);align-self:stretch;margin:0;padding:0 16px;font-size:12px;line-height:18px}.x9jGQq_notifyRow{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-tertiary));overflow-wrap:anywhere;margin:0;padding:0 16px;font-size:12px;line-height:18px}.x9jGQq_error{color:var(--dsw-alias-state-error-primary);align-self:stretch;margin:0;padding:0 4px 2px;font-size:12px;line-height:18px}@media (width<=600px){.x9jGQq_mentionOption{grid-template-columns:16px minmax(0,1fr);min-height:36px;padding-block:6px}.x9jGQq_mentionDescription{display:none}}@media (prefers-reduced-motion:reduce){.x9jGQq_sendButton{transition:none}}";
6834
- const tagId$5 = "@wowyuarm/dsh-agent-team/composer.module.css";
6835
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
6836
- const tag = document.createElement("style");
6837
- tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
6838
- tag.dataset.pluginCss = tagId$5;
6839
- tag.textContent = css$5;
6840
- document.head.appendChild(tag);
7010
+ const MARKDOWN_BLOCK_CONSTRUCT = /(^|\n)[ \t]{0,3}(?:#{1,6}[ \t]|>[ \t]|[-*+][ \t]|\d+[.)][ \t])|^[ \t]*\|.+\|/m;
7011
+ const MARKDOWN_INLINE_CONSTRUCT = /[`*_[\]!]|~~~|```/;
7012
+ /**
7013
+ * Whether an Agent body survives literal rendering unchanged: no fences,
7014
+ * inline code, emphasis markers, links, images, tables, or block constructs.
7015
+ * Only such plain-prose bodies may reuse the Human inline mention flow —
7016
+ * anything richer keeps the trailing chip row because the Markdown primitive
7017
+ * renders block-level documents that cannot interleave inline chips.
7018
+ */
7019
+ function isPlainTextBody(text) {
7020
+ return !(MARKDOWN_BLOCK_CONSTRUCT.test(text) || MARKDOWN_INLINE_CONSTRUCT.test(text));
6841
7021
  }
6842
- var composer_module_css_default = {
6843
- "asTaskOn": "x9jGQq_asTaskOn",
6844
- "attachButton": "x9jGQq_attachButton",
6845
- "card": "x9jGQq_card",
6846
- "confirmation": "x9jGQq_confirmation",
6847
- "error": "x9jGQq_error",
6848
- "fileChip": "x9jGQq_fileChip",
6849
- "fileChipName": "x9jGQq_fileChipName",
6850
- "fileChipRemove": "x9jGQq_fileChipRemove",
6851
- "fileChipSize": "x9jGQq_fileChipSize",
6852
- "fileChips": "x9jGQq_fileChips",
6853
- "fileInput": "x9jGQq_fileInput",
6854
- "imageChip": "x9jGQq_imageChip",
6855
- "imageChipPreview": "x9jGQq_imageChipPreview",
6856
- "inputArea": "x9jGQq_inputArea",
6857
- "mentionAllDot": "x9jGQq_mentionAllDot",
6858
- "mentionDescription": "x9jGQq_mentionDescription",
6859
- "mentionMenu": "x9jGQq_mentionMenu",
6860
- "mentionName": "x9jGQq_mentionName",
6861
- "mentionOption": "x9jGQq_mentionOption",
6862
- "notifyRow": "x9jGQq_notifyRow",
6863
- "root": "x9jGQq_root",
6864
- "sendButton": "x9jGQq_sendButton",
6865
- "toolbar": "x9jGQq_toolbar"
6866
- };
6867
- //#endregion
6868
- //#region src/client/TeamComposer.tsx
6869
- function findMention(draft, caret) {
6870
- const beforeCaret = draft.slice(0, caret);
6871
- if (beforeCaret.length === 0 || /\s/u.test(beforeCaret.at(-1) ?? "")) return void 0;
6872
- let tokenStart = beforeCaret.length;
6873
- while (tokenStart > 0 && !/\s/u.test(beforeCaret[tokenStart - 1])) tokenStart -= 1;
6874
- const at = beforeCaret.lastIndexOf("@");
6875
- if (at < tokenStart) return void 0;
6876
- if (at > 0 && /[\p{L}\p{N}_]/u.test(beforeCaret[at - 1])) return void 0;
6877
- return {
6878
- start: at,
6879
- end: caret,
6880
- query: beforeCaret.slice(at + 1)
6881
- };
7022
+ const pad$1 = (value) => String(value).padStart(2, "0");
7023
+ /** Absolute local `YYYY-MM-DD HH:mm` label: the precise instant behind every shorter form. */
7024
+ function formatAbsoluteTime(occurredAt) {
7025
+ const at = new Date(occurredAt);
7026
+ if (Number.isNaN(at.getTime())) return "";
7027
+ return `${at.getFullYear()}-${pad$1(at.getMonth() + 1)}-${pad$1(at.getDate())} ${pad$1(at.getHours())}:${pad$1(at.getMinutes())}`;
6882
7028
  }
6883
- function escapeRegExp$1(value) {
6884
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7029
+ /**
7030
+ * Wall-clock label for one Message instant: time within the current day,
7031
+ * month-day time within the year, full date otherwise.
7032
+ */
7033
+ function formatMessageTime(occurredAt, now = /* @__PURE__ */ new Date()) {
7034
+ const at = new Date(occurredAt);
7035
+ if (Number.isNaN(at.getTime())) return "";
7036
+ if (at.getFullYear() === now.getFullYear() && at.getMonth() === now.getMonth() && at.getDate() === now.getDate()) return `${pad$1(at.getHours())}:${pad$1(at.getMinutes())}`;
7037
+ const absolute = formatAbsoluteTime(occurredAt);
7038
+ return at.getFullYear() === now.getFullYear() ? absolute.slice(5) : absolute;
6885
7039
  }
6886
- function containsMention(draft, handle) {
6887
- return new RegExp(`(?:^|[^\\p{L}\\p{N}_])@${escapeRegExp$1(handle)}(?=$|[^\\p{L}\\p{N}_])`, "u").test(draft);
7040
+ /**
7041
+ * Calendar days between two instants in the viewer's own zone, so "yesterday"
7042
+ * means yesterday locally rather than 24 hours earlier.
7043
+ */
7044
+ function calendarDayDelta(at, now) {
7045
+ const midnight = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
7046
+ return Math.round((midnight(now) - midnight(at)) / 864e5);
6888
7047
  }
6889
- function mentionCandidates(members, query) {
6890
- const normalized = query.toLocaleLowerCase();
6891
- return members.filter((status) => status.presence !== "unavailable" && status.member.state !== "inactive" && status.member.state !== "archived" && status.member.handle.toLocaleLowerCase().startsWith(normalized));
7048
+ /**
7049
+ * Recency label for one Inbox row's newest fact, shared with the Channel feed's
7050
+ * entry line so the two agree about the same instant. Today is a bare clock time
7051
+ * — the reader is in today, and 「今天」 printed down every row spends the label's
7052
+ * first word on the one segment that never varies, while `HH:mm` alone still
7053
+ * reads as a clock because it is exactly one. The first day that is not today is
7054
+ * the fact the reader has to be told, so it keeps its word; everything older
7055
+ * keeps the Message date form, so the row and the Thread it opens agree.
7056
+ */
7057
+ function formatInboxTime(occurredAt, t, now = /* @__PURE__ */ new Date()) {
7058
+ const at = new Date(occurredAt);
7059
+ if (Number.isNaN(at.getTime())) return "";
7060
+ const days = calendarDayDelta(at, now);
7061
+ if (days === 0) return `${pad$1(at.getHours())}:${pad$1(at.getMinutes())}`;
7062
+ if (days === 1) return `${t("inboxTimeYesterday")} ${pad$1(at.getHours())}:${pad$1(at.getMinutes())}`;
7063
+ return formatMessageTime(occurredAt, now);
6892
7064
  }
6893
- /** Thread followers rank first: mentioning them delivers directly, while a non-follower enters the two-send invite flow. */
6894
- function rankMentionCandidates(candidates, followers) {
6895
- if (followers === void 0 || followers.size === 0) return candidates;
6896
- return [...candidates].sort((left, right) => Number(followers.has(right.member.memberId)) - Number(followers.has(left.member.memberId)));
7065
+ function formatActivity(activity, options) {
7066
+ const actor = options.actorName(activity.actor);
7067
+ if (activity.kind === "accept") return activity.completedClaimRefs !== void 0 && activity.completedClaimRefs.length > 0 ? options.t("activityAcceptedWithClaims", {
7068
+ actor,
7069
+ count: activity.completedClaimRefs.length
7070
+ }) : options.t("activityAccepted", { actor });
7071
+ if (activity.kind === "promote") return options.t("activityPromoted", { actor });
7072
+ if (activity.kind === "close") return options.t("activityClosed", { actor });
7073
+ if (activity.kind === "reopen") return options.t("activityReopened", { actor });
7074
+ const direction = "claimRef" in activity ? options.claims.find((claim) => claim.claimRef === activity.claimRef)?.direction ?? options.t("claims") : options.t("claims");
7075
+ if (activity.kind === "claim") return options.t("activityClaimed", {
7076
+ actor,
7077
+ direction
7078
+ });
7079
+ if (activity.kind === "done") return options.t("activityClaimDone", {
7080
+ actor,
7081
+ direction
7082
+ });
7083
+ if (activity.kind === "release") return options.t("activityClaimReleased", {
7084
+ actor,
7085
+ direction
7086
+ });
7087
+ if (activity.kind === "claims_released") return options.t("activityClaimsReleased", {
7088
+ actor,
7089
+ count: activity.claimRefs.length
7090
+ });
7091
+ throw new Error(`unknown Team Activity kind: ${activity.kind}`);
6897
7092
  }
6898
- /** Every member a manual handle pick could reach: the @all expansion snapshot. */
6899
- function allMentionMembers(members) {
6900
- return members.filter((status) => status.presence !== "unavailable" && status.member.state !== "inactive" && status.member.state !== "archived");
7093
+ /** Remove the machine-facing `[attachment] <path>` prompt lines from a body before display. */
7094
+ function stripAttachmentLines(body) {
7095
+ return body.replaceAll(/^\[attachment\] .*$(\n)?/gm, "").replace(/\n+$/, "");
7096
+ }
7097
+ /** Whether one displayed Message body starts clamped behind the expand control. */
7098
+ function shouldClampMessage(displayBody) {
7099
+ return displayBody.length > 600;
7100
+ }
7101
+ /**
7102
+ * Decide how one Message body renders. Human input and plain-prose Agent
7103
+ * bodies stay literal, with structured mention chips inline where possible;
7104
+ * rich Agent Markdown keeps unmatched mentions and non-Task refs in the
7105
+ * trailing fallback row while the post-render pass handles Task refs at their
7106
+ * authored position. Surfaces without ref navigation render everything
7107
+ * literally and keep the full fallback row.
7108
+ */
7109
+ function planMessageBody(body, options) {
7110
+ const stripped = stripAttachmentLines(body);
7111
+ const displayBody = stripped === "" ? body : stripped;
7112
+ const richAgentBody = !options.human && !isPlainTextBody(displayBody);
7113
+ const inline = (options.human || isPlainTextBody(displayBody)) && options.mentionNames !== void 0 && options.mentionNames.length > 0 ? splitMentionNames(displayBody, options.mentionNames) : void 0;
7114
+ const fallbackNames = inline !== void 0 ? inline.unmatched : richAgentBody && options.canOpenRefs && options.mentionNames !== void 0 ? splitMentionNames(displayBody, options.mentionNames).unmatched : options.mentionNames ?? [];
7115
+ const refs = splitBrandedRefs(displayBody).flatMap((segment) => segment.ref === void 0 ? [] : [segment.ref]);
7116
+ return {
7117
+ displayBody,
7118
+ richAgentBody,
7119
+ render: inline !== void 0 ? "inline" : options.human || options.canOpenRefs && !richAgentBody && refs.length > 0 ? "literal" : "markdown",
7120
+ ...inline === void 0 ? {} : { inline },
7121
+ fallbackNames,
7122
+ fallbackRefs: richAgentBody && !options.canOpenRefs ? refs : [],
7123
+ taskRefs: options.canOpenRefs && !richAgentBody ? refs.filter((ref) => ref.startsWith("task:")).map((ref) => ref) : []
7124
+ };
7125
+ }
7126
+ //#endregion
7127
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/state-dot.module.css.mjs
7128
+ const css$12 = ".DalNWW_quiet{corner-shape:round;border-radius:50%;flex:none;display:inline-block;position:relative}.DalNWW_quiet[data-variant=todo]{border:1px solid var(--dsw-alias-label-tertiary)}.DalNWW_quiet[data-variant=quiet]{color:var(--dsw-alias-label-tertiary)}.DalNWW_quiet[data-variant=quiet]:before{corner-shape:round;content:\"\";opacity:.1;background:currentColor;border-radius:50%;position:absolute;inset:0}.DalNWW_quiet[data-variant=quiet]:after{corner-shape:round;content:\"\";background:currentColor;border-radius:50%;position:absolute;inset:20%}";
7129
+ const tagId$12 = "@wowyuarm/dsh-agent-team/state-dot.module.css";
7130
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$12) + "]") === null) {
7131
+ const tag = document.createElement("style");
7132
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7133
+ tag.dataset.pluginCss = tagId$12;
7134
+ tag.textContent = css$12;
7135
+ document.head.appendChild(tag);
7136
+ }
7137
+ var state_dot_module_css_default = { "quiet": "DalNWW_quiet" };
7138
+ //#endregion
7139
+ //#region src/client/TeamStateDot.tsx
7140
+ /**
7141
+ * Render the one shared Team status indicator. Native StateDot states pass
7142
+ * through; the quiet statuses mirror StateDot geometry locally so every
7143
+ * surface renders the same shape — todo a hollow ring (not started), quiet a
7144
+ * solid tertiary dot with the same 10% halo (closed, unavailable).
7145
+ */
7146
+ function TeamStateDot({ state, size = 10 }) {
7147
+ if (state === "todo" || state === "quiet") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7148
+ className: state_dot_module_css_default.quiet,
7149
+ "data-variant": state,
7150
+ style: {
7151
+ width: size,
7152
+ height: size
7153
+ },
7154
+ "aria-hidden": "true"
7155
+ });
7156
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
7157
+ state,
7158
+ size
7159
+ });
7160
+ }
7161
+ //#endregion
7162
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/presence.module.css.mjs
7163
+ const css$11 = ".-\\36 lQ-q_target{flex:0 0 14px;justify-content:center;align-items:center;display:inline-flex}";
7164
+ const tagId$11 = "@wowyuarm/dsh-agent-team/presence.module.css";
7165
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$11) + "]") === null) {
7166
+ const tag = document.createElement("style");
7167
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7168
+ tag.dataset.pluginCss = tagId$11;
7169
+ tag.textContent = css$11;
7170
+ document.head.appendChild(tag);
7171
+ }
7172
+ var presence_module_css_default = { "target": "-6lQ-q_target" };
7173
+ //#endregion
7174
+ //#region src/client/TeamPresenceDot.tsx
7175
+ function presenceLabel(status, t) {
7176
+ const label = status.presence === "available" ? t("statusAvailable") : status.presence === "working" ? t("statusWorking") : status.presence === "error" ? t("statusError") : t("statusUnavailable");
7177
+ return status.diagnostic === void 0 ? label : `${label}: ${diagnosticText(status)}`;
7178
+ }
7179
+ /** One line of human-readable diagnostic text: the reason, plus the refused artifact path when one was reported. */
7180
+ function diagnosticText(status) {
7181
+ const diagnostic = status.diagnostic;
7182
+ if (diagnostic === void 0) return "";
7183
+ return diagnostic.location === void 0 ? diagnostic.detail : `${diagnostic.detail} (${diagnostic.location.path})`;
7184
+ }
7185
+ /**
7186
+ * Whether the restart action can help an unavailable Member: it heals
7187
+ * transient and repairable failures, but not a transient rollover window
7188
+ * (which resolves on its own) or a refusal already proven non-remediable.
7189
+ */
7190
+ function restartOffered(status) {
7191
+ const diagnostic = status.diagnostic;
7192
+ if (diagnostic === void 0) return true;
7193
+ if (diagnostic.class === "rollover") return false;
7194
+ return !(diagnostic.class === "session-refused" && diagnostic.remediable === false);
7195
+ }
7196
+ /** Shared presence → indicator mapping for dots and avatar badges. */
7197
+ function presenceDotState(presence) {
7198
+ return presence === "available" ? "done" : presence === "working" ? "ongoing" : presence === "error" ? "error" : "quiet";
7199
+ }
7200
+ function TeamPresenceDot({ status, t }) {
7201
+ const label = presenceLabel(status, t);
7202
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
7203
+ label,
7204
+ delayMs: 300,
7205
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7206
+ className: presence_module_css_default.target,
7207
+ role: "img",
7208
+ "aria-label": label,
7209
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamStateDot, { state: presenceDotState(status.presence) })
7210
+ })
7211
+ });
7212
+ }
7213
+ //#endregion
7214
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/sidebar.module.css.mjs
7215
+ const css$10 = "html[data-agent-team-mode=team] button[class*=newSession]{display:none}.d0xfxa_workspaceBrowser{flex-direction:column;height:100%;min-height:0;padding:0 8px 8px;display:flex}.d0xfxa_railButton{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0;display:inline-flex}.d0xfxa_railButton:hover,.d0xfxa_railButton:focus-visible{--team-mark-ring:var(--dsw-alias-interactive-bg-hover);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.d0xfxa_railButton:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.d0xfxa_workspaceList{flex-direction:column;gap:2px;padding-bottom:2px;display:flex}.d0xfxa_workspaceRow{color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;background:0 0;border:0;border-radius:8px;align-items:center;gap:6px;width:100%;height:34px;padding:0 8px;display:flex}.d0xfxa_workspaceRow:hover,.d0xfxa_workspaceRow:focus-visible,.d0xfxa_workspaceRow[aria-current=page]{background:var(--dsw-alias-interactive-bg-hover)}.d0xfxa_workspaceRow:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:-2px}.d0xfxa_workspaceIcon{color:var(--dsw-alias-label-tertiary);flex:0 0 16px;justify-content:center;align-items:center;height:20px;display:inline-flex}.d0xfxa_workspaceRow[data-selected] .d0xfxa_workspaceIcon{color:var(--dsw-alias-state-business-primary)}.d0xfxa_workspaceCopy{min-width:0;display:flex}.d0xfxa_workspaceCopy strong{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:400;line-height:20px;overflow:hidden}.d0xfxa_emptyState{color:var(--dsw-alias-label-tertiary);margin:8px;font-size:12px;line-height:18px}.d0xfxa_inboxCard{color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;background:0 0;border:0;border-radius:8px;flex:none;align-items:center;gap:6px;width:100%;height:34px;margin:4px 0 2px;padding:0 8px;display:flex}.d0xfxa_inboxCard:hover,.d0xfxa_inboxCard:focus-visible,.d0xfxa_inboxCard[aria-current=page]{--team-mark-ring:var(--dsw-alias-interactive-bg-hover);background:var(--dsw-alias-interactive-bg-hover)}.d0xfxa_inboxCard:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:-2px}.d0xfxa_inboxCard .d0xfxa_inboxMark{color:var(--dsw-alias-label-tertiary)}.d0xfxa_inboxCardLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:14px;line-height:20px;overflow:hidden}.d0xfxa_inboxMark{flex:0 0 16px;display:inline-flex;position:relative}.d0xfxa_inboxDot{background:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 2px var(--team-mark-ring,var(--dsw-alias-bg-base));corner-shape:round;border-radius:50%;width:8px;height:8px;position:absolute;top:-2px;left:-2px}.d0xfxa_railWorkspace{flex-direction:column;align-items:center;gap:8px;padding-top:8px;display:flex}.d0xfxa_railButton{corner-shape:round;border-radius:50%;width:36px;height:36px;position:relative}.d0xfxa_railButton[aria-current=page]{--team-mark-ring:var(--dsw-alias-interactive-bg-hover);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.d0xfxa_workspaceSection{flex-direction:column;flex:1;gap:4px;min-height:0;margin-top:2px;display:flex;overflow-y:auto}.d0xfxa_section{flex-direction:column;display:flex}.d0xfxa_sectionHeader{align-items:center;min-height:26px;padding-right:2px;display:flex}.d0xfxa_sectionToggle{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;align-items:center;gap:4px;min-width:0;min-height:24px;padding:0 6px;font-size:12px;line-height:18px;display:inline-flex}.d0xfxa_sectionToggle:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.d0xfxa_sectionToggle:hover .d0xfxa_sectionChevron,.d0xfxa_sectionToggle:focus-visible .d0xfxa_sectionChevron{color:var(--dsw-alias-label-primary)}.d0xfxa_sectionChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .12s,color .12s}.d0xfxa_sectionToggle[aria-expanded=false] .d0xfxa_sectionChevron{transform:rotate(-90deg)}.d0xfxa_sectionTitle{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.d0xfxa_sectionActions{align-items:center;margin-left:auto;display:inline-flex}.d0xfxa_panel{flex-direction:column;display:flex}.d0xfxa_iconButton{corner-shape:round;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:50%;justify-content:center;align-items:center;width:24px;height:24px;padding:0;display:inline-flex}.d0xfxa_iconButton:hover,.d0xfxa_iconButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.d0xfxa_iconButton:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.d0xfxa_textButton{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:2px 5px;font-size:11px;line-height:18px}.d0xfxa_textButton:hover,.d0xfxa_textButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.d0xfxa_textButton:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.d0xfxa_textButton:disabled{cursor:not-allowed;opacity:.4}.d0xfxa_channelList,.d0xfxa_agentList{flex-direction:column;gap:1px;padding:0 4px 4px;display:flex}.d0xfxa_sidebarRowDragging{opacity:.5}.d0xfxa_sidebarRowDropBefore,.d0xfxa_sidebarRowDropAfter{position:relative}.d0xfxa_sidebarRowDropBefore:before,.d0xfxa_sidebarRowDropAfter:after{content:\"\";z-index:1;background:linear-gradient(55deg, transparent calc(50% - 1px), var(--dsw-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 0 / 5px 7px no-repeat, linear-gradient(125deg, transparent calc(50% - 1px), var(--dsw-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 5px / 5px 7px no-repeat, linear-gradient(var(--dsw-alias-state-business-primary) 0 0) 4px 5px / calc(100% - 4px) 2px no-repeat;pointer-events:none;height:12px;position:absolute;left:0;right:4px}.d0xfxa_sidebarRowDropBefore:before{top:-7px}.d0xfxa_sidebarRowDropAfter:after{bottom:-7px}.d0xfxa_channelRow{color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;min-height:30px;display:flex;position:relative}.d0xfxa_channelSelect{box-sizing:border-box;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;border-radius:8px;flex:1;align-items:center;min-width:0;min-height:30px;padding:3px 4px 3px 8px;display:flex}.d0xfxa_channelSelect:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:-2px}.d0xfxa_channelName{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:400;line-height:18px;overflow:hidden}.d0xfxa_agentRow{color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;min-height:38px;display:flex;position:relative}.d0xfxa_agentSelect{box-sizing:border-box;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;border-radius:8px;flex:1;grid-template-columns:24px minmax(0,1fr);align-items:center;gap:0 8px;min-width:0;min-height:38px;padding:3px 4px 3px 8px;display:grid}.d0xfxa_agentSelect:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:-2px}.d0xfxa_agentSelect[aria-current=page]{background:var(--dsw-alias-interactive-bg-hover);border-radius:8px}.d0xfxa_agentRow:hover .d0xfxa_agentSelect[aria-current=page],.d0xfxa_agentRow:focus-within .d0xfxa_agentSelect[aria-current=page],.d0xfxa_agentRow[data-menu-open] .d0xfxa_agentSelect[aria-current=page]{background:0 0}.d0xfxa_agentAvatar{background:hsl(var(--team-avatar-hue,212) 42% 46%);corner-shape:round;color:#fff;cursor:default;border-radius:50%;flex:0 0 24px;justify-content:center;align-items:center;width:24px;height:24px;font-size:11px;font-weight:600;display:inline-flex;position:relative}.d0xfxa_agentAvatarBadge{background:var(--dsw-specific-sidebar-fill);corner-shape:round;box-shadow:0 0 0 1px var(--dsw-specific-sidebar-fill);border-radius:50%;justify-content:center;align-items:center;width:12px;height:12px;padding:1px;line-height:0;display:inline-flex;position:absolute;bottom:-3px;right:-3px}.d0xfxa_agentCopy{flex-direction:column;justify-content:flex-start;min-width:0;display:flex}.d0xfxa_agentCopy strong{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:500;line-height:17px;overflow:hidden}.d0xfxa_agentCopy small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:13px;overflow:hidden}.d0xfxa_unavailableDot{background:var(--dsw-alias-label-tertiary);corner-shape:round;border-radius:50%;width:7px;height:7px;display:inline-block}.d0xfxa_rowMenu{flex:none;align-items:center;padding-right:4px;display:none}.d0xfxa_channelRow:hover .d0xfxa_rowMenu,.d0xfxa_channelRow:focus-within .d0xfxa_rowMenu,.d0xfxa_channelRow[data-menu-open] .d0xfxa_rowMenu,.d0xfxa_agentRow:hover .d0xfxa_rowMenu,.d0xfxa_agentRow:focus-within .d0xfxa_rowMenu,.d0xfxa_agentRow[data-menu-open] .d0xfxa_rowMenu{display:inline-flex}.d0xfxa_channelRow[data-menu-open],.d0xfxa_agentRow[data-menu-open],.d0xfxa_channelRow:hover,.d0xfxa_agentRow:hover,.d0xfxa_channelRow:focus-within,.d0xfxa_agentRow:focus-within,.d0xfxa_channelRow[aria-current=page]{background:var(--dsw-alias-interactive-bg-hover)}.d0xfxa_rowMenuButton{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;justify-content:center;align-items:center;width:20px;height:20px;padding:0;display:inline-flex}.d0xfxa_rowMenuButton:hover,.d0xfxa_rowMenuButton:focus-visible{color:var(--dsw-alias-label-primary)}.d0xfxa_rowMenuButton:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.d0xfxa_retryError{color:var(--dsw-alias-state-error-primary);justify-content:space-between;align-items:center;gap:8px;padding:8px 12px;font-size:11px;display:flex}.d0xfxa_rowAlert{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;padding:2px 8px 6px;font-size:11px}.d0xfxa_error{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:0;padding:4px 12px 6px;font-size:11px;line-height:16px}.d0xfxa_editDescription{color:var(--dsw-alias-label-secondary);margin:0 0 10px;font-size:12px;line-height:18px}.d0xfxa_editMemberList{gap:2px;display:grid}.d0xfxa_editChannelName{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:400;line-height:18px;overflow:hidden}.d0xfxa_editHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:16px}.d0xfxa_menuHint{color:var(--dsw-alias-label-tertiary);margin-left:4px;font-size:10px;line-height:14px}.d0xfxa_rowError{color:var(--dsw-alias-state-error-primary);grid-column:1/-1;margin:2px 0;font-size:11px;line-height:16px}";
7216
+ const tagId$10 = "@wowyuarm/dsh-agent-team/sidebar.module.css";
7217
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$10) + "]") === null) {
7218
+ const tag = document.createElement("style");
7219
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7220
+ tag.dataset.pluginCss = tagId$10;
7221
+ tag.textContent = css$10;
7222
+ document.head.appendChild(tag);
7223
+ }
7224
+ var sidebar_module_css_default = {
7225
+ "agentAvatar": "d0xfxa_agentAvatar",
7226
+ "agentAvatarBadge": "d0xfxa_agentAvatarBadge",
7227
+ "agentCopy": "d0xfxa_agentCopy",
7228
+ "agentList": "d0xfxa_agentList",
7229
+ "agentRow": "d0xfxa_agentRow",
7230
+ "agentSelect": "d0xfxa_agentSelect",
7231
+ "channelList": "d0xfxa_channelList",
7232
+ "channelName": "d0xfxa_channelName",
7233
+ "channelRow": "d0xfxa_channelRow",
7234
+ "channelSelect": "d0xfxa_channelSelect",
7235
+ "editChannelName": "d0xfxa_editChannelName",
7236
+ "editDescription": "d0xfxa_editDescription",
7237
+ "editHint": "d0xfxa_editHint",
7238
+ "editMemberList": "d0xfxa_editMemberList",
7239
+ "emptyState": "d0xfxa_emptyState",
7240
+ "error": "d0xfxa_error",
7241
+ "iconButton": "d0xfxa_iconButton",
7242
+ "inboxCard": "d0xfxa_inboxCard",
7243
+ "inboxCardLabel": "d0xfxa_inboxCardLabel",
7244
+ "inboxDot": "d0xfxa_inboxDot",
7245
+ "inboxMark": "d0xfxa_inboxMark",
7246
+ "menuHint": "d0xfxa_menuHint",
7247
+ "panel": "d0xfxa_panel",
7248
+ "railButton": "d0xfxa_railButton",
7249
+ "railWorkspace": "d0xfxa_railWorkspace",
7250
+ "retryError": "d0xfxa_retryError",
7251
+ "rowAlert": "d0xfxa_rowAlert",
7252
+ "rowError": "d0xfxa_rowError",
7253
+ "rowMenu": "d0xfxa_rowMenu",
7254
+ "rowMenuButton": "d0xfxa_rowMenuButton",
7255
+ "section": "d0xfxa_section",
7256
+ "sectionActions": "d0xfxa_sectionActions",
7257
+ "sectionChevron": "d0xfxa_sectionChevron",
7258
+ "sectionHeader": "d0xfxa_sectionHeader",
7259
+ "sectionTitle": "d0xfxa_sectionTitle",
7260
+ "sectionToggle": "d0xfxa_sectionToggle",
7261
+ "sidebarRowDragging": "d0xfxa_sidebarRowDragging",
7262
+ "sidebarRowDropAfter": "d0xfxa_sidebarRowDropAfter",
7263
+ "sidebarRowDropBefore": "d0xfxa_sidebarRowDropBefore",
7264
+ "textButton": "d0xfxa_textButton",
7265
+ "unavailableDot": "d0xfxa_unavailableDot",
7266
+ "workspaceBrowser": "d0xfxa_workspaceBrowser",
7267
+ "workspaceCopy": "d0xfxa_workspaceCopy",
7268
+ "workspaceIcon": "d0xfxa_workspaceIcon",
7269
+ "workspaceList": "d0xfxa_workspaceList",
7270
+ "workspaceRow": "d0xfxa_workspaceRow",
7271
+ "workspaceSection": "d0xfxa_workspaceSection"
7272
+ };
7273
+ //#endregion
7274
+ //#region src/client/TeamMemberAvatar.tsx
7275
+ /**
7276
+ * Sidebar Member avatar reusing the conversation identity language: the
7277
+ * deterministic member hue and handle initial, with the presence indicator
7278
+ * overlaid at the bottom-right so one glyph carries identity and state.
7279
+ */
7280
+ function TeamMemberAvatar({ status, t }) {
7281
+ const label = presenceLabel(status, t);
7282
+ const state = presenceDotState(status.presence);
7283
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
7284
+ label,
7285
+ delayMs: 300,
7286
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7287
+ className: sidebar_module_css_default.agentAvatar,
7288
+ style: { "--team-avatar-hue": memberHue(status.member.memberId) },
7289
+ role: "img",
7290
+ "aria-label": label,
7291
+ children: [status.member.handle.replace("@", "").slice(0, 1).toUpperCase(), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7292
+ className: sidebar_module_css_default.agentAvatarBadge,
7293
+ "aria-hidden": "true",
7294
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamStateDot, { state })
7295
+ })]
7296
+ })
7297
+ });
7298
+ }
7299
+ //#endregion
7300
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/member-row.module.css.mjs
7301
+ const css$9 = ".xnbzeW_row{border-radius:8px;grid-template-columns:24px minmax(0,1fr);align-items:center;gap:0 10px;min-height:40px;padding:8px 10px;display:grid}.xnbzeW_row:has(button){grid-template-columns:24px minmax(0,1fr) auto}.xnbzeW_row:hover{background:var(--dsw-alias-interactive-bg-hover)}.xnbzeW_copy{min-width:0;display:grid}.xnbzeW_copy strong{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:500;line-height:18px;overflow:hidden}.xnbzeW_copy small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;line-height:16px;overflow:hidden}.xnbzeW_action{justify-self:end;min-width:64px}.xnbzeW_error{color:var(--dsw-alias-state-error-primary);grid-column:2/-1;margin:2px 0 0;font-size:11px;line-height:16px}@media (width<=600px){.xnbzeW_row,.xnbzeW_row:has(button){grid-template-columns:24px minmax(0,1fr);align-items:start}.xnbzeW_action{grid-column:2;justify-self:start;margin-top:6px}}";
7302
+ const tagId$9 = "@wowyuarm/dsh-agent-team/member-row.module.css";
7303
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$9) + "]") === null) {
7304
+ const tag = document.createElement("style");
7305
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7306
+ tag.dataset.pluginCss = tagId$9;
7307
+ tag.textContent = css$9;
7308
+ document.head.appendChild(tag);
7309
+ }
7310
+ var member_row_module_css_default = {
7311
+ "action": "xnbzeW_action",
7312
+ "copy": "xnbzeW_copy",
7313
+ "error": "xnbzeW_error",
7314
+ "row": "xnbzeW_row"
7315
+ };
7316
+ //#endregion
7317
+ //#region src/client/TeamMemberRow.tsx
7318
+ /**
7319
+ * The one place a Member's identity is drawn: the presence-bearing avatar plus
7320
+ * the handle over its description. Read-only rosters, the rosters with a
7321
+ * membership action, and the sidebar Agent list all render this, so identity,
7322
+ * tone and truncation cannot drift between surfaces that show the same person.
7323
+ *
7324
+ * A fragment, not a row: each surface owns its own row element, hit target and
7325
+ * grid, and places this identity in that grid's first two tracks. The handle
7326
+ * spelling is the surface's call — rosters address Members the way the
7327
+ * composer does (`@handle`), the sidebar names them as the directory does.
7328
+ */
7329
+ function TeamMemberIdentity({ status, name, className, t }) {
7330
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberAvatar, {
7331
+ status,
7332
+ t
7333
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7334
+ className: className === void 0 ? member_row_module_css_default.copy : `${member_row_module_css_default.copy} ${className}`,
7335
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: name ?? `@${status.member.handle.replace(/^@/, "")}` }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: status.member.description })]
7336
+ })] });
7337
+ }
7338
+ /**
7339
+ * The one roster row: identity, an optional membership action, and the row's
7340
+ * own failure line. The action is the row's only chrome, so the eye lands on
7341
+ * the handle first and on the action second. A read-only roster omits it and
7342
+ * the trailing track collapses, handing its width back to the description.
7343
+ */
7344
+ function TeamMemberRow({ status, action, error, className, t }) {
7345
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7346
+ className: className === void 0 ? member_row_module_css_default.row : `${member_row_module_css_default.row} ${className}`,
7347
+ "data-team-member-row": true,
7348
+ children: [
7349
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberIdentity, {
7350
+ status,
7351
+ t
7352
+ }),
7353
+ action !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
7354
+ size: "sm",
7355
+ variant: "outline",
7356
+ className: member_row_module_css_default.action,
7357
+ disabled: action.disabled === true,
7358
+ onClick: action.onSelect,
7359
+ children: action.label
7360
+ }),
7361
+ error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7362
+ className: member_row_module_css_default.error,
7363
+ role: "alert",
7364
+ children: error
7365
+ })
7366
+ ]
7367
+ });
7368
+ }
7369
+ //#endregion
7370
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/members.module.css.mjs
7371
+ const css$8 = ".UkovOW_body{max-height:min(65vh,560px);overflow-y:auto}.UkovOW_content{outline:none;gap:12px;display:grid}.UkovOW_group{gap:2px;display:grid}.UkovOW_group+.UkovOW_group{border-top:1px solid var(--dsw-alias-border-l2);padding-top:10px}.UkovOW_group h3{color:var(--dsw-alias-label-secondary);margin:0 0 3px;font-size:12px;font-weight:600;line-height:18px}.UkovOW_member{margin:0 -6px}.UkovOW_state,.UkovOW_error{margin:0;padding:6px 0;font-size:12px;line-height:18px}.UkovOW_state{color:var(--dsw-alias-label-tertiary)}.UkovOW_error{color:var(--dsw-alias-state-error-primary)}@media (width<=600px){.UkovOW_body{max-height:calc(100vh - 160px)}}";
7372
+ const tagId$8 = "@wowyuarm/dsh-agent-team/members.module.css";
7373
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$8) + "]") === null) {
7374
+ const tag = document.createElement("style");
7375
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7376
+ tag.dataset.pluginCss = tagId$8;
7377
+ tag.textContent = css$8;
7378
+ document.head.appendChild(tag);
6901
7379
  }
6902
- function containsAllMention(draft) {
6903
- return /(?:^|[^\p{L}\p{N}_])@all(?=$|[^\p{L}\p{N}_])/u.test(draft);
7380
+ var members_module_css_default = {
7381
+ "body": "UkovOW_body",
7382
+ "content": "UkovOW_content",
7383
+ "error": "UkovOW_error",
7384
+ "group": "UkovOW_group",
7385
+ "member": "UkovOW_member",
7386
+ "state": "UkovOW_state"
7387
+ };
7388
+ //#endregion
7389
+ //#region src/client/TeamMembersAction.tsx
7390
+ function TeamMembersAction({ wide, loadMemberGroups, t }) {
7391
+ const [panelOpen, setPanelOpen] = (0, react.useState)(false);
7392
+ const [groups, setGroups] = (0, react.useState)([]);
7393
+ const [loading, setLoading] = (0, react.useState)(false);
7394
+ const [error, setError] = (0, react.useState)();
7395
+ const triggerRef = (0, react.useRef)(null);
7396
+ const contentRef = (0, react.useRef)(null);
7397
+ (0, react.useEffect)(() => {
7398
+ if (!panelOpen) return;
7399
+ queueMicrotask(() => {
7400
+ contentRef.current?.focus();
7401
+ });
7402
+ }, [panelOpen]);
7403
+ const openMembers = () => {
7404
+ setPanelOpen(true);
7405
+ setLoading(true);
7406
+ setError(void 0);
7407
+ loadMemberGroups().then(setGroups).catch((cause) => {
7408
+ setError(cause instanceof Error ? cause.message : String(cause));
7409
+ }).finally(() => {
7410
+ setLoading(false);
7411
+ });
7412
+ };
7413
+ const closeMembers = () => {
7414
+ setPanelOpen(false);
7415
+ queueMicrotask(() => {
7416
+ triggerRef.current?.focus();
7417
+ });
7418
+ };
7419
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
7420
+ label: t("members"),
7421
+ delayMs: 500,
7422
+ disabled: wide,
7423
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
7424
+ ref: triggerRef,
7425
+ type: "button",
7426
+ className: wide ? team_module_css_default.settingsAction : `${team_module_css_default.settingsAction} ${team_module_css_default.rail}`,
7427
+ "aria-label": t("members"),
7428
+ "aria-haspopup": "dialog",
7429
+ onClick: openMembers,
7430
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconUserOutline16, { size: wide ? 16 : 18 }), wide && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("members") })]
7431
+ })
7432
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
7433
+ open: panelOpen,
7434
+ onClose: closeMembers,
7435
+ title: t("members"),
7436
+ closeLabel: t("close"),
7437
+ contentClassName: members_module_css_default.body,
7438
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7439
+ ref: contentRef,
7440
+ className: members_module_css_default.content,
7441
+ tabIndex: -1,
7442
+ children: [
7443
+ loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7444
+ className: members_module_css_default.state,
7445
+ role: "status",
7446
+ children: t("loadingAgents")
7447
+ }),
7448
+ !loading && groups.length === 0 && error === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7449
+ className: members_module_css_default.state,
7450
+ children: t("emptyAgents")
7451
+ }),
7452
+ !loading && groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
7453
+ className: members_module_css_default.group,
7454
+ "aria-labelledby": `team-members-${group.workspaceId}`,
7455
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
7456
+ id: `team-members-${group.workspaceId}`,
7457
+ children: group.workspaceTitle
7458
+ }), group.members.map((status) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberRow, {
7459
+ status,
7460
+ className: members_module_css_default.member,
7461
+ t
7462
+ }, status.member.memberId))]
7463
+ }, group.workspaceId)),
7464
+ error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7465
+ className: members_module_css_default.error,
7466
+ role: "alert",
7467
+ children: error
7468
+ })
7469
+ ]
7470
+ })
7471
+ })] });
7472
+ }
7473
+ //#endregion
7474
+ //#region src/client/attachment-preview.ts
7475
+ /** Base64 one file payload in chunks so large uploads stay off the call-stack limit. */
7476
+ function bytesToBase64(bytes) {
7477
+ let binary = "";
7478
+ const chunk = 32768;
7479
+ for (let start = 0; start < bytes.length; start += chunk) binary += String.fromCharCode(...bytes.subarray(start, start + chunk));
7480
+ return btoa(binary);
7481
+ }
7482
+ /**
7483
+ * Thumbnail data URLs live in one session-wide cache: message lists re-render
7484
+ * often, and each miss costs a Host round-trip plus a base64 decode. Failed
7485
+ * loads (bytes already GC'd) are cached as `null` so the chip fallback is stable.
7486
+ */
7487
+ const dataUrlCache = /* @__PURE__ */ new Map();
7488
+ function cachedAttachmentDataUrl(attachmentId) {
7489
+ return dataUrlCache.get(attachmentId);
7490
+ }
7491
+ async function loadAttachmentDataUrl(getAttachment, attachment) {
7492
+ const cached = dataUrlCache.get(attachment.attachmentId);
7493
+ if (cached !== void 0) return cached;
7494
+ const result = await getAttachment({ attachmentId: attachment.attachmentId });
7495
+ const url = result.ok && attachment.mediaType.startsWith("image/") ? `data:${attachment.mediaType};base64,${result.value.bytesBase64}` : null;
7496
+ dataUrlCache.set(attachment.attachmentId, url);
7497
+ return url;
7498
+ }
7499
+ /** Human-readable byte size for attachment chips. */
7500
+ function formatByteSize(byteSize) {
7501
+ if (byteSize < 1024) return `${byteSize} B`;
7502
+ if (byteSize < 1024 * 1024) return `${(byteSize / 1024).toFixed(0)} KB`;
7503
+ return `${(byteSize / (1024 * 1024)).toFixed(1)} MB`;
7504
+ }
7505
+ //#endregion
7506
+ //#region src/client/requests.ts
7507
+ /** Fresh idempotency identity for one Client-initiated durable request. */
7508
+ const mintRequestId = () => crypto.randomUUID();
7509
+ /**
7510
+ * Upload composer files in order. One failure stops with the error text; the
7511
+ * caller keeps its chips so a retry uploads only the still-pending files.
7512
+ */
7513
+ const uploadComposerFiles = async (putAttachment, workspaceId, files) => {
7514
+ const attachmentIds = [];
7515
+ for (const file of files) {
7516
+ const uploaded = await putAttachment({
7517
+ requestId: mintRequestId(),
7518
+ workspaceId,
7519
+ name: file.name,
7520
+ mediaType: file.type === "" ? void 0 : file.type,
7521
+ bytesBase64: bytesToBase64(new Uint8Array(await file.arrayBuffer()))
7522
+ });
7523
+ if (!uploaded.ok) return {
7524
+ ok: false,
7525
+ error: uploaded.error.message
7526
+ };
7527
+ attachmentIds.push(uploaded.value.attachmentId);
7528
+ }
7529
+ return {
7530
+ ok: true,
7531
+ attachmentIds
7532
+ };
7533
+ };
7534
+ //#endregion
7535
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/composer.module.css.mjs
7536
+ const css$7 = ".x9jGQq_root{padding:0 var(--dsh-composer-side-clearance,16px) 8px;flex-direction:column;align-items:center;display:flex}.x9jGQq_card{box-sizing:border-box;width:100%;max-width:var(--dsh-composer-card-max-width,780px);border:1px solid var(--dsw-alias-border-l2-darkmode-thin);background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1));box-shadow:var(--dsw-shadow-lv2);border-radius:22px;flex-direction:column;gap:6px;padding:10px 0 0;display:flex;position:relative}.x9jGQq_inputArea{min-height:28px;position:relative}.x9jGQq_inputArea textarea{box-sizing:border-box;resize:none;width:100%;min-height:28px;max-height:336px;color:var(--dsw-alias-label-primary,var(--dsw-alias-label-primary));font:inherit;white-space:pre-wrap;overflow-wrap:anywhere;background:0 0;border:0;outline:0;padding:4px 12px 0 16px;font-size:15px;line-height:24px;display:block;overflow-y:auto}.x9jGQq_inputArea textarea::placeholder{color:var(--dsw-alias-label-caption,var(--dsw-alias-label-tertiary))}.x9jGQq_inputArea textarea:disabled{cursor:not-allowed;opacity:.55}.x9jGQq_mentionMenu{z-index:10;border:1px solid var(--dsw-alias-border-inverted);background:var(--dsw-specific-menu);max-height:min(320px,40vh);box-shadow:var(--dsw-shadow-lv3);border-radius:12px;padding:4px;position:absolute;bottom:calc(100% + 12px);left:0;right:0;overflow-y:auto}.x9jGQq_mentionOption{width:100%;min-height:40px;color:var(--dsw-alias-label-primary,var(--dsw-alias-label-primary));cursor:pointer;text-align:left;background:0 0;border:0;border-radius:10px;grid-template-columns:16px minmax(0,auto) minmax(0,1fr);align-items:center;gap:8px;padding:8px 10px;font-size:14px;line-height:22px;display:grid}.x9jGQq_mentionOption:hover,.x9jGQq_mentionOption[aria-selected=true]{background:var(--dsw-alias-interactive-bg-hover)}.x9jGQq_mentionName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.x9jGQq_mentionAllDot{corner-shape:round;background:var(--dsw-alias-label-primary);border-radius:50%;justify-self:center;width:8px;height:8px}.x9jGQq_mentionDescription{min-width:0;color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-tertiary));text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.x9jGQq_toolbar{justify-content:flex-end;align-items:center;gap:12px;min-height:34px;padding:2px 8px 6px;display:flex;container-type:inline-size}.x9jGQq_asTaskPill{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:24px;flex:none;align-items:center;gap:4px;height:28px;padding:0 10px 0 8px;font-size:13px;font-weight:500;line-height:20px;display:inline-flex}.x9jGQq_asTaskPill:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.x9jGQq_asTaskPill:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.x9jGQq_asTaskPill:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.x9jGQq_asTaskPillOn,.x9jGQq_asTaskPillOn:hover:not(:disabled){background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.x9jGQq_asTaskLabel{white-space:nowrap}@container (width<=460px){.x9jGQq_asTaskPill .x9jGQq_asTaskLabel{display:none}}.x9jGQq_attachButton{background:var(--dsw-specific-selector);corner-shape:round;color:var(--dsw-alias-label-primary);cursor:pointer;border:0;border-radius:999px;flex:none;place-items:center;width:28px;height:28px;display:grid}.x9jGQq_attachButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.x9jGQq_attachButton:disabled{cursor:default;opacity:.5}.x9jGQq_attachButton:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,var(--dsw-specific-selector));outline-offset:1px}.x9jGQq_fileInput{display:none}.x9jGQq_fileChips{flex-wrap:wrap;gap:4px;margin:0;padding:4px 8px 0;list-style:none;display:flex}.x9jGQq_fileChip{background:var(--dsw-alias-interactive-bg-hover);border-radius:6px;align-items:center;gap:4px;max-width:100%;padding:2px 4px 2px 8px;display:inline-flex}.x9jGQq_fileChipSize{color:var(--dsw-alias-label-tertiary);margin-left:6px}.x9jGQq_imageChip{align-items:center;display:flex}.x9jGQq_imageChipPreview{border:1px solid var(--dsw-alias-border-l2);object-fit:cover;border-radius:4px;width:56px;height:40px}.x9jGQq_fileChipName{text-overflow:ellipsis;white-space:nowrap;max-width:220px;font-size:11px;line-height:16px;overflow:hidden}.x9jGQq_fileChipRemove{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;justify-content:center;align-items:center;width:16px;height:16px;padding:0;font-size:12px;display:inline-flex}.x9jGQq_fileChipRemove:hover,.x9jGQq_fileChipRemove:focus-visible{color:var(--dsw-alias-label-primary)}.x9jGQq_fileChipRemove:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.x9jGQq_sendButton{background:var(--dsw-alias-button-info-fill,var(--dsw-alias-button-primary-fill));corner-shape:round;color:#fff;cursor:pointer;border:0;border-radius:999px;justify-content:center;align-items:center;width:34px;height:34px;margin-left:auto;padding:0;transition:background-color .1s,opacity .1s;display:inline-flex;transform:translateY(-2px)}.x9jGQq_sendButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover,var(--dsw-alias-button-primary-hover))}.x9jGQq_sendButton:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.x9jGQq_sendButton:disabled{cursor:default;opacity:.4}.x9jGQq_confirmation{color:var(--dsw-alias-label-tertiary);align-self:stretch;margin:0;padding:0 16px;font-size:12px;line-height:18px}.x9jGQq_notifyRow{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-tertiary));overflow-wrap:anywhere;margin:0;padding:0 16px;font-size:12px;line-height:18px}.x9jGQq_error{color:var(--dsw-alias-state-error-primary);align-self:stretch;margin:0;padding:0 4px 2px;font-size:12px;line-height:18px}@media (width<=600px){.x9jGQq_mentionOption{grid-template-columns:16px minmax(0,1fr);min-height:36px;padding-block:6px}.x9jGQq_mentionDescription{display:none}}@media (prefers-reduced-motion:reduce){.x9jGQq_sendButton{transition:none}}";
7537
+ const tagId$7 = "@wowyuarm/dsh-agent-team/composer.module.css";
7538
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$7) + "]") === null) {
7539
+ const tag = document.createElement("style");
7540
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7541
+ tag.dataset.pluginCss = tagId$7;
7542
+ tag.textContent = css$7;
7543
+ document.head.appendChild(tag);
7544
+ }
7545
+ var composer_module_css_default = {
7546
+ "asTaskLabel": "x9jGQq_asTaskLabel",
7547
+ "asTaskPill": "x9jGQq_asTaskPill",
7548
+ "asTaskPillOn": "x9jGQq_asTaskPillOn",
7549
+ "attachButton": "x9jGQq_attachButton",
7550
+ "card": "x9jGQq_card",
7551
+ "confirmation": "x9jGQq_confirmation",
7552
+ "error": "x9jGQq_error",
7553
+ "fileChip": "x9jGQq_fileChip",
7554
+ "fileChipName": "x9jGQq_fileChipName",
7555
+ "fileChipRemove": "x9jGQq_fileChipRemove",
7556
+ "fileChipSize": "x9jGQq_fileChipSize",
7557
+ "fileChips": "x9jGQq_fileChips",
7558
+ "fileInput": "x9jGQq_fileInput",
7559
+ "imageChip": "x9jGQq_imageChip",
7560
+ "imageChipPreview": "x9jGQq_imageChipPreview",
7561
+ "inputArea": "x9jGQq_inputArea",
7562
+ "mentionAllDot": "x9jGQq_mentionAllDot",
7563
+ "mentionDescription": "x9jGQq_mentionDescription",
7564
+ "mentionMenu": "x9jGQq_mentionMenu",
7565
+ "mentionName": "x9jGQq_mentionName",
7566
+ "mentionOption": "x9jGQq_mentionOption",
7567
+ "notifyRow": "x9jGQq_notifyRow",
7568
+ "root": "x9jGQq_root",
7569
+ "sendButton": "x9jGQq_sendButton",
7570
+ "toolbar": "x9jGQq_toolbar"
7571
+ };
7572
+ //#endregion
7573
+ //#region src/client/TeamComposer.tsx
7574
+ function findMention(draft, caret) {
7575
+ const beforeCaret = draft.slice(0, caret);
7576
+ if (beforeCaret.length === 0 || /\s/u.test(beforeCaret.at(-1) ?? "")) return void 0;
7577
+ let tokenStart = beforeCaret.length;
7578
+ while (tokenStart > 0 && !/\s/u.test(beforeCaret[tokenStart - 1])) tokenStart -= 1;
7579
+ const at = beforeCaret.lastIndexOf("@");
7580
+ if (at < tokenStart) return void 0;
7581
+ if (at > 0 && /[\p{L}\p{N}_]/u.test(beforeCaret[at - 1])) return void 0;
7582
+ return {
7583
+ start: at,
7584
+ end: caret,
7585
+ query: beforeCaret.slice(at + 1)
7586
+ };
7587
+ }
7588
+ function mentionCandidates(members, query) {
7589
+ const normalized = query.toLocaleLowerCase();
7590
+ return members.filter((status) => status.presence !== "unavailable" && status.member.state !== "inactive" && status.member.state !== "archived" && status.member.handle.toLocaleLowerCase().startsWith(normalized));
7591
+ }
7592
+ /** Thread followers rank first: mentioning them delivers directly, while a non-follower enters the two-send invite flow. */
7593
+ function rankMentionCandidates(candidates, followers) {
7594
+ if (followers === void 0 || followers.size === 0) return candidates;
7595
+ return [...candidates].sort((left, right) => Number(followers.has(right.member.memberId)) - Number(followers.has(left.member.memberId)));
6904
7596
  }
6905
7597
  /** One object URL per draft file; revoked when the draft is removed. */
6906
7598
  const draftPreviewUrls = /* @__PURE__ */ new WeakMap();
@@ -6913,13 +7605,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6913
7605
  }
6914
7606
  return url;
6915
7607
  }
6916
- function TeamComposer({ members, followerMemberIds, recipients, draft, pending, confirmation, error, onDraftChange, onRecipientsChange, onSubmit, placeholder, pendingFiles, onFilesChange, asTask, onAsTaskChange, t }) {
7608
+ function TeamComposer({ members, followerMemberIds, drafts, draftKey, pending, confirmation, error, onEdit, onSubmit, placeholder, pendingFiles, onFilesChange, asTask, onAsTaskChange, t }) {
6917
7609
  const inputRef = (0, react.useRef)(null);
6918
7610
  const fileInputRef = (0, react.useRef)(null);
6919
7611
  const rootRef = (0, react.useRef)(null);
6920
7612
  const menuRef = (0, react.useRef)(null);
6921
7613
  const activeOptionRef = (0, react.useRef)(null);
6922
7614
  const composingRef = (0, react.useRef)(false);
7615
+ const { draft, recipients } = (0, react.useSyncExternalStore)(drafts.subscribe, () => drafts.getSnapshot(draftKey));
6923
7616
  const [mention, setMention] = (0, react.useState)();
6924
7617
  const [highlight, setHighlight] = (0, react.useState)(0);
6925
7618
  const memberCandidates = mention === void 0 ? [] : rankMentionCandidates(mentionCandidates(members, mention.query), followerMemberIds);
@@ -6969,14 +7662,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6969
7662
  if (confirmation === void 0 || pending) return;
6970
7663
  inputRef.current?.focus({ preventScroll: true });
6971
7664
  }, [confirmation, pending]);
7665
+ const memberHandles = new Map(members.map((status) => [status.member.memberId, status.member.handle]));
6972
7666
  const pruneRecipients = (nextDraft) => {
6973
7667
  if (containsAllMention(nextDraft)) return;
6974
- const knownMembers = new Map(members.map((status) => [status.member.memberId, status.member]));
6975
7668
  const next = new Set([...recipients].filter((memberId) => {
6976
- const member = knownMembers.get(memberId);
6977
- return member !== void 0 && containsMention(nextDraft, member.handle);
7669
+ const handle = memberHandles.get(memberId);
7670
+ return handle !== void 0 && containsMention(nextDraft, handle);
6978
7671
  }));
6979
- if (next.size !== recipients.size) onRecipientsChange(next);
7672
+ if (next.size !== recipients.size) drafts.writeRecipients(draftKey, next);
6980
7673
  };
6981
7674
  (0, react.useEffect)(() => {
6982
7675
  if (members.length === 0) return;
@@ -6986,6 +7679,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6986
7679
  recipients,
6987
7680
  members
6988
7681
  ]);
7682
+ const notifiedIds = [...new Set([...recipients, ...mentionedMemberIds(draft, members)])].sort();
6989
7683
  const updateMention = (nextDraft, caret) => {
6990
7684
  const match = findMention(nextDraft, caret);
6991
7685
  setMention(match);
@@ -6993,13 +7687,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6993
7687
  };
6994
7688
  const onChange = (event) => {
6995
7689
  const nextDraft = event.target.value;
6996
- onDraftChange(nextDraft);
7690
+ drafts.writeDraft(draftKey, nextDraft);
7691
+ onEdit?.();
6997
7692
  pruneRecipients(nextDraft);
6998
7693
  updateMention(nextDraft, event.target.selectionStart ?? nextDraft.length);
6999
7694
  };
7000
7695
  const commitMention = (nextDraft, nextCaret, nextRecipients) => {
7001
- onDraftChange(nextDraft);
7002
- onRecipientsChange(nextRecipients);
7696
+ drafts.writeDraft(draftKey, nextDraft);
7697
+ drafts.writeRecipients(draftKey, nextRecipients);
7698
+ onEdit?.();
7003
7699
  setMention(void 0);
7004
7700
  setHighlight(0);
7005
7701
  requestAnimationFrame(() => {
@@ -7172,10 +7868,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7172
7868
  }
7173
7869
  })]
7174
7870
  }),
7175
- recipients.size > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7871
+ notifiedIds.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7176
7872
  className: composer_module_css_default.notifyRow,
7177
7873
  "data-team-notify": true,
7178
- children: t("composerNotify", { ids: [...recipients].sort().map((memberId) => `@${members.find((candidate) => candidate.member.memberId === memberId)?.member.handle ?? memberId}`).join(", ") })
7874
+ children: t("composerNotify", { ids: notifiedIds.map((memberId) => `@${memberHandles.get(memberId) ?? memberId}`).join(", ") })
7179
7875
  }),
7180
7876
  onFilesChange !== void 0 && pendingFiles !== void 0 && pendingFiles.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
7181
7877
  className: composer_module_css_default.fileChips,
@@ -7213,21 +7909,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7213
7909
  ]
7214
7910
  }, `${file.name}-${index}`);
7215
7911
  })
7216
- }),
7217
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7218
- className: composer_module_css_default.toolbar,
7219
- children: [
7220
- onAsTaskChange !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
7221
- size: "sm",
7222
- variant: "outline",
7223
- className: asTask === true ? composer_module_css_default.asTaskOn : void 0,
7224
- "aria-pressed": asTask === true,
7225
- disabled: pending,
7226
- onClick: () => {
7227
- onAsTaskChange(asTask !== true);
7228
- },
7229
- children: t("asTask")
7230
- }),
7912
+ }),
7913
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7914
+ className: composer_module_css_default.toolbar,
7915
+ children: [
7231
7916
  onFilesChange !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
7232
7917
  ref: fileInputRef,
7233
7918
  type: "file",
@@ -7240,365 +7925,158 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7240
7925
  if (chosen.length > 0 && pendingFiles !== void 0) onFilesChange([...pendingFiles, ...chosen]);
7241
7926
  event.target.value = "";
7242
7927
  }
7243
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7244
- type: "button",
7245
- className: composer_module_css_default.attachButton,
7246
- "aria-label": t("attachFiles"),
7247
- title: t("attachFiles"),
7248
- disabled: pending,
7249
- onClick: () => {
7250
- fileInputRef.current?.click();
7251
- },
7252
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 })
7928
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
7929
+ label: t("attachFiles"),
7930
+ side: "top",
7931
+ delayMs: 500,
7932
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7933
+ type: "button",
7934
+ className: composer_module_css_default.attachButton,
7935
+ "aria-label": t("attachFiles"),
7936
+ disabled: pending,
7937
+ onClick: () => {
7938
+ fileInputRef.current?.click();
7939
+ },
7940
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPaperclipOutline16, { size: 14 })
7941
+ })
7253
7942
  })] }),
7254
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7255
- type: "submit",
7256
- className: composer_module_css_default.sendButton,
7257
- "aria-label": pending ? t("sendingMessage") : t("sendMessage"),
7258
- disabled: pending || draft.trim() === "",
7259
- onMouseDown: (event) => {
7260
- event.preventDefault();
7261
- inputRef.current?.focus({ preventScroll: true });
7262
- },
7263
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSendOutline16, { size: 16 })
7264
- })
7265
- ]
7266
- })
7267
- ]
7268
- }), error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7269
- className: composer_module_css_default.error,
7270
- role: "alert",
7271
- children: error
7272
- })]
7273
- });
7274
- }
7275
- //#endregion
7276
- //#region src/client/task-refs.ts
7277
- const resolved = /* @__PURE__ */ new Map();
7278
- const pending = /* @__PURE__ */ new Set();
7279
- /** Refs the Host did not recognize; never re-queried (no retry loops). */
7280
- const unresolvable = /* @__PURE__ */ new Set();
7281
- const listeners$2 = /* @__PURE__ */ new Set();
7282
- let version = 0;
7283
- const emit = () => {
7284
- version += 1;
7285
- for (const listener of listeners$2) listener();
7286
- };
7287
- const subscribe = (listener) => {
7288
- listeners$2.add(listener);
7289
- return () => {
7290
- listeners$2.delete(listener);
7291
- };
7292
- };
7293
- /** Stable snapshot token; the map is read directly after this changes. */
7294
- const getSnapshot = () => version;
7295
- /** React binding: re-renders the caller when any ref resolution lands. */
7296
- const useResolvedTaskRefVersion = () => (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
7297
- const cachedResolvedTaskRef = (taskRef) => resolved.get(taskRef);
7298
- /** Store one resolution (click path) and wake every rendered link. */
7299
- const rememberResolvedTaskRef = (entry) => {
7300
- resolved.set(entry.taskRef, entry);
7301
- pending.delete(entry.taskRef);
7302
- emit();
7303
- };
7304
- /** Compare refs by branded prefix plus hyphen-stripped UUID, so abbreviated spellings line up with their full form. */
7305
- function refKeyOf(ref) {
7306
- return ref.toLowerCase().replaceAll("-", "");
7307
- }
7308
- /**
7309
- * Click-path Host lookup: remember every resolved entry and hand them back
7310
- * for immediate navigation. The Host keeps `resolved` in the same order as
7311
- * the input `taskRefs` (one entry per resolvable input, unknowns omitted);
7312
- * the pairing walk below relies on that contract, so it must be preserved
7313
- * together with this implementation.
7314
- */
7315
- const hostTaskRefLookup = (resolveTaskRefs, workspaceId) => async (taskRefs) => {
7316
- const result = await resolveTaskRefs({
7317
- workspaceId,
7318
- taskRefs
7319
- });
7320
- if (!result.ok) return [];
7321
- const entries = result.value.resolved;
7322
- let entryIndex = 0;
7323
- for (const requested of taskRefs) {
7324
- const entry = entries[entryIndex];
7325
- if (entry === void 0 || !refKeyOf(entry.taskRef).startsWith(refKeyOf(requested))) continue;
7326
- if (entry.taskRef !== requested) rememberResolvedTaskRef({
7327
- ...entry,
7328
- taskRef: requested
7329
- });
7330
- rememberResolvedTaskRef(entry);
7331
- entryIndex += 1;
7332
- }
7333
- return entries;
7334
- };
7335
- /** Resolve one Task ref through the Host and jump to its home Channel Thread. */
7336
- const jumpToTaskThread = (resolveTaskRefs, workspaceId, taskRef, selectThread) => {
7337
- resolveTaskRefs({
7338
- workspaceId,
7339
- taskRefs: [taskRef]
7340
- }).then((result) => {
7341
- if (!result.ok) return;
7342
- const hit = result.value.resolved[0];
7343
- if (hit !== void 0) selectThread(hit.threadRef, hit.channelRef, hit.taskRef, hit.taskNumber);
7344
- });
7345
- };
7346
- /**
7347
- * Batch-resolve unknown refs through the Host lookup. Concurrent callers
7348
- * deduplicate through the pending set; failures just clear the pending mark
7349
- * so a later interaction can retry.
7350
- */
7351
- const resolveUnknownTaskRefs = async (refs, lookup) => {
7352
- const missing = refs.filter((taskRef) => !resolved.has(taskRef) && !pending.has(taskRef) && !unresolvable.has(taskRef));
7353
- if (missing.length === 0) return;
7354
- for (const taskRef of missing) pending.add(taskRef);
7355
- try {
7356
- const entries = await lookup(missing);
7357
- for (const entry of entries) {
7358
- resolved.set(entry.taskRef, entry);
7359
- pending.delete(entry.taskRef);
7360
- }
7361
- for (const taskRef of missing) if (!resolved.has(taskRef)) unresolvable.add(taskRef);
7362
- if (entries.length > 0) emit();
7363
- } finally {
7364
- for (const taskRef of missing) pending.delete(taskRef);
7365
- }
7366
- };
7367
- //#endregion
7368
- //#region src/client/team-formatters.ts
7369
- function formatTaskStatus(status, t) {
7370
- return t({
7371
- todo: "taskStatusTodo",
7372
- in_progress: "taskStatusInProgress",
7373
- in_review: "taskStatusInReview",
7374
- done: "taskStatusDone",
7375
- closed: "taskStatusClosed"
7376
- }[status]);
7377
- }
7378
- function formatClaimState(state, t) {
7379
- return t({
7380
- active: "claimStateActive",
7381
- done: "claimStateDone",
7382
- released: "claimStateReleased"
7383
- }[state]);
7384
- }
7385
- /**
7386
- * Status indicator for a Task status, the dot every Task surface renders.
7387
- * Active states map to StateDot variants; every status renders a dot so they
7388
- * share one shape language — todo is a hollow ring (not started), closed a
7389
- * quiet gray dot (archived).
7390
- */
7391
- function taskStatusDot(status) {
7392
- return {
7393
- todo: "todo",
7394
- in_progress: "ongoing",
7395
- in_review: "warning",
7396
- done: "done",
7397
- closed: "quiet"
7398
- }[status];
7399
- }
7400
- /** One-line title snippet derived from the Task's root Message body. */
7401
- function formatTaskTitle(body) {
7402
- const firstLine = body.split("\n", 1)[0]?.trim() ?? "";
7403
- return firstLine.length > 120 ? `${firstLine.slice(0, 119)}…` : firstLine;
7404
- }
7405
- /** Deterministic avatar hue for one Member identity; stable across sessions and themes. */
7406
- function memberHue(memberId) {
7407
- let hash = 0;
7408
- for (let index = 0; index < memberId.length; index += 1) hash = (hash * 31 + memberId.charCodeAt(index)) % 360;
7409
- return hash;
7410
- }
7411
- const BRANDED_REF_PATTERN = /\b(task|channel|thread):{1,2}[0-9a-f]{6,}(?:-[0-9a-f]{1,})*\b/gi;
7412
- /**
7413
- * Canonical form of one matched ref: models occasionally double the colon or
7414
- * uppercase the UUID when citing a ref in prose, while Host lookups and
7415
- * navigation only accept the lowercase single-colon ref the ledger mints.
7416
- */
7417
- function canonicalBrandedRef(match) {
7418
- return match.replace("::", ":").toLowerCase();
7419
- }
7420
- /**
7421
- * Split a literal text run into plain and branded-ref segments. The pattern
7422
- * anchors on the fixed ref prefixes plus a UUID shape (full or abbreviated),
7423
- * so ordinary prose containing a colon never linkifies; a doubled colon from
7424
- * model output is tolerated. Segment refs are always canonical, so resolution
7425
- * and navigation work regardless of how the ref was spelled; text without any
7426
- * ref comes back as one untouched segment.
7427
- */
7428
- function splitBrandedRefs(text) {
7429
- const segments = [];
7430
- let cursor = 0;
7431
- for (const match of text.matchAll(BRANDED_REF_PATTERN)) {
7432
- const start = match.index ?? 0;
7433
- if (start > cursor) segments.push({ text: text.slice(cursor, start) });
7434
- segments.push({
7435
- text: match[0],
7436
- ref: canonicalBrandedRef(match[0])
7437
- });
7438
- cursor = start + match[0].length;
7439
- }
7440
- if (cursor < text.length) segments.push({ text: text.slice(cursor) });
7441
- return segments;
7442
- }
7443
- /**
7444
- * Whether one string's whole content is exactly one branded ref. A code span
7445
- * like this is the model styling a ref as an identifier, not publishing code,
7446
- * so the Markdown pass may linkify it; anything larger stays literal.
7447
- */
7448
- function isSingleBrandedRef(text) {
7449
- const trimmed = text.trim();
7450
- if (trimmed === "") return false;
7451
- const matches = [...trimmed.matchAll(BRANDED_REF_PATTERN)];
7452
- return matches.length === 1 && matches[0][0] === trimmed;
7453
- }
7454
- function escapeRegExp(value) {
7455
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7456
- }
7457
- /**
7458
- * Locate one Message's structured mention names inside its literal body. A
7459
- * name matches case-insensitively with an optional leading '@' on Unicode word
7460
- * boundaries, and longer names win at the same position. Mention segments
7461
- * render the canonical `@Handle`; names absent from the body come back
7462
- * unmatched so the consumer can append them as a fallback chip row.
7463
- */
7464
- function splitMentionNames(text, names) {
7465
- if (names.length === 0) return {
7466
- segments: [{
7467
- text,
7468
- mention: false
7469
- }],
7470
- unmatched: []
7471
- };
7472
- const ordered = [...names].sort((left, right) => right.length - left.length);
7473
- const pattern = new RegExp(`(?<![\\p{L}\\p{N}_@])@?(?:${ordered.map((name) => `(${escapeRegExp(name)})`).join("|")})(?=$|[^\\p{L}\\p{N}_])`, "giu");
7474
- const segments = [];
7475
- const matched = /* @__PURE__ */ new Set();
7476
- let cursor = 0;
7477
- for (const match of text.matchAll(pattern)) {
7478
- const groupIndex = match.findIndex((group, index) => index >= 1 && group !== void 0);
7479
- if (groupIndex < 1) continue;
7480
- if (match.index > cursor) segments.push({
7481
- text: text.slice(cursor, match.index),
7482
- mention: false
7483
- });
7484
- const name = ordered[groupIndex - 1];
7485
- segments.push({
7486
- text: `@${name}`,
7487
- mention: true,
7488
- name
7489
- });
7490
- matched.add(name.toLowerCase());
7491
- cursor = match.index + match[0].length;
7492
- }
7493
- if (cursor < text.length) segments.push({
7494
- text: text.slice(cursor),
7495
- mention: false
7943
+ onAsTaskChange !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
7944
+ type: "button",
7945
+ className: asTask === true ? `${composer_module_css_default.asTaskPill} ${composer_module_css_default.asTaskPillOn}` : composer_module_css_default.asTaskPill,
7946
+ "aria-label": t("asTask"),
7947
+ "aria-pressed": asTask === true,
7948
+ title: t("asTask"),
7949
+ disabled: pending,
7950
+ onClick: () => {
7951
+ onAsTaskChange(asTask !== true);
7952
+ },
7953
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChecklistOutline14, { size: 14 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7954
+ className: composer_module_css_default.asTaskLabel,
7955
+ children: t("asTask")
7956
+ })]
7957
+ }),
7958
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7959
+ type: "submit",
7960
+ className: composer_module_css_default.sendButton,
7961
+ "aria-label": pending ? t("sendingMessage") : t("sendMessage"),
7962
+ disabled: pending || draft.trim() === "",
7963
+ onMouseDown: (event) => {
7964
+ event.preventDefault();
7965
+ inputRef.current?.focus({ preventScroll: true });
7966
+ },
7967
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSendOutline16, { size: 16 })
7968
+ })
7969
+ ]
7970
+ })
7971
+ ]
7972
+ }), error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7973
+ className: composer_module_css_default.error,
7974
+ role: "alert",
7975
+ children: error
7976
+ })]
7496
7977
  });
7497
- return {
7498
- segments,
7499
- unmatched: names.filter((name) => !matched.has(name.toLowerCase()))
7500
- };
7501
- }
7502
- /** Canonical chip handles for one Message's structured mention refs. */
7503
- function mentionNamesOf(mentions, handles) {
7504
- return mentions.map((memberId) => memberId === "member:human" ? "human" : handles.get(memberId)).filter((name) => name !== void 0);
7505
7978
  }
7506
- const MARKDOWN_BLOCK_CONSTRUCT = /(^|\n)[ \t]{0,3}(?:#{1,6}[ \t]|>[ \t]|[-*+][ \t]|\d+[.)][ \t])|^[ \t]*\|.+\|/m;
7507
- const MARKDOWN_INLINE_CONSTRUCT = /[`*_[\]!]|~~~|```/;
7508
- /**
7509
- * Whether an Agent body survives literal rendering unchanged: no fences,
7510
- * inline code, emphasis markers, links, images, tables, or block constructs.
7511
- * Only such plain-prose bodies may reuse the Human inline mention flow —
7512
- * anything richer keeps the trailing chip row because the Markdown primitive
7513
- * renders block-level documents that cannot interleave inline chips.
7514
- */
7515
- function isPlainTextBody(text) {
7516
- return !(MARKDOWN_BLOCK_CONSTRUCT.test(text) || MARKDOWN_INLINE_CONSTRUCT.test(text));
7979
+ //#endregion
7980
+ //#region src/client/task-refs.ts
7981
+ const resolved = /* @__PURE__ */ new Map();
7982
+ const pending = /* @__PURE__ */ new Set();
7983
+ /** Refs the Host did not recognize; never re-queried (no retry loops). */
7984
+ const unresolvable = /* @__PURE__ */ new Set();
7985
+ const listeners$2 = /* @__PURE__ */ new Set();
7986
+ let version = 0;
7987
+ const emit = () => {
7988
+ version += 1;
7989
+ for (const listener of listeners$2) listener();
7990
+ };
7991
+ const subscribe = (listener) => {
7992
+ listeners$2.add(listener);
7993
+ return () => {
7994
+ listeners$2.delete(listener);
7995
+ };
7996
+ };
7997
+ /** Stable snapshot token; the map is read directly after this changes. */
7998
+ const getSnapshot = () => version;
7999
+ /** React binding: re-renders the caller when any ref resolution lands. */
8000
+ const useResolvedTaskRefVersion = () => (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
8001
+ const cachedResolvedTaskRef = (taskRef) => resolved.get(taskRef);
8002
+ /** Store one resolution (click path) and wake every rendered link. */
8003
+ const rememberResolvedTaskRef = (entry) => {
8004
+ resolved.set(entry.taskRef, entry);
8005
+ pending.delete(entry.taskRef);
8006
+ emit();
8007
+ };
8008
+ /** Compare refs by branded prefix plus hyphen-stripped UUID, so abbreviated spellings line up with their full form. */
8009
+ function refKeyOf(ref) {
8010
+ return ref.toLowerCase().replaceAll("-", "");
7517
8011
  }
7518
- const pad$1 = (value) => String(value).padStart(2, "0");
7519
8012
  /**
7520
- * Wall-clock label for one Message instant: time within the current day,
7521
- * month-day time within the year, full date otherwise.
8013
+ * Click-path Host lookup: remember every resolved entry and hand them back
8014
+ * for immediate navigation. The Host keeps `resolved` in the same order as
8015
+ * the input `taskRefs` (one entry per resolvable input, unknowns omitted);
8016
+ * the pairing walk below relies on that contract, so it must be preserved
8017
+ * together with this implementation.
7522
8018
  */
7523
- function formatMessageTime(occurredAt, now = /* @__PURE__ */ new Date()) {
7524
- const at = new Date(occurredAt);
7525
- if (Number.isNaN(at.getTime())) return "";
7526
- const time = `${pad$1(at.getHours())}:${pad$1(at.getMinutes())}`;
7527
- if (at.getFullYear() === now.getFullYear() && at.getMonth() === now.getMonth() && at.getDate() === now.getDate()) return time;
7528
- const date = `${at.getFullYear()}-${pad$1(at.getMonth() + 1)}-${pad$1(at.getDate())}`;
7529
- if (at.getFullYear() === now.getFullYear()) return `${date.slice(5)} ${time}`;
7530
- return `${date} ${time}`;
7531
- }
7532
- function formatActivity(activity, options) {
7533
- const actor = options.actorName(activity.actor);
7534
- if (activity.kind === "accept") return activity.completedClaimRefs !== void 0 && activity.completedClaimRefs.length > 0 ? options.t("activityAcceptedWithClaims", {
7535
- actor,
7536
- count: activity.completedClaimRefs.length
7537
- }) : options.t("activityAccepted", { actor });
7538
- if (activity.kind === "promote") return options.t("activityPromoted", { actor });
7539
- if (activity.kind === "close") return options.t("activityClosed", { actor });
7540
- if (activity.kind === "reopen") return options.t("activityReopened", { actor });
7541
- const direction = "claimRef" in activity ? options.claims.find((claim) => claim.claimRef === activity.claimRef)?.direction ?? options.t("claims") : options.t("claims");
7542
- if (activity.kind === "claim") return options.t("activityClaimed", {
7543
- actor,
7544
- direction
7545
- });
7546
- if (activity.kind === "done") return options.t("activityClaimDone", {
7547
- actor,
7548
- direction
7549
- });
7550
- if (activity.kind === "release") return options.t("activityClaimReleased", {
7551
- actor,
7552
- direction
8019
+ const hostTaskRefLookup = (resolveTaskRefs, workspaceId) => async (taskRefs) => {
8020
+ const result = await resolveTaskRefs({
8021
+ workspaceId,
8022
+ taskRefs
7553
8023
  });
7554
- if (activity.kind === "claims_released") return options.t("activityClaimsReleased", {
7555
- actor,
7556
- count: activity.claimRefs.length
8024
+ if (!result.ok) return [];
8025
+ const entries = result.value.resolved;
8026
+ let entryIndex = 0;
8027
+ for (const requested of taskRefs) {
8028
+ const entry = entries[entryIndex];
8029
+ if (entry === void 0 || !refKeyOf(entry.taskRef).startsWith(refKeyOf(requested))) continue;
8030
+ if (entry.taskRef !== requested) rememberResolvedTaskRef({
8031
+ ...entry,
8032
+ taskRef: requested
8033
+ });
8034
+ rememberResolvedTaskRef(entry);
8035
+ entryIndex += 1;
8036
+ }
8037
+ return entries;
8038
+ };
8039
+ /** Resolve one Task ref through the Host and jump to its home Channel Thread. */
8040
+ const jumpToTaskThread = (resolveTaskRefs, workspaceId, taskRef, selectThread) => {
8041
+ resolveTaskRefs({
8042
+ workspaceId,
8043
+ taskRefs: [taskRef]
8044
+ }).then((result) => {
8045
+ if (!result.ok) return;
8046
+ const hit = result.value.resolved[0];
8047
+ if (hit !== void 0) selectThread(hit.threadRef, hit.channelRef, hit.taskRef, hit.taskNumber);
7557
8048
  });
7558
- throw new Error(`unknown Team Activity kind: ${activity.kind}`);
7559
- }
7560
- /** Remove the machine-facing `[attachment] <path>` prompt lines from a body before display. */
7561
- function stripAttachmentLines(body) {
7562
- return body.replaceAll(/^\[attachment\] .*$(\n)?/gm, "").replace(/\n+$/, "");
7563
- }
7564
- /** Whether one displayed Message body starts clamped behind the expand control. */
7565
- function shouldClampMessage(displayBody) {
7566
- return displayBody.length > 600;
7567
- }
8049
+ };
7568
8050
  /**
7569
- * Decide how one Message body renders. Human input and plain-prose Agent
7570
- * bodies stay literal, with structured mention chips inline where possible;
7571
- * rich Agent Markdown keeps unmatched mentions and non-Task refs in the
7572
- * trailing fallback row while the post-render pass handles Task refs at their
7573
- * authored position. Surfaces without ref navigation render everything
7574
- * literally and keep the full fallback row.
8051
+ * Batch-resolve unknown refs through the Host lookup. Concurrent callers
8052
+ * deduplicate through the pending set; failures just clear the pending mark
8053
+ * so a later interaction can retry.
7575
8054
  */
7576
- function planMessageBody(body, options) {
7577
- const stripped = stripAttachmentLines(body);
7578
- const displayBody = stripped === "" ? body : stripped;
7579
- const richAgentBody = !options.human && !isPlainTextBody(displayBody);
7580
- const inline = (options.human || isPlainTextBody(displayBody)) && options.mentionNames !== void 0 && options.mentionNames.length > 0 ? splitMentionNames(displayBody, options.mentionNames) : void 0;
7581
- const fallbackNames = inline !== void 0 ? inline.unmatched : richAgentBody && options.canOpenRefs && options.mentionNames !== void 0 ? splitMentionNames(displayBody, options.mentionNames).unmatched : options.mentionNames ?? [];
7582
- const refs = splitBrandedRefs(displayBody).flatMap((segment) => segment.ref === void 0 ? [] : [segment.ref]);
7583
- return {
7584
- displayBody,
7585
- richAgentBody,
7586
- render: inline !== void 0 ? "inline" : options.human || options.canOpenRefs && !richAgentBody && refs.length > 0 ? "literal" : "markdown",
7587
- ...inline === void 0 ? {} : { inline },
7588
- fallbackNames,
7589
- fallbackRefs: richAgentBody && !options.canOpenRefs ? refs : [],
7590
- taskRefs: options.canOpenRefs && !richAgentBody ? refs.filter((ref) => ref.startsWith("task:")).map((ref) => ref) : []
7591
- };
7592
- }
8055
+ const resolveUnknownTaskRefs = async (refs, lookup) => {
8056
+ const missing = refs.filter((taskRef) => !resolved.has(taskRef) && !pending.has(taskRef) && !unresolvable.has(taskRef));
8057
+ if (missing.length === 0) return;
8058
+ for (const taskRef of missing) pending.add(taskRef);
8059
+ try {
8060
+ const entries = await lookup(missing);
8061
+ for (const entry of entries) {
8062
+ resolved.set(entry.taskRef, entry);
8063
+ pending.delete(entry.taskRef);
8064
+ }
8065
+ for (const taskRef of missing) if (!resolved.has(taskRef)) unresolvable.add(taskRef);
8066
+ if (entries.length > 0) emit();
8067
+ } finally {
8068
+ for (const taskRef of missing) pending.delete(taskRef);
8069
+ }
8070
+ };
7593
8071
  //#endregion
7594
8072
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/conversation.module.css.mjs
7595
- const css$4 = ".omcBaG_surface{grid-template-rows:auto minmax(0,1fr) auto;min-width:0;height:100%;min-height:0;display:grid;overflow:hidden}.omcBaG_surfaceHeader{border-bottom:1px solid var(--dsw-alias-border-l2);min-width:0;padding:14px clamp(18px,3vw,36px) 12px}.omcBaG_headerRow{justify-content:space-between;align-items:flex-start;gap:16px;min-width:0;max-width:880px;margin:0 auto;display:flex}.omcBaG_headerCopy{min-width:0}.omcBaG_headerCopy h1{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;font-size:20px;font-weight:600;line-height:28px}.omcBaG_headerCopy p{color:var(--dsw-alias-label-secondary);margin:3px 0 0;font-size:13px;line-height:20px}.omcBaG_headerActions{flex:none;align-items:center;gap:6px;display:flex}.omcBaG_backRow{max-width:880px;margin:0 auto 8px}.omcBaG_timeline{overscroll-behavior:contain;scrollbar-gutter:stable;min-height:0;padding:12px clamp(18px,3vw,36px) 24px;overflow:hidden auto}.omcBaG_timelineContent{flex-direction:column;min-width:0;max-width:880px;min-height:100%;margin:0 auto;display:flex}.omcBaG_emptySurface{margin:auto;padding:32px 0}.omcBaG_emptySurface .omcBaG_emptyState{text-align:center;justify-items:center}.omcBaG_timelineAction{justify-content:center;padding:2px 0 8px;display:flex}.omcBaG_messageRow{gap:10px;padding:10px 0;display:flex}.omcBaG_messageRow[data-grouped]{padding-top:2px}.omcBaG_messageRow[data-grouped] .omcBaG_messageBody>:first-child,.omcBaG_messageRow[data-grouped] .omcBaG_messageBody>:first-child>:first-child{margin-top:0}.omcBaG_messageIdentity{background:hsl(var(--team-avatar-hue,212) 42% 46%);color:#fff;border-radius:50%;flex:0 0 28px;justify-content:center;align-items:center;height:28px;font-size:12px;font-weight:600;display:flex}.omcBaG_messageRow[data-human] .omcBaG_messageIdentity{background:var(--dsw-alias-state-business-primary)}.omcBaG_messageRow[data-grouped] .omcBaG_messageIdentity{visibility:hidden}.omcBaG_messageBody{min-width:0}.omcBaG_nameRow{flex-wrap:wrap;align-items:baseline;gap:8px;display:flex}.omcBaG_nameRow strong{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600;line-height:20px}.omcBaG_messageTime{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:20px}.omcBaG_messageText{white-space:pre-wrap;word-break:break-word;margin:6px 0;font-size:14px;line-height:22px}.omcBaG_messageClamp{max-height:176px;overflow:hidden;-webkit-mask-image:linear-gradient(#000 72%,#0000 100%);mask-image:linear-gradient(#000 72%,#0000 100%)}.omcBaG_messageExpand{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;width:fit-content;margin-top:4px;padding:0;font-size:12px;line-height:20px;display:block}.omcBaG_messageExpand:hover,.omcBaG_messageExpand:focus-visible{color:var(--dsw-alias-label-primary);text-underline-offset:2px;outline:none;text-decoration:underline}.omcBaG_messageBody .omcBaG_messageMarkdown{font-size:14px;line-height:22px}.omcBaG_messageBody .omcBaG_messageMarkdown>div:first-child{color:var(--dsw-alias-label-primary);font:inherit}.omcBaG_messageBody .omcBaG_messageMarkdown p{margin:6px 0}.omcBaG_messageBody .omcBaG_messageMarkdown :where(ul,ol){margin:6px 0;padding-left:22px}.omcBaG_messageBody .omcBaG_messageMarkdown li+li{margin-top:2px}.omcBaG_messageBody .omcBaG_messageMarkdown strong{font-weight:600}.omcBaG_messageBody .omcBaG_messageMarkdown :where(h1,h2,h3,h4,h5,h6){margin:12px 0 4px}.omcBaG_messageBody .omcBaG_messageMarkdown :where(h1){font-size:17px;line-height:26px}.omcBaG_messageBody .omcBaG_messageMarkdown :where(h2){font-size:16px;line-height:24px}.omcBaG_messageBody .omcBaG_messageMarkdown :where(h3,h4,h5,h6){font-size:15px;line-height:22px}.omcBaG_messageBody .omcBaG_messageMarkdown pre{margin:8px 0;padding:10px 12px;font-size:13px}.omcBaG_messageBody .omcBaG_messageMarkdown blockquote{margin:6px 0}.omcBaG_messageBody .omcBaG_messageMarkdown :where(th,td){padding-block:5px}.omcBaG_emptyState,.omcBaG_loadingState{color:var(--dsw-alias-label-tertiary);margin:0;padding:14px 0;font-size:13px;line-height:20px}.omcBaG_emptyState{gap:3px;display:grid}.omcBaG_emptyState strong{color:var(--dsw-alias-label-secondary);font-weight:500}.omcBaG_emptyState span{font-size:12px}.omcBaG_loadingState{align-items:center;gap:8px;display:flex}.omcBaG_loadingMark{background:var(--dsw-alias-bg-skeleton);border-radius:50%;width:8px;height:8px;animation:1.2s ease-in-out infinite omcBaG_pulse}.omcBaG_error,.omcBaG_errorState{color:var(--dsw-alias-state-error-primary);max-width:880px;margin:0 auto;padding-top:6px;font-size:12px;line-height:18px}.omcBaG_errorState{justify-content:space-between;align-items:center;gap:8px;display:flex}.omcBaG_welcomeSurface{justify-content:center;align-items:center;min-width:0;height:100%;padding:32px;display:flex}.omcBaG_welcome{text-align:center;max-width:420px}.omcBaG_welcomeEyebrow{color:var(--dsw-alias-label-tertiary);text-transform:uppercase;font-size:12px;line-height:18px}.omcBaG_welcome h1{color:var(--dsw-alias-label-primary);margin:8px 0;font-size:24px;font-weight:600;line-height:32px}.omcBaG_welcome p{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px;line-height:20px}@keyframes omcBaG_pulse{0%,to{opacity:.35}50%{opacity:1}}@media (width<=600px){.omcBaG_surfaceHeader{padding:12px 12px 10px}.omcBaG_headerRow{flex-direction:column;align-items:stretch;gap:8px}.omcBaG_headerActions{flex-wrap:wrap}.omcBaG_backRow{margin-bottom:6px}.omcBaG_timeline{scrollbar-gutter:auto;padding:8px 12px 16px}.omcBaG_messageRow{padding:8px 0}}@media (prefers-reduced-motion:reduce){.omcBaG_loadingMark{animation:none}}.omcBaG_messageRun{margin:2px 0;padding:3px 0}.omcBaG_messageRow[data-grouped]:has(.omcBaG_messageBody>button:not([data-message-expand])){margin-top:3px;padding-top:7px;position:relative}.omcBaG_messageRow[data-grouped]:has(.omcBaG_messageBody>button:not([data-message-expand])):before{background:var(--dsw-alias-border-l2);content:\"\";height:1px;position:absolute;inset:0 0 auto 38px}.omcBaG_runDivider{border-top:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);margin:2px 0 0 38px;padding:5px 0 0;font-size:11px;line-height:16px}.omcBaG_runDivider+.omcBaG_messageRow[data-grouped]:has(.omcBaG_messageBody>button:not([data-message-expand])){margin-top:0}.omcBaG_runDivider+.omcBaG_messageRow[data-grouped]:has(.omcBaG_messageBody>button:not([data-message-expand])):before{content:none}.omcBaG_mention{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 12%, transparent);color:var(--dsw-alias-state-business-primary);border-radius:5px;padding:0 4px;font-weight:500;box-shadow:0 1px 2px #00000014}.omcBaG_mentionsRow{gap:4px;width:fit-content;margin-top:3px;font-size:.85em;display:flex}.omcBaG_attachmentStrip{flex-wrap:wrap;gap:6px;margin-top:4px;display:flex}.omcBaG_attachmentThumb{cursor:zoom-in;border:0;border-radius:8px;padding:0}.omcBaG_attachmentThumb img{object-fit:cover;border-radius:8px;width:128px;height:96px;display:block}.omcBaG_attachmentThumb:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,currentColor);outline-offset:1px}.omcBaG_confirmBody{margin:0 0 8px}.omcBaG_confirmList{gap:6px;margin:0;padding-left:18px;display:grid}.omcBaG_refLink{color:var(--dsw-alias-state-business-primary);cursor:pointer;font:inherit;text-align:left;text-underline-offset:3px;background:0 0;border:none;border-radius:4px;padding:0;text-decoration:underline}.omcBaG_refLink:hover{text-decoration-thickness:2px}.omcBaG_refLink:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}.omcBaG_attachmentModal{width:min(1100px,92vw)}.omcBaG_attachmentZoom{object-fit:contain;border-radius:12px;max-width:100%;max-height:78vh;margin:0 auto;display:block}.omcBaG_attachmentChip{background:var(--dsw-alias-interactive-bg-hover);border-radius:6px;align-items:baseline;gap:6px;max-width:100%;padding:3px 8px;display:inline-flex}.omcBaG_attachmentChipName{text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:17px;overflow:hidden}.omcBaG_attachmentChipSize{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:11px;line-height:17px}";
7596
- const tagId$4 = "@wowyuarm/dsh-agent-team/conversation.module.css";
7597
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
8073
+ const css$6 = ".omcBaG_surface{grid-template-rows:auto minmax(0,1fr) auto;min-width:0;height:100%;min-height:0;display:grid;overflow:hidden}.omcBaG_surfaceHeader{border-bottom:1px solid var(--dsw-alias-border-l2);min-width:0;padding:14px clamp(18px,3vw,36px) 12px}.omcBaG_headerRow{justify-content:space-between;align-items:flex-start;gap:16px;min-width:0;max-width:880px;margin:0 auto;display:flex}.omcBaG_headerCopy{min-width:0}.omcBaG_headerCopy h1{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;font-size:20px;font-weight:600;line-height:28px}.omcBaG_headerCopy p{color:var(--dsw-alias-label-secondary);margin:3px 0 0;font-size:13px;line-height:20px}.omcBaG_headerActions{flex:none;align-items:center;gap:6px;display:flex}.omcBaG_backRow{max-width:880px;margin:0 auto 8px}.omcBaG_timeline{overscroll-behavior:contain;scrollbar-gutter:stable;min-height:0;padding:12px clamp(18px,3vw,36px) 24px;overflow:hidden auto}.omcBaG_timelineContent{flex-direction:column;min-width:0;max-width:880px;min-height:100%;margin:0 auto;display:flex}.omcBaG_emptySurface{margin:auto;padding:32px 0}.omcBaG_emptySurface .omcBaG_emptyState{text-align:center;justify-items:center}.omcBaG_timelineAction{justify-content:center;padding:2px 0 8px;display:flex}.omcBaG_messageRow{gap:10px;padding:10px 0;display:flex}.omcBaG_messageRow[data-grouped]{padding-top:2px}.omcBaG_messageRow[data-grouped] .omcBaG_messageBody>:first-child,.omcBaG_messageRow[data-grouped] .omcBaG_messageBody>:first-child>:first-child{margin-top:0}.omcBaG_messageIdentity{background:hsl(var(--team-avatar-hue,212) 42% 46%);corner-shape:round;color:#fff;border-radius:50%;flex:0 0 28px;justify-content:center;align-items:center;height:28px;font-size:12px;font-weight:600;display:flex}.omcBaG_messageRow[data-human] .omcBaG_messageIdentity{background:var(--dsw-alias-state-business-primary)}.omcBaG_messageRow[data-grouped] .omcBaG_messageIdentity{visibility:hidden}.omcBaG_messageBody{min-width:0}.omcBaG_nameRow{flex-wrap:wrap;align-items:baseline;gap:8px;display:flex}.omcBaG_nameRow strong{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600;line-height:20px}.omcBaG_messageTime{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:20px}.omcBaG_stateCluster{flex:none;align-items:center;gap:6px;display:inline-flex}.omcBaG_statusWord{color:var(--dsw-alias-label-secondary);font-size:11px;line-height:18px}.omcBaG_entryLine{flex-wrap:wrap;align-items:center;gap:8px;max-width:100%;margin:4px 0 0;display:flex}.omcBaG_entryRow{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:2px 0;font-size:12px;line-height:18px;display:inline-flex}.omcBaG_entryRow:hover,.omcBaG_entryRow:focus-visible{color:var(--dsw-alias-label-primary)}.omcBaG_entryRow:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.omcBaG_entryArrow{align-items:center;transition:transform .12s;display:inline-flex}.omcBaG_entryRow:hover .omcBaG_entryArrow,.omcBaG_entryRow:focus-visible .omcBaG_entryArrow{transform:translate(2px)}.omcBaG_messageText{white-space:pre-wrap;word-break:break-word;margin:6px 0;font-size:14px;line-height:22px}.omcBaG_messageClamp{max-height:176px;overflow:hidden;-webkit-mask-image:linear-gradient(#000 72%,#0000 100%);mask-image:linear-gradient(#000 72%,#0000 100%)}.omcBaG_messageExpand{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;width:fit-content;margin-top:4px;padding:0;font-size:12px;line-height:20px;display:block}.omcBaG_messageExpand:hover,.omcBaG_messageExpand:focus-visible{color:var(--dsw-alias-label-primary);text-underline-offset:2px;outline:none;text-decoration:underline}.omcBaG_messageBody .omcBaG_messageMarkdown{font-size:14px;line-height:22px}.omcBaG_messageBody .omcBaG_messageMarkdown>div:first-child{color:var(--dsw-alias-label-primary);font:inherit}.omcBaG_messageBody .omcBaG_messageMarkdown p{margin:6px 0}.omcBaG_messageBody .omcBaG_messageMarkdown :where(ul,ol){margin:6px 0;padding-left:22px}.omcBaG_messageBody .omcBaG_messageMarkdown li+li{margin-top:2px}.omcBaG_messageBody .omcBaG_messageMarkdown strong{font-weight:600}.omcBaG_messageBody .omcBaG_messageMarkdown :where(h1,h2,h3,h4,h5,h6){margin:12px 0 4px}.omcBaG_messageBody .omcBaG_messageMarkdown :where(h1){font-size:17px;line-height:26px}.omcBaG_messageBody .omcBaG_messageMarkdown :where(h2){font-size:16px;line-height:24px}.omcBaG_messageBody .omcBaG_messageMarkdown :where(h3,h4,h5,h6){font-size:15px;line-height:22px}.omcBaG_messageBody .omcBaG_messageMarkdown pre{margin:8px 0;padding:10px 12px;font-size:13px}.omcBaG_messageBody .omcBaG_messageMarkdown blockquote{margin:6px 0}.omcBaG_messageBody .omcBaG_messageMarkdown :where(th,td){padding-block:5px}.omcBaG_emptyState,.omcBaG_loadingState{color:var(--dsw-alias-label-tertiary);margin:0;padding:14px 0;font-size:13px;line-height:20px}.omcBaG_emptyState{gap:3px;display:grid}.omcBaG_emptyState strong{color:var(--dsw-alias-label-secondary);font-weight:500}.omcBaG_emptyState span{font-size:12px}.omcBaG_loadingState{align-items:center;gap:8px;display:flex}.omcBaG_loadingMark{background:var(--dsw-alias-bg-skeleton);corner-shape:round;border-radius:50%;width:8px;height:8px;animation:1.2s ease-in-out infinite omcBaG_pulse}.omcBaG_error{color:var(--dsw-alias-state-error-primary);max-width:880px;margin:0;padding-top:6px;font-size:12px;line-height:18px}.omcBaG_errorState{color:var(--dsw-alias-state-error-primary);justify-content:space-between;align-items:center;gap:8px;max-width:880px;margin:auto;padding:32px 0;font-size:12px;line-height:18px;display:flex}.omcBaG_welcomeSurface{justify-content:center;align-items:center;min-width:0;height:100%;padding:32px;display:flex}.omcBaG_welcome{text-align:center;max-width:420px}.omcBaG_welcomeEyebrow{color:var(--dsw-alias-label-tertiary);text-transform:uppercase;font-size:12px;line-height:18px}.omcBaG_welcome h1{color:var(--dsw-alias-label-primary);margin:8px 0;font-size:24px;font-weight:600;line-height:32px}.omcBaG_welcome p{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px;line-height:20px}@keyframes omcBaG_pulse{0%,to{opacity:.35}50%{opacity:1}}@media (width<=600px){.omcBaG_surfaceHeader{padding:12px 12px 10px}.omcBaG_headerRow{flex-direction:column;align-items:stretch;gap:8px}.omcBaG_headerActions{flex-wrap:wrap}.omcBaG_backRow{margin-bottom:6px}.omcBaG_timeline{scrollbar-gutter:auto;padding:8px 12px 16px}.omcBaG_messageRow{padding:8px 0}}@media (prefers-reduced-motion:reduce){.omcBaG_loadingMark{animation:none}.omcBaG_entryArrow{transition:none}.omcBaG_entryRow:hover .omcBaG_entryArrow,.omcBaG_entryRow:focus-visible .omcBaG_entryArrow{transform:none}}.omcBaG_messageRun{margin:2px 0;padding:3px 0}.omcBaG_messageRow[data-grouped]:has([data-thread-entry]){margin-top:3px;padding-top:7px;position:relative}.omcBaG_messageRow[data-grouped]:has([data-thread-entry]):before{background:var(--dsw-alias-border-l2);content:\"\";height:1px;position:absolute;inset:0 0 auto 38px}.omcBaG_runDivider{border-top:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);margin:2px 0 0 38px;padding:5px 0 0;font-size:11px;line-height:16px}.omcBaG_runDivider+.omcBaG_messageRow[data-grouped]:has([data-thread-entry]){margin-top:0}.omcBaG_runDivider+.omcBaG_messageRow[data-grouped]:has([data-thread-entry]):before{content:none}.omcBaG_mention{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 12%, transparent);color:var(--dsw-alias-state-business-primary);border-radius:6px;padding:0 4px;font-weight:500;box-shadow:0 1px 2px #00000014}.omcBaG_mentionsRow{gap:4px;width:fit-content;margin-top:3px;font-size:.85em;display:flex}.omcBaG_attachmentStrip{flex-wrap:wrap;gap:6px;margin-top:4px;display:flex}.omcBaG_attachmentThumb{cursor:zoom-in;border:0;border-radius:8px;padding:0}.omcBaG_attachmentThumb img{object-fit:cover;border-radius:8px;width:128px;height:96px;display:block}.omcBaG_attachmentThumb:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,currentColor);outline-offset:1px}.omcBaG_confirmBody{margin:0 0 8px}.omcBaG_confirmList{gap:6px;margin:0;padding-left:18px;display:grid}.omcBaG_refLink{color:var(--dsw-alias-state-business-primary);cursor:pointer;font:inherit;text-align:left;text-underline-offset:3px;background:0 0;border:none;border-radius:4px;padding:0;text-decoration:underline}.omcBaG_refLink:hover{text-decoration-thickness:2px}.omcBaG_refLink:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}.omcBaG_attachmentModal{width:min(1100px,92vw)}.omcBaG_attachmentZoom{object-fit:contain;border-radius:12px;max-width:100%;max-height:78vh;margin:0 auto;display:block}.omcBaG_attachmentChip{background:var(--dsw-alias-interactive-bg-hover);border-radius:6px;align-items:baseline;gap:6px;max-width:100%;padding:3px 8px;display:inline-flex}.omcBaG_attachmentChipName{text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:17px;overflow:hidden}.omcBaG_attachmentChipSize{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:11px;line-height:17px}";
8074
+ const tagId$6 = "@wowyuarm/dsh-agent-team/conversation.module.css";
8075
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
7598
8076
  const tag = document.createElement("style");
7599
8077
  tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7600
- tag.dataset.pluginCss = tagId$4;
7601
- tag.textContent = css$4;
8078
+ tag.dataset.pluginCss = tagId$6;
8079
+ tag.textContent = css$6;
7602
8080
  document.head.appendChild(tag);
7603
8081
  }
7604
8082
  var conversation_module_css_default = {
@@ -7614,6 +8092,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7614
8092
  "confirmList": "omcBaG_confirmList",
7615
8093
  "emptyState": "omcBaG_emptyState",
7616
8094
  "emptySurface": "omcBaG_emptySurface",
8095
+ "entryArrow": "omcBaG_entryArrow",
8096
+ "entryLine": "omcBaG_entryLine",
8097
+ "entryRow": "omcBaG_entryRow",
7617
8098
  "error": "omcBaG_error",
7618
8099
  "errorState": "omcBaG_errorState",
7619
8100
  "headerActions": "omcBaG_headerActions",
@@ -7636,6 +8117,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7636
8117
  "pulse": "omcBaG_pulse",
7637
8118
  "refLink": "omcBaG_refLink",
7638
8119
  "runDivider": "omcBaG_runDivider",
8120
+ "stateCluster": "omcBaG_stateCluster",
8121
+ "statusWord": "omcBaG_statusWord",
7639
8122
  "surface": "omcBaG_surface",
7640
8123
  "surfaceHeader": "omcBaG_surfaceHeader",
7641
8124
  "timeline": "omcBaG_timeline",
@@ -7647,8 +8130,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7647
8130
  };
7648
8131
  //#endregion
7649
8132
  //#region src/client/TeamMessage.tsx
7650
- /** One chat message row with identity chrome and sender-appropriate rendering. */
7651
- function TeamMessage({ senderName, memberId, human, body, occurredAt, mentionNames, senderTitle, grouped, showGroupedTime, attachments, loadAttachment, t, onOpenRef, onResolveTaskRefs, children }) {
8133
+ /**
8134
+ * One chat message row with identity chrome and sender-appropriate rendering.
8135
+ *
8136
+ * Memoized because a timeline row is rendered by the page that owns the whole
8137
+ * Thread: the Task-ref subscription below lives inside this component, so
8138
+ * skipping a render here never detaches it. Callers must therefore keep the
8139
+ * props they derive per render (mention names, ref callbacks) identity-stable.
8140
+ */
8141
+ const TeamMessage = (0, react.memo)(function TeamMessage({ senderName, memberId, human, body, occurredAt, mentionNames, senderTitle, grouped, showGroupedTime, attachments, loadAttachment, t, onOpenRef, onResolveTaskRefs, children }) {
7652
8142
  const avatarStyle = human ? void 0 : { "--team-avatar-hue": memberHue(memberId) };
7653
8143
  const plan = planMessageBody(body, {
7654
8144
  human,
@@ -7801,7 +8291,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7801
8291
  ]
7802
8292
  })]
7803
8293
  });
7804
- }
8294
+ });
7805
8295
  /** Text nodes that Markdown rendered as prose rather than code or a link. */
7806
8296
  function markdownProseTextNodes(root) {
7807
8297
  const nodes = [];
@@ -7984,6 +8474,101 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7984
8474
  });
7985
8475
  }
7986
8476
  //#endregion
8477
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/avatar-stack.module.css.mjs
8478
+ const css$5 = ".aACNsW_stack{flex:none;align-items:center;display:inline-flex}.aACNsW_avatar,.aACNsW_overflow{box-shadow:0 0 0 2px var(--team-mark-ring,var(--dsw-alias-bg-base));corner-shape:round;border-radius:50%;justify-content:center;align-items:center;width:18px;height:18px;font-size:9px;font-weight:600;display:inline-flex}.aACNsW_avatar{background:hsl(var(--team-avatar-hue,212) 42% 46%);color:#fff}.aACNsW_overflow{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.aACNsW_avatar+.aACNsW_avatar,.aACNsW_avatar+.aACNsW_overflow{margin-left:-6px}";
8479
+ const tagId$5 = "@wowyuarm/dsh-agent-team/avatar-stack.module.css";
8480
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
8481
+ const tag = document.createElement("style");
8482
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
8483
+ tag.dataset.pluginCss = tagId$5;
8484
+ tag.textContent = css$5;
8485
+ document.head.appendChild(tag);
8486
+ }
8487
+ var avatar_stack_module_css_default = {
8488
+ "avatar": "aACNsW_avatar",
8489
+ "overflow": "aACNsW_overflow",
8490
+ "stack": "aACNsW_stack"
8491
+ };
8492
+ //#endregion
8493
+ //#region src/client/TeamAvatarStack.tsx
8494
+ /** Distinct owners past this count collapse into one `+N` chip. */
8495
+ const MAX_VISIBLE = 3;
8496
+ /**
8497
+ * The compact "who is on this work" stack: overlapping 18px Member circles in
8498
+ * the shared identity language, capped at three plus a `+N` chip. The circles
8499
+ * are presentational, so the stack is one `role="img"` whose label carries the
8500
+ * whole roster — three anonymous initials would read as noise.
8501
+ */
8502
+ function TeamAvatarStack({ owners, label }) {
8503
+ if (owners.length === 0) return null;
8504
+ const shown = owners.slice(0, MAX_VISIBLE);
8505
+ const overflow = owners.length - shown.length;
8506
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8507
+ className: avatar_stack_module_css_default.stack,
8508
+ role: "img",
8509
+ "aria-label": label,
8510
+ children: [shown.map((owner) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8511
+ className: avatar_stack_module_css_default.avatar,
8512
+ style: { "--team-avatar-hue": memberHue(owner.memberId) },
8513
+ children: initial(owner.name)
8514
+ }, owner.memberId)), overflow > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8515
+ className: avatar_stack_module_css_default.overflow,
8516
+ children: `+${overflow}`
8517
+ })]
8518
+ });
8519
+ }
8520
+ /** First visible character of a handle — and of a raw Member id when that is all there is. */
8521
+ function initial(name) {
8522
+ return name.replace(/^@/, "").replace(/^member:/, "").slice(0, 1).toUpperCase();
8523
+ }
8524
+ //#endregion
8525
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/countBadge.module.css.mjs
8526
+ const css$4 = ".LBWXOW_badge{background:var(--dsw-alias-state-business-primary);box-sizing:border-box;color:var(--dsw-alias-label-primary-foreground);corner-shape:round;font-variant-numeric:tabular-nums;border-radius:999px;flex:none;justify-content:center;align-items:center;min-width:18px;height:18px;padding:0 5px;font-size:11px;font-weight:600;line-height:18px;display:inline-flex}.LBWXOW_hairline{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0;padding:0 4px}";
8527
+ const tagId$4 = "@wowyuarm/dsh-agent-team/countBadge.module.css";
8528
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
8529
+ const tag = document.createElement("style");
8530
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
8531
+ tag.dataset.pluginCss = tagId$4;
8532
+ tag.textContent = css$4;
8533
+ document.head.appendChild(tag);
8534
+ }
8535
+ var countBadge_module_css_default = {
8536
+ "badge": "LBWXOW_badge",
8537
+ "hairline": "LBWXOW_hairline"
8538
+ };
8539
+ //#endregion
8540
+ //#region src/client/TeamCountBadge.tsx
8541
+ /** Every count the Human reads is capped at this, so one wide number never widens the capsule. */
8542
+ const COUNT_CAP = 99;
8543
+ /**
8544
+ * The one count capsule. The Human Inbox entry, the Channel feed's Thread
8545
+ * entry, and the Inbox queue row all answer the same question — how much is
8546
+ * waiting here — so they wear the same box rather than one hand-written copy
8547
+ * of the same declarations per surface. Three copies is how the feed's digit
8548
+ * ended up on a different line box from the other two.
8549
+ *
8550
+ * Zero is the absence of a count rather than a capsule reading zero, which is
8551
+ * the rule every caller wants and therefore the component's own.
8552
+ */
8553
+ function TeamCountBadge({ count, tone = "solid", label, className }) {
8554
+ if (count <= 0) return null;
8555
+ const text = count > COUNT_CAP ? `${COUNT_CAP}+` : String(count);
8556
+ const classes = `${countBadge_module_css_default.badge}${tone === "hairline" ? ` ${countBadge_module_css_default.hairline}` : ""}${className === void 0 ? "" : ` ${className}`}`;
8557
+ return label === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8558
+ className: classes,
8559
+ "data-team-count-badge": tone,
8560
+ "aria-hidden": "true",
8561
+ children: text
8562
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8563
+ className: classes,
8564
+ "data-team-count-badge": tone,
8565
+ role: "img",
8566
+ "aria-label": label,
8567
+ title: label,
8568
+ children: text
8569
+ });
8570
+ }
8571
+ //#endregion
7987
8572
  //#region src/client/TeamRunDivider.tsx
7988
8573
  /**
7989
8574
  * Explicit boundary between two same-sender Messages of one run separated by
@@ -8163,7 +8748,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8163
8748
  }
8164
8749
  //#endregion
8165
8750
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/channel.module.css.mjs
8166
- const css$3 = ".MYaRJa_headerMeta{color:var(--dsw-alias-label-tertiary);flex-wrap:wrap;align-items:center;gap:6px;margin-top:7px;font-size:12px;line-height:18px;display:flex}.MYaRJa_headerMeta span+span:before{content:\"·\";margin-right:6px}.MYaRJa_taskFooter{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left;background:0 0;border-radius:999px;align-items:center;gap:6px;max-width:100%;margin:6px 0 0;padding:2px 10px;transition:background-color .12s,border-color .12s,color .12s;display:inline-flex}.MYaRJa_taskFooter:hover,.MYaRJa_taskFooter:focus-visible{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary)}.MYaRJa_taskFooter:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.MYaRJa_taskNumber{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:600;line-height:18px}.MYaRJa_taskStatus,.MYaRJa_taskCount{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:18px}.MYaRJa_taskDot{flex:none;align-items:center;width:8px;display:inline-flex}.MYaRJa_taskArrow{color:var(--dsw-alias-label-tertiary);align-items:center;transition:transform .12s;display:inline-flex}.MYaRJa_taskFooter:hover .MYaRJa_taskArrow,.MYaRJa_taskFooter:focus-visible .MYaRJa_taskArrow{transform:translate(2px)}.MYaRJa_memberList{gap:3px;display:grid}.MYaRJa_memberRow{border-radius:6px;grid-template-columns:14px minmax(0,1fr) auto;align-items:center;gap:0 8px;min-height:40px;padding:4px 6px;display:grid}.MYaRJa_memberRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.MYaRJa_memberCopy{min-width:0;display:grid}.MYaRJa_memberCopy strong{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:500;line-height:18px;overflow:hidden}.MYaRJa_memberCopy small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:14px;overflow:hidden}.MYaRJa_memberAction{min-width:60px}.MYaRJa_memberError{color:var(--dsw-alias-state-error-primary);grid-column:2/-1;margin:2px 0;font-size:11px;line-height:16px}.MYaRJa_modalBody{max-height:min(65vh,520px);overflow-y:auto}@media (width<=600px){.MYaRJa_memberRow{grid-template-columns:14px minmax(0,1fr)}.MYaRJa_memberAction{grid-column:2;justify-self:start;margin-top:3px}}@media (prefers-reduced-motion:reduce){.MYaRJa_taskFooter,.MYaRJa_taskArrow{transition:none}.MYaRJa_taskFooter:hover .MYaRJa_taskArrow,.MYaRJa_taskFooter:focus-visible .MYaRJa_taskArrow{transform:none}}";
8751
+ const css$3 = ".MYaRJa_headerMeta{color:var(--dsw-alias-label-tertiary);flex-wrap:wrap;align-items:center;gap:6px;margin-top:7px;font-size:12px;line-height:18px;display:flex}.MYaRJa_headerMeta span+span:before{content:\"·\";margin-right:6px}.MYaRJa_memberList{gap:2px;margin:0 -6px;display:grid}.MYaRJa_modalBody{max-height:min(65vh,520px);overflow-y:auto}";
8167
8752
  const tagId$3 = "@wowyuarm/dsh-agent-team/channel.module.css";
8168
8753
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
8169
8754
  const tag = document.createElement("style");
@@ -8174,22 +8759,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8174
8759
  }
8175
8760
  var channel_module_css_default = {
8176
8761
  "headerMeta": "MYaRJa_headerMeta",
8177
- "memberAction": "MYaRJa_memberAction",
8178
- "memberCopy": "MYaRJa_memberCopy",
8179
- "memberError": "MYaRJa_memberError",
8180
8762
  "memberList": "MYaRJa_memberList",
8181
- "memberRow": "MYaRJa_memberRow",
8182
- "modalBody": "MYaRJa_modalBody",
8183
- "taskArrow": "MYaRJa_taskArrow",
8184
- "taskCount": "MYaRJa_taskCount",
8185
- "taskDot": "MYaRJa_taskDot",
8186
- "taskFooter": "MYaRJa_taskFooter",
8187
- "taskNumber": "MYaRJa_taskNumber",
8188
- "taskStatus": "MYaRJa_taskStatus"
8763
+ "modalBody": "MYaRJa_modalBody"
8189
8764
  };
8190
8765
  //#endregion
8191
8766
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/thread.module.css.mjs
8192
- const css$2 = ".-Qiwua_titleLine{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.-Qiwua_titleLine h1{margin:0}.-Qiwua_workSection{border-top:1px solid var(--dsw-alias-border-l2);max-width:880px;margin:12px auto 0;padding-top:8px}.-Qiwua_riskSection{border-top:1px solid var(--dsw-alias-border-l2);max-width:880px;margin:12px auto 0;padding-top:10px}.-Qiwua_riskSection h2{color:var(--dsw-alias-state-error-primary);margin:0 0 5px;font-size:12px;font-weight:600;line-height:18px}.-Qiwua_riskRow{color:var(--dsw-alias-label-secondary);align-items:center;gap:8px;margin:3px 0;font-size:12px;line-height:18px;display:flex}.-Qiwua_claimList{gap:4px;padding:4px 0 2px 22px;display:grid}.-Qiwua_claimRow{border-radius:6px;grid-template-columns:14px minmax(96px,auto) minmax(0,1fr) auto auto;align-items:center;gap:4px 8px;min-height:36px;padding:4px 6px;display:grid}.-Qiwua_claimRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.-Qiwua_claimOwner{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;font-weight:500;line-height:18px;overflow:hidden}.-Qiwua_claimDirection{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;min-width:0;font-size:12px;line-height:18px}.-Qiwua_claimState{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:11px;line-height:18px}.-Qiwua_emptyClaims{color:var(--dsw-alias-label-tertiary);margin:0;padding:5px 6px;font-size:11px;line-height:18px}.-Qiwua_activityRow{color:var(--dsw-alias-label-tertiary);text-align:center;justify-content:center;align-items:center;gap:8px;max-width:100%;margin:4px auto;padding:5px 12px;font-size:11px;line-height:18px;display:flex}.-Qiwua_activityText{overflow-wrap:anywhere;min-width:0}.-Qiwua_activityMark{background:var(--dsw-alias-border-l3);border-radius:50%;flex:0 0 5px;width:5px;height:5px}.-Qiwua_activityRow:has(+.-Qiwua_activityRow),.-Qiwua_activityRow+.-Qiwua_activityRow{text-align:left;justify-content:flex-start;padding-left:38px}.-Qiwua_historySection{border-bottom:1px solid var(--dsw-alias-border-l2);max-width:100%;margin:0 auto 12px;padding-bottom:10px}.-Qiwua_historySection h2{color:var(--dsw-alias-label-tertiary);letter-spacing:.02em;text-transform:uppercase;margin:0 0 4px;font-size:11px;font-weight:600;line-height:16px}.-Qiwua_publicSection{min-width:0}.-Qiwua_unreadBoundary{color:var(--dsw-alias-label-tertiary);align-items:center;gap:10px;margin:10px 0 6px;font-size:11px;line-height:16px;display:flex}.-Qiwua_unreadBoundary:before,.-Qiwua_unreadBoundary:after{background:var(--dsw-alias-border-l3);content:\"\";flex:1;height:1px}.-Qiwua_unreadBoundary span{flex:none}.-Qiwua_daySeparator{color:var(--dsw-alias-label-tertiary);letter-spacing:.02em;align-items:center;gap:10px;margin:12px 0 4px;font-size:11px;line-height:16px;display:flex}.-Qiwua_daySeparator:before,.-Qiwua_daySeparator:after{background:var(--dsw-alias-border-l2);content:\"\";flex:1;height:1px}.-Qiwua_daySeparator span{flex:none}.-Qiwua_newUpdates{background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1));border:1px solid var(--dsw-alias-border-l2-darkmode-thin);box-shadow:var(--dsw-shadow-lv2);z-index:2;border-radius:999px;justify-content:center;align-items:center;width:fit-content;margin:8px auto;padding:4px 12px;font-size:12px;line-height:18px;display:flex;position:sticky;bottom:8px}.-Qiwua_newUpdatesJump{color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;line-height:inherit;background:0 0;border:0;padding:0}.-Qiwua_newUpdatesJump:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px;border-radius:6px}.-Qiwua_taskTitle{color:var(--dsw-alias-label-secondary);-webkit-line-clamp:2;overflow-wrap:anywhere;-webkit-box-orient:vertical;margin:2px 0 0;font-size:13px;line-height:20px;display:-webkit-box;overflow:hidden}.-Qiwua_closedBar{flex-direction:column;align-items:center;display:flex}.-Qiwua_closedNotice{color:var(--dsw-alias-label-tertiary);flex-wrap:wrap;justify-content:center;align-items:center;gap:12px;padding:10px 16px 14px;font-size:13px;line-height:20px;display:flex}@media (width<=600px){.-Qiwua_claimRow{grid-template-columns:14px minmax(0,1fr) auto;align-items:start}.-Qiwua_claimState{grid-area:1/3;justify-self:end}.-Qiwua_claimDirection{grid-column:2/-1}.-Qiwua_activityRow{padding-inline:0}.-Qiwua_newUpdates{max-width:calc(100% - 16px)}}";
8767
+ const css$2 = ".-Qiwua_titleLine{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.-Qiwua_titleLine h1{margin:0}.-Qiwua_workSection{border-top:1px solid var(--dsw-alias-border-l2);max-width:880px;margin:12px auto 0;padding-top:8px}.-Qiwua_riskSection{border-top:1px solid var(--dsw-alias-border-l2);max-width:880px;margin:12px auto 0;padding-top:10px}.-Qiwua_riskSection h2{color:var(--dsw-alias-state-error-primary);margin:0 0 5px;font-size:12px;font-weight:600;line-height:18px}.-Qiwua_riskRow{color:var(--dsw-alias-label-secondary);align-items:center;gap:8px;margin:3px 0;font-size:12px;line-height:18px;display:flex}.-Qiwua_claimList{gap:4px;padding:4px 0 2px 22px;display:grid}.-Qiwua_claimRow{border-radius:6px;grid-template-columns:14px minmax(96px,auto) minmax(0,1fr) auto auto;align-items:center;gap:4px 8px;min-height:36px;padding:4px 6px;display:grid}.-Qiwua_claimRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.-Qiwua_claimOwner{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;font-weight:500;line-height:18px;overflow:hidden}.-Qiwua_claimDirection{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;min-width:0;font-size:12px;line-height:18px}.-Qiwua_claimState{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:11px;line-height:18px}.-Qiwua_emptyClaims{color:var(--dsw-alias-label-tertiary);margin:0;padding:5px 6px;font-size:11px;line-height:18px}.-Qiwua_activityRow{color:var(--dsw-alias-label-tertiary);text-align:center;justify-content:center;align-items:center;gap:8px;max-width:100%;margin:4px auto;padding:5px 12px;font-size:11px;line-height:18px;display:flex}.-Qiwua_activityText{overflow-wrap:anywhere;min-width:0}.-Qiwua_activityMark{background:var(--dsw-alias-border-l3);corner-shape:round;border-radius:50%;flex:0 0 5px;width:5px;height:5px}.-Qiwua_activityRow:has(+.-Qiwua_activityRow),.-Qiwua_activityRow+.-Qiwua_activityRow{text-align:left;justify-content:flex-start;padding-left:38px}.-Qiwua_historySection{border-bottom:1px solid var(--dsw-alias-border-l2);max-width:100%;margin:0 auto 12px;padding-bottom:10px}.-Qiwua_historySection h2{color:var(--dsw-alias-label-tertiary);letter-spacing:.02em;text-transform:uppercase;margin:0 0 4px;font-size:11px;font-weight:600;line-height:16px}.-Qiwua_publicSection{min-width:0}.-Qiwua_unreadBoundary{color:var(--dsw-alias-label-tertiary);align-items:center;gap:10px;margin:10px 0 6px;font-size:11px;line-height:16px;display:flex}.-Qiwua_unreadBoundary:before,.-Qiwua_unreadBoundary:after{background:var(--dsw-alias-border-l3);content:\"\";flex:1;height:1px}.-Qiwua_unreadBoundary span{flex:none}.-Qiwua_daySeparator{color:var(--dsw-alias-label-tertiary);letter-spacing:.02em;align-items:center;gap:10px;margin:12px 0 4px;font-size:11px;line-height:16px;display:flex}.-Qiwua_daySeparator:before,.-Qiwua_daySeparator:after{background:var(--dsw-alias-border-l2);content:\"\";flex:1;height:1px}.-Qiwua_daySeparator span{flex:none}.-Qiwua_newUpdates{background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1));border:1px solid var(--dsw-alias-border-l2-darkmode-thin);corner-shape:round;box-shadow:var(--dsw-shadow-lv2);z-index:2;border-radius:999px;justify-content:center;align-items:center;width:fit-content;margin:8px auto;padding:4px 12px;font-size:12px;line-height:18px;display:flex;position:sticky;bottom:8px}.-Qiwua_newUpdatesJump{color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;line-height:inherit;background:0 0;border:0;padding:0}.-Qiwua_newUpdatesJump:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px;border-radius:6px}.-Qiwua_taskTitle{color:var(--dsw-alias-label-secondary);-webkit-line-clamp:2;overflow-wrap:anywhere;-webkit-box-orient:vertical;margin:2px 0 0;font-size:13px;line-height:20px;display:-webkit-box;overflow:hidden}.-Qiwua_closedBar{flex-direction:column;align-items:center;display:flex}.-Qiwua_closedNotice{color:var(--dsw-alias-label-tertiary);flex-wrap:wrap;justify-content:center;align-items:center;gap:12px;padding:10px 16px 14px;font-size:13px;line-height:20px;display:flex}@media (width<=600px){.-Qiwua_claimRow{grid-template-columns:14px minmax(0,1fr) auto;align-items:start}.-Qiwua_claimState{grid-area:1/3;justify-self:end}.-Qiwua_claimDirection{grid-column:2/-1}.-Qiwua_activityRow{padding-inline:0}.-Qiwua_newUpdates{max-width:calc(100% - 16px)}}";
8193
8768
  const tagId$2 = "@wowyuarm/dsh-agent-team/thread.module.css";
8194
8769
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
8195
8770
  const tag = document.createElement("style");
@@ -8225,12 +8800,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8225
8800
  //#endregion
8226
8801
  //#region src/client/TeamChannelPage.tsx
8227
8802
  /**
8228
- * Merge the freshest top-level window over what the reader already has:
8229
- * a change-driven refresh must not discard older messages loaded earlier.
8803
+ * Merge the freshest top-level window over what the reader already has. The
8804
+ * fresh window is authoritative for every Message it covers — a change wake
8805
+ * must move that row's live Task state, newest instant, and unread with it —
8806
+ * while older Messages loaded earlier are retained instead of discarded.
8230
8807
  */
8231
8808
  function mergeChannelView(current, fresh) {
8232
- const known = new Set(current.items.map((item) => item.message.messageRef));
8233
- const items = [...fresh.items.filter((item) => !known.has(item.message.messageRef)), ...current.items].sort((left, right) => left.message.sequence - right.message.sequence);
8809
+ const freshRefs = new Set(fresh.items.map((item) => item.message.messageRef));
8810
+ const items = [...current.items.filter((item) => !freshRefs.has(item.message.messageRef)), ...fresh.items].sort((left, right) => left.message.sequence - right.message.sequence);
8234
8811
  return {
8235
8812
  ...fresh,
8236
8813
  items,
@@ -8238,9 +8815,41 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8238
8815
  hasMore: fresh.hasMore || current.cursor < fresh.cursor
8239
8816
  };
8240
8817
  }
8241
- function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscribeChanges, loadMembers, drafts, putAttachment, getAttachment, sendMessage, joinChannel, removeChannelMember, selectThread, selectChannel, backToChannels, resolveTaskRefs, t }) {
8818
+ /**
8819
+ * The people the Channel feed shows on one Task: owners of its live Claims, in
8820
+ * claim order, deduped. Claim state is a Host fact, not decoration — a released
8821
+ * Claim is no longer work — and only a Task still in progress or review has
8822
+ * any, because a done or closed Task keeps its Claims as history that the state
8823
+ * word already tells the reader.
8824
+ */
8825
+ function liveOwnersByTask(items, claims) {
8826
+ const live = new Set(items.flatMap((item) => item.task === void 0 ? [] : [item.task]).filter((task) => task.status === "in_progress" || task.status === "in_review").map((task) => task.taskRef));
8827
+ const owners = /* @__PURE__ */ new Map();
8828
+ for (const claim of claims) {
8829
+ if (!live.has(claim.taskRef) || claim.state === "released") continue;
8830
+ const known = owners.get(claim.taskRef);
8831
+ if (known === void 0) owners.set(claim.taskRef, [claim.owner]);
8832
+ else if (!known.includes(claim.owner)) known.push(claim.owner);
8833
+ }
8834
+ return owners;
8835
+ }
8836
+ /**
8837
+ * The newest fact instant, or nothing when the entry's own Message is still the
8838
+ * newest fact on its Thread. That difference is exactly what "has follow-up
8839
+ * activity" means, and the Host projects both instants from the ledger.
8840
+ */
8841
+ function followUpAt(item) {
8842
+ const lastActivityAt = item.lastActivityAt;
8843
+ return lastActivityAt === void 0 || lastActivityAt === item.message.occurredAt ? void 0 : lastActivityAt;
8844
+ }
8845
+ /** Host unread per Thread, keyed for the feed's rows: zero unread is the absence of a badge, not a row. */
8846
+ function unreadCounts(inbox) {
8847
+ return new Map(inbox.items.filter((item) => item.unreadCount > 0).map((item) => [item.thread.threadRef, item.unreadCount]));
8848
+ }
8849
+ function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscribeChanges, loadMembers, loadInbox, drafts, putAttachment, getAttachment, sendMessage, joinChannel, removeChannelMember, selectThread, selectChannel, backToChannels, resolveTaskRefs, t }) {
8242
8850
  const [view, setView] = (0, react.useState)();
8243
8851
  const [members, setMembers] = (0, react.useState)([]);
8852
+ const [unreadByThread, setUnreadByThread] = (0, react.useState)(/* @__PURE__ */ new Map());
8244
8853
  const [error, setError] = (0, react.useState)();
8245
8854
  const [pendingFiles, setPendingFiles] = (0, react.useState)([]);
8246
8855
  const [statusMessage, setStatusMessage] = (0, react.useState)();
@@ -8250,10 +8859,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8250
8859
  const [loadingOlder, setLoadingOlder] = (0, react.useState)(false);
8251
8860
  const [managingMembers, setManagingMembers] = (0, react.useState)(false);
8252
8861
  const draftKey = `channel:${channelRef}`;
8253
- const { draft, recipients } = (0, react.useSyncExternalStore)(drafts.subscribe, () => drafts.getSnapshot(draftKey));
8254
8862
  const manageTriggerRef = (0, react.useRef)(null);
8255
8863
  const memberListRef = (0, react.useRef)(null);
8256
8864
  const mountedRef = (0, react.useRef)(false);
8865
+ const loadedRef = (0, react.useRef)(false);
8257
8866
  const refreshSequenceRef = (0, react.useRef)(0);
8258
8867
  const channelLastItem = view?.items[view.items.length - 1];
8259
8868
  const openRef = (ref) => {
@@ -8298,31 +8907,46 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8298
8907
  const channelMembers = members.filter((status) => channelMemberIds.has(status.member.memberId) && status.member.state !== "inactive" && status.member.state !== "archived");
8299
8908
  const onlineCount = channelMembers.filter((status) => status.presence === "available" || status.presence === "working").length;
8300
8909
  const messageSender = (item) => item.message.sender;
8301
- const mentionHandlesMap = new Map(members.map((status) => [status.member.memberId, status.member.handle.replace(/^@/, "")]));
8910
+ const handleByMember = new Map(members.map((status) => [status.member.memberId, status.member.handle.replace(/^@/, "")]));
8911
+ const ownersByTask = liveOwnersByTask(view?.items ?? [], view?.claims ?? []);
8302
8912
  const refresh = async (clearError = false) => {
8303
8913
  if (!mountedRef.current) return false;
8304
8914
  const sequence = refreshSequenceRef.current + 1;
8305
8915
  refreshSequenceRef.current = sequence;
8306
- setLoading(true);
8916
+ if (!loadedRef.current) setLoading(true);
8307
8917
  if (clearError) {
8308
8918
  setError(void 0);
8309
8919
  setStatusMessage(void 0);
8310
8920
  }
8311
8921
  try {
8312
- const [loaded, loadedMembers] = await Promise.all([loadChannels({
8313
- workspaceId,
8314
- channelRef,
8315
- direction: "before",
8316
- topLevelOnly: true,
8317
- includeActivities: false,
8318
- limit: 20
8319
- }), loadMembers({ workspaceId })]);
8922
+ const [loaded, loadedMembers, loadedInbox] = await Promise.all([
8923
+ loadChannels({
8924
+ workspaceId,
8925
+ channelRef,
8926
+ direction: "before",
8927
+ topLevelOnly: true,
8928
+ includeActivities: false,
8929
+ limit: 20
8930
+ }),
8931
+ loadMembers({ workspaceId }),
8932
+ loadInbox({
8933
+ workspaceId,
8934
+ limit: 100
8935
+ })
8936
+ ]);
8320
8937
  if (!mountedRef.current || sequence !== refreshSequenceRef.current) return false;
8321
- if (loaded.ok) setView((current) => current === void 0 ? loaded.value : mergeChannelView(current, loaded.value));
8322
- else setError(loaded.error.message);
8938
+ if (loaded.ok) {
8939
+ setView((current) => current === void 0 ? loaded.value : mergeChannelView(current, loaded.value));
8940
+ loadedRef.current = true;
8941
+ } else setError(loaded.error.message);
8323
8942
  if (loadedMembers.ok) setMembers(loadedMembers.value);
8324
8943
  else setError(loadedMembers.error.message);
8325
- return loaded.ok && loadedMembers.ok;
8944
+ if (loadedInbox.ok) setUnreadByThread(unreadCounts(loadedInbox.value));
8945
+ else {
8946
+ setUnreadByThread(/* @__PURE__ */ new Map());
8947
+ setError(loadedInbox.error.message);
8948
+ }
8949
+ return loaded.ok && loadedMembers.ok && loadedInbox.ok;
8326
8950
  } catch (cause) {
8327
8951
  if (mountedRef.current && sequence === refreshSequenceRef.current) setError(cause instanceof Error ? cause.message : String(cause));
8328
8952
  return false;
@@ -8343,32 +8967,47 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8343
8967
  };
8344
8968
  (0, react.useEffect)(() => {
8345
8969
  mountedRef.current = true;
8970
+ loadedRef.current = false;
8346
8971
  setView(void 0);
8347
8972
  setError(void 0);
8348
8973
  setLoading(true);
8349
8974
  setManagingMembers(false);
8350
8975
  refresh();
8351
- const disposers = [subscribeChanges({
8352
- kind: "channel",
8353
- channelRef
8354
- }, (update) => {
8355
- if (!mountedRef.current) return;
8356
- if (update.type === "failed") {
8357
- setError(update.message);
8358
- return;
8359
- }
8360
- refresh();
8361
- }), subscribeChanges({
8362
- kind: "workspace",
8363
- workspaceId
8364
- }, (update) => {
8365
- if (!mountedRef.current) return;
8366
- if (update.type === "failed") {
8367
- setError(update.message);
8368
- return;
8369
- }
8370
- refreshMembers();
8371
- })];
8976
+ const disposers = [
8977
+ subscribeChanges({
8978
+ kind: "channel",
8979
+ channelRef
8980
+ }, (update) => {
8981
+ if (!mountedRef.current) return;
8982
+ if (update.type === "failed") {
8983
+ setError(update.message);
8984
+ return;
8985
+ }
8986
+ refresh();
8987
+ }),
8988
+ subscribeChanges({
8989
+ kind: "workspace",
8990
+ workspaceId
8991
+ }, (update) => {
8992
+ if (!mountedRef.current) return;
8993
+ if (update.type === "failed") {
8994
+ setError(update.message);
8995
+ return;
8996
+ }
8997
+ refreshMembers();
8998
+ }),
8999
+ subscribeChanges({
9000
+ kind: "presence",
9001
+ workspaceId
9002
+ }, (update) => {
9003
+ if (!mountedRef.current) return;
9004
+ if (update.type === "failed") {
9005
+ setError(update.message);
9006
+ return;
9007
+ }
9008
+ refreshMembers();
9009
+ })
9010
+ ];
8372
9011
  return () => {
8373
9012
  mountedRef.current = false;
8374
9013
  refreshSequenceRef.current += 1;
@@ -8419,7 +9058,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8419
9058
  await refresh();
8420
9059
  });
8421
9060
  const pendingSendId = (0, react.useRef)();
9061
+ const clearSendState = (0, react.useCallback)(() => {
9062
+ setStatusMessage((current) => current === void 0 ? current : void 0);
9063
+ }, []);
8422
9064
  const send = async () => {
9065
+ const { draft, recipients } = drafts.getSnapshot(draftKey);
8423
9066
  if (pending || draft.trim() === "") return;
8424
9067
  const recipientIds = [...recipients].sort();
8425
9068
  const requestId = pendingSendId.current ?? mintRequestId();
@@ -8428,22 +9071,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8428
9071
  setError(void 0);
8429
9072
  setStatusMessage(void 0);
8430
9073
  try {
8431
- const attachmentIds = [];
8432
- for (const file of pendingFiles) {
8433
- const uploaded = await putAttachment({
8434
- requestId: mintRequestId(),
8435
- workspaceId,
8436
- name: file.name,
8437
- mediaType: file.type === "" ? void 0 : file.type,
8438
- bytesBase64: bytesToBase64(new Uint8Array(await file.arrayBuffer()))
8439
- });
8440
- if (!uploaded.ok) {
8441
- pendingSendId.current = void 0;
8442
- setError(uploaded.error.message);
8443
- return;
8444
- }
8445
- attachmentIds.push(uploaded.value.attachmentId);
9074
+ const upload = await uploadComposerFiles(putAttachment, workspaceId, pendingFiles);
9075
+ if (!upload.ok) {
9076
+ pendingSendId.current = void 0;
9077
+ setError(upload.error);
9078
+ return;
8446
9079
  }
9080
+ const attachmentIds = upload.attachmentIds;
8447
9081
  const result = await sendMessage({
8448
9082
  requestId,
8449
9083
  workspaceId,
@@ -8527,39 +9161,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8527
9161
  children: members.filter((status) => status.member.state !== "inactive" && status.member.state !== "archived").map((status) => {
8528
9162
  const joined = channelMemberIds.has(status.member.memberId);
8529
9163
  const rowPending = membership.pending.has(status.member.memberId);
8530
- const disabled = rowPending || !joined && status.presence === "unavailable";
9164
+ const disabled = rowPending || !joined && status.availability !== "active";
8531
9165
  const rowError = membership.errors.get(status.member.memberId);
8532
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8533
- className: channel_module_css_default.memberRow,
8534
- children: [
8535
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamPresenceDot, {
8536
- status,
8537
- t
8538
- }),
8539
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8540
- className: channel_module_css_default.memberCopy,
8541
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: ["@", status.member.handle] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: status.member.description })]
8542
- }),
8543
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8544
- className: channel_module_css_default.memberAction,
8545
- size: "sm",
8546
- disabled,
8547
- onClick: () => {
8548
- membership.change({
8549
- workspaceId,
8550
- channelRef,
8551
- memberId: status.member.memberId,
8552
- joined
8553
- });
8554
- },
8555
- children: rowPending ? t("membershipUpdating") : joined ? t("removeFromChannel") : t("addToChannel")
8556
- }),
8557
- rowError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8558
- className: channel_module_css_default.memberError,
8559
- role: "alert",
8560
- children: rowError
8561
- })
8562
- ]
9166
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberRow, {
9167
+ status,
9168
+ action: {
9169
+ label: rowPending ? t("membershipUpdating") : joined ? t("removeFromChannel") : t("addToChannel"),
9170
+ disabled,
9171
+ onSelect: () => {
9172
+ membership.change({
9173
+ workspaceId,
9174
+ channelRef,
9175
+ memberId: status.member.memberId,
9176
+ joined
9177
+ });
9178
+ }
9179
+ },
9180
+ ...rowError === void 0 ? {} : { error: rowError },
9181
+ t
8563
9182
  }, status.member.memberId);
8564
9183
  })
8565
9184
  })
@@ -8629,7 +9248,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8629
9248
  const human = item.message.sender === view.humanMemberId;
8630
9249
  const sender = human ? t("human") : senderStatus?.member.handle ?? item.message.sender;
8631
9250
  const turnGap = isRunGap(index > 0 ? block.items[index - 1].message.occurredAt : void 0, item.message.occurredAt);
8632
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [turnGap && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamRunDivider, { occurredAt: item.message.occurredAt }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(TeamMessage, {
9251
+ const task = item.task;
9252
+ const owners = task === void 0 ? [] : ownersByTask.get(task.taskRef) ?? [];
9253
+ const unread = unreadByThread.get(item.thread.threadRef) ?? 0;
9254
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [turnGap && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamRunDivider, { occurredAt: item.message.occurredAt }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMessage, {
8633
9255
  senderName: sender,
8634
9256
  memberId: item.message.sender,
8635
9257
  human,
@@ -8638,68 +9260,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8638
9260
  loadAttachment: getAttachment,
8639
9261
  t,
8640
9262
  occurredAt: item.message.occurredAt,
8641
- mentionNames: mentionNamesOf(item.mentions, mentionHandlesMap),
9263
+ mentionNames: mentionNamesOf(item.mentions, handleByMember),
8642
9264
  onOpenRef: openRef,
8643
9265
  onResolveTaskRefs: lookupTaskRefs,
8644
9266
  grouped: index > 0,
8645
9267
  showGroupedTime: item.message.topLevel === true && !turnGap,
8646
9268
  ...senderStatus === void 0 ? {} : { senderTitle: senderStatus.member.description },
8647
- children: [item.message.topLevel && item.task !== void 0 && item.taskNumber !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8648
- type: "button",
8649
- className: channel_module_css_default.taskFooter,
8650
- "aria-label": t("openTask", { number: item.taskNumber }),
8651
- onClick: () => {
8652
- selectThread(item.thread.threadRef, channelRef, item.task?.taskRef, item.taskNumber);
8653
- },
8654
- children: [
8655
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8656
- className: channel_module_css_default.taskDot,
8657
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamStateDot, {
8658
- size: 8,
8659
- state: taskStatusDot(item.task.status)
8660
- })
8661
- }),
8662
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8663
- className: channel_module_css_default.taskNumber,
8664
- children: t("taskLabel", { number: item.taskNumber })
8665
- }),
8666
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8667
- className: channel_module_css_default.taskStatus,
8668
- children: formatTaskStatus(item.task.status, t)
8669
- }),
8670
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8671
- className: channel_module_css_default.taskCount,
8672
- children: t("taskMessageCount", { count: item.messageCount })
8673
- }),
8674
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8675
- className: channel_module_css_default.taskArrow,
8676
- "aria-hidden": "true",
8677
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, { size: 12 })
8678
- })
8679
- ]
8680
- }), item.message.topLevel && item.task === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8681
- type: "button",
8682
- className: channel_module_css_default.taskFooter,
8683
- "aria-label": t("openThread"),
8684
- onClick: () => {
8685
- selectThread(item.thread.threadRef, channelRef);
8686
- },
8687
- children: [
8688
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8689
- className: channel_module_css_default.taskNumber,
8690
- children: t("threadLabel")
8691
- }),
8692
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8693
- className: channel_module_css_default.taskCount,
8694
- children: t("taskMessageCount", { count: item.messageCount })
8695
- }),
8696
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8697
- className: channel_module_css_default.taskArrow,
8698
- "aria-hidden": "true",
8699
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, { size: 12 })
8700
- })
8701
- ]
8702
- })]
9269
+ children: item.message.topLevel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreadEntryRow, {
9270
+ item,
9271
+ owners: owners.map((memberId) => ({
9272
+ memberId,
9273
+ name: handleByMember.get(memberId) ?? memberId
9274
+ })),
9275
+ unread,
9276
+ t,
9277
+ onOpen: () => {
9278
+ selectThread(item.thread.threadRef, channelRef, task?.taskRef, item.taskNumber);
9279
+ }
9280
+ })
8703
9281
  })] }, item.message.messageRef);
8704
9282
  })
8705
9283
  }, `run-${block.items[0].message.messageRef}`))
@@ -8708,19 +9286,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8708
9286
  }),
8709
9287
  channel !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamComposer, {
8710
9288
  members: channelMembers,
8711
- recipients,
8712
- draft,
9289
+ drafts,
9290
+ draftKey,
8713
9291
  pending,
8714
9292
  ...statusMessage === void 0 ? {} : { confirmation: statusMessage },
8715
9293
  ...error === void 0 ? {} : { error },
8716
- onDraftChange: (next) => {
8717
- drafts.writeDraft(draftKey, next);
8718
- setStatusMessage(void 0);
8719
- },
8720
- onRecipientsChange: (next) => {
8721
- drafts.writeRecipients(draftKey, next);
8722
- setStatusMessage(void 0);
8723
- },
9294
+ onEdit: clearSendState,
8724
9295
  onSubmit: () => {
8725
9296
  send();
8726
9297
  },
@@ -8733,6 +9304,453 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8733
9304
  ]
8734
9305
  });
8735
9306
  }
9307
+ /**
9308
+ * One entry's state: who is on the work, where it stands, and how much of it
9309
+ * needs the reader. It leads the entry's own line rather than trailing the
9310
+ * identity line, so a reader meets it where they are already reading instead of
9311
+ * crossing the column for it — and the same placement holds whether this
9312
+ * Message opened its run or continued one, where an identity line would have
9313
+ * carried nothing else. The unread capsule is the only member a taskless
9314
+ * discussion can carry: it needs no Task.
9315
+ */
9316
+ function ThreadStateCluster({ task, owners, unread, t }) {
9317
+ if (task === void 0 && unread === 0) return null;
9318
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9319
+ className: conversation_module_css_default.stateCluster,
9320
+ children: [
9321
+ task !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamAvatarStack, {
9322
+ owners,
9323
+ label: t("claimers", { names: owners.map((owner) => `@${owner.name}`).join(", ") })
9324
+ }),
9325
+ task !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamStateDot, {
9326
+ size: 8,
9327
+ state: taskStatusDot(task.status)
9328
+ }),
9329
+ task !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9330
+ className: conversation_module_css_default.statusWord,
9331
+ children: formatTaskStatus(task.status, t)
9332
+ }),
9333
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamCountBadge, { count: unread })
9334
+ ]
9335
+ });
9336
+ }
9337
+ /**
9338
+ * The gate under one top-level Message: the single row that opens its Thread,
9339
+ * and the one line that says what stands there. State leads it, then what the
9340
+ * entry is: a Task entry keeps its number so the status word never floats free
9341
+ * of the Task it describes, follow-up activity adds when the work last moved,
9342
+ * and an unanswered Thread says only 回复. The instant uses the Inbox's own
9343
+ * 今天/昨天 form with the precise local time on the control's title, and an
9344
+ * unread Thread says so in the control's label rather than only in pixels.
9345
+ */
9346
+ function ThreadEntryRow({ item, owners, unread, t, onOpen }) {
9347
+ const taskNumber = item.taskNumber;
9348
+ const followUp = followUpAt(item);
9349
+ const label = taskNumber !== void 0 ? t("taskLabel", { number: taskNumber }) : followUp === void 0 ? t("replyAction") : t("threadLabel");
9350
+ const text = followUp === void 0 ? label : `${label} · ${t("recentActivity", { time: formatInboxTime(followUp, t) })}`;
9351
+ const openLabel = taskNumber === void 0 ? unread > 0 ? t("openThreadUnread", { count: unread }) : t("openThread") : unread > 0 ? t("openTaskUnread", {
9352
+ number: taskNumber,
9353
+ count: unread
9354
+ }) : t("openTask", { number: taskNumber });
9355
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9356
+ className: conversation_module_css_default.entryLine,
9357
+ "data-thread-entry": "",
9358
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreadStateCluster, {
9359
+ task: item.task,
9360
+ owners,
9361
+ unread,
9362
+ t
9363
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
9364
+ type: "button",
9365
+ className: conversation_module_css_default.entryRow,
9366
+ "aria-label": openLabel,
9367
+ ...followUp === void 0 ? {} : { title: formatAbsoluteTime(followUp) },
9368
+ onClick: onOpen,
9369
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9370
+ className: conversation_module_css_default.entryArrow,
9371
+ "aria-hidden": "true",
9372
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, { size: 12 })
9373
+ })]
9374
+ })]
9375
+ });
9376
+ }
9377
+ //#endregion
9378
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/inbox.module.css.mjs
9379
+ const css$1 = ".s2ibaa_list{flex-direction:column;gap:2px;display:flex}.s2ibaa_headerMeta{font-variant-numeric:tabular-nums;flex-wrap:wrap;align-items:baseline;gap:0 10px;display:flex;overflow:hidden}.s2ibaa_headerUnread{color:var(--dsw-alias-label-primary);font-weight:600}.s2ibaa_row{color:inherit;cursor:pointer;font:inherit;text-align:left;background:0 0;border:0;border-radius:8px;grid-template-columns:max-content minmax(0,1fr);align-items:baseline;gap:1px 8px;width:100%;padding:8px;display:grid}.s2ibaa_row:hover,.s2ibaa_row:focus-visible{--team-mark-ring:var(--dsw-alias-interactive-bg-hover);background:var(--dsw-alias-interactive-bg-hover)}.s2ibaa_row:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:-2px}.s2ibaa_rowActor{grid-area:1/1;display:flex}.s2ibaa_rowLine{grid-area:1/2;align-items:baseline;gap:2px 8px;min-width:0;display:flex}.s2ibaa_rowCrumb{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;font-size:13px;line-height:20px;overflow:hidden}.s2ibaa_rowWorkspace{color:var(--dsw-alias-label-tertiary);font-size:12px}.s2ibaa_rowChannel{color:var(--dsw-alias-label-primary);font-weight:600}.s2ibaa_rowTask{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:6px;flex:none;margin-left:3px;padding:0 5px;font-size:11px;font-weight:600;line-height:15px}.s2ibaa_rowTime{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;flex:none;font-size:11px;line-height:18px}.s2ibaa_rowPreview{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;grid-area:2/2;min-width:0;font-size:13px;line-height:20px;overflow:hidden}.s2ibaa_section{flex-direction:column;display:flex}.s2ibaa_section+.s2ibaa_section{margin-top:20px}.s2ibaa_sectionTitle{color:var(--dsw-alias-label-tertiary);margin:0 0 4px;padding:0 8px 0 34px;font-size:12px;font-weight:600;line-height:18px}.s2ibaa_sectionCount{font-variant-numeric:tabular-nums;margin-left:6px}";
9380
+ const tagId$1 = "@wowyuarm/dsh-agent-team/inbox.module.css";
9381
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
9382
+ const tag = document.createElement("style");
9383
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
9384
+ tag.dataset.pluginCss = tagId$1;
9385
+ tag.textContent = css$1;
9386
+ document.head.appendChild(tag);
9387
+ }
9388
+ var inbox_module_css_default = {
9389
+ "headerMeta": "s2ibaa_headerMeta",
9390
+ "headerUnread": "s2ibaa_headerUnread",
9391
+ "list": "s2ibaa_list",
9392
+ "row": "s2ibaa_row",
9393
+ "rowActor": "s2ibaa_rowActor",
9394
+ "rowChannel": "s2ibaa_rowChannel",
9395
+ "rowCrumb": "s2ibaa_rowCrumb",
9396
+ "rowLine": "s2ibaa_rowLine",
9397
+ "rowPreview": "s2ibaa_rowPreview",
9398
+ "rowTask": "s2ibaa_rowTask",
9399
+ "rowTime": "s2ibaa_rowTime",
9400
+ "rowWorkspace": "s2ibaa_rowWorkspace",
9401
+ "section": "s2ibaa_section",
9402
+ "sectionCount": "s2ibaa_sectionCount",
9403
+ "sectionTitle": "s2ibaa_sectionTitle"
9404
+ };
9405
+ //#endregion
9406
+ //#region src/client/TeamInboxPage.tsx
9407
+ /**
9408
+ * How many 「最近活跃」 rows the merged page may show. The Host bounds each
9409
+ * Workspace's own slice; this is the single bound across every Workspace on
9410
+ * screen, so the section stays the same size no matter how many are open — and
9411
+ * it stays a way back into work rather than a second queue, which is why it is
9412
+ * shorter than the queue the reader is actually being asked to work through.
9413
+ */
9414
+ const RECENT_ROWS_LIMIT = 5;
9415
+ /**
9416
+ * Queue order: newest unread first, one total order across Workspaces. Each
9417
+ * Workspace slice arrives in the Host's own order (that order is the Host's
9418
+ * truncation policy); the merged display order is decided here, where the
9419
+ * merge happens, and the ledger sequence breaks ties so the queue never
9420
+ * reshuffles two rows that share an instant.
9421
+ */
9422
+ function compareInboxRows(left, right) {
9423
+ const leftAt = Date.parse(left.item.newestOccurredAt);
9424
+ const rightAt = Date.parse(right.item.newestOccurredAt);
9425
+ const byTime = (Number.isNaN(rightAt) ? 0 : rightAt) - (Number.isNaN(leftAt) ? 0 : leftAt);
9426
+ return byTime !== 0 ? byTime : right.item.newestSequence - left.item.newestSequence;
9427
+ }
9428
+ /**
9429
+ * The Human Inbox: one Inbox call per visible Workspace, rendering the Host's
9430
+ * two slices — the unread queue (「需要我」, mentions counted inside it rather
9431
+ * than alone) and the 「最近活跃」 tail of Threads the reader took part in.
9432
+ * Both merge across every Workspace into one recency-ordered list, newest
9433
+ * first, since a queue is read by recency rather than by Workspace.
9434
+ * Opening the page never acknowledges anything — only a durable Thread read
9435
+ * advances the watermark and consumes a mention marker, so rows and the badge
9436
+ * drop after the Thread is opened through the existing auto-ack path. A Thread
9437
+ * holding unread is only ever in the queue: the Host already excludes it from
9438
+ * the tail, and this page never re-derives that judgement.
9439
+ */
9440
+ function TeamInboxPage({ useWorkspaces, loadInbox, subscribeChanges, selectWorkspace, selectThread, t }) {
9441
+ const workspaces = useWorkspaces((state) => state.items);
9442
+ const [rows, setRows] = (0, react.useState)();
9443
+ const [recentRows, setRecentRows] = (0, react.useState)([]);
9444
+ const [loading, setLoading] = (0, react.useState)(true);
9445
+ const [error, setError] = (0, react.useState)();
9446
+ const loadedRef = (0, react.useRef)(false);
9447
+ const refresh = (0, react.useCallback)(async () => {
9448
+ if (!loadedRef.current) setLoading(true);
9449
+ const results = await Promise.all(workspaces.map(async (workspace) => {
9450
+ const result = await loadInbox({
9451
+ workspaceId: workspace.workspaceId,
9452
+ limit: 100
9453
+ });
9454
+ return result.ok ? {
9455
+ ok: true,
9456
+ workspaceId: workspace.workspaceId,
9457
+ workspaceTitle: workspace.title,
9458
+ items: result.value.items,
9459
+ recent: result.value.recent
9460
+ } : {
9461
+ ok: false,
9462
+ message: result.error.message
9463
+ };
9464
+ }));
9465
+ const failure = results.find((result) => !result.ok);
9466
+ const asRows = (items, workspaceId, workspaceTitle) => items.map((item) => ({
9467
+ workspaceId,
9468
+ workspaceTitle,
9469
+ item
9470
+ }));
9471
+ setRows(results.flatMap((result) => result.ok ? asRows(result.items, result.workspaceId, result.workspaceTitle) : []).sort(compareInboxRows));
9472
+ setRecentRows(results.flatMap((result) => result.ok ? asRows(result.recent, result.workspaceId, result.workspaceTitle) : []).sort(compareInboxRows).slice(0, RECENT_ROWS_LIMIT));
9473
+ setError(failure?.ok === false ? failure.message : void 0);
9474
+ loadedRef.current = true;
9475
+ setLoading(false);
9476
+ }, [loadInbox, workspaces]);
9477
+ (0, react.useEffect)(() => {
9478
+ refresh();
9479
+ }, [refresh]);
9480
+ (0, react.useEffect)(() => subscribeChanges(void 0, (update) => {
9481
+ if (update.type === "failed") {
9482
+ setError(update.message);
9483
+ return;
9484
+ }
9485
+ refresh();
9486
+ }), [subscribeChanges, refresh]);
9487
+ const open = (row) => {
9488
+ selectWorkspace(row.workspaceId);
9489
+ selectThread(row.item.thread.threadRef, row.item.channelRef, row.item.task?.taskRef, row.item.taskNumber);
9490
+ };
9491
+ const totalUnread = rows?.reduce((sum, row) => sum + row.item.unreadCount, 0) ?? 0;
9492
+ const totalMentions = rows?.reduce((sum, row) => sum + row.item.directCount, 0) ?? 0;
9493
+ const shownWorkspaces = /* @__PURE__ */ new Set();
9494
+ for (const row of rows ?? []) shownWorkspaces.add(row.workspaceTitle);
9495
+ for (const row of recentRows) shownWorkspaces.add(row.workspaceTitle);
9496
+ const showWorkspace = shownWorkspaces.size > 1;
9497
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("main", {
9498
+ className: conversation_module_css_default.surface,
9499
+ "data-team-inbox": true,
9500
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9501
+ className: conversation_module_css_default.surfaceHeader,
9502
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("header", {
9503
+ className: conversation_module_css_default.headerRow,
9504
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9505
+ className: conversation_module_css_default.headerCopy,
9506
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", { children: t("inboxTitle") }), rows !== void 0 && rows.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
9507
+ className: inbox_module_css_default.headerMeta,
9508
+ children: [
9509
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("inboxHeaderThreads", { count: rows.length }) }),
9510
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9511
+ className: inbox_module_css_default.headerUnread,
9512
+ children: t("inboxHeaderUnread", { count: totalUnread })
9513
+ }),
9514
+ totalMentions > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("inboxHeaderMentions", { count: totalMentions }) })
9515
+ ]
9516
+ })]
9517
+ })
9518
+ })
9519
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9520
+ className: conversation_module_css_default.timeline,
9521
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9522
+ className: conversation_module_css_default.timelineContent,
9523
+ children: [
9524
+ loading && rows === void 0 && error === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9525
+ className: conversation_module_css_default.emptySurface,
9526
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
9527
+ className: conversation_module_css_default.loadingState,
9528
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9529
+ className: conversation_module_css_default.loadingMark,
9530
+ "aria-hidden": "true"
9531
+ }), t("loadingInbox")]
9532
+ })
9533
+ }),
9534
+ !loading && rows === void 0 && error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9535
+ className: conversation_module_css_default.errorState,
9536
+ role: "alert",
9537
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: error }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
9538
+ size: "sm",
9539
+ variant: "outline",
9540
+ onClick: () => {
9541
+ refresh();
9542
+ },
9543
+ children: t("retry")
9544
+ })]
9545
+ }),
9546
+ rows !== void 0 && (rows.length === 0 && recentRows.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9547
+ className: conversation_module_css_default.emptySurface,
9548
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9549
+ className: conversation_module_css_default.emptyState,
9550
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("inboxEmptyTitle") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("inboxEmptyHint") })]
9551
+ })
9552
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [rows.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
9553
+ className: inbox_module_css_default.section,
9554
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
9555
+ className: inbox_module_css_default.sectionTitle,
9556
+ children: [t("inboxSectionNeedsMe"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9557
+ className: inbox_module_css_default.sectionCount,
9558
+ children: rows.length
9559
+ })]
9560
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9561
+ className: inbox_module_css_default.list,
9562
+ children: rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InboxQueueRow, {
9563
+ row,
9564
+ t,
9565
+ showWorkspace,
9566
+ onOpen: () => {
9567
+ open(row);
9568
+ }
9569
+ }, `${row.workspaceId} ${row.item.thread.threadRef}`))
9570
+ })]
9571
+ }), recentRows.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
9572
+ className: inbox_module_css_default.section,
9573
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
9574
+ className: inbox_module_css_default.sectionTitle,
9575
+ children: [t("inboxSectionRecent"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9576
+ className: inbox_module_css_default.sectionCount,
9577
+ children: recentRows.length
9578
+ })]
9579
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9580
+ className: inbox_module_css_default.list,
9581
+ children: recentRows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InboxQueueRow, {
9582
+ row,
9583
+ t,
9584
+ showWorkspace,
9585
+ onOpen: () => {
9586
+ open(row);
9587
+ }
9588
+ }, `${row.workspaceId} ${row.item.thread.threadRef}`))
9589
+ })]
9590
+ })] })),
9591
+ rows !== void 0 && error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9592
+ className: conversation_module_css_default.error,
9593
+ role: "alert",
9594
+ children: error
9595
+ })
9596
+ ]
9597
+ })
9598
+ })]
9599
+ });
9600
+ }
9601
+ /**
9602
+ * One queue row, shaped like the shipped two-line result row: who is on this
9603
+ * Thread leads in the gutter, the identity line answers which Thread this is,
9604
+ * how much is waiting, and when it last moved, and the gist sits under it on the
9605
+ * same column as evidence for that identity rather than as the row's subject.
9606
+ *
9607
+ * The gutter carries the one thing every row has — who is on the work, or who
9608
+ * moved a Thread nobody has claimed — so a Thread that merely arrived and one
9609
+ * that named the reader open on the same edge instead of the quieter one opening
9610
+ * on a slot reserved for a count it does not hold. It is the grammar the Channel
9611
+ * feed's Thread entry row already speaks, where the people on the work lead the
9612
+ * row.
9613
+ *
9614
+ * Before the queue admitted every unread Thread, each row was a mention and the
9615
+ * rows were interchangeable; now that named and ambient unread share one list,
9616
+ * the row has to carry that difference itself. The count closes the identity
9617
+ * line and only its ink changes — the shared capsule fill for a row that names
9618
+ * the reader, a hairline for one that merely moved. The two numbers behind that
9619
+ * ink (unread, mentions) reach assistive tech through the capsule's own name,
9620
+ * because a second visible count beside the first would cost the row the one
9621
+ * thing it needs to stay scannable.
9622
+ */
9623
+ function InboxQueueRow({ row, t, showWorkspace, onOpen }) {
9624
+ const { item } = row;
9625
+ const actor = item.newestActor;
9626
+ const owners = item.claimOwners;
9627
+ const named = item.directCount > 0;
9628
+ const countLabel = named ? t("inboxRowUnreadMentions", {
9629
+ count: item.unreadCount,
9630
+ mentions: item.directCount
9631
+ }) : t("inboxRowUnread", { count: item.unreadCount });
9632
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
9633
+ type: "button",
9634
+ className: inbox_module_css_default.row,
9635
+ "data-named": named || void 0,
9636
+ onClick: onOpen,
9637
+ children: [
9638
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9639
+ className: inbox_module_css_default.rowActor,
9640
+ children: owners.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamAvatarStack, {
9641
+ owners,
9642
+ label: t("claimers", { names: owners.map((owner) => `@${owner.name}`).join(", ") })
9643
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamAvatarStack, {
9644
+ owners: [actor],
9645
+ label: t("inboxRowActor", { name: `@${actor.name}` })
9646
+ })
9647
+ }),
9648
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9649
+ className: inbox_module_css_default.rowLine,
9650
+ children: [
9651
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9652
+ className: inbox_module_css_default.rowCrumb,
9653
+ children: [
9654
+ showWorkspace && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9655
+ className: inbox_module_css_default.rowWorkspace,
9656
+ children: row.workspaceTitle
9657
+ }),
9658
+ showWorkspace && " / ",
9659
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9660
+ className: inbox_module_css_default.rowChannel,
9661
+ children: ["#", item.channelName]
9662
+ }),
9663
+ " ",
9664
+ item.taskNumber !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9665
+ className: inbox_module_css_default.rowTask,
9666
+ children: t("taskLabel", { number: item.taskNumber })
9667
+ })
9668
+ ]
9669
+ }),
9670
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamCountBadge, {
9671
+ count: item.unreadCount,
9672
+ tone: named ? "solid" : "hairline",
9673
+ label: countLabel
9674
+ }),
9675
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
9676
+ className: inbox_module_css_default.rowTime,
9677
+ dateTime: item.newestOccurredAt,
9678
+ title: formatAbsoluteTime(item.newestOccurredAt),
9679
+ children: formatInboxTime(item.newestOccurredAt, t)
9680
+ })
9681
+ ]
9682
+ }),
9683
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9684
+ className: inbox_module_css_default.rowPreview,
9685
+ children: item.previewText
9686
+ })
9687
+ ]
9688
+ });
9689
+ }
9690
+ //#endregion
9691
+ //#region src/client/scope-coverage.ts
9692
+ /**
9693
+ * Per-scope coverage of the change versions one surface has already answered.
9694
+ *
9695
+ * A version is only comparable inside the scope that issued it: the Host
9696
+ * answers a workspace scope from the durable ledger position and a presence
9697
+ * scope from its process-local wake epoch, which starts low and climbs on every
9698
+ * Agent transition. One high-water mark shared by both would therefore let a
9699
+ * presence epoch swallow a later, smaller ledger sequence and park the surface
9700
+ * on stale data, so coverage and pending versions are kept per scope.
9701
+ *
9702
+ * One round answers one version per scope. The Host delivers one event to every
9703
+ * matching scope, so the first version a round sees in a scope it has not
9704
+ * answered yet is that event reaching a second scope, and joins the round
9705
+ * already fetching instead of earning a second identical read. A newer version
9706
+ * in a scope the round has answered arrived after the round issued its fetch,
9707
+ * so it owes one trailing round.
9708
+ */
9709
+ var ScopeCoverage = class {
9710
+ covered = /* @__PURE__ */ new Map();
9711
+ pending = /* @__PURE__ */ new Map();
9712
+ /** The scopes the open round has an answer for. */
9713
+ answered = /* @__PURE__ */ new Set();
9714
+ fetching = false;
9715
+ /** Folds one wake in and answers whether it opens a round. */
9716
+ wake(scope, version) {
9717
+ if (version <= this.coveredOf(scope)) return false;
9718
+ if (this.fetching && this.answered.has(scope)) {
9719
+ this.pending.set(scope, Math.max(this.pending.get(scope) ?? 0, version));
9720
+ return false;
9721
+ }
9722
+ this.answered.add(scope);
9723
+ this.covered.set(scope, version);
9724
+ return !this.fetching;
9725
+ }
9726
+ /** Opens a round's fetch window; versions observed from here on are pending. */
9727
+ beginRound() {
9728
+ this.pending.clear();
9729
+ this.fetching = true;
9730
+ }
9731
+ /** Closes a round's fetch window and answers whether a trailing round is owed. */
9732
+ finishRound() {
9733
+ this.fetching = false;
9734
+ this.answered.clear();
9735
+ let owed = false;
9736
+ for (const [scope, version] of this.pending) {
9737
+ if (version <= this.coveredOf(scope)) continue;
9738
+ this.covered.set(scope, version);
9739
+ owed = true;
9740
+ }
9741
+ return owed;
9742
+ }
9743
+ /** Drops every observation: a new owner starts with nothing covered. */
9744
+ reset() {
9745
+ this.covered.clear();
9746
+ this.pending.clear();
9747
+ this.answered.clear();
9748
+ this.fetching = false;
9749
+ }
9750
+ coveredOf(scope) {
9751
+ return this.covered.get(scope) ?? 0;
9752
+ }
9753
+ };
8736
9754
  //#endregion
8737
9755
  //#region src/client/TeamThreadPage.tsx
8738
9756
  function factKey(fact) {
@@ -8747,6 +9765,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8747
9765
  occurredAt: message.occurredAt
8748
9766
  };
8749
9767
  }
9768
+ /**
9769
+ * A fact owns its mention array, so the rendered name list is cached against
9770
+ * that array. Every roster refresh replaces the handles map with a fresh Map of
9771
+ * identical content, so the cache compares the resolved names rather than the
9772
+ * map identity: identity stays stable while the names are unchanged, which is
9773
+ * what keeps a memoized row from re-rendering on every refresh.
9774
+ */
9775
+ const mentionNamesCache = /* @__PURE__ */ new WeakMap();
9776
+ function stableMentionNames(mentions, handles) {
9777
+ const names = mentionNamesOf(mentions, handles);
9778
+ const cached = mentionNamesCache.get(mentions);
9779
+ if (cached !== void 0 && cached.length === names.length && cached.every((name, index) => name === names[index])) return cached;
9780
+ mentionNamesCache.set(mentions, names);
9781
+ return names;
9782
+ }
8750
9783
  function mergeFacts(...groups) {
8751
9784
  const byKey = /* @__PURE__ */ new Map();
8752
9785
  for (const group of groups) for (const fact of group) byKey.set(factKey(fact), fact);
@@ -8777,7 +9810,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8777
9810
  const [autoReadExhausted, setAutoReadExhausted] = (0, react.useState)(false);
8778
9811
  const [newFactsCount, setNewFactsCount] = (0, react.useState)(0);
8779
9812
  const draftKey = `thread:${threadRef}`;
8780
- const { draft, recipients } = (0, react.useSyncExternalStore)(drafts.subscribe, () => drafts.getSnapshot(draftKey));
8781
9813
  const [claimsOpen, setClaimsOpen] = (0, react.useState)(false);
8782
9814
  const [confirmingAccept, setConfirmingAccept] = (0, react.useState)(false);
8783
9815
  (0, react.useEffect)(() => {
@@ -8847,7 +9879,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8847
9879
  if (mountedRef.current && sequence === sequenceRef.current) setLoading(false);
8848
9880
  }
8849
9881
  };
8850
- const refreshSupplemental = async () => {
9882
+ /** One roster + view read. Answers false once the page is gone. */
9883
+ const applySupplemental = async () => {
8851
9884
  try {
8852
9885
  const [loadedMembers, loadedView] = await Promise.all([loadMembers({ workspaceId }), loadChannels({
8853
9886
  workspaceId,
@@ -8856,15 +9889,36 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8856
9889
  includeActivities: false,
8857
9890
  limit: 1
8858
9891
  })]);
8859
- if (!mountedRef.current) return;
9892
+ if (!mountedRef.current) return false;
8860
9893
  if (loadedMembers.ok) setMembers(loadedMembers.value);
8861
9894
  if (loadedView.ok) setChannelView(loadedView.value);
8862
9895
  const failure = [loadedMembers, loadedView].find((result) => !result.ok);
8863
9896
  if (failure !== void 0 && !failure.ok) setError(failure.error.message);
9897
+ return true;
8864
9898
  } catch (cause) {
8865
9899
  if (mountedRef.current) setError(cause instanceof Error ? cause.message : String(cause));
9900
+ return mountedRef.current;
8866
9901
  }
8867
9902
  };
9903
+ const supplementalRef = (0, react.useRef)();
9904
+ const supplementalCoverageRef = (0, react.useRef)(new ScopeCoverage());
9905
+ const refreshSupplemental = (wake) => {
9906
+ const inFlight = supplementalRef.current;
9907
+ if (wake === void 0) {
9908
+ if (inFlight !== void 0) return inFlight;
9909
+ } else if (!supplementalCoverageRef.current.wake(wake.scope, wake.version)) return inFlight ?? Promise.resolve();
9910
+ const coverage = supplementalCoverageRef.current;
9911
+ const round = (async () => {
9912
+ for (;;) {
9913
+ coverage.beginRound();
9914
+ if (!await applySupplemental() || !coverage.finishRound()) return;
9915
+ }
9916
+ })().finally(() => {
9917
+ if (supplementalRef.current === round) supplementalRef.current = void 0;
9918
+ });
9919
+ supplementalRef.current = round;
9920
+ return round;
9921
+ };
8868
9922
  const refreshPassiveFacts = async () => {
8869
9923
  try {
8870
9924
  const result = await loadThreadHistory({
@@ -8911,6 +9965,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8911
9965
  };
8912
9966
  (0, react.useEffect)(() => {
8913
9967
  mountedRef.current = true;
9968
+ supplementalRef.current = void 0;
9969
+ supplementalCoverageRef.current.reset();
8914
9970
  projectionRef.current = void 0;
8915
9971
  setProjection(void 0);
8916
9972
  setChannelView(void 0);
@@ -8969,28 +10025,48 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8969
10025
  await drainUnread();
8970
10026
  })();
8971
10027
  refreshSupplemental();
8972
- const disposers = [subscribeChanges({
8973
- kind: "thread",
8974
- threadRef
8975
- }, (update) => {
8976
- if (!mountedRef.current) return;
8977
- if (update.type === "failed") {
8978
- setError(update.message);
8979
- return;
8980
- }
8981
- refreshPassiveFacts();
8982
- refreshFollowers();
8983
- }), subscribeChanges({
8984
- kind: "workspace",
8985
- workspaceId
8986
- }, (update) => {
8987
- if (!mountedRef.current) return;
8988
- if (update.type === "failed") {
8989
- setError(update.message);
8990
- return;
8991
- }
8992
- refreshSupplemental();
8993
- })];
10028
+ const disposers = [
10029
+ subscribeChanges({
10030
+ kind: "thread",
10031
+ threadRef
10032
+ }, (update) => {
10033
+ if (!mountedRef.current) return;
10034
+ if (update.type === "failed") {
10035
+ setError(update.message);
10036
+ return;
10037
+ }
10038
+ refreshPassiveFacts();
10039
+ refreshFollowers();
10040
+ }),
10041
+ subscribeChanges({
10042
+ kind: "workspace",
10043
+ workspaceId
10044
+ }, (update) => {
10045
+ if (!mountedRef.current) return;
10046
+ if (update.type === "failed") {
10047
+ setError(update.message);
10048
+ return;
10049
+ }
10050
+ refreshSupplemental({
10051
+ scope: "workspace",
10052
+ version: update.version
10053
+ });
10054
+ }),
10055
+ subscribeChanges({
10056
+ kind: "presence",
10057
+ workspaceId
10058
+ }, (update) => {
10059
+ if (!mountedRef.current) return;
10060
+ if (update.type === "failed") {
10061
+ setError(update.message);
10062
+ return;
10063
+ }
10064
+ refreshSupplemental({
10065
+ scope: "presence",
10066
+ version: update.version
10067
+ });
10068
+ })
10069
+ ];
8994
10070
  return () => {
8995
10071
  mountedRef.current = false;
8996
10072
  sequenceRef.current += 1;
@@ -9066,7 +10142,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9066
10142
  };
9067
10143
  const messageSender = (fact) => fact.kind === "message" ? fact.message.sender : void 0;
9068
10144
  const [pendingFiles, setPendingFiles] = (0, react.useState)([]);
9069
- const openRef = (ref) => {
10145
+ const openRef = (0, react.useCallback)((ref) => {
9070
10146
  if (ref.startsWith("channel:") && ref !== channelRef) {
9071
10147
  selectChannel(ref);
9072
10148
  return;
@@ -9087,8 +10163,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9087
10163
  return;
9088
10164
  }
9089
10165
  if (ref.startsWith("task:") && ref !== taskRef) jumpToTaskThread(resolveTaskRefs, workspaceId, ref, selectThread);
9090
- };
9091
- const lookupTaskRefs = hostTaskRefLookup(resolveTaskRefs, workspaceId);
10166
+ }, [
10167
+ channelRef,
10168
+ threadRef,
10169
+ taskRef,
10170
+ workspaceId,
10171
+ selectChannel,
10172
+ selectThread,
10173
+ loadChannels,
10174
+ resolveTaskRefs
10175
+ ]);
10176
+ const lookupTaskRefs = (0, react.useMemo)(() => hostTaskRefLookup(resolveTaskRefs, workspaceId), [resolveTaskRefs, workspaceId]);
9092
10177
  const renderFact = (fact, grouped = false) => {
9093
10178
  if (fact.kind === "message") {
9094
10179
  const sender = memberName(fact.message.sender);
@@ -9102,7 +10187,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9102
10187
  loadAttachment: getAttachment,
9103
10188
  t,
9104
10189
  occurredAt: fact.message.occurredAt,
9105
- mentionNames: mentionNamesOf(fact.mentions, mentionHandlesMap),
10190
+ mentionNames: stableMentionNames(fact.mentions, mentionHandlesMap),
9106
10191
  onOpenRef: openRef,
9107
10192
  onResolveTaskRefs: lookupTaskRefs,
9108
10193
  grouped,
@@ -9287,28 +10372,25 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9287
10372
  setMutating(void 0);
9288
10373
  }
9289
10374
  };
10375
+ const clearSendState = (0, react.useCallback)(() => {
10376
+ setConfirmation((current) => current === void 0 ? current : void 0);
10377
+ setReplyRequestId((current) => current === void 0 ? current : void 0);
10378
+ setStatusMessage((current) => current === void 0 ? current : void 0);
10379
+ }, []);
9290
10380
  const sendReply = async () => {
10381
+ const { draft, recipients } = drafts.getSnapshot(draftKey);
9291
10382
  if (pending || thread === void 0 || draft.trim() === "") return;
9292
10383
  const id = replyRequestId ?? mintRequestId();
9293
10384
  setReplyRequestId(id);
9294
10385
  setPending(true);
9295
10386
  setError(void 0);
9296
10387
  try {
9297
- const attachmentIds = [];
9298
- for (const file of pendingFiles) {
9299
- const uploaded = await putAttachment({
9300
- requestId: mintRequestId(),
9301
- workspaceId,
9302
- name: file.name,
9303
- mediaType: file.type === "" ? void 0 : file.type,
9304
- bytesBase64: bytesToBase64(new Uint8Array(await file.arrayBuffer()))
9305
- });
9306
- if (!uploaded.ok) {
9307
- setError(uploaded.error.message);
9308
- return;
9309
- }
9310
- attachmentIds.push(uploaded.value.attachmentId);
10388
+ const upload = await uploadComposerFiles(putAttachment, workspaceId, pendingFiles);
10389
+ if (!upload.ok) {
10390
+ setError(upload.error);
10391
+ return;
9311
10392
  }
10393
+ const attachmentIds = upload.attachmentIds;
9312
10394
  const result = await reply({
9313
10395
  requestId: id,
9314
10396
  workspaceId,
@@ -9326,12 +10408,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9326
10408
  }
9327
10409
  if (result.value.kind === "committed") {
9328
10410
  const committed = result.value;
10411
+ const optimisticMentions = [...new Set([...recipients, ...mentionedMemberIds(draft, channelMembers)])].sort();
9329
10412
  setCurrentFacts((current) => {
9330
10413
  const merged = mergeFacts(current, [{
9331
10414
  kind: "message",
9332
10415
  sequence: committed.message.sequence,
9333
10416
  message: committed.message,
9334
- mentions: [...recipients].sort(),
10417
+ mentions: optimisticMentions,
9335
10418
  occurredAt: committed.receipt.occurredAt
9336
10419
  }]);
9337
10420
  currentFactsRef.current = merged;
@@ -9477,7 +10560,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9477
10560
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
9478
10561
  t("runtimeRiskDetail", {
9479
10562
  member: status.member.handle,
9480
- diagnostic: status.diagnostic ?? t("statusError")
10563
+ diagnostic: diagnosticText(status) || t("statusError")
9481
10564
  }),
9482
10565
  " · ",
9483
10566
  claim.direction
@@ -9667,23 +10750,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9667
10750
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamComposer, {
9668
10751
  members: channelMembers,
9669
10752
  followerMemberIds: followerIds,
9670
- recipients,
9671
- draft,
10753
+ drafts,
10754
+ draftKey,
9672
10755
  pending,
9673
10756
  ...statusMessage === void 0 ? {} : { confirmation: statusMessage },
9674
- ...error === void 0 ? {} : { error },
9675
- onDraftChange: (next) => {
9676
- drafts.writeDraft(draftKey, next);
9677
- setConfirmation(void 0);
9678
- setReplyRequestId(void 0);
9679
- setStatusMessage(void 0);
9680
- },
9681
- onRecipientsChange: (next) => {
9682
- drafts.writeRecipients(draftKey, next);
9683
- setConfirmation(void 0);
9684
- setReplyRequestId(void 0);
9685
- setStatusMessage(void 0);
9686
- },
10757
+ ...error === void 0 ? {} : { error },
10758
+ onEdit: clearSendState,
9687
10759
  onSubmit: () => {
9688
10760
  sendReply();
9689
10761
  },
@@ -9697,9 +10769,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9697
10769
  }
9698
10770
  //#endregion
9699
10771
  //#region src/client/TeamConversation.tsx
9700
- function TeamConversation({ t, useWorkspaces, navigation, drafts, putAttachment, getAttachment, loadChannels, readThread, loadThreadHistory, threadObservations, subscribeChanges, loadMembers, sendMessage, joinChannel, removeChannelMember, reply, changeTask, promoteThread, selectThread, selectChannel, backToWorkspace, backToChannels, resolveTaskRefs }) {
10772
+ function TeamConversation({ t, useWorkspaces, navigation, drafts, putAttachment, getAttachment, loadChannels, readThread, loadThreadHistory, threadObservations, subscribeChanges, loadMembers, loadInbox, sendMessage, joinChannel, removeChannelMember, reply, changeTask, promoteThread, selectThread, selectChannel, selectWorkspace, backToWorkspace, backToChannels, resolveTaskRefs }) {
9701
10773
  const navigationState = (0, react.useSyncExternalStore)(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
9702
10774
  const current = useWorkspaces((state) => state.items).find((workspace) => workspace.workspaceId === navigationState.workspaceId);
10775
+ if (navigationState.inbox === true) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamInboxPage, {
10776
+ useWorkspaces,
10777
+ loadInbox,
10778
+ subscribeChanges,
10779
+ selectWorkspace,
10780
+ selectThread,
10781
+ t
10782
+ }, "inbox");
9703
10783
  if (current !== void 0 && navigationState.threadRef !== void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamThreadPage, {
9704
10784
  workspaceId: current.workspaceId,
9705
10785
  putAttachment,
@@ -9733,6 +10813,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9733
10813
  loadChannels,
9734
10814
  subscribeChanges,
9735
10815
  loadMembers,
10816
+ loadInbox,
9736
10817
  sendMessage,
9737
10818
  joinChannel,
9738
10819
  removeChannelMember,
@@ -9768,64 +10849,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9768
10849
  });
9769
10850
  }
9770
10851
  //#endregion
9771
- //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/sidebar.module.css.mjs
9772
- const css$1 = "html[data-agent-team-mode=team] button[class*=newSession]{display:none}.d0xfxa_workspaceBrowser{flex-direction:column;height:100%;min-height:0;padding:0 8px 8px;display:flex}.d0xfxa_railButton{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0;display:inline-flex}.d0xfxa_railButton:hover,.d0xfxa_railButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);outline:none}.d0xfxa_workspaceList{flex-direction:column;gap:2px;padding-bottom:2px;display:flex}.d0xfxa_workspaceRow{color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;background:0 0;border:0;border-radius:8px;align-items:center;gap:6px;width:100%;height:34px;padding:0 8px;display:flex}.d0xfxa_workspaceRow:hover,.d0xfxa_workspaceRow:focus-visible,.d0xfxa_workspaceRow[aria-current=page]{background:var(--dsw-alias-interactive-bg-hover);outline:none}.d0xfxa_workspaceRow:focus-visible{box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l3)}.d0xfxa_workspaceIcon{color:var(--dsw-alias-label-tertiary);flex:0 0 16px;justify-content:center;align-items:center;height:20px;display:inline-flex}.d0xfxa_workspaceRow[data-selected] .d0xfxa_workspaceIcon{color:var(--dsw-alias-state-business-primary)}.d0xfxa_workspaceCopy{min-width:0;display:flex}.d0xfxa_workspaceCopy strong{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:400;line-height:20px;overflow:hidden}.d0xfxa_emptyState{color:var(--dsw-alias-label-tertiary);margin:8px;font-size:12px;line-height:18px}.d0xfxa_railWorkspace{flex-direction:column;align-items:center;gap:8px;padding-top:8px;display:flex}.d0xfxa_railButton{border-radius:50%;width:36px;height:36px}.d0xfxa_railButton[data-active]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.d0xfxa_workspaceSection{flex-direction:column;flex:1;gap:4px;min-height:0;margin-top:2px;display:flex;overflow-y:auto}.d0xfxa_section{flex-direction:column;display:flex}.d0xfxa_sectionHeader{align-items:center;min-height:26px;padding-right:2px;display:flex}.d0xfxa_sectionToggle{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;align-items:center;gap:4px;min-width:0;min-height:24px;padding:0 6px;font-size:12px;line-height:18px;display:inline-flex}.d0xfxa_sectionToggle:focus-visible{outline:none}.d0xfxa_sectionToggle:hover .d0xfxa_sectionChevron,.d0xfxa_sectionToggle:focus-visible .d0xfxa_sectionChevron{color:var(--dsw-alias-label-primary)}.d0xfxa_sectionChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .12s,color .12s}.d0xfxa_sectionToggle[aria-expanded=false] .d0xfxa_sectionChevron{transform:rotate(-90deg)}.d0xfxa_sectionTitle{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.d0xfxa_sectionActions{align-items:center;margin-left:auto;display:inline-flex}.d0xfxa_panel{flex-direction:column;display:flex}.d0xfxa_iconButton{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:50%;justify-content:center;align-items:center;width:24px;height:24px;padding:0;display:inline-flex}.d0xfxa_iconButton:hover,.d0xfxa_iconButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);outline:none}.d0xfxa_textButton{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:2px 5px;font-size:11px;line-height:18px}.d0xfxa_textButton:hover,.d0xfxa_textButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);outline:none}.d0xfxa_textButton:disabled{cursor:not-allowed;opacity:.4}.d0xfxa_channelList,.d0xfxa_agentList{flex-direction:column;gap:1px;padding:0 4px 4px;display:flex}.d0xfxa_sidebarRowDragging{opacity:.5}.d0xfxa_sidebarRowDropBefore,.d0xfxa_sidebarRowDropAfter{position:relative}.d0xfxa_sidebarRowDropBefore:before,.d0xfxa_sidebarRowDropAfter:after{content:\"\";z-index:1;background:linear-gradient(55deg, transparent calc(50% - 1px), var(--dsw-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 0 / 5px 7px no-repeat, linear-gradient(125deg, transparent calc(50% - 1px), var(--dsw-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 5px / 5px 7px no-repeat, linear-gradient(var(--dsw-alias-state-business-primary) 0 0) 4px 5px / calc(100% - 4px) 2px no-repeat;pointer-events:none;height:12px;position:absolute;left:0;right:4px}.d0xfxa_sidebarRowDropBefore:before{top:-7px}.d0xfxa_sidebarRowDropAfter:after{bottom:-7px}.d0xfxa_channelRow{color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;min-height:30px;display:flex;position:relative}.d0xfxa_channelSelect{box-sizing:border-box;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;flex:1;align-items:center;min-width:0;min-height:30px;padding:3px 4px 3px 8px;display:flex}.d0xfxa_channelSelect:focus-visible{outline:none}.d0xfxa_channelName{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:400;line-height:18px;overflow:hidden}.d0xfxa_agentRow{color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;min-height:38px;display:flex;position:relative}.d0xfxa_agentSelect{box-sizing:border-box;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;flex:1;grid-template-columns:24px minmax(0,1fr);align-items:center;gap:0 8px;min-width:0;min-height:38px;padding:3px 4px 3px 8px;display:grid}.d0xfxa_agentSelect:focus-visible{outline:none}.d0xfxa_agentSelect[aria-current=page]{background:var(--dsw-alias-interactive-bg-hover);border-radius:8px}.d0xfxa_agentRow:hover .d0xfxa_agentSelect[aria-current=page],.d0xfxa_agentRow:focus-within .d0xfxa_agentSelect[aria-current=page],.d0xfxa_agentRow[data-menu-open] .d0xfxa_agentSelect[aria-current=page]{background:0 0}.d0xfxa_agentAvatar{background:hsl(var(--team-avatar-hue,212) 42% 46%);color:#fff;cursor:default;border-radius:50%;flex:0 0 24px;justify-content:center;align-items:center;width:24px;height:24px;font-size:11px;font-weight:600;display:inline-flex;position:relative}.d0xfxa_agentAvatarBadge{background:var(--dsw-specific-sidebar-fill);box-shadow:0 0 0 1px var(--dsw-specific-sidebar-fill);border-radius:50%;justify-content:center;align-items:center;width:12px;height:12px;padding:1px;line-height:0;display:inline-flex;position:absolute;bottom:-3px;right:-3px}.d0xfxa_agentCopy{flex-direction:column;min-width:0;display:flex}.d0xfxa_agentCopy strong{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:400;line-height:17px;overflow:hidden}.d0xfxa_agentCopy small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:13px;overflow:hidden}.d0xfxa_unavailableDot{background:var(--dsw-alias-label-tertiary);border-radius:50%;width:7px;height:7px;display:inline-block}.d0xfxa_rowMenu{flex:none;align-items:center;padding-right:4px;display:none}.d0xfxa_channelRow:hover .d0xfxa_rowMenu,.d0xfxa_channelRow:focus-within .d0xfxa_rowMenu,.d0xfxa_channelRow[data-menu-open] .d0xfxa_rowMenu,.d0xfxa_agentRow:hover .d0xfxa_rowMenu,.d0xfxa_agentRow:focus-within .d0xfxa_rowMenu,.d0xfxa_agentRow[data-menu-open] .d0xfxa_rowMenu{display:inline-flex}.d0xfxa_channelRow[data-menu-open],.d0xfxa_agentRow[data-menu-open],.d0xfxa_channelRow:hover,.d0xfxa_agentRow:hover,.d0xfxa_channelRow:focus-within,.d0xfxa_agentRow:focus-within,.d0xfxa_channelRow[aria-current=page]{background:var(--dsw-alias-interactive-bg-hover)}.d0xfxa_rowMenuButton{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;justify-content:center;align-items:center;width:20px;height:20px;padding:0;display:inline-flex}.d0xfxa_rowMenuButton:hover,.d0xfxa_rowMenuButton:focus-visible{color:var(--dsw-alias-label-primary);outline:none}.d0xfxa_retryError{color:var(--dsw-alias-state-error-primary);justify-content:space-between;align-items:center;gap:8px;padding:8px;font-size:11px;display:flex}.d0xfxa_rowAlert{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;padding:2px 8px 6px;font-size:11px}.d0xfxa_editDescription{color:var(--dsw-alias-label-secondary);margin:0 0 10px;font-size:12px;line-height:18px}.d0xfxa_editMemberList{gap:3px;display:grid}.d0xfxa_editMemberRow{border-radius:6px;grid-template-columns:14px minmax(0,1fr) auto;align-items:center;gap:0 8px;min-height:40px;padding:3px 6px;display:grid}.d0xfxa_editMemberRowChannels{grid-template-columns:minmax(0,1fr) auto}.d0xfxa_editMemberRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.d0xfxa_editMemberCopy{min-width:0;display:grid}.d0xfxa_editMemberCopy strong{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:500;line-height:18px;overflow:hidden}.d0xfxa_editMemberCopy small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:14px;overflow:hidden}.d0xfxa_editChannelName{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:400;line-height:18px;overflow:hidden}.d0xfxa_editMemberRow button{min-width:60px}.d0xfxa_editHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:16px}.d0xfxa_menuHint{color:var(--dsw-alias-label-tertiary);margin-left:4px;font-size:10px;line-height:14px}.d0xfxa_rowError{color:var(--dsw-alias-state-error-primary);grid-column:1/-1;margin:2px 0;font-size:11px;line-height:16px}";
9773
- const tagId$1 = "@wowyuarm/dsh-agent-team/sidebar.module.css";
9774
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
9775
- const tag = document.createElement("style");
9776
- tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
9777
- tag.dataset.pluginCss = tagId$1;
9778
- tag.textContent = css$1;
9779
- document.head.appendChild(tag);
9780
- }
9781
- var sidebar_module_css_default = {
9782
- "agentAvatar": "d0xfxa_agentAvatar",
9783
- "agentAvatarBadge": "d0xfxa_agentAvatarBadge",
9784
- "agentCopy": "d0xfxa_agentCopy",
9785
- "agentList": "d0xfxa_agentList",
9786
- "agentRow": "d0xfxa_agentRow",
9787
- "agentSelect": "d0xfxa_agentSelect",
9788
- "channelList": "d0xfxa_channelList",
9789
- "channelName": "d0xfxa_channelName",
9790
- "channelRow": "d0xfxa_channelRow",
9791
- "channelSelect": "d0xfxa_channelSelect",
9792
- "editChannelName": "d0xfxa_editChannelName",
9793
- "editDescription": "d0xfxa_editDescription",
9794
- "editHint": "d0xfxa_editHint",
9795
- "editMemberCopy": "d0xfxa_editMemberCopy",
9796
- "editMemberList": "d0xfxa_editMemberList",
9797
- "editMemberRow": "d0xfxa_editMemberRow",
9798
- "editMemberRowChannels": "d0xfxa_editMemberRowChannels",
9799
- "emptyState": "d0xfxa_emptyState",
9800
- "iconButton": "d0xfxa_iconButton",
9801
- "menuHint": "d0xfxa_menuHint",
9802
- "panel": "d0xfxa_panel",
9803
- "railButton": "d0xfxa_railButton",
9804
- "railWorkspace": "d0xfxa_railWorkspace",
9805
- "retryError": "d0xfxa_retryError",
9806
- "rowAlert": "d0xfxa_rowAlert",
9807
- "rowError": "d0xfxa_rowError",
9808
- "rowMenu": "d0xfxa_rowMenu",
9809
- "rowMenuButton": "d0xfxa_rowMenuButton",
9810
- "section": "d0xfxa_section",
9811
- "sectionActions": "d0xfxa_sectionActions",
9812
- "sectionChevron": "d0xfxa_sectionChevron",
9813
- "sectionHeader": "d0xfxa_sectionHeader",
9814
- "sectionTitle": "d0xfxa_sectionTitle",
9815
- "sectionToggle": "d0xfxa_sectionToggle",
9816
- "sidebarRowDragging": "d0xfxa_sidebarRowDragging",
9817
- "sidebarRowDropAfter": "d0xfxa_sidebarRowDropAfter",
9818
- "sidebarRowDropBefore": "d0xfxa_sidebarRowDropBefore",
9819
- "textButton": "d0xfxa_textButton",
9820
- "unavailableDot": "d0xfxa_unavailableDot",
9821
- "workspaceBrowser": "d0xfxa_workspaceBrowser",
9822
- "workspaceCopy": "d0xfxa_workspaceCopy",
9823
- "workspaceIcon": "d0xfxa_workspaceIcon",
9824
- "workspaceList": "d0xfxa_workspaceList",
9825
- "workspaceRow": "d0xfxa_workspaceRow",
9826
- "workspaceSection": "d0xfxa_workspaceSection"
9827
- };
9828
- //#endregion
9829
10852
  //#region src/client/TeamWorkspaceRow.tsx
9830
10853
  function TeamWorkspaceRow({ workspaceId, title, path, selected, current, onSelect }) {
9831
10854
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
@@ -9960,32 +10983,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9960
10983
  for (const listener of listeners$1) listener();
9961
10984
  }
9962
10985
  //#endregion
9963
- //#region src/client/TeamMemberAvatar.tsx
9964
- /**
9965
- * Sidebar Member avatar reusing the conversation identity language: the
9966
- * deterministic member hue and handle initial, with the presence indicator
9967
- * overlaid at the bottom-right so one glyph carries identity and state.
9968
- */
9969
- function TeamMemberAvatar({ status, t }) {
9970
- const label = presenceLabel(status, t);
9971
- const state = presenceDotState(status.presence);
9972
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
9973
- label,
9974
- delayMs: 300,
9975
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9976
- className: sidebar_module_css_default.agentAvatar,
9977
- style: { "--team-avatar-hue": memberHue(status.member.memberId) },
9978
- role: "img",
9979
- "aria-label": label,
9980
- children: [status.member.handle.replace("@", "").slice(0, 1).toUpperCase(), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9981
- className: sidebar_module_css_default.agentAvatarBadge,
9982
- "aria-hidden": "true",
9983
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamStateDot, { state })
9984
- })]
9985
- })
9986
- });
9987
- }
9988
- //#endregion
9989
10986
  //#region src/client/sidebar-drag.tsx
9990
10987
  /**
9991
10988
  * Native whole-row drag for the Team sidebar lists. Unlike the Harness
@@ -10260,8 +11257,45 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10260
11257
  });
10261
11258
  }
10262
11259
  //#endregion
11260
+ //#region src/client/team-dialog-save.ts
11261
+ /**
11262
+ * Shared edit-dialog save lifecycle: one in-flight durable update, the dialog
11263
+ * held disabled while it runs, a refusal reported in place, and a close only
11264
+ * after the parent has re-read the committed state. Callers keep their own
11265
+ * payload and request reuse, and hold `pendingRequest` so that editing a field
11266
+ * drops a request the Host may already have committed.
11267
+ */
11268
+ function useEditDialogSave({ save, onCommitted, onClose }) {
11269
+ const [saving, setSaving] = (0, react.useState)(false);
11270
+ const [error, setError] = (0, react.useState)();
11271
+ const pendingRequest = (0, react.useRef)();
11272
+ const submit = async (request) => {
11273
+ pendingRequest.current = request;
11274
+ setSaving(true);
11275
+ setError(void 0);
11276
+ try {
11277
+ const result = await save(request);
11278
+ if (result.ok) {
11279
+ pendingRequest.current = void 0;
11280
+ await onCommitted();
11281
+ onClose();
11282
+ } else setError(result.error.message);
11283
+ } catch (cause) {
11284
+ setError(cause instanceof Error ? cause.message : String(cause));
11285
+ } finally {
11286
+ setSaving(false);
11287
+ }
11288
+ };
11289
+ return {
11290
+ saving,
11291
+ error,
11292
+ pendingRequest,
11293
+ save: submit
11294
+ };
11295
+ }
11296
+ //#endregion
10263
11297
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/create.module.css.mjs
10264
- const css = "._1henIG_form{gap:16px;display:grid}._1henIG_field{color:var(--dsw-alias-label-secondary);gap:6px;font-size:12px;line-height:18px;display:grid}._1henIG_input{box-sizing:border-box;width:100%}._1henIG_menuCap{max-height:min(320px,56vh)}._1henIG_selectTrigger{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);box-sizing:border-box;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;border-radius:8px;justify-content:space-between;align-items:center;gap:8px;min-height:32px;padding:4px 10px;font-size:14px;line-height:22px;display:flex}._1henIG_selectTrigger:disabled{cursor:default;opacity:.6}._1henIG_selectTrigger:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}._1henIG_selectValue{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}._1henIG_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .12s;display:inline-flex}._1henIG_chevronOpen{transform:rotate(180deg)}._1henIG_memberPicker{border:0;gap:4px;max-height:220px;margin:0;padding:0;display:grid;overflow-y:auto}._1henIG_memberPicker legend{color:var(--dsw-alias-label-secondary);padding:0 0 6px;font-size:12px;line-height:18px}._1henIG_memberOption{color:var(--dsw-alias-label-primary);border-radius:6px;grid-template-columns:auto 14px minmax(0,1fr);align-items:center;gap:0 7px;min-height:32px;padding:3px 6px;display:grid}._1henIG_memberOption:hover{background:var(--dsw-alias-interactive-bg-hover)}._1henIG_memberOption input{margin:0}._1henIG_memberOption small{color:var(--dsw-alias-label-tertiary);grid-column:3;font-size:10px;line-height:14px}._1henIG_unavailableDot{background:var(--dsw-alias-label-tertiary);border-radius:50%;justify-self:center;width:7px;height:7px;display:inline-block}._1henIG_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}._1henIG_dialogContent{max-height:min(70vh,560px);overflow-y:auto}@media (width<=600px){._1henIG_dialogContent{max-height:calc(100vh - 180px)}._1henIG_memberPicker{max-height:180px}}";
11298
+ const css = "._1henIG_form{gap:16px;display:grid}._1henIG_field{color:var(--dsw-alias-label-secondary);gap:6px;font-size:12px;line-height:18px;display:grid}._1henIG_input{box-sizing:border-box;width:100%}._1henIG_menuCap{max-height:min(320px,56vh)}._1henIG_selectTrigger{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);box-sizing:border-box;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;border-radius:8px;justify-content:space-between;align-items:center;gap:8px;min-height:32px;padding:4px 10px;font-size:14px;line-height:22px;display:flex}._1henIG_selectTrigger:disabled{cursor:default;opacity:.6}._1henIG_selectTrigger:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}._1henIG_selectValue{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}._1henIG_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .12s;display:inline-flex}._1henIG_chevronOpen{transform:rotate(180deg)}._1henIG_memberPicker{border:0;gap:4px;max-height:220px;margin:0;padding:0;display:grid;overflow-y:auto}._1henIG_memberPicker legend{color:var(--dsw-alias-label-secondary);padding:0 0 6px;font-size:12px;line-height:18px}._1henIG_memberOption{color:var(--dsw-alias-label-primary);border-radius:6px;grid-template-columns:auto 14px minmax(0,1fr);align-items:center;gap:0 7px;min-height:32px;padding:3px 6px;display:grid}._1henIG_memberOption:hover{background:var(--dsw-alias-interactive-bg-hover)}._1henIG_memberOption input{margin:0}._1henIG_memberOption small{color:var(--dsw-alias-label-tertiary);grid-column:3;font-size:10px;line-height:14px}._1henIG_unavailableDot{background:var(--dsw-alias-label-tertiary);corner-shape:round;border-radius:50%;justify-self:center;width:7px;height:7px;display:inline-block}._1henIG_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}._1henIG_dialogContent{max-height:min(70vh,560px);overflow-y:auto}@media (width<=600px){._1henIG_dialogContent{max-height:calc(100vh - 180px)}._1henIG_memberPicker{max-height:180px}}";
10265
11299
  const tagId = "@wowyuarm/dsh-agent-team/create.module.css";
10266
11300
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
10267
11301
  const tag = document.createElement("style");
@@ -10454,9 +11488,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10454
11488
  const [handle, setHandle] = (0, react.useState)(status.member.handle);
10455
11489
  const [description, setDescription] = (0, react.useState)(status.member.description);
10456
11490
  const [model, setModel] = (0, react.useState)(status.member.model);
10457
- const [saving, setSaving] = (0, react.useState)(false);
10458
- const [error, setError] = (0, react.useState)();
10459
- const pendingRequest = (0, react.useRef)();
11491
+ const { saving, error, pendingRequest, save } = useEditDialogSave({
11492
+ save: updateMember,
11493
+ onCommitted,
11494
+ onClose
11495
+ });
10460
11496
  const dirty = handle.trim() !== status.member.handle || description.trim() !== status.member.description || !sameModel(model, status.member.model);
10461
11497
  const submit = async (event) => {
10462
11498
  event.preventDefault();
@@ -10470,25 +11506,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10470
11506
  ...model === void 0 ? {} : { model },
10471
11507
  ...status.member.capabilities === void 0 ? {} : { capabilities: status.member.capabilities }
10472
11508
  };
10473
- const request = pendingRequest.current !== void 0 && pendingRequest.current.memberId === payload.memberId && pendingRequest.current.handle === payload.handle && pendingRequest.current.description === payload.description && sameModel(pendingRequest.current.model, model) ? pendingRequest.current : {
11509
+ await save(pendingRequest.current !== void 0 && pendingRequest.current.memberId === payload.memberId && pendingRequest.current.handle === payload.handle && pendingRequest.current.description === payload.description && sameModel(pendingRequest.current.model, model) ? pendingRequest.current : {
10474
11510
  requestId: mintRequestId(),
10475
11511
  ...payload
10476
- };
10477
- pendingRequest.current = request;
10478
- setSaving(true);
10479
- setError(void 0);
10480
- try {
10481
- const result = await updateMember(request);
10482
- if (result.ok) {
10483
- pendingRequest.current = void 0;
10484
- await onCommitted();
10485
- onClose();
10486
- } else setError(result.error.message);
10487
- } catch (cause) {
10488
- setError(cause instanceof Error ? cause.message : String(cause));
10489
- } finally {
10490
- setSaving(false);
10491
- }
11512
+ });
10492
11513
  };
10493
11514
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
10494
11515
  open: true,
@@ -10623,14 +11644,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10623
11644
  }
10624
11645
  }
10625
11646
  }, []);
11647
+ const loadedRef = (0, react.useRef)(false);
10626
11648
  const refresh = (0, react.useCallback)(async () => {
10627
- setLoading(true);
11649
+ if (!loadedRef.current) setLoading(true);
10628
11650
  const result = await loadMembers({ workspaceId });
10629
11651
  if (result.ok) {
10630
11652
  const next = result.value.filter((status) => status.member.state !== "inactive" && status.member.state !== "archived");
10631
11653
  setMembers(next);
10632
11654
  followRollover(next);
10633
11655
  setError(void 0);
11656
+ loadedRef.current = true;
10634
11657
  } else setError(result.error.message);
10635
11658
  setLoading(false);
10636
11659
  }, [
@@ -10655,6 +11678,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10655
11678
  refresh,
10656
11679
  workspaceId
10657
11680
  ]);
11681
+ (0, react.useEffect)(() => subscribeChanges({
11682
+ kind: "presence",
11683
+ workspaceId
11684
+ }, (update) => {
11685
+ if (update.type === "failed") {
11686
+ setError(update.message);
11687
+ return;
11688
+ }
11689
+ refresh();
11690
+ }), [
11691
+ subscribeChanges,
11692
+ refresh,
11693
+ workspaceId
11694
+ ]);
10658
11695
  const closeForm = () => {
10659
11696
  if (creating) return;
10660
11697
  setFormOpen(false);
@@ -10678,7 +11715,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10678
11715
  setDescription("");
10679
11716
  setModel(void 0);
10680
11717
  setFormOpen(false);
10681
- if (result.value.status.presence === "unavailable") setError(result.value.status.diagnostic ?? t("statusUnavailable"));
11718
+ if (result.value.status.presence === "unavailable") setError(diagnosticText(result.value.status) || t("statusUnavailable"));
10682
11719
  else setRetryRequest(void 0);
10683
11720
  queueMicrotask(() => {
10684
11721
  triggerRef.current?.focus();
@@ -10805,7 +11842,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10805
11842
  className: sidebar_module_css_default.emptyState,
10806
11843
  children: t("loadingAgents")
10807
11844
  }),
10808
- !loading && members.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11845
+ !loading && error === void 0 && members.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10809
11846
  className: sidebar_module_css_default.emptyState,
10810
11847
  children: t("emptyAgents")
10811
11848
  }),
@@ -10870,7 +11907,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10870
11907
  return;
10871
11908
  }
10872
11909
  if (result.value.status.availability === "unavailable") {
10873
- setRowAlert(t("restartStillUnavailable", { diagnostic: result.value.status.diagnostic ?? t("statusUnavailable") }));
11910
+ const diagnostic = result.value.status.diagnostic;
11911
+ if (diagnostic?.class === "session-refused" && diagnostic.remediable === false) {
11912
+ setRowAlert(t("restartRefusedNoRestart", { detail: diagnosticText(result.value.status) }));
11913
+ return;
11914
+ }
11915
+ setRowAlert(t("restartStillUnavailable", { diagnostic: diagnosticText(result.value.status) || t("statusUnavailable") }));
10874
11916
  return;
10875
11917
  }
10876
11918
  setRowAlert(void 0);
@@ -10894,8 +11936,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10894
11936
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
10895
11937
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10896
11938
  className: sidebar_module_css_default.agentRow,
11939
+ "data-agent-row": true,
10897
11940
  "data-menu-open": menuOpen || void 0,
10898
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
11941
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
10899
11942
  type: "button",
10900
11943
  className: sidebar_module_css_default.agentSelect,
10901
11944
  "aria-label": t("openAgentSession", { name: status.member.handle }),
@@ -10904,13 +11947,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10904
11947
  onClick: () => {
10905
11948
  openMemberSession(status.member.sessionId);
10906
11949
  },
10907
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberAvatar, {
11950
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberIdentity, {
10908
11951
  status,
10909
- t
10910
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
11952
+ name: status.member.handle.replace(/^@/, ""),
10911
11953
  className: sidebar_module_css_default.agentCopy,
10912
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: status.member.handle }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: status.member.description })]
10913
- })]
11954
+ t
11955
+ })
10914
11956
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10915
11957
  className: sidebar_module_css_default.rowMenu,
10916
11958
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamRowMenu, {
@@ -10926,7 +11968,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10926
11968
  label: t("resumeAgent"),
10927
11969
  icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlayOutline16, {})
10928
11970
  }] : [],
10929
- ...status.availability === "unavailable" ? [{
11971
+ ...status.availability === "unavailable" && restartOffered(status) ? [{
10930
11972
  id: "restart",
10931
11973
  label: t("restartAgent"),
10932
11974
  icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, {})
@@ -11083,8 +12125,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11083
12125
  onCommit: applyMove
11084
12126
  });
11085
12127
  const sectionOpen = useSidebarSectionOpen(workspaceId, "channels");
12128
+ const loadedRef = (0, react.useRef)(false);
11086
12129
  const refresh = (0, react.useCallback)(async () => {
11087
- setLoading(true);
12130
+ if (!loadedRef.current) setLoading(true);
11088
12131
  const [channelResult, memberResult] = await Promise.all([loadChannels({
11089
12132
  workspaceId,
11090
12133
  limit: 1
@@ -11096,6 +12139,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11096
12139
  const selectable = new Set(visibleMembers.filter((status) => status.presence !== "unavailable").map((status) => status.member.memberId));
11097
12140
  setSelected((current) => new Set([...current].filter((memberId) => selectable.has(memberId))));
11098
12141
  setError(void 0);
12142
+ loadedRef.current = true;
11099
12143
  } else if (!channelResult.ok) setError(channelResult.error.message);
11100
12144
  else if (!memberResult.ok) setError(memberResult.error.message);
11101
12145
  setLoading(false);
@@ -11299,7 +12343,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11299
12343
  className: sidebar_module_css_default.emptyState,
11300
12344
  children: t("loadingChannels")
11301
12345
  }),
11302
- !loading && (view?.channels.length ?? 0) === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12346
+ !loading && error === void 0 && view !== void 0 && view.channels.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11303
12347
  className: sidebar_module_css_default.emptyState,
11304
12348
  children: t("emptyChannels")
11305
12349
  }),
@@ -11452,9 +12496,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11452
12496
  function ChannelEditorDialog({ channel, members, joinedIds, updateChannel, joinChannel, removeChannelMember, onCommitted, onClose, t }) {
11453
12497
  const [name, setName] = (0, react.useState)(channel.name);
11454
12498
  const [description, setDescription] = (0, react.useState)(channel.description);
11455
- const [saving, setSaving] = (0, react.useState)(false);
11456
- const [error, setError] = (0, react.useState)();
11457
- const pendingRequest = (0, react.useRef)();
12499
+ const { saving, error, pendingRequest, save } = useEditDialogSave({
12500
+ save: updateChannel,
12501
+ onCommitted,
12502
+ onClose
12503
+ });
11458
12504
  const membership = useChannelMembership({
11459
12505
  joinChannel,
11460
12506
  removeChannelMember
@@ -11467,28 +12513,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11467
12513
  const normalizedName = name.trim();
11468
12514
  const normalizedDescription = description.trim();
11469
12515
  if (saving || !dirty || normalizedName === "") return;
11470
- const request = pendingRequest.current !== void 0 && pendingRequest.current.channelRef === channel.channelRef && pendingRequest.current.name === normalizedName && pendingRequest.current.description === normalizedDescription ? pendingRequest.current : {
12516
+ await save(pendingRequest.current !== void 0 && pendingRequest.current.channelRef === channel.channelRef && pendingRequest.current.name === normalizedName && pendingRequest.current.description === normalizedDescription ? pendingRequest.current : {
11471
12517
  requestId: mintRequestId(),
11472
12518
  workspaceId: channel.workspaceId,
11473
12519
  channelRef: channel.channelRef,
11474
12520
  name: normalizedName,
11475
12521
  description: normalizedDescription
11476
- };
11477
- pendingRequest.current = request;
11478
- setSaving(true);
11479
- setError(void 0);
11480
- try {
11481
- const result = await updateChannel(request);
11482
- if (result.ok) {
11483
- pendingRequest.current = void 0;
11484
- await onCommitted();
11485
- onClose();
11486
- } else setError(result.error.message);
11487
- } catch (cause) {
11488
- setError(cause instanceof Error ? cause.message : String(cause));
11489
- } finally {
11490
- setSaving(false);
11491
- }
12522
+ });
11492
12523
  };
11493
12524
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
11494
12525
  open: true,
@@ -11548,39 +12579,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11548
12579
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", { children: t("channelMembersSection") }), members.map((status) => {
11549
12580
  const joined = joinedIds.has(status.member.memberId);
11550
12581
  const rowPending = membership.pending.has(status.member.memberId);
11551
- const disabled = rowPending || !joined && status.presence === "unavailable";
12582
+ const disabled = rowPending || !joined && status.availability !== "active";
11552
12583
  const rowError = membership.errors.get(status.member.memberId);
11553
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11554
- className: sidebar_module_css_default.editMemberRow,
11555
- children: [
11556
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamPresenceDot, {
11557
- status,
11558
- t
11559
- }),
11560
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
11561
- className: sidebar_module_css_default.editMemberCopy,
11562
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: ["@", status.member.handle] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: status.member.description })]
11563
- }),
11564
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
11565
- size: "sm",
11566
- variant: "outline",
11567
- disabled,
11568
- onClick: () => {
11569
- membership.change({
11570
- workspaceId: channel.workspaceId,
11571
- channelRef: channel.channelRef,
11572
- memberId: status.member.memberId,
11573
- joined
11574
- });
11575
- },
11576
- children: rowPending ? t("membershipUpdating") : joined ? t("removeFromChannel") : t("addToChannel")
11577
- }),
11578
- rowError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11579
- className: sidebar_module_css_default.rowError,
11580
- role: "alert",
11581
- children: rowError
11582
- })
11583
- ]
12584
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberRow, {
12585
+ status,
12586
+ action: {
12587
+ label: rowPending ? t("membershipUpdating") : joined ? t("removeFromChannel") : t("addToChannel"),
12588
+ disabled,
12589
+ onSelect: () => {
12590
+ membership.change({
12591
+ workspaceId: channel.workspaceId,
12592
+ channelRef: channel.channelRef,
12593
+ memberId: status.member.memberId,
12594
+ joined
12595
+ });
12596
+ }
12597
+ },
12598
+ ...rowError === void 0 ? {} : { error: rowError },
12599
+ t
11584
12600
  }, status.member.memberId);
11585
12601
  })]
11586
12602
  }),
@@ -11595,20 +12611,78 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11595
12611
  }
11596
12612
  //#endregion
11597
12613
  //#region src/client/TeamWorkspaceBrowser.tsx
11598
- function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, t, useWorkspaces, loadMembers, subscribeChanges, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, archiveMember, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
12614
+ /**
12615
+ * The Inbox entry's icon with its unread mark. The quantity left this surface
12616
+ * and lives in the control's accessible name: the sidebar answers whether
12617
+ * anything is waiting at a glance, and the number — which moves on every fact —
12618
+ * is what a reader asks for on purpose. The mark hangs off the icon rather than
12619
+ * off the control, so the wide card and the 36px rail button put the same dot
12620
+ * on the same corner of the same glyph.
12621
+ */
12622
+ function InboxMark({ unread }) {
12623
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
12624
+ className: sidebar_module_css_default.inboxMark,
12625
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQueueOutline14, { size: 16 }), unread > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12626
+ className: sidebar_module_css_default.inboxDot,
12627
+ "data-team-inbox-dot": true,
12628
+ "aria-hidden": "true"
12629
+ })]
12630
+ });
12631
+ }
12632
+ function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, selectInbox, t, useWorkspaces, loadMembers, loadInbox, subscribeChanges, subscribeReads, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, archiveMember, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
11599
12633
  const navigationState = (0, react.useSyncExternalStore)(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
11600
12634
  const workspaces = useWorkspaces((state) => state.items);
11601
12635
  const selected = navigationState.workspaceId;
11602
12636
  const selectedId = selected !== void 0 && workspaces.some((workspace) => workspace.workspaceId === selected) ? selected : workspaces[0]?.workspaceId;
11603
- const overviewIsCurrent = navigationState.channelRef === void 0 && navigationState.memberSessionId === void 0;
12637
+ const overviewIsCurrent = navigationState.channelRef === void 0 && navigationState.memberSessionId === void 0 && navigationState.inbox !== true;
12638
+ const inboxIsCurrent = navigationState.inbox === true && navigationState.memberSessionId === void 0;
11604
12639
  const [creatingAgents, setCreatingAgents] = (0, react.useState)([]);
11605
12640
  const [pendingSection, setPendingSection] = (0, react.useState)();
11606
12641
  const channelsRef = (0, react.useRef)(null);
11607
12642
  const agentsRef = (0, react.useRef)(null);
11608
12643
  const workspacesOpen = useSidebarSectionOpen(void 0, "workspaces");
12644
+ const [inboxTotal, setInboxTotal] = (0, react.useState)(0);
12645
+ const inboxLabel = inboxTotal > 0 ? t("inboxTitleWithCount", { count: inboxTotal }) : t("inboxTitle");
12646
+ (0, react.useEffect)(() => {
12647
+ let disposed = false;
12648
+ let scheduled;
12649
+ const refresh = async () => {
12650
+ const results = await Promise.all(workspaces.map((workspace) => loadInbox({
12651
+ workspaceId: workspace.workspaceId,
12652
+ limit: 1
12653
+ })));
12654
+ if (disposed) return;
12655
+ setInboxTotal(results.reduce((sum, result) => result.ok ? sum + result.value.totalUnreadCount : sum, 0));
12656
+ };
12657
+ const schedule = () => {
12658
+ if (scheduled !== void 0) return;
12659
+ scheduled = setTimeout(() => {
12660
+ scheduled = void 0;
12661
+ refresh();
12662
+ }, 200);
12663
+ };
12664
+ refresh();
12665
+ const unsubscribe = subscribeChanges(void 0, (update) => {
12666
+ if (update.type === "changed") schedule();
12667
+ });
12668
+ const unsubscribeReads = subscribeReads(schedule);
12669
+ return () => {
12670
+ disposed = true;
12671
+ if (scheduled !== void 0) clearTimeout(scheduled);
12672
+ unsubscribe();
12673
+ unsubscribeReads();
12674
+ };
12675
+ }, [
12676
+ loadInbox,
12677
+ subscribeChanges,
12678
+ subscribeReads,
12679
+ workspaces
12680
+ ]);
11609
12681
  (0, react.useEffect)(() => {
12682
+ if (navigationState.inbox === true) return;
11610
12683
  if (navigationState.mode === "team" && selectedId !== void 0 && selectedId !== selected) selectWorkspace(selectedId);
11611
12684
  }, [
12685
+ navigationState.inbox,
11612
12686
  navigationState.mode,
11613
12687
  selected,
11614
12688
  selectedId,
@@ -11625,96 +12699,128 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11625
12699
  if (!wide) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
11626
12700
  className: sidebar_module_css_default.railWorkspace,
11627
12701
  "aria-label": t("workspaceSections"),
11628
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
11629
- label: t("channels"),
11630
- side: "right",
11631
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
11632
- type: "button",
11633
- className: sidebar_module_css_default.railButton,
11634
- "aria-label": t("channels"),
11635
- onClick: () => {
11636
- setPendingSection("channels");
11637
- expandSidebar();
11638
- },
11639
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16, { size: 16 })
11640
- })
11641
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
11642
- label: t("agents"),
11643
- side: "right",
11644
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
11645
- type: "button",
11646
- className: sidebar_module_css_default.railButton,
11647
- "aria-label": t("agents"),
11648
- onClick: () => {
11649
- setPendingSection("agents");
11650
- expandSidebar();
11651
- },
11652
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconAgentPresetOutline16, { size: 16 })
12702
+ children: [
12703
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
12704
+ label: inboxLabel,
12705
+ side: "right",
12706
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
12707
+ type: "button",
12708
+ className: sidebar_module_css_default.railButton,
12709
+ "aria-label": inboxLabel,
12710
+ "aria-current": inboxIsCurrent ? "page" : void 0,
12711
+ onClick: () => {
12712
+ selectInbox();
12713
+ expandSidebar();
12714
+ },
12715
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InboxMark, { unread: inboxTotal })
12716
+ })
12717
+ }),
12718
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
12719
+ label: t("channels"),
12720
+ side: "right",
12721
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
12722
+ type: "button",
12723
+ className: sidebar_module_css_default.railButton,
12724
+ "aria-label": t("channels"),
12725
+ onClick: () => {
12726
+ setPendingSection("channels");
12727
+ expandSidebar();
12728
+ },
12729
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16, { size: 16 })
12730
+ })
12731
+ }),
12732
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
12733
+ label: t("agents"),
12734
+ side: "right",
12735
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
12736
+ type: "button",
12737
+ className: sidebar_module_css_default.railButton,
12738
+ "aria-label": t("agents"),
12739
+ onClick: () => {
12740
+ setPendingSection("agents");
12741
+ expandSidebar();
12742
+ },
12743
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconAgentPresetOutline16, { size: 16 })
12744
+ })
11653
12745
  })
11654
- })]
12746
+ ]
11655
12747
  });
11656
12748
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
11657
12749
  className: sidebar_module_css_default.workspaceBrowser,
11658
12750
  "aria-label": t("workspaces"),
11659
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamSidebarSection, {
11660
- title: t("workspaces"),
11661
- open: workspacesOpen,
11662
- onToggle: (open) => {
11663
- setSidebarSectionOpen(void 0, "workspaces", open);
11664
- },
11665
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11666
- className: sidebar_module_css_default.workspaceList,
11667
- children: [workspaces.map((workspace) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamWorkspaceRow, {
11668
- workspaceId: workspace.workspaceId,
11669
- title: workspace.title,
11670
- path: workspace.path,
11671
- selected: workspace.workspaceId === selectedId,
11672
- current: workspace.workspaceId === selectedId && overviewIsCurrent,
11673
- onSelect: selectWorkspace
11674
- }, workspace.workspaceId)), workspaces.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11675
- className: sidebar_module_css_default.emptyState,
11676
- children: t("empty")
12751
+ children: [
12752
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
12753
+ type: "button",
12754
+ className: sidebar_module_css_default.inboxCard,
12755
+ "aria-label": inboxLabel,
12756
+ "aria-current": inboxIsCurrent ? "page" : void 0,
12757
+ onClick: selectInbox,
12758
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InboxMark, { unread: inboxTotal }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12759
+ className: sidebar_module_css_default.inboxCardLabel,
12760
+ children: t("inboxTitle")
12761
+ })]
12762
+ }),
12763
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamSidebarSection, {
12764
+ title: t("workspaces"),
12765
+ open: workspacesOpen,
12766
+ onToggle: (open) => {
12767
+ setSidebarSectionOpen(void 0, "workspaces", open);
12768
+ },
12769
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12770
+ className: sidebar_module_css_default.workspaceList,
12771
+ children: [workspaces.map((workspace) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamWorkspaceRow, {
12772
+ workspaceId: workspace.workspaceId,
12773
+ title: workspace.title,
12774
+ path: workspace.path,
12775
+ selected: workspace.workspaceId === selectedId,
12776
+ current: workspace.workspaceId === selectedId && overviewIsCurrent,
12777
+ onSelect: selectWorkspace
12778
+ }, workspace.workspaceId)), workspaces.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12779
+ className: sidebar_module_css_default.emptyState,
12780
+ children: t("empty")
12781
+ })]
12782
+ })
12783
+ }),
12784
+ selectedId !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12785
+ className: sidebar_module_css_default.workspaceSection,
12786
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
12787
+ ref: channelsRef,
12788
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamChannelsPanel, {
12789
+ workspaceId: selectedId,
12790
+ loadMembers,
12791
+ loadChannels,
12792
+ subscribeChanges,
12793
+ createChannel,
12794
+ updateChannel,
12795
+ archiveChannel,
12796
+ joinChannel,
12797
+ removeChannelMember,
12798
+ creatingAgents: creatingAgents.filter((request) => request.workspaceId === selectedId),
12799
+ ...navigationState.memberSessionId !== void 0 || navigationState.channelRef === void 0 ? {} : { selectedChannelRef: navigationState.channelRef },
12800
+ selectChannel,
12801
+ t
12802
+ }, selectedId)
12803
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
12804
+ ref: agentsRef,
12805
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamAgentsPanel, {
12806
+ workspaceId: selectedId,
12807
+ loadMembers,
12808
+ subscribeChanges,
12809
+ addMember,
12810
+ updateMember,
12811
+ recoverMember,
12812
+ archiveMember,
12813
+ loadModels,
12814
+ ...navigationState.memberSessionId === void 0 ? {} : { memberSessionId: navigationState.memberSessionId },
12815
+ openMemberSession,
12816
+ onCreatingChange: (request, creating) => {
12817
+ setCreatingAgents((current) => creating ? [...current.filter((item) => item.requestId !== request.requestId), request] : current.filter((item) => item.requestId !== request.requestId));
12818
+ },
12819
+ t
12820
+ }, selectedId)
11677
12821
  })]
11678
12822
  })
11679
- }), selectedId !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11680
- className: sidebar_module_css_default.workspaceSection,
11681
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11682
- ref: channelsRef,
11683
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamChannelsPanel, {
11684
- workspaceId: selectedId,
11685
- loadMembers,
11686
- loadChannels,
11687
- subscribeChanges,
11688
- createChannel,
11689
- updateChannel,
11690
- archiveChannel,
11691
- joinChannel,
11692
- removeChannelMember,
11693
- creatingAgents: creatingAgents.filter((request) => request.workspaceId === selectedId),
11694
- ...navigationState.memberSessionId !== void 0 || navigationState.channelRef === void 0 ? {} : { selectedChannelRef: navigationState.channelRef },
11695
- selectChannel,
11696
- t
11697
- }, selectedId)
11698
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11699
- ref: agentsRef,
11700
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamAgentsPanel, {
11701
- workspaceId: selectedId,
11702
- loadMembers,
11703
- subscribeChanges,
11704
- addMember,
11705
- updateMember,
11706
- recoverMember,
11707
- archiveMember,
11708
- loadModels,
11709
- ...navigationState.memberSessionId === void 0 ? {} : { memberSessionId: navigationState.memberSessionId },
11710
- openMemberSession,
11711
- onCreatingChange: (request, creating) => {
11712
- setCreatingAgents((current) => creating ? [...current.filter((item) => item.requestId !== request.requestId), request] : current.filter((item) => item.requestId !== request.requestId));
11713
- },
11714
- t
11715
- }, selectedId)
11716
- })]
11717
- })]
12823
+ ]
11718
12824
  });
11719
12825
  }
11720
12826
  //#endregion
@@ -11748,6 +12854,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11748
12854
  statusError: "错误",
11749
12855
  statusUnavailable: "不可用",
11750
12856
  addChannel: "新建频道",
12857
+ inboxTitle: "收件箱",
12858
+ inboxTitleWithCount: "收件箱,{count} 条未读",
12859
+ loadingInbox: "正在加载收件箱…",
12860
+ inboxEmptyTitle: "收件箱是空的",
12861
+ inboxEmptyHint: "你参与的 Thread 有新活动、或有人提到你时,会出现在这里",
12862
+ inboxTimeYesterday: "昨天",
12863
+ inboxHeaderThreads: "{count} 个 Thread",
12864
+ inboxHeaderUnread: "{count} 条未读",
12865
+ inboxHeaderMentions: "{count} 条提及",
12866
+ inboxRowUnread: "{count} 条未读",
12867
+ inboxRowUnreadMentions: "{count} 条未读,其中 {mentions} 条提及",
12868
+ inboxRowActor: "最新来自 {name}",
12869
+ inboxSectionNeedsMe: "需要我",
12870
+ inboxSectionRecent: "最近活跃",
11751
12871
  channelName: "名称",
11752
12872
  channelDescription: "说明",
11753
12873
  initialMembers: "初始成员",
@@ -11761,6 +12881,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11761
12881
  resumeAgent: "恢复",
11762
12882
  restartAgent: "重启",
11763
12883
  restartStillUnavailable: "重启已执行,成员仍不可用:{diagnostic}",
12884
+ restartRefusedNoRestart: "会话日志被确定拒绝,修复无可用项,重启无法解决:{detail}",
11764
12885
  restartFailed: "重启执行失败:{message}",
11765
12886
  archiveAgent: "归档",
11766
12887
  archiveAgentTitle: "归档 Agent:{name}",
@@ -11812,12 +12933,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11812
12933
  taskStatusInReview: "待验收",
11813
12934
  taskStatusDone: "已完成",
11814
12935
  taskStatusClosed: "已关闭",
11815
- taskMessageCount: "{count} 条消息",
11816
12936
  taskLabel: "Task #{number}",
11817
12937
  taskPending: "Task …",
11818
12938
  openTask: "打开 Task #{number}",
11819
12939
  openThread: "打开讨论",
12940
+ openTaskUnread: "打开 Task #{number}({count} 条新动态)",
12941
+ openThreadUnread: "打开讨论({count} 条新动态)",
11820
12942
  threadLabel: "讨论",
12943
+ recentActivity: "最近活动 {time}",
12944
+ replyAction: "回复",
12945
+ claimers: "由 {names} 处理",
11821
12946
  asTask: "作为任务",
11822
12947
  promoteToTask: "转为 Task",
11823
12948
  promotingTask: "正在转为 Task…",
@@ -11896,6 +13021,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11896
13021
  statusError: "Error",
11897
13022
  statusUnavailable: "Unavailable",
11898
13023
  addChannel: "New Channel",
13024
+ inboxTitle: "Inbox",
13025
+ inboxTitleWithCount: "Inbox, {count} unread",
13026
+ loadingInbox: "Loading Inbox…",
13027
+ inboxEmptyTitle: "Your Inbox is empty",
13028
+ inboxEmptyHint: "Threads you take part in appear here when they have new activity or mention you",
13029
+ inboxTimeYesterday: "Yesterday",
13030
+ inboxHeaderThreads: "{count} Thread(s)",
13031
+ inboxHeaderUnread: "{count} unread",
13032
+ inboxHeaderMentions: "{count} mention(s)",
13033
+ inboxRowUnread: "{count} unread",
13034
+ inboxRowUnreadMentions: "{count} unread, {mentions} mention(s)",
13035
+ inboxRowActor: "Latest from {name}",
13036
+ inboxSectionNeedsMe: "Needs me",
13037
+ inboxSectionRecent: "Recently active",
11899
13038
  channelName: "Name",
11900
13039
  channelDescription: "Description",
11901
13040
  initialMembers: "Initial members",
@@ -11909,6 +13048,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11909
13048
  resumeAgent: "Resume",
11910
13049
  restartAgent: "Restart",
11911
13050
  restartStillUnavailable: "Restart ran, but the Member is still unavailable: {diagnostic}",
13051
+ restartRefusedNoRestart: "The session log is deterministically refused with nothing repairable; restarting cannot fix it: {detail}",
11912
13052
  restartFailed: "Restart failed: {message}",
11913
13053
  archiveAgent: "Archive",
11914
13054
  archiveAgentTitle: "Archive Agent: {name}",
@@ -11960,12 +13100,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11960
13100
  taskStatusInReview: "In review",
11961
13101
  taskStatusDone: "Done",
11962
13102
  taskStatusClosed: "Closed",
11963
- taskMessageCount: "{count} messages",
11964
13103
  taskLabel: "Task #{number}",
11965
13104
  taskPending: "Task …",
11966
13105
  openTask: "Open Task #{number}",
11967
13106
  openThread: "Open thread",
13107
+ openTaskUnread: "Open Task #{number} ({count} new updates)",
13108
+ openThreadUnread: "Open thread ({count} new updates)",
11968
13109
  threadLabel: "Thread",
13110
+ recentActivity: "Last activity {time}",
13111
+ replyAction: "Reply",
13112
+ claimers: "Handled by {names}",
11969
13113
  asTask: "As task",
11970
13114
  promoteToTask: "Convert to Task",
11971
13115
  promotingTask: "Converting to Task…",
@@ -12028,7 +13172,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12028
13172
  "connection",
12029
13173
  "conversation"
12030
13174
  ];
12031
- function registerModeShadow(ctx, navigation, changes, drafts, name, component, extraInject, entryKey) {
13175
+ function registerModeShadow(ctx, navigation, changes, reads, drafts, name, component, extraInject, entryKey) {
12032
13176
  const openMemberSessionImpl = (sessionId) => {
12033
13177
  const sessions = ctx.sessions;
12034
13178
  const snapshot = navigation.getSnapshot();
@@ -12039,6 +13183,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12039
13183
  };
12040
13184
  const sharedRemotes = {
12041
13185
  loadChannels: (request) => ctx.remote.agentTeam.view(request),
13186
+ loadInbox: (request) => ctx.remote.agentTeam.inbox(request),
13187
+ subscribeReads: (listener) => reads.subscribe(listener),
12042
13188
  subscribeChanges: (scope, listener) => changes.subscribe(scope, listener),
12043
13189
  drafts,
12044
13190
  loadMembers: (request) => ctx.remote.agentTeam.members(request),
@@ -12069,7 +13215,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12069
13215
  ...navigation.actions(),
12070
13216
  ...sharedRemotes,
12071
13217
  ...name === "main" ? {
12072
- readThread: (request) => ctx.remote.agentTeam.readThread(request),
13218
+ readThread: async (request) => {
13219
+ const result = await ctx.remote.agentTeam.readThread(request);
13220
+ if (result.ok) reads.bump();
13221
+ return result;
13222
+ },
12073
13223
  loadThreadHistory: (request) => ctx.remote.agentTeam.threadHistory(request),
12074
13224
  threadObservations: (request) => ctx.remote.agentTeam.threadObservations(request),
12075
13225
  sendMessage: (request) => ctx.remote.agentTeam.sendMessage(request),
@@ -12135,6 +13285,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12135
13285
  };
12136
13286
  }, "agent-team: member session restore");
12137
13287
  const changes = new TeamChangeStream((request, signal) => ctx.remote.agentTeam.changes(request, signal));
13288
+ const reads = new TeamReadStream();
12138
13289
  const loadMemberGroups = async () => {
12139
13290
  const workspaces = ctx.workspaces.list.getSnapshot().items;
12140
13291
  return (await Promise.all(workspaces.map(async (workspace) => {
@@ -12159,13 +13310,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12159
13310
  leaveTeam: () => {
12160
13311
  navigation.actions().exitMemberSession();
12161
13312
  navigation.actions().leaveTeam();
12162
- },
12163
- loadMemberGroups
13313
+ }
12164
13314
  })
12165
13315
  }, TeamFooterAction));
12166
- registerModeShadow(ctx, navigation, changes, drafts, "sidebar.workspaces", TeamWorkspaceBrowser);
12167
- registerModeShadow(ctx, navigation, changes, drafts, "main", TeamConversation, void 0, "conversation");
12168
- registerModeShadow(ctx, navigation, changes, drafts, "sidebar.settings", TeamSettings, () => ({ loadMemberGroups }));
13316
+ registerModeShadow(ctx, navigation, changes, reads, drafts, "sidebar.workspaces", TeamWorkspaceBrowser);
13317
+ registerModeShadow(ctx, navigation, changes, reads, drafts, "main", TeamConversation, void 0, "conversation");
13318
+ registerModeShadow(ctx, navigation, changes, reads, drafts, "sidebar.settings", TeamMembersAction, () => ({ loadMemberGroups }));
12169
13319
  }
12170
13320
  async function apply(ctx) {
12171
13321
  const disposeRemote = await ctx.remote.$mount(TYPERT_REMOTE);