@wowyuarm/dsh-agent-team 0.1.11 → 0.1.13

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 (114) hide show
  1. package/README.md +6 -4
  2. package/README.zh.md +6 -4
  3. package/cordis.patch.yml +7 -3
  4. package/package.json +16 -3
  5. package/packages/agent-team/README.md +4 -4
  6. package/packages/agent-team/README.zh.md +4 -4
  7. package/packages/agent-team/lib/context-projection.js +5 -1
  8. package/packages/agent-team/lib/index.js +162 -113
  9. package/packages/agent-team/lib/ledger.js +496 -169
  10. package/packages/agent-team/lib/member-context.js +18 -1
  11. package/packages/agent-team/lib/member-runtime.js +48 -9
  12. package/packages/agent-team/lib/mentions.js +80 -0
  13. package/packages/agent-team/lib/spec.js +20 -0
  14. package/packages/agent-team/lib/typert.host.js +241 -46
  15. package/packages/agent-team/lib/typert.remote-client.d.ts +7 -3
  16. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  17. package/packages/agent-team/lib/typert.remote-client.js +178 -28
  18. package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -1
  19. package/packages/agent-team/lib/types/index.d.ts +33 -14
  20. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  21. package/packages/agent-team/lib/types/ledger.d.ts +120 -18
  22. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  23. package/packages/agent-team/lib/types/member-context.d.ts +6 -0
  24. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  25. package/packages/agent-team/lib/types/member-runtime.d.ts +2 -1
  26. package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
  27. package/packages/agent-team/lib/types/mentions.d.ts +47 -0
  28. package/packages/agent-team/lib/types/mentions.d.ts.map +1 -0
  29. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  30. package/packages/agent-team/lib/types/types/entities.d.ts +3 -20
  31. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
  32. package/packages/agent-team/lib/types/types/operations.d.ts +37 -1
  33. package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
  34. package/packages/agent-team/lib/types/types/requests-results.d.ts +107 -25
  35. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
  36. package/packages/agent-team/lib/types/vendor/storage-sqlite/index.d.ts +87 -0
  37. package/packages/agent-team/lib/types/vendor/storage-sqlite/index.d.ts.map +1 -0
  38. package/packages/agent-team/lib/types/vendor/storage-sqlite/schema.d.ts +59 -0
  39. package/packages/agent-team/lib/types/vendor/storage-sqlite/schema.d.ts.map +1 -0
  40. package/packages/agent-team/lib/types/vendor/storage-sqlite/unit.d.ts +57 -0
  41. package/packages/agent-team/lib/types/vendor/storage-sqlite/unit.d.ts.map +1 -0
  42. package/packages/agent-team/lib/vendor/storage-sqlite/index.js +139 -0
  43. package/packages/agent-team/lib/vendor/storage-sqlite/schema.js +120 -0
  44. package/packages/agent-team/lib/vendor/storage-sqlite/unit.js +132 -0
  45. package/packages/agent-team/preset/team-member/agent.cordis.yml +48 -8
  46. package/packages/client-agent-team/README.md +1 -1
  47. package/packages/client-agent-team/README.zh.md +1 -1
  48. package/packages/client-agent-team/lib/client.js +2123 -1406
  49. package/packages/client-agent-team/lib/client.js.map +1 -1
  50. package/packages/client-agent-team/lib/types/client/TeamAgentImport.d.ts +12 -0
  51. package/packages/client-agent-team/lib/types/client/TeamAgentImport.d.ts.map +1 -0
  52. package/packages/client-agent-team/lib/types/client/TeamAgentImport.js +69 -0
  53. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +3 -1
  54. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  55. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +31 -19
  56. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts +18 -0
  57. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts.map +1 -0
  58. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.js +22 -0
  59. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +3 -1
  60. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  61. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +111 -24
  62. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
  63. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +10 -3
  64. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
  65. package/packages/client-agent-team/lib/types/client/TeamComposer.js +11 -17
  66. package/packages/client-agent-team/lib/types/client/TeamConversation.js +1 -1
  67. package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts +20 -0
  68. package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts.map +1 -0
  69. package/packages/client-agent-team/lib/types/client/TeamCountBadge.js +25 -0
  70. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +9 -5
  71. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -1
  72. package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +92 -23
  73. package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts +43 -0
  74. package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts.map +1 -0
  75. package/packages/client-agent-team/lib/types/client/TeamMemberRow.js +27 -0
  76. package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts +2 -2
  77. package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts.map +1 -1
  78. package/packages/client-agent-team/lib/types/client/TeamMembersAction.js +2 -2
  79. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +1 -1
  80. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
  81. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  82. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +21 -31
  83. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  84. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  85. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +29 -11
  86. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  87. package/packages/client-agent-team/lib/types/client/index.js +11 -5
  88. package/packages/client-agent-team/lib/types/client/locales.d.ts +54 -16
  89. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  90. package/packages/client-agent-team/lib/types/client/locales.js +54 -16
  91. package/packages/client-agent-team/lib/types/client/slots.d.ts +3 -2
  92. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  93. package/packages/client-agent-team/lib/types/client/team-changes.d.ts +15 -25
  94. package/packages/client-agent-team/lib/types/client/team-changes.d.ts.map +1 -1
  95. package/packages/client-agent-team/lib/types/client/team-changes.js +82 -80
  96. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +45 -10
  97. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  98. package/packages/client-agent-team/lib/types/client/team-formatters.js +71 -30
  99. package/packages/tool-agent-team/README.md +3 -3
  100. package/packages/tool-agent-team/README.zh.md +3 -3
  101. package/packages/tool-agent-team/lib/host-access.js +19 -0
  102. package/packages/tool-agent-team/lib/index.js +71 -49
  103. package/packages/tool-agent-team/lib/types/host-access.d.ts +10 -0
  104. package/packages/tool-agent-team/lib/types/host-access.d.ts.map +1 -1
  105. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
  106. package/packages/agent-team/lib/progress-nudge.js +0 -328
  107. package/packages/agent-team/lib/types/progress-nudge.d.ts +0 -136
  108. package/packages/agent-team/lib/types/progress-nudge.d.ts.map +0 -1
  109. package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts +0 -3
  110. package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts.map +0 -1
  111. package/packages/client-agent-team/lib/types/client/TeamSettings.js +0 -5
  112. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts +0 -41
  113. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts.map +0 -1
  114. package/packages/client-agent-team/lib/types/client/scope-coverage.js +0 -64
@@ -4,6 +4,7 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let _deepseek_ai_dsh_api_gateway_client = require("@deepseek-ai/dsh-api-gateway/client");
7
8
  let react = require("react");
8
9
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
10
  let react_jsx_runtime = require("react/jsx-runtime");
@@ -4296,27 +4297,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4296
4297
  "readThroughSequence": number().readonly()
4297
4298
  }).readonly().optional()
4298
4299
  });
4299
- const _wowyuarm_dsh_agent_team_agentTeam_changes_parameter_0$schema = object({
4300
- "afterVersion": number().readonly(),
4301
- "scope": union([
4302
- object({
4303
- "kind": literal("workspace").readonly(),
4304
- "workspaceId": intersection(string(), unknown()).readonly()
4305
- }),
4306
- object({
4307
- "kind": literal("channel").readonly(),
4308
- "channelRef": intersection(string(), unknown()).readonly()
4309
- }),
4310
- object({
4311
- "kind": literal("thread").readonly(),
4312
- "threadRef": intersection(string(), unknown()).readonly()
4313
- }),
4314
- object({
4315
- "kind": literal("presence").readonly(),
4316
- "workspaceId": intersection(string(), unknown()).readonly()
4317
- })
4318
- ]).readonly().optional()
4319
- });
4300
+ const _wowyuarm_dsh_agent_team_agentTeam_changes_parameter_0$schema = object({ "scope": union([
4301
+ object({
4302
+ "kind": literal("workspace").readonly(),
4303
+ "workspaceId": intersection(string(), unknown()).readonly()
4304
+ }),
4305
+ object({
4306
+ "kind": literal("channel").readonly(),
4307
+ "channelRef": intersection(string(), unknown()).readonly()
4308
+ }),
4309
+ object({
4310
+ "kind": literal("thread").readonly(),
4311
+ "threadRef": intersection(string(), unknown()).readonly()
4312
+ }),
4313
+ object({
4314
+ "kind": literal("presence").readonly(),
4315
+ "workspaceId": intersection(string(), unknown()).readonly()
4316
+ })
4317
+ ]).readonly().optional() });
4320
4318
  const _wowyuarm_dsh_agent_team_agentTeam_changes_result$schema = object({ "version": number().readonly() });
4321
4319
  const _wowyuarm_dsh_agent_team_agentTeam_changeTask_parameter_0$schema = object({
4322
4320
  "requestId": intersection(string(), unknown()).readonly(),
@@ -4512,11 +4510,58 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4512
4510
  });
4513
4511
  const _wowyuarm_dsh_agent_team_agentTeam_inbox_parameter_0$schema = object({
4514
4512
  "workspaceId": intersection(string(), unknown()).readonly(),
4515
- "limit": number().readonly().optional(),
4516
- "directOnly": boolean().readonly().optional()
4513
+ "limit": number().readonly().optional()
4517
4514
  });
4518
4515
  const _wowyuarm_dsh_agent_team_agentTeam_inbox_result$schema = object({
4519
4516
  "items": array(object({
4517
+ "workspaceId": intersection(string(), unknown()).readonly(),
4518
+ "channelRef": intersection(string(), unknown()).readonly(),
4519
+ "channelName": string().readonly().optional(),
4520
+ "task": object({
4521
+ "taskRef": intersection(string(), unknown()).readonly(),
4522
+ "channelRef": intersection(string(), unknown()).readonly(),
4523
+ "threadRef": intersection(string(), unknown()).readonly(),
4524
+ "status": union([
4525
+ literal("done"),
4526
+ literal("todo"),
4527
+ literal("in_progress"),
4528
+ literal("in_review"),
4529
+ literal("closed")
4530
+ ]).readonly(),
4531
+ "resolution": union([
4532
+ literal("closed"),
4533
+ literal("open"),
4534
+ literal("accepted")
4535
+ ]).readonly()
4536
+ }).readonly().optional(),
4537
+ "taskNumber": number().readonly().optional(),
4538
+ "thread": object({
4539
+ "threadRef": intersection(string(), unknown()).readonly(),
4540
+ "taskRef": intersection(string(), unknown()).readonly().optional(),
4541
+ "revision": number().readonly()
4542
+ }).readonly(),
4543
+ "unreadCount": number().readonly(),
4544
+ "directCount": number().readonly(),
4545
+ "previewText": string().readonly().optional(),
4546
+ "newestSequence": number().readonly(),
4547
+ "newestOccurredAt": string().readonly(),
4548
+ "newestActor": object({
4549
+ "memberId": intersection(string(), unknown()).readonly(),
4550
+ "name": string().readonly()
4551
+ }).readonly(),
4552
+ "claimOwners": array(object({
4553
+ "memberId": intersection(string(), unknown()).readonly(),
4554
+ "name": string().readonly()
4555
+ })).readonly(),
4556
+ "attention": object({
4557
+ "memberId": intersection(string(), unknown()).readonly(),
4558
+ "threadRef": intersection(string(), unknown()).readonly(),
4559
+ "startSequence": number().readonly(),
4560
+ "readThroughSequence": number().readonly()
4561
+ }).readonly().optional()
4562
+ })).readonly(),
4563
+ "recent": array(object({
4564
+ "workspaceId": intersection(string(), unknown()).readonly(),
4520
4565
  "channelRef": intersection(string(), unknown()).readonly(),
4521
4566
  "channelName": string().readonly().optional(),
4522
4567
  "task": object({
@@ -4547,6 +4592,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4547
4592
  "previewText": string().readonly().optional(),
4548
4593
  "newestSequence": number().readonly(),
4549
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(),
4550
4603
  "attention": object({
4551
4604
  "memberId": intersection(string(), unknown()).readonly(),
4552
4605
  "threadRef": intersection(string(), unknown()).readonly(),
@@ -4573,7 +4626,54 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4573
4626
  "channelRef": intersection(string(), unknown()).readonly(),
4574
4627
  "memberId": intersection(string(), unknown()).readonly()
4575
4628
  });
4576
- const _wowyuarm_dsh_agent_team_agentTeam_members_parameter_0$schema = object({ "workspaceId": intersection(string(), unknown()).readonly() });
4629
+ const _wowyuarm_dsh_agent_team_agentTeam_joinWorkspace_parameter_0$schema = object({
4630
+ "requestId": intersection(string(), unknown()).readonly(),
4631
+ "workspaceId": intersection(string(), unknown()).readonly(),
4632
+ "memberId": intersection(string(), unknown()).readonly()
4633
+ });
4634
+ const _wowyuarm_dsh_agent_team_agentTeam_joinWorkspace_result$schema = object({
4635
+ "receipt": object({
4636
+ "operationId": intersection(string(), unknown()).readonly(),
4637
+ "requestId": intersection(string(), unknown()).readonly(),
4638
+ "sequence": number().readonly(),
4639
+ "occurredAt": string().readonly()
4640
+ }).readonly(),
4641
+ "memberId": intersection(string(), unknown()).readonly(),
4642
+ "workspaceId": intersection(string(), unknown()).readonly()
4643
+ });
4644
+ const _wowyuarm_dsh_agent_team_agentTeam_leaveWorkspace_parameter_0$schema = object({
4645
+ "requestId": intersection(string(), unknown()).readonly(),
4646
+ "workspaceId": intersection(string(), unknown()).readonly(),
4647
+ "memberId": intersection(string(), unknown()).readonly()
4648
+ });
4649
+ const _wowyuarm_dsh_agent_team_agentTeam_leaveWorkspace_result$schema = object({
4650
+ "receipt": object({
4651
+ "operationId": intersection(string(), unknown()).readonly(),
4652
+ "requestId": intersection(string(), unknown()).readonly(),
4653
+ "sequence": number().readonly(),
4654
+ "occurredAt": string().readonly()
4655
+ }).readonly(),
4656
+ "memberId": intersection(string(), unknown()).readonly(),
4657
+ "workspaceId": intersection(string(), unknown()).readonly(),
4658
+ "releasedClaims": array(object({
4659
+ "claimRef": intersection(string(), unknown()).readonly(),
4660
+ "taskRef": intersection(string(), unknown()).readonly(),
4661
+ "threadRef": intersection(string(), unknown()).readonly(),
4662
+ "owner": intersection(string(), unknown()).readonly(),
4663
+ "direction": string().readonly(),
4664
+ "normalizedDirection": string().readonly(),
4665
+ "state": union([
4666
+ literal("active"),
4667
+ literal("done"),
4668
+ literal("released")
4669
+ ]).readonly()
4670
+ })).readonly(),
4671
+ "removedAttention": array(object({
4672
+ "memberId": intersection(string(), unknown()).readonly(),
4673
+ "threadRef": intersection(string(), unknown()).readonly()
4674
+ })).readonly()
4675
+ });
4676
+ const _wowyuarm_dsh_agent_team_agentTeam_members_parameter_0$schema = object({ "workspaceId": intersection(string(), unknown()).readonly().optional() });
4577
4677
  const _wowyuarm_dsh_agent_team_agentTeam_members_result$schema = array(object({
4578
4678
  "member": object({
4579
4679
  "memberId": intersection(string(), unknown()).readonly(),
@@ -4598,6 +4698,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4598
4698
  literal("archived")
4599
4699
  ]).readonly()
4600
4700
  }).readonly(),
4701
+ "workspaceIds": array(intersection(string(), unknown())).readonly(),
4601
4702
  "availability": union([
4602
4703
  literal("suspended"),
4603
4704
  literal("inactive"),
@@ -4856,6 +4957,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4856
4957
  })).readonly(),
4857
4958
  "readThroughSequence": number().readonly(),
4858
4959
  "remainingUnreadCount": number().readonly(),
4960
+ "earlierFactCount": number().readonly().optional(),
4859
4961
  "attention": object({
4860
4962
  "memberId": intersection(string(), unknown()).readonly(),
4861
4963
  "threadRef": intersection(string(), unknown()).readonly(),
@@ -5085,7 +5187,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5085
5187
  "threadRef": intersection(string(), unknown()).readonly(),
5086
5188
  "messageRef": intersection(string(), unknown()).readonly(),
5087
5189
  "sequence": number().readonly()
5088
- })).readonly()
5190
+ })).readonly(),
5191
+ "undeliveredMentions": array(intersection(string(), unknown())).readonly().optional()
5089
5192
  })
5090
5193
  ]);
5091
5194
  const _wowyuarm_dsh_agent_team_agentTeam_resolveTaskRefs_parameter_0$schema = object({
@@ -5455,6 +5558,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5455
5558
  });
5456
5559
  const _wowyuarm_dsh_agent_team_agentTeam_view_result$schema = object({
5457
5560
  "humanMemberId": intersection(string(), unknown()).readonly(),
5561
+ "workspaces": array(object({
5562
+ "workspaceId": intersection(string(), unknown()).readonly(),
5563
+ "title": union([_undefined(), string()]).readonly().optional(),
5564
+ "default": boolean().readonly()
5565
+ })).readonly(),
5458
5566
  "channels": array(object({
5459
5567
  "channelRef": intersection(string(), unknown()).readonly(),
5460
5568
  "workspaceId": intersection(string(), unknown()).readonly(),
@@ -5535,6 +5643,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5535
5643
  "revision": number().readonly()
5536
5644
  }).readonly(),
5537
5645
  "taskNumber": number().readonly().optional(),
5646
+ "claimOwners": array(object({
5647
+ "memberId": intersection(string(), unknown()).readonly(),
5648
+ "name": string().readonly()
5649
+ })).readonly(),
5538
5650
  "messageCount": number().readonly(),
5539
5651
  "lastActivityAt": string().readonly()
5540
5652
  })).readonly(),
@@ -5620,7 +5732,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5620
5732
  },
5621
5733
  sourceLocation: {
5622
5734
  "file": "packages/agent-team/src/index.ts",
5623
- "line": 718,
5735
+ "line": 727,
5624
5736
  "column": 9
5625
5737
  }
5626
5738
  },
@@ -5647,7 +5759,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5647
5759
  },
5648
5760
  sourceLocation: {
5649
5761
  "file": "packages/agent-team/src/index.ts",
5650
- "line": 708,
5762
+ "line": 717,
5651
5763
  "column": 9
5652
5764
  }
5653
5765
  },
@@ -5674,7 +5786,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5674
5786
  },
5675
5787
  sourceLocation: {
5676
5788
  "file": "packages/agent-team/src/index.ts",
5677
- "line": 1105,
5789
+ "line": 1108,
5678
5790
  "column": 9
5679
5791
  }
5680
5792
  },
@@ -5701,7 +5813,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5701
5813
  },
5702
5814
  sourceLocation: {
5703
5815
  "file": "packages/agent-team/src/index.ts",
5704
- "line": 1227,
5816
+ "line": 1248,
5705
5817
  "column": 9
5706
5818
  }
5707
5819
  },
@@ -5710,6 +5822,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5710
5822
  service: "agentTeam",
5711
5823
  namespace: "agentTeam",
5712
5824
  method: "changes",
5825
+ mode: "stream",
5713
5826
  invocation: { kind: "direct" },
5714
5827
  parameters: [{
5715
5828
  name: "request",
@@ -5729,8 +5842,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5729
5842
  },
5730
5843
  sourceLocation: {
5731
5844
  "file": "packages/agent-team/src/index.ts",
5732
- "line": 639,
5733
- "column": 9
5845
+ "line": 650,
5846
+ "column": 11
5734
5847
  }
5735
5848
  },
5736
5849
  {
@@ -5756,7 +5869,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5756
5869
  },
5757
5870
  sourceLocation: {
5758
5871
  "file": "packages/agent-team/src/index.ts",
5759
- "line": 1117,
5872
+ "line": 1120,
5760
5873
  "column": 9
5761
5874
  }
5762
5875
  },
@@ -5783,7 +5896,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5783
5896
  },
5784
5897
  sourceLocation: {
5785
5898
  "file": "packages/agent-team/src/index.ts",
5786
- "line": 833,
5899
+ "line": 842,
5787
5900
  "column": 9
5788
5901
  }
5789
5902
  },
@@ -5810,7 +5923,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5810
5923
  },
5811
5924
  sourceLocation: {
5812
5925
  "file": "packages/agent-team/src/index.ts",
5813
- "line": 681,
5926
+ "line": 690,
5814
5927
  "column": 9
5815
5928
  }
5816
5929
  },
@@ -5837,7 +5950,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5837
5950
  },
5838
5951
  sourceLocation: {
5839
5952
  "file": "packages/agent-team/src/index.ts",
5840
- "line": 1213,
5953
+ "line": 1234,
5841
5954
  "column": 9
5842
5955
  }
5843
5956
  },
@@ -5864,7 +5977,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5864
5977
  },
5865
5978
  sourceLocation: {
5866
5979
  "file": "packages/agent-team/src/index.ts",
5867
- "line": 1236,
5980
+ "line": 1257,
5868
5981
  "column": 3
5869
5982
  }
5870
5983
  },
@@ -5891,7 +6004,61 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5891
6004
  },
5892
6005
  sourceLocation: {
5893
6006
  "file": "packages/agent-team/src/index.ts",
5894
- "line": 1137,
6007
+ "line": 1140,
6008
+ "column": 9
6009
+ }
6010
+ },
6011
+ {
6012
+ id: "@wowyuarm/dsh-agent-team#agentTeam/joinWorkspace",
6013
+ service: "agentTeam",
6014
+ namespace: "agentTeam",
6015
+ method: "joinWorkspace",
6016
+ invocation: { kind: "direct" },
6017
+ parameters: [{
6018
+ name: "request",
6019
+ wire: "request",
6020
+ source: "json",
6021
+ codec: {
6022
+ mode: "strict",
6023
+ typeSymbol: "@wowyuarm/dsh-agent-team/types#AgentTeamJoinWorkspaceRequest",
6024
+ schema: _wowyuarm_dsh_agent_team_agentTeam_joinWorkspace_parameter_0$schema
6025
+ }
6026
+ }],
6027
+ result: {
6028
+ mode: "strict",
6029
+ typeSymbol: "@wowyuarm/dsh-agent-team/types#AgentTeamJoinWorkspaceResult",
6030
+ schema: _wowyuarm_dsh_agent_team_agentTeam_joinWorkspace_result$schema
6031
+ },
6032
+ sourceLocation: {
6033
+ "file": "packages/agent-team/src/index.ts",
6034
+ "line": 1160,
6035
+ "column": 9
6036
+ }
6037
+ },
6038
+ {
6039
+ id: "@wowyuarm/dsh-agent-team#agentTeam/leaveWorkspace",
6040
+ service: "agentTeam",
6041
+ namespace: "agentTeam",
6042
+ method: "leaveWorkspace",
6043
+ invocation: { kind: "direct" },
6044
+ parameters: [{
6045
+ name: "request",
6046
+ wire: "request",
6047
+ source: "json",
6048
+ codec: {
6049
+ mode: "strict",
6050
+ typeSymbol: "@wowyuarm/dsh-agent-team/types#AgentTeamLeaveWorkspaceRequest",
6051
+ schema: _wowyuarm_dsh_agent_team_agentTeam_leaveWorkspace_parameter_0$schema
6052
+ }
6053
+ }],
6054
+ result: {
6055
+ mode: "strict",
6056
+ typeSymbol: "@wowyuarm/dsh-agent-team/types#AgentTeamLeaveWorkspaceResult",
6057
+ schema: _wowyuarm_dsh_agent_team_agentTeam_leaveWorkspace_result$schema
6058
+ },
6059
+ sourceLocation: {
6060
+ "file": "packages/agent-team/src/index.ts",
6061
+ "line": 1169,
5895
6062
  "column": 9
5896
6063
  }
5897
6064
  },
@@ -5919,7 +6086,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5919
6086
  },
5920
6087
  sourceLocation: {
5921
6088
  "file": "packages/agent-team/src/index.ts",
5922
- "line": 630,
6089
+ "line": 640,
5923
6090
  "column": 3
5924
6091
  }
5925
6092
  },
@@ -5946,7 +6113,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5946
6113
  },
5947
6114
  sourceLocation: {
5948
6115
  "file": "packages/agent-team/src/index.ts",
5949
- "line": 1127,
6116
+ "line": 1130,
5950
6117
  "column": 9
5951
6118
  }
5952
6119
  },
@@ -5973,7 +6140,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5973
6140
  },
5974
6141
  sourceLocation: {
5975
6142
  "file": "packages/agent-team/src/index.ts",
5976
- "line": 1200,
6143
+ "line": 1221,
5977
6144
  "column": 9
5978
6145
  }
5979
6146
  },
@@ -6000,7 +6167,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6000
6167
  },
6001
6168
  sourceLocation: {
6002
6169
  "file": "packages/agent-team/src/index.ts",
6003
- "line": 1243,
6170
+ "line": 1264,
6004
6171
  "column": 9
6005
6172
  }
6006
6173
  },
@@ -6027,7 +6194,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6027
6194
  },
6028
6195
  sourceLocation: {
6029
6196
  "file": "packages/agent-team/src/index.ts",
6030
- "line": 778,
6197
+ "line": 787,
6031
6198
  "column": 9
6032
6199
  }
6033
6200
  },
@@ -6054,7 +6221,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6054
6221
  },
6055
6222
  sourceLocation: {
6056
6223
  "file": "packages/agent-team/src/index.ts",
6057
- "line": 1148,
6224
+ "line": 1151,
6058
6225
  "column": 9
6059
6226
  }
6060
6227
  },
@@ -6081,7 +6248,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6081
6248
  },
6082
6249
  sourceLocation: {
6083
6250
  "file": "packages/agent-team/src/index.ts",
6084
- "line": 1221,
6251
+ "line": 1242,
6085
6252
  "column": 9
6086
6253
  }
6087
6254
  },
@@ -6108,7 +6275,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6108
6275
  },
6109
6276
  sourceLocation: {
6110
6277
  "file": "packages/agent-team/src/index.ts",
6111
- "line": 617,
6278
+ "line": 627,
6112
6279
  "column": 3
6113
6280
  }
6114
6281
  },
@@ -6135,7 +6302,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6135
6302
  },
6136
6303
  sourceLocation: {
6137
6304
  "file": "packages/agent-team/src/index.ts",
6138
- "line": 1157,
6305
+ "line": 1178,
6139
6306
  "column": 9
6140
6307
  }
6141
6308
  },
@@ -6162,7 +6329,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6162
6329
  },
6163
6330
  sourceLocation: {
6164
6331
  "file": "packages/agent-team/src/index.ts",
6165
- "line": 1261,
6332
+ "line": 1282,
6166
6333
  "column": 3
6167
6334
  }
6168
6335
  },
@@ -6189,7 +6356,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6189
6356
  },
6190
6357
  sourceLocation: {
6191
6358
  "file": "packages/agent-team/src/index.ts",
6192
- "line": 1254,
6359
+ "line": 1275,
6193
6360
  "column": 3
6194
6361
  }
6195
6362
  },
@@ -6216,7 +6383,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6216
6383
  },
6217
6384
  sourceLocation: {
6218
6385
  "file": "packages/agent-team/src/index.ts",
6219
- "line": 693,
6386
+ "line": 702,
6220
6387
  "column": 9
6221
6388
  }
6222
6389
  },
@@ -6243,7 +6410,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6243
6410
  },
6244
6411
  sourceLocation: {
6245
6412
  "file": "packages/agent-team/src/index.ts",
6246
- "line": 1045,
6413
+ "line": 1048,
6247
6414
  "column": 9
6248
6415
  }
6249
6416
  },
@@ -6270,7 +6437,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6270
6437
  },
6271
6438
  sourceLocation: {
6272
6439
  "file": "packages/agent-team/src/index.ts",
6273
- "line": 1268,
6440
+ "line": 1289,
6274
6441
  "column": 3
6275
6442
  }
6276
6443
  }
@@ -6456,91 +6623,92 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6456
6623
  function scopeKey(scope) {
6457
6624
  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}`;
6458
6625
  }
6459
- /**
6460
- * One long-poll per change scope, shared by every listening surface: panels
6461
- * and pages never open parallel `changes` requests for the same scope, and
6462
- * the poll is aborted as soon as the last subscriber leaves.
6463
- *
6464
- * Each poll keeps its own cursor, and a cursor only means something inside the
6465
- * scope it was issued for: the Host answers a presence scope from a
6466
- * process-local wake epoch and every other scope from a durable ledger
6467
- * position.
6468
- */
6626
+ /** One logical stream per scope per page; Harness owns the shared transport and recovery. */
6469
6627
  var TeamChangeStream = class {
6470
- changes;
6471
- polls = /* @__PURE__ */ new Map();
6472
- /**
6473
- * The last version each scope key answered with, kept after that scope's poll
6474
- * is torn down: a commit landing while no poll exists is otherwise folded into
6475
- * the replacement poll's opening sample, which reports nothing.
6476
- */
6477
- observed = /* @__PURE__ */ new Map();
6478
- constructor(changes) {
6479
- this.changes = changes;
6628
+ remote;
6629
+ subscriptions = /* @__PURE__ */ new Map();
6630
+ constructor(remote) {
6631
+ this.remote = remote;
6480
6632
  }
6481
6633
  subscribe(scope, listener) {
6482
6634
  const key = scopeKey(scope);
6483
- let poll = this.polls.get(key);
6484
- if (poll === void 0) {
6485
- poll = {
6486
- controller: new AbortController(),
6487
- listeners: /* @__PURE__ */ new Set(),
6488
- resumeFrom: this.observed.get(key)
6489
- };
6490
- this.polls.set(key, poll);
6491
- this.run(key, scope, poll);
6635
+ let subscription = this.subscriptions.get(key);
6636
+ if (subscription === void 0) {
6637
+ subscription = this.open(scope, new Set([listener]));
6638
+ this.subscriptions.set(key, subscription);
6639
+ this.run(key, subscription);
6640
+ } else {
6641
+ subscription.listeners.add(listener);
6642
+ if (subscription.failure !== void 0) listener({
6643
+ type: "failed",
6644
+ message: subscription.failure
6645
+ });
6492
6646
  }
6493
- poll.listeners.add(listener);
6647
+ const owned = subscription;
6494
6648
  return () => {
6495
- const current = this.polls.get(key);
6496
- if (current === void 0 || !current.listeners.delete(listener)) return;
6497
- if (current.listeners.size === 0) {
6498
- this.polls.delete(key);
6499
- current.controller.abort();
6500
- }
6649
+ if (!owned.listeners.delete(listener) || owned.listeners.size !== 0) return;
6650
+ if (this.subscriptions.get(key) === owned) this.subscriptions.delete(key);
6651
+ owned.stream.dispose();
6501
6652
  };
6502
6653
  }
6503
- async run(key, scope, poll) {
6504
- const { signal } = poll.controller;
6505
- const request = (afterVersion) => ({
6506
- afterVersion,
6507
- ...scope === void 0 ? {} : { scope }
6508
- });
6509
- let version = poll.resumeFrom;
6510
- if (version === void 0) {
6511
- const probe = await this.changes(request(0), signal);
6512
- if (signal.aborted) return;
6513
- if (!probe.ok) {
6514
- this.fail(key, poll, probe.error.message);
6515
- return;
6516
- }
6517
- version = probe.value.version;
6518
- this.observed.set(key, version);
6519
- }
6520
- while (!signal.aborted) {
6521
- const result = await this.changes(request(version), signal);
6522
- if (signal.aborted) return;
6523
- if (!result.ok) {
6524
- this.fail(key, poll, result.error.message);
6525
- return;
6526
- }
6527
- this.observed.set(key, result.value.version);
6528
- if (result.value.version !== version) {
6529
- version = result.value.version;
6530
- for (const listener of poll.listeners) listener({
6531
- type: "changed",
6532
- version
6533
- });
6534
- }
6654
+ /**
6655
+ * Reopen every scope whose stream already ended for good. The Harness resumes a
6656
+ * live generation across reconnects, but a terminated one is gone for good: a new
6657
+ * Host generation is the moment the scope was waiting for can come back, and the
6658
+ * listeners keep their seats, so only the stream is replaced.
6659
+ */
6660
+ recover() {
6661
+ for (const [key, subscription] of this.subscriptions) {
6662
+ if (subscription.failure === void 0) continue;
6663
+ const replacement = this.open(subscription.scope, subscription.listeners);
6664
+ this.subscriptions.set(key, replacement);
6665
+ subscription.stream.dispose();
6666
+ this.run(key, replacement);
6535
6667
  }
6536
6668
  }
6537
- fail(key, poll, message) {
6538
- if (this.polls.get(key) === poll) this.polls.delete(key);
6539
- for (const listener of poll.listeners) listener({
6669
+ open(scope, listeners) {
6670
+ const key = scopeKey(scope);
6671
+ return {
6672
+ scope,
6673
+ stream: this.remote.$stream({
6674
+ name: `Team changes ${key}`,
6675
+ open: (signal) => this.remote.agentTeam.changes(scope === void 0 ? {} : { scope }, signal),
6676
+ ended: (accepted) => accepted ? new _deepseek_ai_dsh_api_gateway_client.RemoteStreamCarrierError("Team change subscription ended without a terminal result") : /* @__PURE__ */ new Error("Team change subscription ended before its opening baseline"),
6677
+ carrierFailed: (error) => this.fail(key, error.message)
6678
+ }),
6679
+ listeners,
6680
+ failure: void 0
6681
+ };
6682
+ }
6683
+ async dispose() {
6684
+ const subscriptions = [...this.subscriptions.values()];
6685
+ this.subscriptions.clear();
6686
+ await Promise.all(subscriptions.map((subscription) => subscription.stream.dispose()));
6687
+ }
6688
+ fail(key, message) {
6689
+ const subscription = this.subscriptions.get(key);
6690
+ if (subscription === void 0 || subscription.failure !== void 0) return;
6691
+ subscription.failure = message;
6692
+ for (const listener of subscription.listeners) listener({
6540
6693
  type: "failed",
6541
6694
  message
6542
6695
  });
6543
6696
  }
6697
+ async run(key, subscription) {
6698
+ try {
6699
+ for await (const item of subscription.stream) {
6700
+ if (this.subscriptions.get(key) !== subscription) return;
6701
+ item.accept();
6702
+ subscription.failure = void 0;
6703
+ for (const listener of subscription.listeners) listener({
6704
+ type: "changed",
6705
+ version: item.value.version
6706
+ });
6707
+ }
6708
+ } catch (error) {
6709
+ if (this.subscriptions.get(key) === subscription) this.fail(key, error instanceof Error ? error.message : String(error));
6710
+ }
6711
+ }
6544
6712
  };
6545
6713
  /**
6546
6714
  * The Host's `changes` stream never wakes on a Thread read — a read advances
@@ -6695,13 +6863,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6695
6863
  };
6696
6864
  //#endregion
6697
6865
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/team.module.css.mjs
6698
- const css$10 = ".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}";
6699
- const tagId$10 = "@wowyuarm/dsh-agent-team/team.module.css";
6700
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$10) + "]") === null) {
6866
+ 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}";
6867
+ const tagId$13 = "@wowyuarm/dsh-agent-team/team.module.css";
6868
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$13) + "]") === null) {
6701
6869
  const tag = document.createElement("style");
6702
6870
  tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
6703
- tag.dataset.pluginCss = tagId$10;
6704
- tag.textContent = css$10;
6871
+ tag.dataset.pluginCss = tagId$13;
6872
+ tag.textContent = css$13;
6705
6873
  document.head.appendChild(tag);
6706
6874
  }
6707
6875
  var team_module_css_default = {
@@ -6744,459 +6912,965 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6744
6912
  }) });
6745
6913
  }
6746
6914
  //#endregion
6747
- //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/state-dot.module.css.mjs
6748
- const css$9 = ".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%}";
6749
- const tagId$9 = "@wowyuarm/dsh-agent-team/state-dot.module.css";
6750
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$9) + "]") === null) {
6751
- const tag = document.createElement("style");
6752
- tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
6753
- tag.dataset.pluginCss = tagId$9;
6754
- tag.textContent = css$9;
6755
- document.head.appendChild(tag);
6915
+ //#region ../agent-team/src/mentions.ts
6916
+ function escapeRegExp(value) {
6917
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6756
6918
  }
6757
- var state_dot_module_css_default = { "quiet": "DalNWW_quiet" };
6758
- //#endregion
6759
- //#region src/client/TeamStateDot.tsx
6760
6919
  /**
6761
- * Render the one shared Team status indicator. Native StateDot states pass
6762
- * through; the quiet statuses mirror StateDot geometry locally so every
6763
- * surface renders the same shape todo a hollow ring (not started), quiet a
6764
- * solid tertiary dot with the same 10% halo (closed, unavailable).
6920
+ * Character ranges the scanner must not read as mentions: fenced code blocks
6921
+ * and inline code spans. Authors quote handles there to talk *about* a name
6922
+ * rather than call it, and resolving those would notify the wrong Member.
6923
+ * The alternation tries the fenced form first so a block is never mistaken for
6924
+ * a run of inline spans.
6765
6925
  */
6766
- function TeamStateDot({ state, size = 10 }) {
6767
- if (state === "todo" || state === "quiet") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6768
- className: state_dot_module_css_default.quiet,
6769
- "data-variant": state,
6770
- style: {
6771
- width: size,
6772
- height: size
6773
- },
6774
- "aria-hidden": "true"
6775
- });
6776
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
6777
- state,
6778
- size
6779
- });
6780
- }
6781
- //#endregion
6782
- //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/presence.module.css.mjs
6783
- const css$8 = ".-\\36 lQ-q_target{flex:0 0 14px;justify-content:center;align-items:center;display:inline-flex}";
6784
- const tagId$8 = "@wowyuarm/dsh-agent-team/presence.module.css";
6785
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$8) + "]") === null) {
6786
- const tag = document.createElement("style");
6787
- tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
6788
- tag.dataset.pluginCss = tagId$8;
6789
- tag.textContent = css$8;
6790
- document.head.appendChild(tag);
6791
- }
6792
- var presence_module_css_default = { "target": "-6lQ-q_target" };
6793
- //#endregion
6794
- //#region src/client/TeamPresenceDot.tsx
6795
- function presenceLabel(status, t) {
6796
- const label = status.presence === "available" ? t("statusAvailable") : status.presence === "working" ? t("statusWorking") : status.presence === "error" ? t("statusError") : t("statusUnavailable");
6797
- return status.diagnostic === void 0 ? label : `${label}: ${diagnosticText(status)}`;
6926
+ function codeRanges(body) {
6927
+ const ranges = [];
6928
+ for (const match of body.matchAll(/```[\s\S]*?```|`[^`\n]*`/g)) {
6929
+ const start = match.index ?? 0;
6930
+ ranges.push([start, start + match[0].length]);
6931
+ }
6932
+ return ranges;
6798
6933
  }
6799
- /** One line of human-readable diagnostic text: the reason, plus the refused artifact path when one was reported. */
6800
- function diagnosticText(status) {
6801
- const diagnostic = status.diagnostic;
6802
- if (diagnostic === void 0) return "";
6803
- return diagnostic.location === void 0 ? diagnostic.detail : `${diagnostic.detail} (${diagnostic.location.path})`;
6934
+ const ALL_MARKER = /(?<![\p{L}\p{N}_@])@all(?=$|[^\p{L}\p{N}_])/iu;
6935
+ /** Whether one body carries the `@all` marker outside code. */
6936
+ function hasAllMarker(body) {
6937
+ const excluded = codeRanges(body);
6938
+ const marker = ALL_MARKER.exec(body);
6939
+ return marker !== null && !excluded.some(([start, end]) => marker.index >= start && marker.index < end);
6804
6940
  }
6805
6941
  /**
6806
- * Whether the restart action can help an unavailable Member: it heals
6807
- * transient and repairable failures, but not a transient rollover window
6808
- * (which resolves on its own) or a refusal already proven non-remediable.
6942
+ * Every `@Handle` occurrence in one body that names one of `handles`:
6943
+ * case-insensitive, on Unicode word boundaries, longest handle first, outside
6944
+ * code. Writing `@` is required: bare handles are ordinary words. This is the
6945
+ * single definition of an authored mention — the Host delivery resolution and
6946
+ * the Client's chip rendering and draft preview all read through it, so a name
6947
+ * that renders as a chip is the same name that delivers a notification.
6809
6948
  */
6810
- function restartOffered(status) {
6811
- const diagnostic = status.diagnostic;
6812
- if (diagnostic === void 0) return true;
6813
- if (diagnostic.class === "rollover") return false;
6814
- return !(diagnostic.class === "session-refused" && diagnostic.remediable === false);
6815
- }
6816
- /** Shared presence → indicator mapping for dots and avatar badges. */
6817
- function presenceDotState(presence) {
6818
- return presence === "available" ? "done" : presence === "working" ? "ongoing" : presence === "error" ? "error" : "quiet";
6819
- }
6820
- function TeamPresenceDot({ status, t }) {
6821
- const label = presenceLabel(status, t);
6822
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
6823
- label,
6824
- delayMs: 300,
6825
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6826
- className: presence_module_css_default.target,
6827
- role: "img",
6828
- "aria-label": label,
6829
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamStateDot, { state: presenceDotState(status.presence) })
6830
- })
6831
- });
6832
- }
6833
- //#endregion
6834
- //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/members.module.css.mjs
6835
- const css$7 = ".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)}}";
6836
- const tagId$7 = "@wowyuarm/dsh-agent-team/members.module.css";
6837
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$7) + "]") === null) {
6838
- const tag = document.createElement("style");
6839
- tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
6840
- tag.dataset.pluginCss = tagId$7;
6841
- tag.textContent = css$7;
6842
- document.head.appendChild(tag);
6949
+ function scanBodyHandles(body, handles) {
6950
+ const seen = /* @__PURE__ */ new Set();
6951
+ const usable = [];
6952
+ for (const handle of handles) {
6953
+ const key = handle.toLowerCase();
6954
+ if (handle.trim() === "" || seen.has(key)) continue;
6955
+ seen.add(key);
6956
+ usable.push(handle);
6957
+ }
6958
+ if (usable.length === 0) return Object.freeze([]);
6959
+ const excluded = codeRanges(body);
6960
+ const ordered = [...usable].sort((left, right) => right.length - left.length);
6961
+ const pattern = new RegExp(`(?<![\\p{L}\\p{N}_@])@(?:${ordered.map((handle) => escapeRegExp(handle)).join("|")})(?=$|[^\\p{L}\\p{N}_])`, "giu");
6962
+ const matches = [];
6963
+ for (const match of body.matchAll(pattern)) {
6964
+ const start = match.index ?? 0;
6965
+ if (excluded.some(([rangeStart, rangeEnd]) => start >= rangeStart && start < rangeEnd)) continue;
6966
+ const written = match[0].slice(1).toLowerCase();
6967
+ const hit = ordered.find((handle) => handle.toLowerCase() === written);
6968
+ if (hit === void 0) continue;
6969
+ matches.push(Object.freeze({
6970
+ handle: hit,
6971
+ start,
6972
+ end: start + match[0].length
6973
+ }));
6974
+ }
6975
+ return Object.freeze(matches);
6843
6976
  }
6844
- var members_module_css_default = {
6845
- "body": "UkovOW_body",
6846
- "content": "UkovOW_content",
6847
- "copy": "UkovOW_copy",
6848
- "error": "UkovOW_error",
6849
- "group": "UkovOW_group",
6850
- "member": "UkovOW_member",
6851
- "state": "UkovOW_state"
6852
- };
6853
- //#endregion
6854
- //#region src/client/TeamMembersAction.tsx
6855
- function TeamMembersAction({ wide, loadMemberGroups, t }) {
6856
- const [panelOpen, setPanelOpen] = (0, react.useState)(false);
6857
- const [groups, setGroups] = (0, react.useState)([]);
6858
- const [loading, setLoading] = (0, react.useState)(false);
6859
- const [error, setError] = (0, react.useState)();
6860
- const triggerRef = (0, react.useRef)(null);
6861
- const contentRef = (0, react.useRef)(null);
6862
- (0, react.useEffect)(() => {
6863
- if (!panelOpen) return;
6864
- queueMicrotask(() => {
6865
- contentRef.current?.focus();
6866
- });
6867
- }, [panelOpen]);
6868
- const openMembers = () => {
6869
- setPanelOpen(true);
6870
- setLoading(true);
6871
- setError(void 0);
6872
- loadMemberGroups().then(setGroups).catch((cause) => {
6873
- setError(cause instanceof Error ? cause.message : String(cause));
6874
- }).finally(() => {
6875
- setLoading(false);
6876
- });
6877
- };
6878
- const closeMembers = () => {
6879
- setPanelOpen(false);
6880
- queueMicrotask(() => {
6881
- triggerRef.current?.focus();
6882
- });
6977
+ /**
6978
+ * Resolve the `@Handle` mentions authored in one Message body.
6979
+ *
6980
+ * Callers pass the candidates reachable in the Message's Channel, so a name
6981
+ * that resolves here is already an addressable target; handles the Channel
6982
+ * cannot reach simply stay prose.
6983
+ *
6984
+ * `sender` is excluded because a Message never mentions its own author, which
6985
+ * also keeps the result usable as a recipient set without further filtering.
6986
+ */
6987
+ function resolveBodyMentions(body, candidates, sender) {
6988
+ const usable = candidates.filter((candidate) => candidate.memberId !== sender && candidate.handle.trim() !== "");
6989
+ const all = hasAllMarker(body);
6990
+ if (usable.length === 0) return {
6991
+ memberIds: Object.freeze([]),
6992
+ all
6993
+ };
6994
+ const matched = new Set(scanBodyHandles(body, usable.map((candidate) => candidate.handle)).map((match) => match.handle.toLowerCase()));
6995
+ return {
6996
+ memberIds: Object.freeze(usable.filter((candidate) => matched.has(candidate.handle.toLowerCase())).map((candidate) => candidate.memberId)),
6997
+ all
6883
6998
  };
6884
- 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, {
6885
- label: t("members"),
6886
- delayMs: 500,
6887
- disabled: wide,
6888
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
6889
- ref: triggerRef,
6890
- type: "button",
6891
- className: wide ? team_module_css_default.settingsAction : `${team_module_css_default.settingsAction} ${team_module_css_default.rail}`,
6892
- "aria-label": t("members"),
6893
- "aria-haspopup": "dialog",
6894
- onClick: openMembers,
6895
- 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") })]
6896
- })
6897
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
6898
- open: panelOpen,
6899
- onClose: closeMembers,
6900
- title: t("members"),
6901
- closeLabel: t("close"),
6902
- contentClassName: members_module_css_default.body,
6903
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6904
- ref: contentRef,
6905
- className: members_module_css_default.content,
6906
- tabIndex: -1,
6907
- children: [
6908
- loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6909
- className: members_module_css_default.state,
6910
- role: "status",
6911
- children: t("loadingAgents")
6912
- }),
6913
- !loading && groups.length === 0 && error === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6914
- className: members_module_css_default.state,
6915
- children: t("emptyAgents")
6916
- }),
6917
- !loading && groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
6918
- className: members_module_css_default.group,
6919
- "aria-labelledby": `team-members-${group.workspaceId}`,
6920
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
6921
- id: `team-members-${group.workspaceId}`,
6922
- children: group.workspaceTitle
6923
- }), group.members.map((status) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6924
- className: members_module_css_default.member,
6925
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamPresenceDot, {
6926
- status,
6927
- t
6928
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6929
- className: members_module_css_default.copy,
6930
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: ["@", status.member.handle] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: status.member.description })]
6931
- })]
6932
- }, status.member.memberId))]
6933
- }, group.workspaceId)),
6934
- error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6935
- className: members_module_css_default.error,
6936
- role: "alert",
6937
- children: error
6938
- })
6939
- ]
6940
- })
6941
- })] });
6942
6999
  }
6943
7000
  //#endregion
6944
- //#region src/client/TeamSettings.tsx
6945
- function TeamSettings({ wide, loadMemberGroups, t }) {
6946
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMembersAction, {
6947
- wide,
6948
- loadMemberGroups,
6949
- t
6950
- });
7001
+ //#region src/client/team-formatters.ts
7002
+ function formatTaskStatus(status, t) {
7003
+ return t({
7004
+ todo: "taskStatusTodo",
7005
+ in_progress: "taskStatusInProgress",
7006
+ in_review: "taskStatusInReview",
7007
+ done: "taskStatusDone",
7008
+ closed: "taskStatusClosed"
7009
+ }[status]);
6951
7010
  }
6952
- //#endregion
6953
- //#region src/client/attachment-preview.ts
6954
- /** Base64 one file payload in chunks so large uploads stay off the call-stack limit. */
6955
- function bytesToBase64(bytes) {
6956
- let binary = "";
6957
- const chunk = 32768;
6958
- for (let start = 0; start < bytes.length; start += chunk) binary += String.fromCharCode(...bytes.subarray(start, start + chunk));
6959
- return btoa(binary);
7011
+ function formatClaimState(state, t) {
7012
+ return t({
7013
+ active: "claimStateActive",
7014
+ done: "claimStateDone",
7015
+ released: "claimStateReleased"
7016
+ }[state]);
6960
7017
  }
6961
7018
  /**
6962
- * Thumbnail data URLs live in one session-wide cache: message lists re-render
6963
- * often, and each miss costs a Host round-trip plus a base64 decode. Failed
6964
- * loads (bytes already GC'd) are cached as `null` so the chip fallback is stable.
7019
+ * Status indicator for a Task status, the dot every Task surface renders.
7020
+ * Active states map to StateDot variants; every status renders a dot so they
7021
+ * share one shape language todo is a hollow ring (not started), closed a
7022
+ * quiet gray dot (archived).
6965
7023
  */
6966
- const dataUrlCache = /* @__PURE__ */ new Map();
6967
- function cachedAttachmentDataUrl(attachmentId) {
6968
- return dataUrlCache.get(attachmentId);
7024
+ function taskStatusDot(status) {
7025
+ return {
7026
+ todo: "todo",
7027
+ in_progress: "ongoing",
7028
+ in_review: "warning",
7029
+ done: "done",
7030
+ closed: "quiet"
7031
+ }[status];
6969
7032
  }
6970
- async function loadAttachmentDataUrl(getAttachment, attachment) {
6971
- const cached = dataUrlCache.get(attachment.attachmentId);
6972
- if (cached !== void 0) return cached;
6973
- const result = await getAttachment({ attachmentId: attachment.attachmentId });
6974
- const url = result.ok && attachment.mediaType.startsWith("image/") ? `data:${attachment.mediaType};base64,${result.value.bytesBase64}` : null;
6975
- dataUrlCache.set(attachment.attachmentId, url);
6976
- return url;
7033
+ /** One-line title snippet derived from the Task's root Message body. */
7034
+ function formatTaskTitle(body) {
7035
+ const firstLine = body.split("\n", 1)[0]?.trim() ?? "";
7036
+ return firstLine.length > 120 ? `${firstLine.slice(0, 119)}…` : firstLine;
6977
7037
  }
6978
- /** Human-readable byte size for attachment chips. */
6979
- function formatByteSize(byteSize) {
6980
- if (byteSize < 1024) return `${byteSize} B`;
6981
- if (byteSize < 1024 * 1024) return `${(byteSize / 1024).toFixed(0)} KB`;
6982
- return `${(byteSize / (1024 * 1024)).toFixed(1)} MB`;
7038
+ /** Deterministic avatar hue for one Member identity; stable across sessions and themes. */
7039
+ function memberHue(memberId) {
7040
+ let hash = 0;
7041
+ for (let index = 0; index < memberId.length; index += 1) hash = (hash * 31 + memberId.charCodeAt(index)) % 360;
7042
+ return hash;
6983
7043
  }
6984
- //#endregion
6985
- //#region src/client/requests.ts
6986
- /** Fresh idempotency identity for one Client-initiated durable request. */
6987
- const mintRequestId = () => crypto.randomUUID();
7044
+ const BRANDED_REF_PATTERN = /\b(task|channel|thread):{1,2}[0-9a-f]{6,}(?:-[0-9a-f]{1,})*\b/gi;
6988
7045
  /**
6989
- * Upload composer files in order. One failure stops with the error text; the
6990
- * caller keeps its chips so a retry uploads only the still-pending files.
7046
+ * Canonical form of one matched ref: models occasionally double the colon or
7047
+ * uppercase the UUID when citing a ref in prose, while Host lookups and
7048
+ * navigation only accept the lowercase single-colon ref the ledger mints.
6991
7049
  */
6992
- const uploadComposerFiles = async (putAttachment, workspaceId, files) => {
6993
- const attachmentIds = [];
6994
- for (const file of files) {
6995
- const uploaded = await putAttachment({
6996
- requestId: mintRequestId(),
6997
- workspaceId,
6998
- name: file.name,
6999
- mediaType: file.type === "" ? void 0 : file.type,
7000
- bytesBase64: bytesToBase64(new Uint8Array(await file.arrayBuffer()))
7050
+ function canonicalBrandedRef(match) {
7051
+ return match.replace("::", ":").toLowerCase();
7052
+ }
7053
+ /**
7054
+ * Split a literal text run into plain and branded-ref segments. The pattern
7055
+ * anchors on the fixed ref prefixes plus a UUID shape (full or abbreviated),
7056
+ * so ordinary prose containing a colon never linkifies; a doubled colon from
7057
+ * model output is tolerated. Segment refs are always canonical, so resolution
7058
+ * and navigation work regardless of how the ref was spelled; text without any
7059
+ * ref comes back as one untouched segment.
7060
+ */
7061
+ function splitBrandedRefs(text) {
7062
+ const segments = [];
7063
+ let cursor = 0;
7064
+ for (const match of text.matchAll(BRANDED_REF_PATTERN)) {
7065
+ const start = match.index ?? 0;
7066
+ if (start > cursor) segments.push({ text: text.slice(cursor, start) });
7067
+ segments.push({
7068
+ text: match[0],
7069
+ ref: canonicalBrandedRef(match[0])
7001
7070
  });
7002
- if (!uploaded.ok) return {
7003
- ok: false,
7004
- error: uploaded.error.message
7005
- };
7006
- attachmentIds.push(uploaded.value.attachmentId);
7071
+ cursor = start + match[0].length;
7007
7072
  }
7008
- return {
7009
- ok: true,
7010
- attachmentIds
7011
- };
7012
- };
7013
- //#endregion
7014
- //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/composer.module.css.mjs
7015
- const css$6 = ".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}}";
7016
- const tagId$6 = "@wowyuarm/dsh-agent-team/composer.module.css";
7017
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
7018
- const tag = document.createElement("style");
7019
- tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7020
- tag.dataset.pluginCss = tagId$6;
7021
- tag.textContent = css$6;
7022
- document.head.appendChild(tag);
7073
+ if (cursor < text.length) segments.push({ text: text.slice(cursor) });
7074
+ return segments;
7023
7075
  }
7024
- var composer_module_css_default = {
7025
- "asTaskLabel": "x9jGQq_asTaskLabel",
7026
- "asTaskPill": "x9jGQq_asTaskPill",
7027
- "asTaskPillOn": "x9jGQq_asTaskPillOn",
7028
- "attachButton": "x9jGQq_attachButton",
7029
- "card": "x9jGQq_card",
7030
- "confirmation": "x9jGQq_confirmation",
7031
- "error": "x9jGQq_error",
7032
- "fileChip": "x9jGQq_fileChip",
7033
- "fileChipName": "x9jGQq_fileChipName",
7034
- "fileChipRemove": "x9jGQq_fileChipRemove",
7035
- "fileChipSize": "x9jGQq_fileChipSize",
7036
- "fileChips": "x9jGQq_fileChips",
7037
- "fileInput": "x9jGQq_fileInput",
7038
- "imageChip": "x9jGQq_imageChip",
7039
- "imageChipPreview": "x9jGQq_imageChipPreview",
7040
- "inputArea": "x9jGQq_inputArea",
7041
- "mentionAllDot": "x9jGQq_mentionAllDot",
7042
- "mentionDescription": "x9jGQq_mentionDescription",
7043
- "mentionMenu": "x9jGQq_mentionMenu",
7044
- "mentionName": "x9jGQq_mentionName",
7045
- "mentionOption": "x9jGQq_mentionOption",
7046
- "notifyRow": "x9jGQq_notifyRow",
7047
- "root": "x9jGQq_root",
7048
- "sendButton": "x9jGQq_sendButton",
7049
- "toolbar": "x9jGQq_toolbar"
7050
- };
7051
- //#endregion
7052
- //#region src/client/TeamComposer.tsx
7053
- function findMention(draft, caret) {
7054
- const beforeCaret = draft.slice(0, caret);
7055
- if (beforeCaret.length === 0 || /\s/u.test(beforeCaret.at(-1) ?? "")) return void 0;
7056
- let tokenStart = beforeCaret.length;
7057
- while (tokenStart > 0 && !/\s/u.test(beforeCaret[tokenStart - 1])) tokenStart -= 1;
7058
- const at = beforeCaret.lastIndexOf("@");
7059
- if (at < tokenStart) return void 0;
7060
- if (at > 0 && /[\p{L}\p{N}_]/u.test(beforeCaret[at - 1])) return void 0;
7076
+ /**
7077
+ * Whether one string's whole content is exactly one branded ref. A code span
7078
+ * like this is the model styling a ref as an identifier, not publishing code,
7079
+ * so the Markdown pass may linkify it; anything larger stays literal.
7080
+ */
7081
+ function isSingleBrandedRef(text) {
7082
+ const trimmed = text.trim();
7083
+ if (trimmed === "") return false;
7084
+ const matches = [...trimmed.matchAll(BRANDED_REF_PATTERN)];
7085
+ return matches.length === 1 && matches[0][0] === trimmed;
7086
+ }
7087
+ /**
7088
+ * Locate one Message's delivered mention names inside its literal body. Matching
7089
+ * is the shared Host delivery scan — an authored `@`, case-insensitive on Unicode
7090
+ * word boundaries, longest handle first, code quoted rather than called — so a chip
7091
+ * never lands where delivery would not reach. Mention segments render the canonical
7092
+ * `@Handle`; names absent from the body come back unmatched so the consumer can
7093
+ * append them as a fallback chip row.
7094
+ */
7095
+ function splitMentionNames(text, names) {
7096
+ if (names.length === 0) return {
7097
+ segments: [{
7098
+ text,
7099
+ mention: false
7100
+ }],
7101
+ unmatched: []
7102
+ };
7103
+ const segments = [];
7104
+ const matched = /* @__PURE__ */ new Set();
7105
+ let cursor = 0;
7106
+ for (const match of scanBodyHandles(text, names)) {
7107
+ if (match.start > cursor) segments.push({
7108
+ text: text.slice(cursor, match.start),
7109
+ mention: false
7110
+ });
7111
+ segments.push({
7112
+ text: `@${match.handle}`,
7113
+ mention: true,
7114
+ name: match.handle
7115
+ });
7116
+ matched.add(match.handle.toLowerCase());
7117
+ cursor = match.end;
7118
+ }
7119
+ if (cursor < text.length) segments.push({
7120
+ text: text.slice(cursor),
7121
+ mention: false
7122
+ });
7061
7123
  return {
7062
- start: at,
7063
- end: caret,
7064
- query: beforeCaret.slice(at + 1)
7124
+ segments,
7125
+ unmatched: names.filter((name) => !matched.has(name.toLowerCase()))
7065
7126
  };
7066
7127
  }
7067
- function escapeRegExp$1(value) {
7068
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7069
- }
7070
- function containsMention(draft, handle) {
7071
- return new RegExp(`(?:^|[^\\p{L}\\p{N}_])@${escapeRegExp$1(handle)}(?=$|[^\\p{L}\\p{N}_])`, "u").test(draft);
7072
- }
7073
- function mentionCandidates(members, query) {
7074
- const normalized = query.toLocaleLowerCase();
7075
- return members.filter((status) => status.presence !== "unavailable" && status.member.state !== "inactive" && status.member.state !== "archived" && status.member.handle.toLocaleLowerCase().startsWith(normalized));
7128
+ /**
7129
+ * Whether one draft spells a handle as an authored `@mention`: the shared
7130
+ * delivery scan, so the composer's recipient prune and will-notify preview agree
7131
+ * with the Host on what the draft actually calls.
7132
+ */
7133
+ function containsMention(body, handle) {
7134
+ return scanBodyHandles(body, [handle]).length > 0;
7076
7135
  }
7077
- /** Thread followers rank first: mentioning them delivers directly, while a non-follower enters the two-send invite flow. */
7078
- function rankMentionCandidates(candidates, followers) {
7079
- if (followers === void 0 || followers.size === 0) return candidates;
7080
- return [...candidates].sort((left, right) => Number(followers.has(right.member.memberId)) - Number(followers.has(left.member.memberId)));
7136
+ /** Whether one draft carries the `@all` marker the mention menu expands. */
7137
+ function containsAllMention(body) {
7138
+ return hasAllMarker(body);
7081
7139
  }
7082
- /** Every member a manual handle pick could reach: the @all expansion snapshot. */
7140
+ /**
7141
+ * Every Member the mention menu's `@all` row stands for: the roster this
7142
+ * composer was handed minus Members who cannot take a Message right now — the
7143
+ * same filter the per-handle rows apply, so the expansion and the menu agree.
7144
+ */
7083
7145
  function allMentionMembers(members) {
7084
7146
  return members.filter((status) => status.presence !== "unavailable" && status.member.state !== "inactive" && status.member.state !== "archived");
7085
7147
  }
7086
- function containsAllMention(draft) {
7087
- return /(?:^|[^\p{L}\p{N}_])@all(?=$|[^\p{L}\p{N}_])/u.test(draft);
7148
+ /**
7149
+ * Member ids one draft asks to notify by text alone: the Client's preview of
7150
+ * the Host's own body mention resolution, so a hand-typed `@Handle` reports
7151
+ * exactly like a pick from the mention menu. `@all` stands for the menu's
7152
+ * expansion; a written handle counts whenever its Member can still take a
7153
+ * Message — state decides, not presence, because an offline Member is notified
7154
+ * and reads it later.
7155
+ *
7156
+ * The result is preview-only. Only picked recipients travel as explicit
7157
+ * recipients, where a name the Channel cannot reach would be a rejected target
7158
+ * rather than the prose the Host reads.
7159
+ */
7160
+ function mentionedMemberIds(body, members) {
7161
+ if (hasAllMarker(body)) return allMentionMembers(members).map((status) => status.member.memberId);
7162
+ return resolveBodyMentions(body, members.filter((status) => status.member.state !== "inactive" && status.member.state !== "archived").map((status) => ({
7163
+ memberId: status.member.memberId,
7164
+ handle: status.member.handle
7165
+ })), "member:human").memberIds;
7088
7166
  }
7089
- /** One object URL per draft file; revoked when the draft is removed. */
7090
- const draftPreviewUrls = /* @__PURE__ */ new WeakMap();
7091
- function draftPreviewUrl(file) {
7092
- if (!file.type.startsWith("image/")) return void 0;
7093
- let url = draftPreviewUrls.get(file);
7094
- if (url === void 0) {
7095
- url = URL.createObjectURL(file);
7096
- draftPreviewUrls.set(file, url);
7097
- }
7098
- return url;
7167
+ /** Canonical chip handles for one Message's structured mention refs. */
7168
+ function mentionNamesOf(mentions, handles) {
7169
+ return mentions.map((memberId) => memberId === "member:human" ? "human" : handles.get(memberId)).filter((name) => name !== void 0);
7099
7170
  }
7100
- function TeamComposer({ members, followerMemberIds, drafts, draftKey, pending, confirmation, error, onEdit, onSubmit, placeholder, pendingFiles, onFilesChange, asTask, onAsTaskChange, t }) {
7101
- const inputRef = (0, react.useRef)(null);
7102
- const fileInputRef = (0, react.useRef)(null);
7103
- const rootRef = (0, react.useRef)(null);
7104
- const menuRef = (0, react.useRef)(null);
7105
- const activeOptionRef = (0, react.useRef)(null);
7106
- const composingRef = (0, react.useRef)(false);
7107
- const { draft, recipients } = (0, react.useSyncExternalStore)(drafts.subscribe, () => drafts.getSnapshot(draftKey));
7108
- const [mention, setMention] = (0, react.useState)();
7109
- const [highlight, setHighlight] = (0, react.useState)(0);
7110
- const memberCandidates = mention === void 0 ? [] : rankMentionCandidates(mentionCandidates(members, mention.query), followerMemberIds);
7111
- const options = mention !== void 0 && "all".startsWith(mention.query.toLocaleLowerCase()) ? [{ kind: "all" }, ...memberCandidates.map((status) => ({
7112
- kind: "member",
7113
- status
7114
- }))] : memberCandidates.map((status) => ({
7115
- kind: "member",
7116
- status
7117
- }));
7118
- const menuOpen = mention !== void 0 && options.length > 0;
7119
- const activeOption = options[highlight];
7120
- const activeOptionKey = activeOption === void 0 ? void 0 : activeOption.kind === "all" ? "all" : activeOption.status.member.memberId;
7121
- const allCount = allMentionMembers(members).length;
7122
- const listId = "team-mention-suggestions";
7123
- const menuMaxHeight = (0, _deepseek_ai_dsh_client_ui_primitives.useAnchoredMaxHeight)(menuRef, 320, menuOpen ? draft : null);
7124
- (0, _deepseek_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer)(rootRef, menuOpen, (open) => {
7125
- if (!open) setMention(void 0);
7171
+ /** Accessible label for one "who is on this work" stack: its owners' handles, comma-separated. */
7172
+ function claimersLabel(owners, t) {
7173
+ return t("claimers", { names: owners.map((owner) => `@${owner.name}`).join(", ") });
7174
+ }
7175
+ const MARKDOWN_BLOCK_CONSTRUCT = /(^|\n)[ \t]{0,3}(?:#{1,6}[ \t]|>[ \t]|[-*+][ \t]|\d+[.)][ \t])|^[ \t]*\|.+\|/m;
7176
+ const MARKDOWN_INLINE_CONSTRUCT = /[`*_[\]!]|~~~|```/;
7177
+ /**
7178
+ * Whether an Agent body survives literal rendering unchanged: no fences,
7179
+ * inline code, emphasis markers, links, images, tables, or block constructs.
7180
+ * Only such plain-prose bodies may reuse the Human inline mention flow —
7181
+ * anything richer keeps the trailing chip row because the Markdown primitive
7182
+ * renders block-level documents that cannot interleave inline chips.
7183
+ */
7184
+ function isPlainTextBody(text) {
7185
+ return !(MARKDOWN_BLOCK_CONSTRUCT.test(text) || MARKDOWN_INLINE_CONSTRUCT.test(text));
7186
+ }
7187
+ const pad$1 = (value) => String(value).padStart(2, "0");
7188
+ /** Absolute local `YYYY-MM-DD HH:mm` label: the precise instant behind every shorter form. */
7189
+ function formatAbsoluteTime(occurredAt) {
7190
+ const at = new Date(occurredAt);
7191
+ if (Number.isNaN(at.getTime())) return "";
7192
+ return `${at.getFullYear()}-${pad$1(at.getMonth() + 1)}-${pad$1(at.getDate())} ${pad$1(at.getHours())}:${pad$1(at.getMinutes())}`;
7193
+ }
7194
+ /**
7195
+ * Wall-clock label for one Message instant: time within the current day,
7196
+ * month-day time within the year, full date otherwise.
7197
+ */
7198
+ function formatMessageTime(occurredAt, now = /* @__PURE__ */ new Date()) {
7199
+ const at = new Date(occurredAt);
7200
+ if (Number.isNaN(at.getTime())) return "";
7201
+ if (at.getFullYear() === now.getFullYear() && at.getMonth() === now.getMonth() && at.getDate() === now.getDate()) return `${pad$1(at.getHours())}:${pad$1(at.getMinutes())}`;
7202
+ const absolute = formatAbsoluteTime(occurredAt);
7203
+ return at.getFullYear() === now.getFullYear() ? absolute.slice(5) : absolute;
7204
+ }
7205
+ /**
7206
+ * Calendar days between two instants in the viewer's own zone, so "yesterday"
7207
+ * means yesterday locally rather than 24 hours earlier.
7208
+ */
7209
+ function calendarDayDelta(at, now) {
7210
+ const midnight = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
7211
+ return Math.round((midnight(now) - midnight(at)) / 864e5);
7212
+ }
7213
+ /**
7214
+ * Recency label for one Inbox row's newest fact, shared with the Channel feed's
7215
+ * entry line so the two agree about the same instant. Today is a bare clock time
7216
+ * — the reader is in today, and 「今天」 printed down every row spends the label's
7217
+ * first word on the one segment that never varies, while `HH:mm` alone still
7218
+ * reads as a clock because it is exactly one. The first day that is not today is
7219
+ * the fact the reader has to be told, so it keeps its word; everything older
7220
+ * keeps the Message date form, so the row and the Thread it opens agree.
7221
+ */
7222
+ function formatInboxTime(occurredAt, t, now = /* @__PURE__ */ new Date()) {
7223
+ const at = new Date(occurredAt);
7224
+ if (Number.isNaN(at.getTime())) return "";
7225
+ const days = calendarDayDelta(at, now);
7226
+ if (days === 0) return `${pad$1(at.getHours())}:${pad$1(at.getMinutes())}`;
7227
+ if (days === 1) return `${t("inboxTimeYesterday")} ${pad$1(at.getHours())}:${pad$1(at.getMinutes())}`;
7228
+ return formatMessageTime(occurredAt, now);
7229
+ }
7230
+ function formatActivity(activity, options) {
7231
+ const actor = options.actorName(activity.actor);
7232
+ if (activity.kind === "accept") return activity.completedClaimRefs !== void 0 && activity.completedClaimRefs.length > 0 ? options.t("activityAcceptedWithClaims", {
7233
+ actor,
7234
+ count: activity.completedClaimRefs.length
7235
+ }) : options.t("activityAccepted", { actor });
7236
+ if (activity.kind === "promote") return options.t("activityPromoted", { actor });
7237
+ if (activity.kind === "close") return options.t("activityClosed", { actor });
7238
+ if (activity.kind === "reopen") return options.t("activityReopened", { actor });
7239
+ const direction = "claimRef" in activity ? options.claims.find((claim) => claim.claimRef === activity.claimRef)?.direction ?? options.t("claims") : options.t("claims");
7240
+ if (activity.kind === "claim") return options.t("activityClaimed", {
7241
+ actor,
7242
+ direction
7126
7243
  });
7127
- (0, react.useLayoutEffect)(() => {
7128
- const input = inputRef.current;
7129
- if (input === null) return;
7130
- input.style.height = "auto";
7131
- input.style.height = `${Math.min(input.scrollHeight, 180)}px`;
7132
- }, [draft]);
7133
- (0, react.useEffect)(() => {
7134
- if (mention === void 0 || options.length === 0) {
7135
- setHighlight(0);
7136
- return;
7137
- }
7138
- setHighlight((current) => Math.min(current, options.length - 1));
7139
- }, [mention, options.length]);
7140
- (0, react.useLayoutEffect)(() => {
7141
- if (!menuOpen) return;
7142
- activeOptionRef.current?.scrollIntoView?.({ block: "nearest" });
7143
- }, [
7144
- menuOpen,
7145
- highlight,
7146
- activeOptionKey
7147
- ]);
7148
- (0, react.useEffect)(() => {
7149
- const active = document.activeElement;
7150
- if (active !== document.body && active?.closest("[aria-current=\"page\"]") === null) return;
7151
- inputRef.current?.focus({ preventScroll: true });
7152
- }, []);
7153
- (0, react.useEffect)(() => {
7154
- if (confirmation === void 0 || pending) return;
7155
- inputRef.current?.focus({ preventScroll: true });
7156
- }, [confirmation, pending]);
7157
- const pruneRecipients = (nextDraft) => {
7158
- if (containsAllMention(nextDraft)) return;
7159
- const knownMembers = new Map(members.map((status) => [status.member.memberId, status.member]));
7160
- const next = new Set([...recipients].filter((memberId) => {
7161
- const member = knownMembers.get(memberId);
7162
- return member !== void 0 && containsMention(nextDraft, member.handle);
7163
- }));
7164
- if (next.size !== recipients.size) drafts.writeRecipients(draftKey, next);
7165
- };
7166
- (0, react.useEffect)(() => {
7167
- if (members.length === 0) return;
7168
- pruneRecipients(draft);
7169
- }, [
7170
- draft,
7171
- recipients,
7172
- members
7173
- ]);
7174
- const updateMention = (nextDraft, caret) => {
7175
- const match = findMention(nextDraft, caret);
7176
- setMention(match);
7177
- if (match === void 0) setHighlight(0);
7178
- };
7179
- const onChange = (event) => {
7180
- const nextDraft = event.target.value;
7181
- drafts.writeDraft(draftKey, nextDraft);
7182
- onEdit?.();
7183
- pruneRecipients(nextDraft);
7184
- updateMention(nextDraft, event.target.selectionStart ?? nextDraft.length);
7185
- };
7186
- const commitMention = (nextDraft, nextCaret, nextRecipients) => {
7187
- drafts.writeDraft(draftKey, nextDraft);
7188
- drafts.writeRecipients(draftKey, nextRecipients);
7189
- onEdit?.();
7190
- setMention(void 0);
7191
- setHighlight(0);
7192
- requestAnimationFrame(() => {
7193
- const input = inputRef.current;
7194
- if (input === null) return;
7195
- input.focus({ preventScroll: true });
7196
- input.setSelectionRange(nextCaret, nextCaret);
7197
- });
7198
- };
7199
- const selectOption = (option) => {
7244
+ if (activity.kind === "done") return options.t("activityClaimDone", {
7245
+ actor,
7246
+ direction
7247
+ });
7248
+ if (activity.kind === "release") return options.t("activityClaimReleased", {
7249
+ actor,
7250
+ direction
7251
+ });
7252
+ if (activity.kind === "claims_released") return options.t("activityClaimsReleased", {
7253
+ actor,
7254
+ count: activity.claimRefs.length
7255
+ });
7256
+ throw new Error(`unknown Team Activity kind: ${activity.kind}`);
7257
+ }
7258
+ /** Remove the machine-facing `[attachment] <path>` prompt lines from a body before display. */
7259
+ function stripAttachmentLines(body) {
7260
+ return body.replaceAll(/^\[attachment\] .*$(\n)?/gm, "").replace(/\n+$/, "");
7261
+ }
7262
+ /** Whether one displayed Message body starts clamped behind the expand control. */
7263
+ function shouldClampMessage(displayBody) {
7264
+ return displayBody.length > 600;
7265
+ }
7266
+ /**
7267
+ * Decide how one Message body renders. Human input and plain-prose Agent
7268
+ * bodies stay literal, with structured mention chips inline where possible;
7269
+ * rich Agent Markdown keeps unmatched mentions and non-Task refs in the
7270
+ * trailing fallback row while the post-render pass handles Task refs at their
7271
+ * authored position. Surfaces without ref navigation render everything
7272
+ * literally and keep the full fallback row.
7273
+ */
7274
+ function planMessageBody(body, options) {
7275
+ const stripped = stripAttachmentLines(body);
7276
+ const displayBody = stripped === "" ? body : stripped;
7277
+ const richAgentBody = !options.human && !isPlainTextBody(displayBody);
7278
+ const inline = (options.human || isPlainTextBody(displayBody)) && options.mentionNames !== void 0 && options.mentionNames.length > 0 ? splitMentionNames(displayBody, options.mentionNames) : void 0;
7279
+ const fallbackNames = inline !== void 0 ? inline.unmatched : richAgentBody && options.canOpenRefs && options.mentionNames !== void 0 ? splitMentionNames(displayBody, options.mentionNames).unmatched : options.mentionNames ?? [];
7280
+ const refs = splitBrandedRefs(displayBody).flatMap((segment) => segment.ref === void 0 ? [] : [segment.ref]);
7281
+ return {
7282
+ displayBody,
7283
+ richAgentBody,
7284
+ render: inline !== void 0 ? "inline" : options.human || options.canOpenRefs && !richAgentBody && refs.length > 0 ? "literal" : "markdown",
7285
+ ...inline === void 0 ? {} : { inline },
7286
+ fallbackNames,
7287
+ fallbackRefs: richAgentBody && !options.canOpenRefs ? refs : [],
7288
+ taskRefs: options.canOpenRefs && !richAgentBody ? refs.filter((ref) => ref.startsWith("task:")).map((ref) => ref) : []
7289
+ };
7290
+ }
7291
+ //#endregion
7292
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/state-dot.module.css.mjs
7293
+ 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%}";
7294
+ const tagId$12 = "@wowyuarm/dsh-agent-team/state-dot.module.css";
7295
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$12) + "]") === null) {
7296
+ const tag = document.createElement("style");
7297
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7298
+ tag.dataset.pluginCss = tagId$12;
7299
+ tag.textContent = css$12;
7300
+ document.head.appendChild(tag);
7301
+ }
7302
+ var state_dot_module_css_default = { "quiet": "DalNWW_quiet" };
7303
+ //#endregion
7304
+ //#region src/client/TeamStateDot.tsx
7305
+ /**
7306
+ * Render the one shared Team status indicator. Native StateDot states pass
7307
+ * through; the quiet statuses mirror StateDot geometry locally so every
7308
+ * surface renders the same shape — todo a hollow ring (not started), quiet a
7309
+ * solid tertiary dot with the same 10% halo (closed, unavailable).
7310
+ */
7311
+ function TeamStateDot({ state, size = 10 }) {
7312
+ if (state === "todo" || state === "quiet") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7313
+ className: state_dot_module_css_default.quiet,
7314
+ "data-variant": state,
7315
+ style: {
7316
+ width: size,
7317
+ height: size
7318
+ },
7319
+ "aria-hidden": "true"
7320
+ });
7321
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
7322
+ state,
7323
+ size
7324
+ });
7325
+ }
7326
+ //#endregion
7327
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/presence.module.css.mjs
7328
+ const css$11 = ".-\\36 lQ-q_target{flex:0 0 14px;justify-content:center;align-items:center;display:inline-flex}";
7329
+ const tagId$11 = "@wowyuarm/dsh-agent-team/presence.module.css";
7330
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$11) + "]") === null) {
7331
+ const tag = document.createElement("style");
7332
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7333
+ tag.dataset.pluginCss = tagId$11;
7334
+ tag.textContent = css$11;
7335
+ document.head.appendChild(tag);
7336
+ }
7337
+ var presence_module_css_default = { "target": "-6lQ-q_target" };
7338
+ //#endregion
7339
+ //#region src/client/TeamPresenceDot.tsx
7340
+ function presenceLabel(status, t) {
7341
+ const label = status.presence === "available" ? t("statusAvailable") : status.presence === "working" ? t("statusWorking") : status.presence === "error" ? t("statusError") : t("statusUnavailable");
7342
+ return status.diagnostic === void 0 ? label : `${label}: ${diagnosticText(status)}`;
7343
+ }
7344
+ /** One line of human-readable diagnostic text: the reason, plus the refused artifact path when one was reported. */
7345
+ function diagnosticText(status) {
7346
+ const diagnostic = status.diagnostic;
7347
+ if (diagnostic === void 0) return "";
7348
+ return diagnostic.location === void 0 ? diagnostic.detail : `${diagnostic.detail} (${diagnostic.location.path})`;
7349
+ }
7350
+ /**
7351
+ * Whether the restart action can help an unavailable Member: it heals
7352
+ * transient and repairable failures, but not a transient rollover window
7353
+ * (which resolves on its own) or a refusal already proven non-remediable.
7354
+ */
7355
+ function restartOffered(status) {
7356
+ const diagnostic = status.diagnostic;
7357
+ if (diagnostic === void 0) return true;
7358
+ if (diagnostic.class === "rollover") return false;
7359
+ return !(diagnostic.class === "session-refused" && diagnostic.remediable === false);
7360
+ }
7361
+ /** Shared presence → indicator mapping for dots and avatar badges. */
7362
+ function presenceDotState(presence) {
7363
+ return presence === "available" ? "done" : presence === "working" ? "ongoing" : presence === "error" ? "error" : "quiet";
7364
+ }
7365
+ function TeamPresenceDot({ status, t }) {
7366
+ const label = presenceLabel(status, t);
7367
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
7368
+ label,
7369
+ delayMs: 300,
7370
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7371
+ className: presence_module_css_default.target,
7372
+ role: "img",
7373
+ "aria-label": label,
7374
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamStateDot, { state: presenceDotState(status.presence) })
7375
+ })
7376
+ });
7377
+ }
7378
+ //#endregion
7379
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/sidebar.module.css.mjs
7380
+ 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}";
7381
+ const tagId$10 = "@wowyuarm/dsh-agent-team/sidebar.module.css";
7382
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$10) + "]") === null) {
7383
+ const tag = document.createElement("style");
7384
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7385
+ tag.dataset.pluginCss = tagId$10;
7386
+ tag.textContent = css$10;
7387
+ document.head.appendChild(tag);
7388
+ }
7389
+ var sidebar_module_css_default = {
7390
+ "agentAvatar": "d0xfxa_agentAvatar",
7391
+ "agentAvatarBadge": "d0xfxa_agentAvatarBadge",
7392
+ "agentCopy": "d0xfxa_agentCopy",
7393
+ "agentList": "d0xfxa_agentList",
7394
+ "agentRow": "d0xfxa_agentRow",
7395
+ "agentSelect": "d0xfxa_agentSelect",
7396
+ "channelList": "d0xfxa_channelList",
7397
+ "channelName": "d0xfxa_channelName",
7398
+ "channelRow": "d0xfxa_channelRow",
7399
+ "channelSelect": "d0xfxa_channelSelect",
7400
+ "editChannelName": "d0xfxa_editChannelName",
7401
+ "editDescription": "d0xfxa_editDescription",
7402
+ "editHint": "d0xfxa_editHint",
7403
+ "editMemberList": "d0xfxa_editMemberList",
7404
+ "emptyState": "d0xfxa_emptyState",
7405
+ "error": "d0xfxa_error",
7406
+ "iconButton": "d0xfxa_iconButton",
7407
+ "inboxCard": "d0xfxa_inboxCard",
7408
+ "inboxCardLabel": "d0xfxa_inboxCardLabel",
7409
+ "inboxDot": "d0xfxa_inboxDot",
7410
+ "inboxMark": "d0xfxa_inboxMark",
7411
+ "menuHint": "d0xfxa_menuHint",
7412
+ "panel": "d0xfxa_panel",
7413
+ "railButton": "d0xfxa_railButton",
7414
+ "railWorkspace": "d0xfxa_railWorkspace",
7415
+ "retryError": "d0xfxa_retryError",
7416
+ "rowAlert": "d0xfxa_rowAlert",
7417
+ "rowError": "d0xfxa_rowError",
7418
+ "rowMenu": "d0xfxa_rowMenu",
7419
+ "rowMenuButton": "d0xfxa_rowMenuButton",
7420
+ "section": "d0xfxa_section",
7421
+ "sectionActions": "d0xfxa_sectionActions",
7422
+ "sectionChevron": "d0xfxa_sectionChevron",
7423
+ "sectionHeader": "d0xfxa_sectionHeader",
7424
+ "sectionTitle": "d0xfxa_sectionTitle",
7425
+ "sectionToggle": "d0xfxa_sectionToggle",
7426
+ "sidebarRowDragging": "d0xfxa_sidebarRowDragging",
7427
+ "sidebarRowDropAfter": "d0xfxa_sidebarRowDropAfter",
7428
+ "sidebarRowDropBefore": "d0xfxa_sidebarRowDropBefore",
7429
+ "textButton": "d0xfxa_textButton",
7430
+ "unavailableDot": "d0xfxa_unavailableDot",
7431
+ "workspaceBrowser": "d0xfxa_workspaceBrowser",
7432
+ "workspaceCopy": "d0xfxa_workspaceCopy",
7433
+ "workspaceIcon": "d0xfxa_workspaceIcon",
7434
+ "workspaceList": "d0xfxa_workspaceList",
7435
+ "workspaceRow": "d0xfxa_workspaceRow",
7436
+ "workspaceSection": "d0xfxa_workspaceSection"
7437
+ };
7438
+ //#endregion
7439
+ //#region src/client/TeamMemberAvatar.tsx
7440
+ /**
7441
+ * Sidebar Member avatar reusing the conversation identity language: the
7442
+ * deterministic member hue and handle initial, with the presence indicator
7443
+ * overlaid at the bottom-right so one glyph carries identity and state.
7444
+ */
7445
+ function TeamMemberAvatar({ status, t }) {
7446
+ const label = presenceLabel(status, t);
7447
+ const state = presenceDotState(status.presence);
7448
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
7449
+ label,
7450
+ delayMs: 300,
7451
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7452
+ className: sidebar_module_css_default.agentAvatar,
7453
+ style: { "--team-avatar-hue": memberHue(status.member.memberId) },
7454
+ role: "img",
7455
+ "aria-label": label,
7456
+ children: [status.member.handle.replace("@", "").slice(0, 1).toUpperCase(), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7457
+ className: sidebar_module_css_default.agentAvatarBadge,
7458
+ "aria-hidden": "true",
7459
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamStateDot, { state })
7460
+ })]
7461
+ })
7462
+ });
7463
+ }
7464
+ //#endregion
7465
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/member-row.module.css.mjs
7466
+ 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}}";
7467
+ const tagId$9 = "@wowyuarm/dsh-agent-team/member-row.module.css";
7468
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$9) + "]") === null) {
7469
+ const tag = document.createElement("style");
7470
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7471
+ tag.dataset.pluginCss = tagId$9;
7472
+ tag.textContent = css$9;
7473
+ document.head.appendChild(tag);
7474
+ }
7475
+ var member_row_module_css_default = {
7476
+ "action": "xnbzeW_action",
7477
+ "copy": "xnbzeW_copy",
7478
+ "error": "xnbzeW_error",
7479
+ "row": "xnbzeW_row"
7480
+ };
7481
+ //#endregion
7482
+ //#region src/client/TeamMemberRow.tsx
7483
+ /**
7484
+ * The one place a Member's identity is drawn: the presence-bearing avatar plus
7485
+ * the handle over its description. Read-only rosters, the rosters with a
7486
+ * membership action, and the sidebar Agent list all render this, so identity,
7487
+ * tone and truncation cannot drift between surfaces that show the same person.
7488
+ *
7489
+ * A fragment, not a row: each surface owns its own row element, hit target and
7490
+ * grid, and places this identity in that grid's first two tracks. The handle
7491
+ * spelling is the surface's call — rosters address Members the way the
7492
+ * composer does (`@handle`), the sidebar names them as the directory does.
7493
+ */
7494
+ function TeamMemberIdentity({ status, name, className, t }) {
7495
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberAvatar, {
7496
+ status,
7497
+ t
7498
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7499
+ className: className === void 0 ? member_row_module_css_default.copy : `${member_row_module_css_default.copy} ${className}`,
7500
+ 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 })]
7501
+ })] });
7502
+ }
7503
+ /**
7504
+ * The one roster row: identity, an optional membership action, and the row's
7505
+ * own failure line. The action is the row's only chrome, so the eye lands on
7506
+ * the handle first and on the action second. A read-only roster omits it and
7507
+ * the trailing track collapses, handing its width back to the description.
7508
+ */
7509
+ function TeamMemberRow({ status, action, error, className, t }) {
7510
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7511
+ className: className === void 0 ? member_row_module_css_default.row : `${member_row_module_css_default.row} ${className}`,
7512
+ "data-team-member-row": true,
7513
+ children: [
7514
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberIdentity, {
7515
+ status,
7516
+ t
7517
+ }),
7518
+ action !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
7519
+ size: "sm",
7520
+ variant: "outline",
7521
+ className: member_row_module_css_default.action,
7522
+ disabled: action.disabled === true,
7523
+ onClick: action.onSelect,
7524
+ children: action.label
7525
+ }),
7526
+ error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7527
+ className: member_row_module_css_default.error,
7528
+ role: "alert",
7529
+ children: error
7530
+ })
7531
+ ]
7532
+ });
7533
+ }
7534
+ //#endregion
7535
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/members.module.css.mjs
7536
+ 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)}}";
7537
+ const tagId$8 = "@wowyuarm/dsh-agent-team/members.module.css";
7538
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$8) + "]") === null) {
7539
+ const tag = document.createElement("style");
7540
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7541
+ tag.dataset.pluginCss = tagId$8;
7542
+ tag.textContent = css$8;
7543
+ document.head.appendChild(tag);
7544
+ }
7545
+ var members_module_css_default = {
7546
+ "body": "UkovOW_body",
7547
+ "content": "UkovOW_content",
7548
+ "error": "UkovOW_error",
7549
+ "group": "UkovOW_group",
7550
+ "member": "UkovOW_member",
7551
+ "state": "UkovOW_state"
7552
+ };
7553
+ //#endregion
7554
+ //#region src/client/TeamMembersAction.tsx
7555
+ function TeamMembersAction({ wide, loadMemberGroups, t }) {
7556
+ const [panelOpen, setPanelOpen] = (0, react.useState)(false);
7557
+ const [groups, setGroups] = (0, react.useState)([]);
7558
+ const [loading, setLoading] = (0, react.useState)(false);
7559
+ const [error, setError] = (0, react.useState)();
7560
+ const triggerRef = (0, react.useRef)(null);
7561
+ const contentRef = (0, react.useRef)(null);
7562
+ (0, react.useEffect)(() => {
7563
+ if (!panelOpen) return;
7564
+ queueMicrotask(() => {
7565
+ contentRef.current?.focus();
7566
+ });
7567
+ }, [panelOpen]);
7568
+ const openMembers = () => {
7569
+ setPanelOpen(true);
7570
+ setLoading(true);
7571
+ setError(void 0);
7572
+ loadMemberGroups().then(setGroups).catch((cause) => {
7573
+ setError(cause instanceof Error ? cause.message : String(cause));
7574
+ }).finally(() => {
7575
+ setLoading(false);
7576
+ });
7577
+ };
7578
+ const closeMembers = () => {
7579
+ setPanelOpen(false);
7580
+ queueMicrotask(() => {
7581
+ triggerRef.current?.focus();
7582
+ });
7583
+ };
7584
+ 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, {
7585
+ label: t("members"),
7586
+ delayMs: 500,
7587
+ disabled: wide,
7588
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
7589
+ ref: triggerRef,
7590
+ type: "button",
7591
+ className: wide ? team_module_css_default.settingsAction : `${team_module_css_default.settingsAction} ${team_module_css_default.rail}`,
7592
+ "aria-label": t("members"),
7593
+ "aria-haspopup": "dialog",
7594
+ onClick: openMembers,
7595
+ 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") })]
7596
+ })
7597
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
7598
+ open: panelOpen,
7599
+ onClose: closeMembers,
7600
+ title: t("members"),
7601
+ closeLabel: t("close"),
7602
+ contentClassName: members_module_css_default.body,
7603
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7604
+ ref: contentRef,
7605
+ className: members_module_css_default.content,
7606
+ tabIndex: -1,
7607
+ children: [
7608
+ loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7609
+ className: members_module_css_default.state,
7610
+ role: "status",
7611
+ children: t("loadingAgents")
7612
+ }),
7613
+ !loading && groups.length === 0 && error === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7614
+ className: members_module_css_default.state,
7615
+ children: t("emptyAgents")
7616
+ }),
7617
+ !loading && groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
7618
+ className: members_module_css_default.group,
7619
+ "aria-labelledby": `team-members-${group.workspaceId}`,
7620
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
7621
+ id: `team-members-${group.workspaceId}`,
7622
+ children: group.workspaceTitle
7623
+ }), group.members.map((status) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberRow, {
7624
+ status,
7625
+ className: members_module_css_default.member,
7626
+ t
7627
+ }, status.member.memberId))]
7628
+ }, group.workspaceId)),
7629
+ error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7630
+ className: members_module_css_default.error,
7631
+ role: "alert",
7632
+ children: error
7633
+ })
7634
+ ]
7635
+ })
7636
+ })] });
7637
+ }
7638
+ //#endregion
7639
+ //#region src/client/attachment-preview.ts
7640
+ /** Base64 one file payload in chunks so large uploads stay off the call-stack limit. */
7641
+ function bytesToBase64(bytes) {
7642
+ let binary = "";
7643
+ const chunk = 32768;
7644
+ for (let start = 0; start < bytes.length; start += chunk) binary += String.fromCharCode(...bytes.subarray(start, start + chunk));
7645
+ return btoa(binary);
7646
+ }
7647
+ /**
7648
+ * Thumbnail data URLs live in one session-wide cache: message lists re-render
7649
+ * often, and each miss costs a Host round-trip plus a base64 decode. Failed
7650
+ * loads (bytes already GC'd) are cached as `null` so the chip fallback is stable.
7651
+ */
7652
+ const dataUrlCache = /* @__PURE__ */ new Map();
7653
+ function cachedAttachmentDataUrl(attachmentId) {
7654
+ return dataUrlCache.get(attachmentId);
7655
+ }
7656
+ async function loadAttachmentDataUrl(getAttachment, attachment) {
7657
+ const cached = dataUrlCache.get(attachment.attachmentId);
7658
+ if (cached !== void 0) return cached;
7659
+ const result = await getAttachment({ attachmentId: attachment.attachmentId });
7660
+ const url = result.ok && attachment.mediaType.startsWith("image/") ? `data:${attachment.mediaType};base64,${result.value.bytesBase64}` : null;
7661
+ dataUrlCache.set(attachment.attachmentId, url);
7662
+ return url;
7663
+ }
7664
+ /** Human-readable byte size for attachment chips. */
7665
+ function formatByteSize(byteSize) {
7666
+ if (byteSize < 1024) return `${byteSize} B`;
7667
+ if (byteSize < 1024 * 1024) return `${(byteSize / 1024).toFixed(0)} KB`;
7668
+ return `${(byteSize / (1024 * 1024)).toFixed(1)} MB`;
7669
+ }
7670
+ //#endregion
7671
+ //#region src/client/requests.ts
7672
+ /** Fresh idempotency identity for one Client-initiated durable request. */
7673
+ const mintRequestId = () => crypto.randomUUID();
7674
+ /**
7675
+ * Upload composer files in order. One failure stops with the error text; the
7676
+ * caller keeps its chips so a retry uploads only the still-pending files.
7677
+ */
7678
+ const uploadComposerFiles = async (putAttachment, workspaceId, files) => {
7679
+ const attachmentIds = [];
7680
+ for (const file of files) {
7681
+ const uploaded = await putAttachment({
7682
+ requestId: mintRequestId(),
7683
+ workspaceId,
7684
+ name: file.name,
7685
+ mediaType: file.type === "" ? void 0 : file.type,
7686
+ bytesBase64: bytesToBase64(new Uint8Array(await file.arrayBuffer()))
7687
+ });
7688
+ if (!uploaded.ok) return {
7689
+ ok: false,
7690
+ error: uploaded.error.message
7691
+ };
7692
+ attachmentIds.push(uploaded.value.attachmentId);
7693
+ }
7694
+ return {
7695
+ ok: true,
7696
+ attachmentIds
7697
+ };
7698
+ };
7699
+ //#endregion
7700
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/composer.module.css.mjs
7701
+ 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}}";
7702
+ const tagId$7 = "@wowyuarm/dsh-agent-team/composer.module.css";
7703
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$7) + "]") === null) {
7704
+ const tag = document.createElement("style");
7705
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7706
+ tag.dataset.pluginCss = tagId$7;
7707
+ tag.textContent = css$7;
7708
+ document.head.appendChild(tag);
7709
+ }
7710
+ var composer_module_css_default = {
7711
+ "asTaskLabel": "x9jGQq_asTaskLabel",
7712
+ "asTaskPill": "x9jGQq_asTaskPill",
7713
+ "asTaskPillOn": "x9jGQq_asTaskPillOn",
7714
+ "attachButton": "x9jGQq_attachButton",
7715
+ "card": "x9jGQq_card",
7716
+ "confirmation": "x9jGQq_confirmation",
7717
+ "error": "x9jGQq_error",
7718
+ "fileChip": "x9jGQq_fileChip",
7719
+ "fileChipName": "x9jGQq_fileChipName",
7720
+ "fileChipRemove": "x9jGQq_fileChipRemove",
7721
+ "fileChipSize": "x9jGQq_fileChipSize",
7722
+ "fileChips": "x9jGQq_fileChips",
7723
+ "fileInput": "x9jGQq_fileInput",
7724
+ "imageChip": "x9jGQq_imageChip",
7725
+ "imageChipPreview": "x9jGQq_imageChipPreview",
7726
+ "inputArea": "x9jGQq_inputArea",
7727
+ "mentionAllDot": "x9jGQq_mentionAllDot",
7728
+ "mentionDescription": "x9jGQq_mentionDescription",
7729
+ "mentionMenu": "x9jGQq_mentionMenu",
7730
+ "mentionName": "x9jGQq_mentionName",
7731
+ "mentionOption": "x9jGQq_mentionOption",
7732
+ "notifyRow": "x9jGQq_notifyRow",
7733
+ "root": "x9jGQq_root",
7734
+ "sendButton": "x9jGQq_sendButton",
7735
+ "toolbar": "x9jGQq_toolbar"
7736
+ };
7737
+ //#endregion
7738
+ //#region src/client/TeamComposer.tsx
7739
+ function findMention(draft, caret) {
7740
+ const beforeCaret = draft.slice(0, caret);
7741
+ if (beforeCaret.length === 0 || /\s/u.test(beforeCaret.at(-1) ?? "")) return void 0;
7742
+ let tokenStart = beforeCaret.length;
7743
+ while (tokenStart > 0 && !/\s/u.test(beforeCaret[tokenStart - 1])) tokenStart -= 1;
7744
+ const at = beforeCaret.lastIndexOf("@");
7745
+ if (at < tokenStart) return void 0;
7746
+ if (at > 0 && /[\p{L}\p{N}_]/u.test(beforeCaret[at - 1])) return void 0;
7747
+ return {
7748
+ start: at,
7749
+ end: caret,
7750
+ query: beforeCaret.slice(at + 1)
7751
+ };
7752
+ }
7753
+ function mentionCandidates(members, query) {
7754
+ const normalized = query.toLocaleLowerCase();
7755
+ return members.filter((status) => status.presence !== "unavailable" && status.member.state !== "inactive" && status.member.state !== "archived" && status.member.handle.toLocaleLowerCase().startsWith(normalized));
7756
+ }
7757
+ /** Thread followers rank first: mentioning them delivers directly, while a non-follower enters the two-send invite flow. */
7758
+ function rankMentionCandidates(candidates, followers) {
7759
+ if (followers === void 0 || followers.size === 0) return candidates;
7760
+ return [...candidates].sort((left, right) => Number(followers.has(right.member.memberId)) - Number(followers.has(left.member.memberId)));
7761
+ }
7762
+ /** One object URL per draft file; revoked when the draft is removed. */
7763
+ const draftPreviewUrls = /* @__PURE__ */ new WeakMap();
7764
+ function draftPreviewUrl(file) {
7765
+ if (!file.type.startsWith("image/")) return void 0;
7766
+ let url = draftPreviewUrls.get(file);
7767
+ if (url === void 0) {
7768
+ url = URL.createObjectURL(file);
7769
+ draftPreviewUrls.set(file, url);
7770
+ }
7771
+ return url;
7772
+ }
7773
+ function TeamComposer({ members, followerMemberIds, drafts, draftKey, pending, confirmation, error, onEdit, onSubmit, placeholder, pendingFiles, onFilesChange, asTask, onAsTaskChange, t }) {
7774
+ const inputRef = (0, react.useRef)(null);
7775
+ const fileInputRef = (0, react.useRef)(null);
7776
+ const rootRef = (0, react.useRef)(null);
7777
+ const menuRef = (0, react.useRef)(null);
7778
+ const activeOptionRef = (0, react.useRef)(null);
7779
+ const composingRef = (0, react.useRef)(false);
7780
+ const { draft, recipients } = (0, react.useSyncExternalStore)(drafts.subscribe, () => drafts.getSnapshot(draftKey));
7781
+ const [mention, setMention] = (0, react.useState)();
7782
+ const [highlight, setHighlight] = (0, react.useState)(0);
7783
+ const memberCandidates = mention === void 0 ? [] : rankMentionCandidates(mentionCandidates(members, mention.query), followerMemberIds);
7784
+ const options = mention !== void 0 && "all".startsWith(mention.query.toLocaleLowerCase()) ? [{ kind: "all" }, ...memberCandidates.map((status) => ({
7785
+ kind: "member",
7786
+ status
7787
+ }))] : memberCandidates.map((status) => ({
7788
+ kind: "member",
7789
+ status
7790
+ }));
7791
+ const menuOpen = mention !== void 0 && options.length > 0;
7792
+ const activeOption = options[highlight];
7793
+ const activeOptionKey = activeOption === void 0 ? void 0 : activeOption.kind === "all" ? "all" : activeOption.status.member.memberId;
7794
+ const allCount = allMentionMembers(members).length;
7795
+ const listId = "team-mention-suggestions";
7796
+ const menuMaxHeight = (0, _deepseek_ai_dsh_client_ui_primitives.useAnchoredMaxHeight)(menuRef, 320, menuOpen ? draft : null);
7797
+ (0, _deepseek_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer)(rootRef, menuOpen, (open) => {
7798
+ if (!open) setMention(void 0);
7799
+ });
7800
+ (0, react.useLayoutEffect)(() => {
7801
+ const input = inputRef.current;
7802
+ if (input === null) return;
7803
+ input.style.height = "auto";
7804
+ input.style.height = `${Math.min(input.scrollHeight, 180)}px`;
7805
+ }, [draft]);
7806
+ (0, react.useEffect)(() => {
7807
+ if (mention === void 0 || options.length === 0) {
7808
+ setHighlight(0);
7809
+ return;
7810
+ }
7811
+ setHighlight((current) => Math.min(current, options.length - 1));
7812
+ }, [mention, options.length]);
7813
+ (0, react.useLayoutEffect)(() => {
7814
+ if (!menuOpen) return;
7815
+ activeOptionRef.current?.scrollIntoView?.({ block: "nearest" });
7816
+ }, [
7817
+ menuOpen,
7818
+ highlight,
7819
+ activeOptionKey
7820
+ ]);
7821
+ (0, react.useEffect)(() => {
7822
+ const active = document.activeElement;
7823
+ if (active !== document.body && active?.closest("[aria-current=\"page\"]") === null) return;
7824
+ inputRef.current?.focus({ preventScroll: true });
7825
+ }, []);
7826
+ (0, react.useEffect)(() => {
7827
+ if (confirmation === void 0 || pending) return;
7828
+ inputRef.current?.focus({ preventScroll: true });
7829
+ }, [confirmation, pending]);
7830
+ const memberHandles = new Map(members.map((status) => [status.member.memberId, status.member.handle]));
7831
+ const pruneRecipients = (nextDraft) => {
7832
+ if (containsAllMention(nextDraft)) return;
7833
+ const next = new Set([...recipients].filter((memberId) => {
7834
+ const handle = memberHandles.get(memberId);
7835
+ return handle !== void 0 && containsMention(nextDraft, handle);
7836
+ }));
7837
+ if (next.size !== recipients.size) drafts.writeRecipients(draftKey, next);
7838
+ };
7839
+ (0, react.useEffect)(() => {
7840
+ if (members.length === 0) return;
7841
+ pruneRecipients(draft);
7842
+ }, [
7843
+ draft,
7844
+ recipients,
7845
+ members
7846
+ ]);
7847
+ const notifiedIds = [...new Set([...recipients, ...mentionedMemberIds(draft, members)])].sort();
7848
+ const updateMention = (nextDraft, caret) => {
7849
+ const match = findMention(nextDraft, caret);
7850
+ setMention(match);
7851
+ if (match === void 0) setHighlight(0);
7852
+ };
7853
+ const onChange = (event) => {
7854
+ const nextDraft = event.target.value;
7855
+ drafts.writeDraft(draftKey, nextDraft);
7856
+ onEdit?.();
7857
+ pruneRecipients(nextDraft);
7858
+ updateMention(nextDraft, event.target.selectionStart ?? nextDraft.length);
7859
+ };
7860
+ const commitMention = (nextDraft, nextCaret, nextRecipients) => {
7861
+ drafts.writeDraft(draftKey, nextDraft);
7862
+ drafts.writeRecipients(draftKey, nextRecipients);
7863
+ onEdit?.();
7864
+ setMention(void 0);
7865
+ setHighlight(0);
7866
+ requestAnimationFrame(() => {
7867
+ const input = inputRef.current;
7868
+ if (input === null) return;
7869
+ input.focus({ preventScroll: true });
7870
+ input.setSelectionRange(nextCaret, nextCaret);
7871
+ });
7872
+ };
7873
+ const selectOption = (option) => {
7200
7874
  if (mention === void 0) return;
7201
7875
  if (option.kind === "all") {
7202
7876
  const nextDraft = `${draft.slice(0, mention.start)}@all ${draft.slice(mention.end)}`;
@@ -7359,10 +8033,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7359
8033
  }
7360
8034
  })]
7361
8035
  }),
7362
- recipients.size > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8036
+ notifiedIds.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7363
8037
  className: composer_module_css_default.notifyRow,
7364
8038
  "data-team-notify": true,
7365
- children: t("composerNotify", { ids: [...recipients].sort().map((memberId) => `@${members.find((candidate) => candidate.member.memberId === memberId)?.member.handle ?? memberId}`).join(", ") })
8039
+ children: t("composerNotify", { ids: notifiedIds.map((memberId) => `@${memberHandles.get(memberId) ?? memberId}`).join(", ") })
7366
8040
  }),
7367
8041
  onFilesChange !== void 0 && pendingFiles !== void 0 && pendingFiles.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
7368
8042
  className: composer_module_css_default.fileChips,
@@ -7436,389 +8110,138 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7436
8110
  className: asTask === true ? `${composer_module_css_default.asTaskPill} ${composer_module_css_default.asTaskPillOn}` : composer_module_css_default.asTaskPill,
7437
8111
  "aria-label": t("asTask"),
7438
8112
  "aria-pressed": asTask === true,
7439
- title: t("asTask"),
7440
- disabled: pending,
7441
- onClick: () => {
7442
- onAsTaskChange(asTask !== true);
7443
- },
7444
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChecklistOutline14, { size: 14 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7445
- className: composer_module_css_default.asTaskLabel,
7446
- children: t("asTask")
7447
- })]
7448
- }),
7449
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7450
- type: "submit",
7451
- className: composer_module_css_default.sendButton,
7452
- "aria-label": pending ? t("sendingMessage") : t("sendMessage"),
7453
- disabled: pending || draft.trim() === "",
7454
- onMouseDown: (event) => {
7455
- event.preventDefault();
7456
- inputRef.current?.focus({ preventScroll: true });
7457
- },
7458
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSendOutline16, { size: 16 })
7459
- })
7460
- ]
7461
- })
7462
- ]
7463
- }), error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7464
- className: composer_module_css_default.error,
7465
- role: "alert",
7466
- children: error
7467
- })]
7468
- });
7469
- }
7470
- //#endregion
7471
- //#region src/client/task-refs.ts
7472
- const resolved = /* @__PURE__ */ new Map();
7473
- const pending = /* @__PURE__ */ new Set();
7474
- /** Refs the Host did not recognize; never re-queried (no retry loops). */
7475
- const unresolvable = /* @__PURE__ */ new Set();
7476
- const listeners$2 = /* @__PURE__ */ new Set();
7477
- let version = 0;
7478
- const emit = () => {
7479
- version += 1;
7480
- for (const listener of listeners$2) listener();
7481
- };
7482
- const subscribe = (listener) => {
7483
- listeners$2.add(listener);
7484
- return () => {
7485
- listeners$2.delete(listener);
7486
- };
7487
- };
7488
- /** Stable snapshot token; the map is read directly after this changes. */
7489
- const getSnapshot = () => version;
7490
- /** React binding: re-renders the caller when any ref resolution lands. */
7491
- const useResolvedTaskRefVersion = () => (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
7492
- const cachedResolvedTaskRef = (taskRef) => resolved.get(taskRef);
7493
- /** Store one resolution (click path) and wake every rendered link. */
7494
- const rememberResolvedTaskRef = (entry) => {
7495
- resolved.set(entry.taskRef, entry);
7496
- pending.delete(entry.taskRef);
7497
- emit();
7498
- };
7499
- /** Compare refs by branded prefix plus hyphen-stripped UUID, so abbreviated spellings line up with their full form. */
7500
- function refKeyOf(ref) {
7501
- return ref.toLowerCase().replaceAll("-", "");
7502
- }
7503
- /**
7504
- * Click-path Host lookup: remember every resolved entry and hand them back
7505
- * for immediate navigation. The Host keeps `resolved` in the same order as
7506
- * the input `taskRefs` (one entry per resolvable input, unknowns omitted);
7507
- * the pairing walk below relies on that contract, so it must be preserved
7508
- * together with this implementation.
7509
- */
7510
- const hostTaskRefLookup = (resolveTaskRefs, workspaceId) => async (taskRefs) => {
7511
- const result = await resolveTaskRefs({
7512
- workspaceId,
7513
- taskRefs
7514
- });
7515
- if (!result.ok) return [];
7516
- const entries = result.value.resolved;
7517
- let entryIndex = 0;
7518
- for (const requested of taskRefs) {
7519
- const entry = entries[entryIndex];
7520
- if (entry === void 0 || !refKeyOf(entry.taskRef).startsWith(refKeyOf(requested))) continue;
7521
- if (entry.taskRef !== requested) rememberResolvedTaskRef({
7522
- ...entry,
7523
- taskRef: requested
7524
- });
7525
- rememberResolvedTaskRef(entry);
7526
- entryIndex += 1;
7527
- }
7528
- return entries;
7529
- };
7530
- /** Resolve one Task ref through the Host and jump to its home Channel Thread. */
7531
- const jumpToTaskThread = (resolveTaskRefs, workspaceId, taskRef, selectThread) => {
7532
- resolveTaskRefs({
7533
- workspaceId,
7534
- taskRefs: [taskRef]
7535
- }).then((result) => {
7536
- if (!result.ok) return;
7537
- const hit = result.value.resolved[0];
7538
- if (hit !== void 0) selectThread(hit.threadRef, hit.channelRef, hit.taskRef, hit.taskNumber);
8113
+ title: t("asTask"),
8114
+ disabled: pending,
8115
+ onClick: () => {
8116
+ onAsTaskChange(asTask !== true);
8117
+ },
8118
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChecklistOutline14, { size: 14 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8119
+ className: composer_module_css_default.asTaskLabel,
8120
+ children: t("asTask")
8121
+ })]
8122
+ }),
8123
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8124
+ type: "submit",
8125
+ className: composer_module_css_default.sendButton,
8126
+ "aria-label": pending ? t("sendingMessage") : t("sendMessage"),
8127
+ disabled: pending || draft.trim() === "",
8128
+ onMouseDown: (event) => {
8129
+ event.preventDefault();
8130
+ inputRef.current?.focus({ preventScroll: true });
8131
+ },
8132
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSendOutline16, { size: 16 })
8133
+ })
8134
+ ]
8135
+ })
8136
+ ]
8137
+ }), error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8138
+ className: composer_module_css_default.error,
8139
+ role: "alert",
8140
+ children: error
8141
+ })]
7539
8142
  });
7540
- };
7541
- /**
7542
- * Batch-resolve unknown refs through the Host lookup. Concurrent callers
7543
- * deduplicate through the pending set; failures just clear the pending mark
7544
- * so a later interaction can retry.
7545
- */
7546
- const resolveUnknownTaskRefs = async (refs, lookup) => {
7547
- const missing = refs.filter((taskRef) => !resolved.has(taskRef) && !pending.has(taskRef) && !unresolvable.has(taskRef));
7548
- if (missing.length === 0) return;
7549
- for (const taskRef of missing) pending.add(taskRef);
7550
- try {
7551
- const entries = await lookup(missing);
7552
- for (const entry of entries) {
7553
- resolved.set(entry.taskRef, entry);
7554
- pending.delete(entry.taskRef);
7555
- }
7556
- for (const taskRef of missing) if (!resolved.has(taskRef)) unresolvable.add(taskRef);
7557
- if (entries.length > 0) emit();
7558
- } finally {
7559
- for (const taskRef of missing) pending.delete(taskRef);
7560
- }
7561
- };
7562
- //#endregion
7563
- //#region src/client/team-formatters.ts
7564
- function formatTaskStatus(status, t) {
7565
- return t({
7566
- todo: "taskStatusTodo",
7567
- in_progress: "taskStatusInProgress",
7568
- in_review: "taskStatusInReview",
7569
- done: "taskStatusDone",
7570
- closed: "taskStatusClosed"
7571
- }[status]);
7572
- }
7573
- function formatClaimState(state, t) {
7574
- return t({
7575
- active: "claimStateActive",
7576
- done: "claimStateDone",
7577
- released: "claimStateReleased"
7578
- }[state]);
7579
- }
7580
- /**
7581
- * Status indicator for a Task status, the dot every Task surface renders.
7582
- * Active states map to StateDot variants; every status renders a dot so they
7583
- * share one shape language — todo is a hollow ring (not started), closed a
7584
- * quiet gray dot (archived).
7585
- */
7586
- function taskStatusDot(status) {
7587
- return {
7588
- todo: "todo",
7589
- in_progress: "ongoing",
7590
- in_review: "warning",
7591
- done: "done",
7592
- closed: "quiet"
7593
- }[status];
7594
- }
7595
- /** One-line title snippet derived from the Task's root Message body. */
7596
- function formatTaskTitle(body) {
7597
- const firstLine = body.split("\n", 1)[0]?.trim() ?? "";
7598
- return firstLine.length > 120 ? `${firstLine.slice(0, 119)}…` : firstLine;
7599
- }
7600
- /** Deterministic avatar hue for one Member identity; stable across sessions and themes. */
7601
- function memberHue(memberId) {
7602
- let hash = 0;
7603
- for (let index = 0; index < memberId.length; index += 1) hash = (hash * 31 + memberId.charCodeAt(index)) % 360;
7604
- return hash;
7605
- }
7606
- const BRANDED_REF_PATTERN = /\b(task|channel|thread):{1,2}[0-9a-f]{6,}(?:-[0-9a-f]{1,})*\b/gi;
7607
- /**
7608
- * Canonical form of one matched ref: models occasionally double the colon or
7609
- * uppercase the UUID when citing a ref in prose, while Host lookups and
7610
- * navigation only accept the lowercase single-colon ref the ledger mints.
7611
- */
7612
- function canonicalBrandedRef(match) {
7613
- return match.replace("::", ":").toLowerCase();
7614
- }
7615
- /**
7616
- * Split a literal text run into plain and branded-ref segments. The pattern
7617
- * anchors on the fixed ref prefixes plus a UUID shape (full or abbreviated),
7618
- * so ordinary prose containing a colon never linkifies; a doubled colon from
7619
- * model output is tolerated. Segment refs are always canonical, so resolution
7620
- * and navigation work regardless of how the ref was spelled; text without any
7621
- * ref comes back as one untouched segment.
7622
- */
7623
- function splitBrandedRefs(text) {
7624
- const segments = [];
7625
- let cursor = 0;
7626
- for (const match of text.matchAll(BRANDED_REF_PATTERN)) {
7627
- const start = match.index ?? 0;
7628
- if (start > cursor) segments.push({ text: text.slice(cursor, start) });
7629
- segments.push({
7630
- text: match[0],
7631
- ref: canonicalBrandedRef(match[0])
7632
- });
7633
- cursor = start + match[0].length;
7634
- }
7635
- if (cursor < text.length) segments.push({ text: text.slice(cursor) });
7636
- return segments;
7637
- }
7638
- /**
7639
- * Whether one string's whole content is exactly one branded ref. A code span
7640
- * like this is the model styling a ref as an identifier, not publishing code,
7641
- * so the Markdown pass may linkify it; anything larger stays literal.
7642
- */
7643
- function isSingleBrandedRef(text) {
7644
- const trimmed = text.trim();
7645
- if (trimmed === "") return false;
7646
- const matches = [...trimmed.matchAll(BRANDED_REF_PATTERN)];
7647
- return matches.length === 1 && matches[0][0] === trimmed;
7648
- }
7649
- function escapeRegExp(value) {
7650
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7651
8143
  }
7652
- /**
7653
- * Locate one Message's structured mention names inside its literal body. A
7654
- * name matches case-insensitively with an optional leading '@' on Unicode word
7655
- * boundaries, and longer names win at the same position. Mention segments
7656
- * render the canonical `@Handle`; names absent from the body come back
7657
- * unmatched so the consumer can append them as a fallback chip row.
7658
- */
7659
- function splitMentionNames(text, names) {
7660
- if (names.length === 0) return {
7661
- segments: [{
7662
- text,
7663
- mention: false
7664
- }],
7665
- unmatched: []
7666
- };
7667
- const ordered = [...names].sort((left, right) => right.length - left.length);
7668
- const pattern = new RegExp(`(?<![\\p{L}\\p{N}_@])@?(?:${ordered.map((name) => `(${escapeRegExp(name)})`).join("|")})(?=$|[^\\p{L}\\p{N}_])`, "giu");
7669
- const segments = [];
7670
- const matched = /* @__PURE__ */ new Set();
7671
- let cursor = 0;
7672
- for (const match of text.matchAll(pattern)) {
7673
- const groupIndex = match.findIndex((group, index) => index >= 1 && group !== void 0);
7674
- if (groupIndex < 1) continue;
7675
- if (match.index > cursor) segments.push({
7676
- text: text.slice(cursor, match.index),
7677
- mention: false
7678
- });
7679
- const name = ordered[groupIndex - 1];
7680
- segments.push({
7681
- text: `@${name}`,
7682
- mention: true,
7683
- name
7684
- });
7685
- matched.add(name.toLowerCase());
7686
- cursor = match.index + match[0].length;
7687
- }
7688
- if (cursor < text.length) segments.push({
7689
- text: text.slice(cursor),
7690
- mention: false
7691
- });
7692
- return {
7693
- segments,
7694
- unmatched: names.filter((name) => !matched.has(name.toLowerCase()))
8144
+ //#endregion
8145
+ //#region src/client/task-refs.ts
8146
+ const resolved = /* @__PURE__ */ new Map();
8147
+ const pending = /* @__PURE__ */ new Set();
8148
+ /** Refs the Host did not recognize; never re-queried (no retry loops). */
8149
+ const unresolvable = /* @__PURE__ */ new Set();
8150
+ const listeners$2 = /* @__PURE__ */ new Set();
8151
+ let version = 0;
8152
+ const emit = () => {
8153
+ version += 1;
8154
+ for (const listener of listeners$2) listener();
8155
+ };
8156
+ const subscribe = (listener) => {
8157
+ listeners$2.add(listener);
8158
+ return () => {
8159
+ listeners$2.delete(listener);
7695
8160
  };
7696
- }
7697
- /** Canonical chip handles for one Message's structured mention refs. */
7698
- function mentionNamesOf(mentions, handles) {
7699
- return mentions.map((memberId) => memberId === "member:human" ? "human" : handles.get(memberId)).filter((name) => name !== void 0);
7700
- }
7701
- const MARKDOWN_BLOCK_CONSTRUCT = /(^|\n)[ \t]{0,3}(?:#{1,6}[ \t]|>[ \t]|[-*+][ \t]|\d+[.)][ \t])|^[ \t]*\|.+\|/m;
7702
- const MARKDOWN_INLINE_CONSTRUCT = /[`*_[\]!]|~~~|```/;
7703
- /**
7704
- * Whether an Agent body survives literal rendering unchanged: no fences,
7705
- * inline code, emphasis markers, links, images, tables, or block constructs.
7706
- * Only such plain-prose bodies may reuse the Human inline mention flow —
7707
- * anything richer keeps the trailing chip row because the Markdown primitive
7708
- * renders block-level documents that cannot interleave inline chips.
7709
- */
7710
- function isPlainTextBody(text) {
7711
- return !(MARKDOWN_BLOCK_CONSTRUCT.test(text) || MARKDOWN_INLINE_CONSTRUCT.test(text));
7712
- }
7713
- const pad$1 = (value) => String(value).padStart(2, "0");
7714
- /** Absolute local `YYYY-MM-DD HH:mm` label: the precise instant behind every shorter form. */
7715
- function formatAbsoluteTime(occurredAt) {
7716
- const at = new Date(occurredAt);
7717
- if (Number.isNaN(at.getTime())) return "";
7718
- return `${at.getFullYear()}-${pad$1(at.getMonth() + 1)}-${pad$1(at.getDate())} ${pad$1(at.getHours())}:${pad$1(at.getMinutes())}`;
7719
- }
7720
- /**
7721
- * Wall-clock label for one Message instant: time within the current day,
7722
- * month-day time within the year, full date otherwise.
7723
- */
7724
- function formatMessageTime(occurredAt, now = /* @__PURE__ */ new Date()) {
7725
- const at = new Date(occurredAt);
7726
- if (Number.isNaN(at.getTime())) return "";
7727
- if (at.getFullYear() === now.getFullYear() && at.getMonth() === now.getMonth() && at.getDate() === now.getDate()) return `${pad$1(at.getHours())}:${pad$1(at.getMinutes())}`;
7728
- const absolute = formatAbsoluteTime(occurredAt);
7729
- return at.getFullYear() === now.getFullYear() ? absolute.slice(5) : absolute;
7730
- }
7731
- /**
7732
- * Calendar days between two instants in the viewer's own zone, so "yesterday"
7733
- * means yesterday locally rather than 24 hours earlier.
7734
- */
7735
- function calendarDayDelta(at, now) {
7736
- const midnight = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
7737
- return Math.round((midnight(now) - midnight(at)) / 864e5);
7738
- }
7739
- /**
7740
- * Queue label for one Inbox row's newest mention. The mention queue scans by
7741
- * recency, so the two days a reader reasons about by name are named ("今天" /
7742
- * "昨天") while everything older keeps the Message date form, so the row and
7743
- * the Thread it opens agree about the same instant.
7744
- */
7745
- function formatInboxTime(occurredAt, t, now = /* @__PURE__ */ new Date()) {
7746
- const at = new Date(occurredAt);
7747
- if (Number.isNaN(at.getTime())) return "";
7748
- const days = calendarDayDelta(at, now);
7749
- if (days === 0 || days === 1) return `${t(days === 0 ? "inboxTimeToday" : "inboxTimeYesterday")} ${pad$1(at.getHours())}:${pad$1(at.getMinutes())}`;
7750
- return formatMessageTime(occurredAt, now);
7751
- }
7752
- function formatActivity(activity, options) {
7753
- const actor = options.actorName(activity.actor);
7754
- if (activity.kind === "accept") return activity.completedClaimRefs !== void 0 && activity.completedClaimRefs.length > 0 ? options.t("activityAcceptedWithClaims", {
7755
- actor,
7756
- count: activity.completedClaimRefs.length
7757
- }) : options.t("activityAccepted", { actor });
7758
- if (activity.kind === "promote") return options.t("activityPromoted", { actor });
7759
- if (activity.kind === "close") return options.t("activityClosed", { actor });
7760
- if (activity.kind === "reopen") return options.t("activityReopened", { actor });
7761
- const direction = "claimRef" in activity ? options.claims.find((claim) => claim.claimRef === activity.claimRef)?.direction ?? options.t("claims") : options.t("claims");
7762
- if (activity.kind === "claim") return options.t("activityClaimed", {
7763
- actor,
7764
- direction
7765
- });
7766
- if (activity.kind === "done") return options.t("activityClaimDone", {
7767
- actor,
7768
- direction
7769
- });
7770
- if (activity.kind === "release") return options.t("activityClaimReleased", {
7771
- actor,
7772
- direction
8161
+ };
8162
+ /** Stable snapshot token; the map is read directly after this changes. */
8163
+ const getSnapshot = () => version;
8164
+ /** React binding: re-renders the caller when any ref resolution lands. */
8165
+ const useResolvedTaskRefVersion = () => (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
8166
+ const cachedResolvedTaskRef = (taskRef) => resolved.get(taskRef);
8167
+ /** Store one resolution (click path) and wake every rendered link. */
8168
+ const rememberResolvedTaskRef = (entry) => {
8169
+ resolved.set(entry.taskRef, entry);
8170
+ pending.delete(entry.taskRef);
8171
+ emit();
8172
+ };
8173
+ /** Compare refs by branded prefix plus hyphen-stripped UUID, so abbreviated spellings line up with their full form. */
8174
+ function refKeyOf(ref) {
8175
+ return ref.toLowerCase().replaceAll("-", "");
8176
+ }
8177
+ /**
8178
+ * Click-path Host lookup: remember every resolved entry and hand them back
8179
+ * for immediate navigation. The Host keeps `resolved` in the same order as
8180
+ * the input `taskRefs` (one entry per resolvable input, unknowns omitted);
8181
+ * the pairing walk below relies on that contract, so it must be preserved
8182
+ * together with this implementation.
8183
+ */
8184
+ const hostTaskRefLookup = (resolveTaskRefs, workspaceId) => async (taskRefs) => {
8185
+ const result = await resolveTaskRefs({
8186
+ workspaceId,
8187
+ taskRefs
7773
8188
  });
7774
- if (activity.kind === "claims_released") return options.t("activityClaimsReleased", {
7775
- actor,
7776
- count: activity.claimRefs.length
8189
+ if (!result.ok) return [];
8190
+ const entries = result.value.resolved;
8191
+ let entryIndex = 0;
8192
+ for (const requested of taskRefs) {
8193
+ const entry = entries[entryIndex];
8194
+ if (entry === void 0 || !refKeyOf(entry.taskRef).startsWith(refKeyOf(requested))) continue;
8195
+ if (entry.taskRef !== requested) rememberResolvedTaskRef({
8196
+ ...entry,
8197
+ taskRef: requested
8198
+ });
8199
+ rememberResolvedTaskRef(entry);
8200
+ entryIndex += 1;
8201
+ }
8202
+ return entries;
8203
+ };
8204
+ /** Resolve one Task ref through the Host and jump to its home Channel Thread. */
8205
+ const jumpToTaskThread = (resolveTaskRefs, workspaceId, taskRef, selectThread) => {
8206
+ resolveTaskRefs({
8207
+ workspaceId,
8208
+ taskRefs: [taskRef]
8209
+ }).then((result) => {
8210
+ if (!result.ok) return;
8211
+ const hit = result.value.resolved[0];
8212
+ if (hit !== void 0) selectThread(hit.threadRef, hit.channelRef, hit.taskRef, hit.taskNumber);
7777
8213
  });
7778
- throw new Error(`unknown Team Activity kind: ${activity.kind}`);
7779
- }
7780
- /** Remove the machine-facing `[attachment] <path>` prompt lines from a body before display. */
7781
- function stripAttachmentLines(body) {
7782
- return body.replaceAll(/^\[attachment\] .*$(\n)?/gm, "").replace(/\n+$/, "");
7783
- }
7784
- /** Whether one displayed Message body starts clamped behind the expand control. */
7785
- function shouldClampMessage(displayBody) {
7786
- return displayBody.length > 600;
7787
- }
8214
+ };
7788
8215
  /**
7789
- * Decide how one Message body renders. Human input and plain-prose Agent
7790
- * bodies stay literal, with structured mention chips inline where possible;
7791
- * rich Agent Markdown keeps unmatched mentions and non-Task refs in the
7792
- * trailing fallback row while the post-render pass handles Task refs at their
7793
- * authored position. Surfaces without ref navigation render everything
7794
- * literally and keep the full fallback row.
8216
+ * Batch-resolve unknown refs through the Host lookup. Concurrent callers
8217
+ * deduplicate through the pending set; failures just clear the pending mark
8218
+ * so a later interaction can retry.
7795
8219
  */
7796
- function planMessageBody(body, options) {
7797
- const stripped = stripAttachmentLines(body);
7798
- const displayBody = stripped === "" ? body : stripped;
7799
- const richAgentBody = !options.human && !isPlainTextBody(displayBody);
7800
- const inline = (options.human || isPlainTextBody(displayBody)) && options.mentionNames !== void 0 && options.mentionNames.length > 0 ? splitMentionNames(displayBody, options.mentionNames) : void 0;
7801
- const fallbackNames = inline !== void 0 ? inline.unmatched : richAgentBody && options.canOpenRefs && options.mentionNames !== void 0 ? splitMentionNames(displayBody, options.mentionNames).unmatched : options.mentionNames ?? [];
7802
- const refs = splitBrandedRefs(displayBody).flatMap((segment) => segment.ref === void 0 ? [] : [segment.ref]);
7803
- return {
7804
- displayBody,
7805
- richAgentBody,
7806
- render: inline !== void 0 ? "inline" : options.human || options.canOpenRefs && !richAgentBody && refs.length > 0 ? "literal" : "markdown",
7807
- ...inline === void 0 ? {} : { inline },
7808
- fallbackNames,
7809
- fallbackRefs: richAgentBody && !options.canOpenRefs ? refs : [],
7810
- taskRefs: options.canOpenRefs && !richAgentBody ? refs.filter((ref) => ref.startsWith("task:")).map((ref) => ref) : []
7811
- };
7812
- }
8220
+ const resolveUnknownTaskRefs = async (refs, lookup) => {
8221
+ const missing = refs.filter((taskRef) => !resolved.has(taskRef) && !pending.has(taskRef) && !unresolvable.has(taskRef));
8222
+ if (missing.length === 0) return;
8223
+ for (const taskRef of missing) pending.add(taskRef);
8224
+ try {
8225
+ const entries = await lookup(missing);
8226
+ for (const entry of entries) {
8227
+ resolved.set(entry.taskRef, entry);
8228
+ pending.delete(entry.taskRef);
8229
+ }
8230
+ for (const taskRef of missing) if (!resolved.has(taskRef)) unresolvable.add(taskRef);
8231
+ if (entries.length > 0) emit();
8232
+ } finally {
8233
+ for (const taskRef of missing) pending.delete(taskRef);
8234
+ }
8235
+ };
7813
8236
  //#endregion
7814
8237
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/conversation.module.css.mjs
7815
- const css$5 = ".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_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,.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: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}";
7816
- const tagId$5 = "@wowyuarm/dsh-agent-team/conversation.module.css";
7817
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
8238
+ 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}";
8239
+ const tagId$6 = "@wowyuarm/dsh-agent-team/conversation.module.css";
8240
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
7818
8241
  const tag = document.createElement("style");
7819
8242
  tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
7820
- tag.dataset.pluginCss = tagId$5;
7821
- tag.textContent = css$5;
8243
+ tag.dataset.pluginCss = tagId$6;
8244
+ tag.textContent = css$6;
7822
8245
  document.head.appendChild(tag);
7823
8246
  }
7824
8247
  var conversation_module_css_default = {
@@ -7834,6 +8257,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7834
8257
  "confirmList": "omcBaG_confirmList",
7835
8258
  "emptyState": "omcBaG_emptyState",
7836
8259
  "emptySurface": "omcBaG_emptySurface",
8260
+ "entryArrow": "omcBaG_entryArrow",
8261
+ "entryLine": "omcBaG_entryLine",
8262
+ "entryRow": "omcBaG_entryRow",
7837
8263
  "error": "omcBaG_error",
7838
8264
  "errorState": "omcBaG_errorState",
7839
8265
  "headerActions": "omcBaG_headerActions",
@@ -7856,6 +8282,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7856
8282
  "pulse": "omcBaG_pulse",
7857
8283
  "refLink": "omcBaG_refLink",
7858
8284
  "runDivider": "omcBaG_runDivider",
8285
+ "stateCluster": "omcBaG_stateCluster",
8286
+ "statusWord": "omcBaG_statusWord",
7859
8287
  "surface": "omcBaG_surface",
7860
8288
  "surfaceHeader": "omcBaG_surfaceHeader",
7861
8289
  "timeline": "omcBaG_timeline",
@@ -8211,6 +8639,101 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8211
8639
  });
8212
8640
  }
8213
8641
  //#endregion
8642
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/avatar-stack.module.css.mjs
8643
+ 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}";
8644
+ const tagId$5 = "@wowyuarm/dsh-agent-team/avatar-stack.module.css";
8645
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
8646
+ const tag = document.createElement("style");
8647
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
8648
+ tag.dataset.pluginCss = tagId$5;
8649
+ tag.textContent = css$5;
8650
+ document.head.appendChild(tag);
8651
+ }
8652
+ var avatar_stack_module_css_default = {
8653
+ "avatar": "aACNsW_avatar",
8654
+ "overflow": "aACNsW_overflow",
8655
+ "stack": "aACNsW_stack"
8656
+ };
8657
+ //#endregion
8658
+ //#region src/client/TeamAvatarStack.tsx
8659
+ /** Distinct owners past this count collapse into one `+N` chip. */
8660
+ const MAX_VISIBLE = 3;
8661
+ /**
8662
+ * The compact "who is on this work" stack: overlapping 18px Member circles in
8663
+ * the shared identity language, capped at three plus a `+N` chip. The circles
8664
+ * are presentational, so the stack is one `role="img"` whose label carries the
8665
+ * whole roster — three anonymous initials would read as noise.
8666
+ */
8667
+ function TeamAvatarStack({ owners, label }) {
8668
+ if (owners.length === 0) return null;
8669
+ const shown = owners.slice(0, MAX_VISIBLE);
8670
+ const overflow = owners.length - shown.length;
8671
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8672
+ className: avatar_stack_module_css_default.stack,
8673
+ role: "img",
8674
+ "aria-label": label,
8675
+ children: [shown.map((owner) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8676
+ className: avatar_stack_module_css_default.avatar,
8677
+ style: { "--team-avatar-hue": memberHue(owner.memberId) },
8678
+ children: initial(owner.name)
8679
+ }, owner.memberId)), overflow > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8680
+ className: avatar_stack_module_css_default.overflow,
8681
+ children: `+${overflow}`
8682
+ })]
8683
+ });
8684
+ }
8685
+ /** First visible character of a handle — and of a raw Member id when that is all there is. */
8686
+ function initial(name) {
8687
+ return name.replace(/^@/, "").replace(/^member:/, "").slice(0, 1).toUpperCase();
8688
+ }
8689
+ //#endregion
8690
+ //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/countBadge.module.css.mjs
8691
+ 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}";
8692
+ const tagId$4 = "@wowyuarm/dsh-agent-team/countBadge.module.css";
8693
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
8694
+ const tag = document.createElement("style");
8695
+ tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
8696
+ tag.dataset.pluginCss = tagId$4;
8697
+ tag.textContent = css$4;
8698
+ document.head.appendChild(tag);
8699
+ }
8700
+ var countBadge_module_css_default = {
8701
+ "badge": "LBWXOW_badge",
8702
+ "hairline": "LBWXOW_hairline"
8703
+ };
8704
+ //#endregion
8705
+ //#region src/client/TeamCountBadge.tsx
8706
+ /** Every count the Human reads is capped at this, so one wide number never widens the capsule. */
8707
+ const COUNT_CAP = 99;
8708
+ /**
8709
+ * The one count capsule. The Human Inbox entry, the Channel feed's Thread
8710
+ * entry, and the Inbox queue row all answer the same question — how much is
8711
+ * waiting here — so they wear the same box rather than one hand-written copy
8712
+ * of the same declarations per surface. Three copies is how the feed's digit
8713
+ * ended up on a different line box from the other two.
8714
+ *
8715
+ * Zero is the absence of a count rather than a capsule reading zero, which is
8716
+ * the rule every caller wants and therefore the component's own.
8717
+ */
8718
+ function TeamCountBadge({ count, tone = "solid", label, className }) {
8719
+ if (count <= 0) return null;
8720
+ const text = count > COUNT_CAP ? `${COUNT_CAP}+` : String(count);
8721
+ const classes = `${countBadge_module_css_default.badge}${tone === "hairline" ? ` ${countBadge_module_css_default.hairline}` : ""}${className === void 0 ? "" : ` ${className}`}`;
8722
+ return label === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8723
+ className: classes,
8724
+ "data-team-count-badge": tone,
8725
+ "aria-hidden": "true",
8726
+ children: text
8727
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8728
+ className: classes,
8729
+ "data-team-count-badge": tone,
8730
+ role: "img",
8731
+ "aria-label": label,
8732
+ title: label,
8733
+ children: text
8734
+ });
8735
+ }
8736
+ //#endregion
8214
8737
  //#region src/client/TeamRunDivider.tsx
8215
8738
  /**
8216
8739
  * Explicit boundary between two same-sender Messages of one run separated by
@@ -8390,39 +8913,29 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8390
8913
  }
8391
8914
  //#endregion
8392
8915
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/channel.module.css.mjs
8393
- const css$4 = ".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);corner-shape:round;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}}";
8394
- const tagId$4 = "@wowyuarm/dsh-agent-team/channel.module.css";
8395
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
8916
+ 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}";
8917
+ const tagId$3 = "@wowyuarm/dsh-agent-team/channel.module.css";
8918
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
8396
8919
  const tag = document.createElement("style");
8397
8920
  tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
8398
- tag.dataset.pluginCss = tagId$4;
8399
- tag.textContent = css$4;
8921
+ tag.dataset.pluginCss = tagId$3;
8922
+ tag.textContent = css$3;
8400
8923
  document.head.appendChild(tag);
8401
8924
  }
8402
8925
  var channel_module_css_default = {
8403
8926
  "headerMeta": "MYaRJa_headerMeta",
8404
- "memberAction": "MYaRJa_memberAction",
8405
- "memberCopy": "MYaRJa_memberCopy",
8406
- "memberError": "MYaRJa_memberError",
8407
8927
  "memberList": "MYaRJa_memberList",
8408
- "memberRow": "MYaRJa_memberRow",
8409
- "modalBody": "MYaRJa_modalBody",
8410
- "taskArrow": "MYaRJa_taskArrow",
8411
- "taskCount": "MYaRJa_taskCount",
8412
- "taskDot": "MYaRJa_taskDot",
8413
- "taskFooter": "MYaRJa_taskFooter",
8414
- "taskNumber": "MYaRJa_taskNumber",
8415
- "taskStatus": "MYaRJa_taskStatus"
8928
+ "modalBody": "MYaRJa_modalBody"
8416
8929
  };
8417
8930
  //#endregion
8418
8931
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/thread.module.css.mjs
8419
- const css$3 = ".-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)}}";
8420
- const tagId$3 = "@wowyuarm/dsh-agent-team/thread.module.css";
8421
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
8932
+ 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)}}";
8933
+ const tagId$2 = "@wowyuarm/dsh-agent-team/thread.module.css";
8934
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
8422
8935
  const tag = document.createElement("style");
8423
8936
  tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
8424
- tag.dataset.pluginCss = tagId$3;
8425
- tag.textContent = css$3;
8937
+ tag.dataset.pluginCss = tagId$2;
8938
+ tag.textContent = css$2;
8426
8939
  document.head.appendChild(tag);
8427
8940
  }
8428
8941
  var thread_module_css_default = {
@@ -8452,12 +8965,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8452
8965
  //#endregion
8453
8966
  //#region src/client/TeamChannelPage.tsx
8454
8967
  /**
8455
- * Merge the freshest top-level window over what the reader already has:
8456
- * a change-driven refresh must not discard older messages loaded earlier.
8968
+ * Merge the freshest top-level window over what the reader already has. The
8969
+ * fresh window is authoritative for every Message it covers — a change wake
8970
+ * must move that row's live Task state, newest instant, and unread with it —
8971
+ * while older Messages loaded earlier are retained instead of discarded.
8457
8972
  */
8458
8973
  function mergeChannelView(current, fresh) {
8459
- const known = new Set(current.items.map((item) => item.message.messageRef));
8460
- const items = [...fresh.items.filter((item) => !known.has(item.message.messageRef)), ...current.items].sort((left, right) => left.message.sequence - right.message.sequence);
8974
+ const freshRefs = new Set(fresh.items.map((item) => item.message.messageRef));
8975
+ const items = [...current.items.filter((item) => !freshRefs.has(item.message.messageRef)), ...fresh.items].sort((left, right) => left.message.sequence - right.message.sequence);
8461
8976
  return {
8462
8977
  ...fresh,
8463
8978
  items,
@@ -8465,10 +8980,26 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8465
8980
  hasMore: fresh.hasMore || current.cursor < fresh.cursor
8466
8981
  };
8467
8982
  }
8468
- function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscribeChanges, loadMembers, drafts, putAttachment, getAttachment, sendMessage, joinChannel, removeChannelMember, selectThread, selectChannel, backToChannels, resolveTaskRefs, t }) {
8983
+ /**
8984
+ * The newest fact instant, or nothing when the entry's own Message is still the
8985
+ * newest fact on its Thread. That difference is exactly what "has follow-up
8986
+ * activity" means, and the Host projects both instants from the ledger.
8987
+ */
8988
+ function followUpAt(item) {
8989
+ const lastActivityAt = item.lastActivityAt;
8990
+ return lastActivityAt === void 0 || lastActivityAt === item.message.occurredAt ? void 0 : lastActivityAt;
8991
+ }
8992
+ /** Host unread per Thread, keyed for the feed's rows: zero unread is the absence of a badge, not a row. */
8993
+ function unreadCounts(inbox) {
8994
+ return new Map(inbox.items.filter((item) => item.unreadCount > 0).map((item) => [item.thread.threadRef, item.unreadCount]));
8995
+ }
8996
+ function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscribeChanges, loadMembers, loadInbox, drafts, putAttachment, getAttachment, sendMessage, joinChannel, removeChannelMember, selectThread, selectChannel, backToChannels, resolveTaskRefs, t }) {
8469
8997
  const [view, setView] = (0, react.useState)();
8470
8998
  const [members, setMembers] = (0, react.useState)([]);
8471
- const [error, setError] = (0, react.useState)();
8999
+ const [unreadByThread, setUnreadByThread] = (0, react.useState)(/* @__PURE__ */ new Map());
9000
+ const [actionError, setError] = (0, react.useState)();
9001
+ const [loadError, setLoadError] = (0, react.useState)();
9002
+ const error = actionError ?? loadError;
8472
9003
  const [pendingFiles, setPendingFiles] = (0, react.useState)([]);
8473
9004
  const [statusMessage, setStatusMessage] = (0, react.useState)();
8474
9005
  const [loading, setLoading] = (0, react.useState)(true);
@@ -8525,35 +9056,48 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8525
9056
  const channelMembers = members.filter((status) => channelMemberIds.has(status.member.memberId) && status.member.state !== "inactive" && status.member.state !== "archived");
8526
9057
  const onlineCount = channelMembers.filter((status) => status.presence === "available" || status.presence === "working").length;
8527
9058
  const messageSender = (item) => item.message.sender;
8528
- const mentionHandlesMap = new Map(members.map((status) => [status.member.memberId, status.member.handle.replace(/^@/, "")]));
9059
+ const handleByMember = new Map(members.map((status) => [status.member.memberId, status.member.handle.replace(/^@/, "")]));
8529
9060
  const refresh = async (clearError = false) => {
8530
9061
  if (!mountedRef.current) return false;
8531
9062
  const sequence = refreshSequenceRef.current + 1;
8532
9063
  refreshSequenceRef.current = sequence;
8533
9064
  if (!loadedRef.current) setLoading(true);
8534
9065
  if (clearError) {
8535
- setError(void 0);
9066
+ setLoadError(void 0);
8536
9067
  setStatusMessage(void 0);
8537
9068
  }
8538
9069
  try {
8539
- const [loaded, loadedMembers] = await Promise.all([loadChannels({
8540
- workspaceId,
8541
- channelRef,
8542
- direction: "before",
8543
- topLevelOnly: true,
8544
- includeActivities: false,
8545
- limit: 20
8546
- }), loadMembers({ workspaceId })]);
9070
+ const [loaded, loadedMembers, loadedInbox] = await Promise.all([
9071
+ loadChannels({
9072
+ workspaceId,
9073
+ channelRef,
9074
+ direction: "before",
9075
+ topLevelOnly: true,
9076
+ includeActivities: false,
9077
+ limit: 20
9078
+ }),
9079
+ loadMembers({ workspaceId }),
9080
+ loadInbox({
9081
+ workspaceId,
9082
+ limit: 100
9083
+ })
9084
+ ]);
8547
9085
  if (!mountedRef.current || sequence !== refreshSequenceRef.current) return false;
8548
9086
  if (loaded.ok) {
8549
9087
  setView((current) => current === void 0 ? loaded.value : mergeChannelView(current, loaded.value));
8550
9088
  loadedRef.current = true;
8551
- } else setError(loaded.error.message);
9089
+ } else setLoadError(loaded.error.message);
8552
9090
  if (loadedMembers.ok) setMembers(loadedMembers.value);
8553
- else setError(loadedMembers.error.message);
8554
- return loaded.ok && loadedMembers.ok;
9091
+ else setLoadError(loadedMembers.error.message);
9092
+ if (loadedInbox.ok) setUnreadByThread(unreadCounts(loadedInbox.value));
9093
+ else {
9094
+ setUnreadByThread(/* @__PURE__ */ new Map());
9095
+ setLoadError(loadedInbox.error.message);
9096
+ }
9097
+ if (loaded.ok && loadedMembers.ok && loadedInbox.ok) setLoadError(void 0);
9098
+ return loaded.ok && loadedMembers.ok && loadedInbox.ok;
8555
9099
  } catch (cause) {
8556
- if (mountedRef.current && sequence === refreshSequenceRef.current) setError(cause instanceof Error ? cause.message : String(cause));
9100
+ if (mountedRef.current && sequence === refreshSequenceRef.current) setLoadError(cause instanceof Error ? cause.message : String(cause));
8557
9101
  return false;
8558
9102
  } finally {
8559
9103
  if (mountedRef.current && sequence === refreshSequenceRef.current) setLoading(false);
@@ -8565,16 +9109,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8565
9109
  const loaded = await loadMembers({ workspaceId });
8566
9110
  if (!mountedRef.current) return;
8567
9111
  if (loaded.ok) setMembers(loaded.value);
8568
- else setError(loaded.error.message);
9112
+ else setLoadError(loaded.error.message);
8569
9113
  } catch (cause) {
8570
- if (mountedRef.current) setError(cause instanceof Error ? cause.message : String(cause));
9114
+ if (mountedRef.current) setLoadError(cause instanceof Error ? cause.message : String(cause));
8571
9115
  }
8572
9116
  };
8573
9117
  (0, react.useEffect)(() => {
8574
9118
  mountedRef.current = true;
8575
9119
  loadedRef.current = false;
8576
9120
  setView(void 0);
8577
- setError(void 0);
9121
+ setLoadError(void 0);
8578
9122
  setLoading(true);
8579
9123
  setManagingMembers(false);
8580
9124
  refresh();
@@ -8585,7 +9129,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8585
9129
  }, (update) => {
8586
9130
  if (!mountedRef.current) return;
8587
9131
  if (update.type === "failed") {
8588
- setError(update.message);
9132
+ setLoadError(update.message);
8589
9133
  return;
8590
9134
  }
8591
9135
  refresh();
@@ -8596,7 +9140,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8596
9140
  }, (update) => {
8597
9141
  if (!mountedRef.current) return;
8598
9142
  if (update.type === "failed") {
8599
- setError(update.message);
9143
+ setLoadError(update.message);
8600
9144
  return;
8601
9145
  }
8602
9146
  refreshMembers();
@@ -8607,7 +9151,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8607
9151
  }, (update) => {
8608
9152
  if (!mountedRef.current) return;
8609
9153
  if (update.type === "failed") {
8610
- setError(update.message);
9154
+ setLoadError(update.message);
8611
9155
  return;
8612
9156
  }
8613
9157
  refreshMembers();
@@ -8766,39 +9310,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8766
9310
  children: members.filter((status) => status.member.state !== "inactive" && status.member.state !== "archived").map((status) => {
8767
9311
  const joined = channelMemberIds.has(status.member.memberId);
8768
9312
  const rowPending = membership.pending.has(status.member.memberId);
8769
- const disabled = rowPending || !joined && status.presence === "unavailable";
9313
+ const disabled = rowPending || !joined && status.availability !== "active";
8770
9314
  const rowError = membership.errors.get(status.member.memberId);
8771
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8772
- className: channel_module_css_default.memberRow,
8773
- children: [
8774
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamPresenceDot, {
8775
- status,
8776
- t
8777
- }),
8778
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8779
- className: channel_module_css_default.memberCopy,
8780
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: ["@", status.member.handle] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: status.member.description })]
8781
- }),
8782
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8783
- className: channel_module_css_default.memberAction,
8784
- size: "sm",
8785
- disabled,
8786
- onClick: () => {
8787
- membership.change({
8788
- workspaceId,
8789
- channelRef,
8790
- memberId: status.member.memberId,
8791
- joined
8792
- });
8793
- },
8794
- children: rowPending ? t("membershipUpdating") : joined ? t("removeFromChannel") : t("addToChannel")
8795
- }),
8796
- rowError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8797
- className: channel_module_css_default.memberError,
8798
- role: "alert",
8799
- children: rowError
8800
- })
8801
- ]
9315
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberRow, {
9316
+ status,
9317
+ action: {
9318
+ label: rowPending ? t("membershipUpdating") : joined ? t("removeFromChannel") : t("addToChannel"),
9319
+ disabled,
9320
+ onSelect: () => {
9321
+ membership.change({
9322
+ workspaceId,
9323
+ channelRef,
9324
+ memberId: status.member.memberId,
9325
+ joined
9326
+ });
9327
+ }
9328
+ },
9329
+ ...rowError === void 0 ? {} : { error: rowError },
9330
+ t
8802
9331
  }, status.member.memberId);
8803
9332
  })
8804
9333
  })
@@ -8868,7 +9397,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8868
9397
  const human = item.message.sender === view.humanMemberId;
8869
9398
  const sender = human ? t("human") : senderStatus?.member.handle ?? item.message.sender;
8870
9399
  const turnGap = isRunGap(index > 0 ? block.items[index - 1].message.occurredAt : void 0, item.message.occurredAt);
8871
- 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, {
9400
+ const task = item.task;
9401
+ const unread = unreadByThread.get(item.thread.threadRef) ?? 0;
9402
+ 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, {
8872
9403
  senderName: sender,
8873
9404
  memberId: item.message.sender,
8874
9405
  human,
@@ -8877,68 +9408,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8877
9408
  loadAttachment: getAttachment,
8878
9409
  t,
8879
9410
  occurredAt: item.message.occurredAt,
8880
- mentionNames: mentionNamesOf(item.mentions, mentionHandlesMap),
9411
+ mentionNames: mentionNamesOf(item.mentions, handleByMember),
8881
9412
  onOpenRef: openRef,
8882
9413
  onResolveTaskRefs: lookupTaskRefs,
8883
9414
  grouped: index > 0,
8884
9415
  showGroupedTime: item.message.topLevel === true && !turnGap,
8885
9416
  ...senderStatus === void 0 ? {} : { senderTitle: senderStatus.member.description },
8886
- children: [item.message.topLevel && item.task !== void 0 && item.taskNumber !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8887
- type: "button",
8888
- className: channel_module_css_default.taskFooter,
8889
- "aria-label": t("openTask", { number: item.taskNumber }),
8890
- onClick: () => {
8891
- selectThread(item.thread.threadRef, channelRef, item.task?.taskRef, item.taskNumber);
8892
- },
8893
- children: [
8894
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8895
- className: channel_module_css_default.taskDot,
8896
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamStateDot, {
8897
- size: 8,
8898
- state: taskStatusDot(item.task.status)
8899
- })
8900
- }),
8901
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8902
- className: channel_module_css_default.taskNumber,
8903
- children: t("taskLabel", { number: item.taskNumber })
8904
- }),
8905
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8906
- className: channel_module_css_default.taskStatus,
8907
- children: formatTaskStatus(item.task.status, t)
8908
- }),
8909
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8910
- className: channel_module_css_default.taskCount,
8911
- children: t("taskMessageCount", { count: item.messageCount })
8912
- }),
8913
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8914
- className: channel_module_css_default.taskArrow,
8915
- "aria-hidden": "true",
8916
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, { size: 12 })
8917
- })
8918
- ]
8919
- }), item.message.topLevel && item.task === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8920
- type: "button",
8921
- className: channel_module_css_default.taskFooter,
8922
- "aria-label": t("openThread"),
8923
- onClick: () => {
8924
- selectThread(item.thread.threadRef, channelRef);
8925
- },
8926
- children: [
8927
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8928
- className: channel_module_css_default.taskNumber,
8929
- children: t("threadLabel")
8930
- }),
8931
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8932
- className: channel_module_css_default.taskCount,
8933
- children: t("taskMessageCount", { count: item.messageCount })
8934
- }),
8935
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8936
- className: channel_module_css_default.taskArrow,
8937
- "aria-hidden": "true",
8938
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, { size: 12 })
8939
- })
8940
- ]
8941
- })]
9417
+ children: item.message.topLevel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreadEntryRow, {
9418
+ item,
9419
+ owners: item.claimOwners,
9420
+ unread,
9421
+ t,
9422
+ onOpen: () => {
9423
+ selectThread(item.thread.threadRef, channelRef, task?.taskRef, item.taskNumber);
9424
+ }
9425
+ })
8942
9426
  })] }, item.message.messageRef);
8943
9427
  })
8944
9428
  }, `run-${block.items[0].message.messageRef}`))
@@ -8965,53 +9449,142 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8965
9449
  ]
8966
9450
  });
8967
9451
  }
9452
+ /**
9453
+ * One entry's state: who is on the work, where it stands, and how much of it
9454
+ * needs the reader. It leads the entry's own line rather than trailing the
9455
+ * identity line, so a reader meets it where they are already reading instead of
9456
+ * crossing the column for it — and the same placement holds whether this
9457
+ * Message opened its run or continued one, where an identity line would have
9458
+ * carried nothing else. The unread capsule is the only member a taskless
9459
+ * discussion can carry: it needs no Task.
9460
+ */
9461
+ function ThreadStateCluster({ task, owners, unread, t }) {
9462
+ if (task === void 0 && unread === 0) return null;
9463
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9464
+ className: conversation_module_css_default.stateCluster,
9465
+ children: [
9466
+ task !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamAvatarStack, {
9467
+ owners,
9468
+ label: claimersLabel(owners, t)
9469
+ }),
9470
+ task !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamStateDot, {
9471
+ size: 8,
9472
+ state: taskStatusDot(task.status)
9473
+ }),
9474
+ task !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9475
+ className: conversation_module_css_default.statusWord,
9476
+ children: formatTaskStatus(task.status, t)
9477
+ }),
9478
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamCountBadge, { count: unread })
9479
+ ]
9480
+ });
9481
+ }
9482
+ /**
9483
+ * The gate under one top-level Message: the single row that opens its Thread,
9484
+ * and the one line that says what stands there. State leads it, then what the
9485
+ * entry is: a Task entry keeps its number so the status word never floats free
9486
+ * of the Task it describes, follow-up activity adds when the work last moved,
9487
+ * and an unanswered Thread says only 回复. The instant uses the Inbox's own
9488
+ * 今天/昨天 form with the precise local time on the control's title, and an
9489
+ * unread Thread says so in the control's label rather than only in pixels.
9490
+ */
9491
+ function ThreadEntryRow({ item, owners, unread, t, onOpen }) {
9492
+ const taskNumber = item.taskNumber;
9493
+ const followUp = followUpAt(item);
9494
+ const label = taskNumber !== void 0 ? t("taskLabel", { number: taskNumber }) : followUp === void 0 ? t("replyAction") : t("threadLabel");
9495
+ const text = followUp === void 0 ? label : `${label} · ${t("recentActivity", { time: formatInboxTime(followUp, t) })}`;
9496
+ const openLabel = taskNumber === void 0 ? unread > 0 ? t("openThreadUnread", { count: unread }) : t("openThread") : unread > 0 ? t("openTaskUnread", {
9497
+ number: taskNumber,
9498
+ count: unread
9499
+ }) : t("openTask", { number: taskNumber });
9500
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9501
+ className: conversation_module_css_default.entryLine,
9502
+ "data-thread-entry": "",
9503
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreadStateCluster, {
9504
+ task: item.task,
9505
+ owners,
9506
+ unread,
9507
+ t
9508
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
9509
+ type: "button",
9510
+ className: conversation_module_css_default.entryRow,
9511
+ "aria-label": openLabel,
9512
+ ...followUp === void 0 ? {} : { title: formatAbsoluteTime(followUp) },
9513
+ onClick: onOpen,
9514
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9515
+ className: conversation_module_css_default.entryArrow,
9516
+ "aria-hidden": "true",
9517
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, { size: 12 })
9518
+ })]
9519
+ })]
9520
+ });
9521
+ }
8968
9522
  //#endregion
8969
9523
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/inbox.module.css.mjs
8970
- const css$2 = ".s2ibaa_list{flex-direction:column;gap:2px;display:flex}.s2ibaa_headerMeta{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.s2ibaa_row{color:inherit;cursor:pointer;font:inherit;text-align:left;background:0 0;border:0;border-radius:8px;grid-template-columns:minmax(0,1fr) auto;align-items:baseline;gap:2px 12px;width:100%;padding:9px 8px;display:grid}.s2ibaa_row:hover,.s2ibaa_row:focus-visible{background:var(--dsw-alias-interactive-bg-hover)}.s2ibaa_row:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:-2px}.s2ibaa_rowCrumb{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;grid-column:1;min-width:0;font-size:12px;line-height:18px;overflow:hidden}.s2ibaa_rowChannel{color:var(--dsw-alias-label-secondary);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;margin-left:8px;padding:0 5px;font-size:11px;font-weight:600;line-height:15px}.s2ibaa_rowPreview{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;grid-column:1/-1;min-width:0;font-size:14px;line-height:22px;overflow:hidden}.s2ibaa_rowTime{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;grid-area:1/2;font-size:11px;line-height:18px}";
8971
- const tagId$2 = "@wowyuarm/dsh-agent-team/inbox.module.css";
8972
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
9524
+ 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}";
9525
+ const tagId$1 = "@wowyuarm/dsh-agent-team/inbox.module.css";
9526
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
8973
9527
  const tag = document.createElement("style");
8974
9528
  tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
8975
- tag.dataset.pluginCss = tagId$2;
8976
- tag.textContent = css$2;
9529
+ tag.dataset.pluginCss = tagId$1;
9530
+ tag.textContent = css$1;
8977
9531
  document.head.appendChild(tag);
8978
9532
  }
8979
9533
  var inbox_module_css_default = {
8980
9534
  "headerMeta": "s2ibaa_headerMeta",
9535
+ "headerUnread": "s2ibaa_headerUnread",
8981
9536
  "list": "s2ibaa_list",
8982
9537
  "row": "s2ibaa_row",
9538
+ "rowActor": "s2ibaa_rowActor",
8983
9539
  "rowChannel": "s2ibaa_rowChannel",
8984
9540
  "rowCrumb": "s2ibaa_rowCrumb",
9541
+ "rowLine": "s2ibaa_rowLine",
8985
9542
  "rowPreview": "s2ibaa_rowPreview",
8986
9543
  "rowTask": "s2ibaa_rowTask",
8987
- "rowTime": "s2ibaa_rowTime"
9544
+ "rowTime": "s2ibaa_rowTime",
9545
+ "rowWorkspace": "s2ibaa_rowWorkspace",
9546
+ "section": "s2ibaa_section",
9547
+ "sectionCount": "s2ibaa_sectionCount",
9548
+ "sectionTitle": "s2ibaa_sectionTitle"
8988
9549
  };
8989
9550
  //#endregion
8990
9551
  //#region src/client/TeamInboxPage.tsx
8991
9552
  /**
8992
- * Queue order: newest mention first, one total order across Workspaces. Each
8993
- * Workspace slice arrives in the Host's own order (that order is the Host's
8994
- * truncation policy); the merged display order is decided here, where the
8995
- * merge happens, and the ledger sequence breaks ties so the queue never
8996
- * reshuffles two rows that share an instant.
9553
+ * How many 「最近活跃」 rows the merged page may show. The Host bounds each
9554
+ * Workspace's own slice; this is the single bound across every Workspace on
9555
+ * screen, so the section stays the same size no matter how many are open — and
9556
+ * it stays a way back into work rather than a second queue, which is why it is
9557
+ * shorter than the queue the reader is actually being asked to work through.
9558
+ */
9559
+ const RECENT_ROWS_LIMIT = 5;
9560
+ /**
9561
+ * Queue order, one total order across Workspaces: the Host's own keys —
9562
+ * mentions first, then the ledger sequence, then the Thread ref. Each Workspace
9563
+ * slice already arrives in this order, and it is also the Host's truncation
9564
+ * policy, so the merge re-applies it instead of inventing a second one: a row
9565
+ * that survived the cut on mentions must not sink below a merely newer row
9566
+ * after the merge. `newestSequence` is a global ledger position, so it stays
9567
+ * comparable across Workspaces.
8997
9568
  */
8998
9569
  function compareInboxRows(left, right) {
8999
- const leftAt = Date.parse(left.item.newestOccurredAt);
9000
- const rightAt = Date.parse(right.item.newestOccurredAt);
9001
- const byTime = (Number.isNaN(rightAt) ? 0 : rightAt) - (Number.isNaN(leftAt) ? 0 : leftAt);
9002
- return byTime !== 0 ? byTime : right.item.newestSequence - left.item.newestSequence;
9570
+ return right.item.directCount - left.item.directCount || right.item.newestSequence - left.item.newestSequence || left.item.thread.threadRef.localeCompare(right.item.thread.threadRef);
9003
9571
  }
9004
9572
  /**
9005
- * The Human 「提到我」 queue: one direct-only Inbox call per visible Workspace,
9006
- * merged into a single recency-ordered list newest mention first across every
9007
- * Workspace, since a queue is read by recency rather than by Workspace.
9573
+ * The Human Inbox: one Inbox call per visible Workspace, rendering the Host's
9574
+ * two slices the unread queue (「需要我」, mentions counted inside it rather
9575
+ * than alone) and the 「最近活跃」 tail of Threads the reader took part in.
9576
+ * Both merge across every Workspace into one list in the Host's own order,
9577
+ * mentions first and then newest, rather than by Workspace.
9008
9578
  * Opening the page never acknowledges anything — only a durable Thread read
9009
- * consumes a mention marker, so rows and the badge drop after the Thread is
9010
- * opened through the existing auto-ack path.
9579
+ * advances the watermark and consumes a mention marker, so rows and the badge
9580
+ * drop after the Thread is opened through the existing auto-ack path. A Thread
9581
+ * holding unread is only ever in the queue: the Host already excludes it from
9582
+ * the tail, and this page never re-derives that judgement.
9011
9583
  */
9012
9584
  function TeamInboxPage({ useWorkspaces, loadInbox, subscribeChanges, selectWorkspace, selectThread, t }) {
9013
9585
  const workspaces = useWorkspaces((state) => state.items);
9014
9586
  const [rows, setRows] = (0, react.useState)();
9587
+ const [recentRows, setRecentRows] = (0, react.useState)([]);
9015
9588
  const [loading, setLoading] = (0, react.useState)(true);
9016
9589
  const [error, setError] = (0, react.useState)();
9017
9590
  const loadedRef = (0, react.useRef)(false);
@@ -9020,25 +9593,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9020
9593
  const results = await Promise.all(workspaces.map(async (workspace) => {
9021
9594
  const result = await loadInbox({
9022
9595
  workspaceId: workspace.workspaceId,
9023
- directOnly: true,
9024
9596
  limit: 100
9025
9597
  });
9026
9598
  return result.ok ? {
9027
9599
  ok: true,
9028
9600
  workspaceId: workspace.workspaceId,
9029
9601
  workspaceTitle: workspace.title,
9030
- items: result.value.items
9602
+ items: result.value.items,
9603
+ recent: result.value.recent
9031
9604
  } : {
9032
9605
  ok: false,
9033
9606
  message: result.error.message
9034
9607
  };
9035
9608
  }));
9036
9609
  const failure = results.find((result) => !result.ok);
9037
- setRows(results.flatMap((result) => result.ok ? result.items.map((item) => ({
9038
- workspaceId: result.workspaceId,
9039
- workspaceTitle: result.workspaceTitle,
9610
+ const asRows = (items, workspaceId, workspaceTitle) => items.map((item) => ({
9611
+ workspaceId,
9612
+ workspaceTitle,
9040
9613
  item
9041
- })) : []).sort(compareInboxRows));
9614
+ }));
9615
+ setRows(results.flatMap((result) => result.ok ? asRows(result.items, result.workspaceId, result.workspaceTitle) : []).sort(compareInboxRows));
9616
+ setRecentRows(results.flatMap((result) => result.ok ? asRows(result.recent, result.workspaceId, result.workspaceTitle) : []).sort(compareInboxRows).slice(0, RECENT_ROWS_LIMIT));
9042
9617
  setError(failure?.ok === false ? failure.message : void 0);
9043
9618
  loadedRef.current = true;
9044
9619
  setLoading(false);
@@ -9057,6 +9632,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9057
9632
  selectWorkspace(row.workspaceId);
9058
9633
  selectThread(row.item.thread.threadRef, row.item.channelRef, row.item.task?.taskRef, row.item.taskNumber);
9059
9634
  };
9635
+ const totalUnread = rows?.reduce((sum, row) => sum + row.item.unreadCount, 0) ?? 0;
9636
+ const totalMentions = rows?.reduce((sum, row) => sum + row.item.directCount, 0) ?? 0;
9637
+ const shownWorkspaces = /* @__PURE__ */ new Set();
9638
+ for (const row of rows ?? []) shownWorkspaces.add(row.workspaceTitle);
9639
+ for (const row of recentRows) shownWorkspaces.add(row.workspaceTitle);
9640
+ const showWorkspace = shownWorkspaces.size > 1;
9060
9641
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("main", {
9061
9642
  className: conversation_module_css_default.surface,
9062
9643
  "data-team-inbox": true,
@@ -9066,12 +9647,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9066
9647
  className: conversation_module_css_default.headerRow,
9067
9648
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9068
9649
  className: conversation_module_css_default.headerCopy,
9069
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", { children: t("mentionsOfMe") }), rows !== void 0 && rows.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9650
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", { children: t("inboxTitle") }), rows !== void 0 && rows.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
9070
9651
  className: inbox_module_css_default.headerMeta,
9071
- children: t("inboxHeaderMeta", {
9072
- threads: rows.length,
9073
- mentions: rows.reduce((sum, row) => sum + row.item.directCount, 0)
9074
- })
9652
+ children: [
9653
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("inboxHeaderThreads", { count: rows.length }) }),
9654
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9655
+ className: inbox_module_css_default.headerUnread,
9656
+ children: t("inboxHeaderUnread", { count: totalUnread })
9657
+ }),
9658
+ totalMentions > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("inboxHeaderMentions", { count: totalMentions }) })
9659
+ ]
9075
9660
  })]
9076
9661
  })
9077
9662
  })
@@ -9102,49 +9687,51 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9102
9687
  children: t("retry")
9103
9688
  })]
9104
9689
  }),
9105
- rows !== void 0 && (rows.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9690
+ rows !== void 0 && (rows.length === 0 && recentRows.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9106
9691
  className: conversation_module_css_default.emptySurface,
9107
9692
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9108
9693
  className: conversation_module_css_default.emptyState,
9109
9694
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("inboxEmptyTitle") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("inboxEmptyHint") })]
9110
9695
  })
9111
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9112
- className: inbox_module_css_default.list,
9113
- children: rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
9114
- type: "button",
9115
- className: inbox_module_css_default.row,
9116
- onClick: () => {
9117
- open(row);
9118
- },
9119
- children: [
9120
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9121
- className: inbox_module_css_default.rowCrumb,
9122
- children: [
9123
- row.workspaceTitle,
9124
- " / ",
9125
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9126
- className: inbox_module_css_default.rowChannel,
9127
- children: ["#", row.item.channelName]
9128
- }),
9129
- row.item.taskNumber !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9130
- className: inbox_module_css_default.rowTask,
9131
- children: t("taskLabel", { number: row.item.taskNumber })
9132
- })
9133
- ]
9134
- }),
9135
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9136
- className: inbox_module_css_default.rowPreview,
9137
- children: row.item.previewText
9138
- }),
9139
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
9140
- className: inbox_module_css_default.rowTime,
9141
- dateTime: row.item.newestOccurredAt,
9142
- title: formatAbsoluteTime(row.item.newestOccurredAt),
9143
- children: formatInboxTime(row.item.newestOccurredAt, t)
9144
- })
9145
- ]
9146
- }, `${row.workspaceId} ${row.item.thread.threadRef}`))
9147
- })),
9696
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [rows.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
9697
+ className: inbox_module_css_default.section,
9698
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
9699
+ className: inbox_module_css_default.sectionTitle,
9700
+ children: [t("inboxSectionNeedsMe"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9701
+ className: inbox_module_css_default.sectionCount,
9702
+ children: rows.length
9703
+ })]
9704
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9705
+ className: inbox_module_css_default.list,
9706
+ children: rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InboxQueueRow, {
9707
+ row,
9708
+ t,
9709
+ showWorkspace,
9710
+ onOpen: () => {
9711
+ open(row);
9712
+ }
9713
+ }, `${row.workspaceId} ${row.item.thread.threadRef}`))
9714
+ })]
9715
+ }), recentRows.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
9716
+ className: inbox_module_css_default.section,
9717
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
9718
+ className: inbox_module_css_default.sectionTitle,
9719
+ children: [t("inboxSectionRecent"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9720
+ className: inbox_module_css_default.sectionCount,
9721
+ children: recentRows.length
9722
+ })]
9723
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9724
+ className: inbox_module_css_default.list,
9725
+ children: recentRows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InboxQueueRow, {
9726
+ row,
9727
+ t,
9728
+ showWorkspace,
9729
+ onOpen: () => {
9730
+ open(row);
9731
+ }
9732
+ }, `${row.workspaceId} ${row.item.thread.threadRef}`))
9733
+ })]
9734
+ })] })),
9148
9735
  rows !== void 0 && error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9149
9736
  className: conversation_module_css_default.error,
9150
9737
  role: "alert",
@@ -9155,70 +9742,95 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9155
9742
  })]
9156
9743
  });
9157
9744
  }
9158
- //#endregion
9159
- //#region src/client/scope-coverage.ts
9160
9745
  /**
9161
- * Per-scope coverage of the change versions one surface has already answered.
9746
+ * One queue row, shaped like the shipped two-line result row: who is on this
9747
+ * Thread leads in the gutter, the identity line answers which Thread this is,
9748
+ * how much is waiting, and when it last moved, and the gist sits under it on the
9749
+ * same column as evidence for that identity rather than as the row's subject.
9162
9750
  *
9163
- * A version is only comparable inside the scope that issued it: the Host
9164
- * answers a workspace scope from the durable ledger position and a presence
9165
- * scope from its process-local wake epoch, which starts low and climbs on every
9166
- * Agent transition. One high-water mark shared by both would therefore let a
9167
- * presence epoch swallow a later, smaller ledger sequence and park the surface
9168
- * on stale data, so coverage and pending versions are kept per scope.
9751
+ * The gutter carries the one thing every row has who is on the work, or who
9752
+ * moved a Thread nobody has claimed so a Thread that merely arrived and one
9753
+ * that named the reader open on the same edge instead of the quieter one opening
9754
+ * on a slot reserved for a count it does not hold. It is the grammar the Channel
9755
+ * feed's Thread entry row already speaks, where the people on the work lead the
9756
+ * row.
9169
9757
  *
9170
- * One round answers one version per scope. The Host delivers one event to every
9171
- * matching scope, so the first version a round sees in a scope it has not
9172
- * answered yet is that event reaching a second scope, and joins the round
9173
- * already fetching instead of earning a second identical read. A newer version
9174
- * in a scope the round has answered arrived after the round issued its fetch,
9175
- * so it owes one trailing round.
9758
+ * Before the queue admitted every unread Thread, each row was a mention and the
9759
+ * rows were interchangeable; now that named and ambient unread share one list,
9760
+ * the row has to carry that difference itself. The count closes the identity
9761
+ * line and only its ink changes the shared capsule fill for a row that names
9762
+ * the reader, a hairline for one that merely moved. The two numbers behind that
9763
+ * ink (unread, mentions) reach assistive tech through the capsule's own name,
9764
+ * because a second visible count beside the first would cost the row the one
9765
+ * thing it needs to stay scannable.
9176
9766
  */
9177
- var ScopeCoverage = class {
9178
- covered = /* @__PURE__ */ new Map();
9179
- pending = /* @__PURE__ */ new Map();
9180
- /** The scopes the open round has an answer for. */
9181
- answered = /* @__PURE__ */ new Set();
9182
- fetching = false;
9183
- /** Folds one wake in and answers whether it opens a round. */
9184
- wake(scope, version) {
9185
- if (version <= this.coveredOf(scope)) return false;
9186
- if (this.fetching && this.answered.has(scope)) {
9187
- this.pending.set(scope, Math.max(this.pending.get(scope) ?? 0, version));
9188
- return false;
9189
- }
9190
- this.answered.add(scope);
9191
- this.covered.set(scope, version);
9192
- return !this.fetching;
9193
- }
9194
- /** Opens a round's fetch window; versions observed from here on are pending. */
9195
- beginRound() {
9196
- this.pending.clear();
9197
- this.fetching = true;
9198
- }
9199
- /** Closes a round's fetch window and answers whether a trailing round is owed. */
9200
- finishRound() {
9201
- this.fetching = false;
9202
- this.answered.clear();
9203
- let owed = false;
9204
- for (const [scope, version] of this.pending) {
9205
- if (version <= this.coveredOf(scope)) continue;
9206
- this.covered.set(scope, version);
9207
- owed = true;
9208
- }
9209
- return owed;
9210
- }
9211
- /** Drops every observation: a new owner starts with nothing covered. */
9212
- reset() {
9213
- this.covered.clear();
9214
- this.pending.clear();
9215
- this.answered.clear();
9216
- this.fetching = false;
9217
- }
9218
- coveredOf(scope) {
9219
- return this.covered.get(scope) ?? 0;
9220
- }
9221
- };
9767
+ function InboxQueueRow({ row, t, showWorkspace, onOpen }) {
9768
+ const { item } = row;
9769
+ const actor = item.newestActor;
9770
+ const owners = item.claimOwners;
9771
+ const named = item.directCount > 0;
9772
+ const countLabel = named ? t("inboxRowUnreadMentions", {
9773
+ count: item.unreadCount,
9774
+ mentions: item.directCount
9775
+ }) : t("inboxRowUnread", { count: item.unreadCount });
9776
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
9777
+ type: "button",
9778
+ className: inbox_module_css_default.row,
9779
+ "data-named": named || void 0,
9780
+ onClick: onOpen,
9781
+ children: [
9782
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9783
+ className: inbox_module_css_default.rowActor,
9784
+ children: owners.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamAvatarStack, {
9785
+ owners,
9786
+ label: claimersLabel(owners, t)
9787
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamAvatarStack, {
9788
+ owners: [actor],
9789
+ label: t("inboxRowActor", { name: `@${actor.name}` })
9790
+ })
9791
+ }),
9792
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9793
+ className: inbox_module_css_default.rowLine,
9794
+ children: [
9795
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9796
+ className: inbox_module_css_default.rowCrumb,
9797
+ children: [
9798
+ showWorkspace && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9799
+ className: inbox_module_css_default.rowWorkspace,
9800
+ children: row.workspaceTitle
9801
+ }),
9802
+ showWorkspace && " / ",
9803
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9804
+ className: inbox_module_css_default.rowChannel,
9805
+ children: ["#", item.channelName]
9806
+ }),
9807
+ " ",
9808
+ item.taskNumber !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9809
+ className: inbox_module_css_default.rowTask,
9810
+ children: t("taskLabel", { number: item.taskNumber })
9811
+ })
9812
+ ]
9813
+ }),
9814
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamCountBadge, {
9815
+ count: item.unreadCount,
9816
+ tone: named ? "solid" : "hairline",
9817
+ label: countLabel
9818
+ }),
9819
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
9820
+ className: inbox_module_css_default.rowTime,
9821
+ dateTime: item.newestOccurredAt,
9822
+ title: formatAbsoluteTime(item.newestOccurredAt),
9823
+ children: formatInboxTime(item.newestOccurredAt, t)
9824
+ })
9825
+ ]
9826
+ }),
9827
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9828
+ className: inbox_module_css_default.rowPreview,
9829
+ children: item.previewText
9830
+ })
9831
+ ]
9832
+ });
9833
+ }
9222
9834
  //#endregion
9223
9835
  //#region src/client/TeamThreadPage.tsx
9224
9836
  function factKey(fact) {
@@ -9369,17 +9981,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9369
9981
  }
9370
9982
  };
9371
9983
  const supplementalRef = (0, react.useRef)();
9372
- const supplementalCoverageRef = (0, react.useRef)(new ScopeCoverage());
9373
- const refreshSupplemental = (wake) => {
9374
- const inFlight = supplementalRef.current;
9375
- if (wake === void 0) {
9376
- if (inFlight !== void 0) return inFlight;
9377
- } else if (!supplementalCoverageRef.current.wake(wake.scope, wake.version)) return inFlight ?? Promise.resolve();
9378
- const coverage = supplementalCoverageRef.current;
9984
+ const supplementalPendingRef = (0, react.useRef)(false);
9985
+ const refreshSupplemental = () => {
9986
+ supplementalPendingRef.current = true;
9987
+ if (supplementalRef.current !== void 0) return supplementalRef.current;
9379
9988
  const round = (async () => {
9380
- for (;;) {
9381
- coverage.beginRound();
9382
- if (!await applySupplemental() || !coverage.finishRound()) return;
9989
+ await Promise.resolve();
9990
+ while (mountedRef.current && supplementalPendingRef.current) {
9991
+ supplementalPendingRef.current = false;
9992
+ if (!await applySupplemental()) return;
9383
9993
  }
9384
9994
  })().finally(() => {
9385
9995
  if (supplementalRef.current === round) supplementalRef.current = void 0;
@@ -9434,7 +10044,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9434
10044
  (0, react.useEffect)(() => {
9435
10045
  mountedRef.current = true;
9436
10046
  supplementalRef.current = void 0;
9437
- supplementalCoverageRef.current.reset();
10047
+ supplementalPendingRef.current = false;
9438
10048
  projectionRef.current = void 0;
9439
10049
  setProjection(void 0);
9440
10050
  setChannelView(void 0);
@@ -9515,10 +10125,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9515
10125
  setError(update.message);
9516
10126
  return;
9517
10127
  }
9518
- refreshSupplemental({
9519
- scope: "workspace",
9520
- version: update.version
9521
- });
10128
+ refreshSupplemental();
9522
10129
  }),
9523
10130
  subscribeChanges({
9524
10131
  kind: "presence",
@@ -9529,10 +10136,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9529
10136
  setError(update.message);
9530
10137
  return;
9531
10138
  }
9532
- refreshSupplemental({
9533
- scope: "presence",
9534
- version: update.version
9535
- });
10139
+ refreshSupplemental();
9536
10140
  })
9537
10141
  ];
9538
10142
  return () => {
@@ -9876,12 +10480,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9876
10480
  }
9877
10481
  if (result.value.kind === "committed") {
9878
10482
  const committed = result.value;
10483
+ const optimisticMentions = [...new Set([...recipients, ...mentionedMemberIds(draft, channelMembers)])].sort();
9879
10484
  setCurrentFacts((current) => {
9880
10485
  const merged = mergeFacts(current, [{
9881
10486
  kind: "message",
9882
10487
  sequence: committed.message.sequence,
9883
10488
  message: committed.message,
9884
- mentions: [...recipients].sort(),
10489
+ mentions: optimisticMentions,
9885
10490
  occurredAt: committed.receipt.occurredAt
9886
10491
  }]);
9887
10492
  currentFactsRef.current = merged;
@@ -10280,6 +10885,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10280
10885
  loadChannels,
10281
10886
  subscribeChanges,
10282
10887
  loadMembers,
10888
+ loadInbox,
10283
10889
  sendMessage,
10284
10890
  joinChannel,
10285
10891
  removeChannelMember,
@@ -10315,67 +10921,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10315
10921
  });
10316
10922
  }
10317
10923
  //#endregion
10318
- //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/sidebar.module.css.mjs
10319
- 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)}.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]{background:var(--dsw-alias-interactive-bg-hover)}.d0xfxa_inboxCard:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:-2px}.d0xfxa_inboxCard>svg{color:var(--dsw-alias-label-tertiary);flex:0 0 16px}.d0xfxa_inboxCardLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:14px;line-height:20px;overflow:hidden}.d0xfxa_inboxBadge{background:var(--dsw-alias-state-business-primary);box-sizing:border-box;color:var(--dsw-alias-label-primary-foreground);corner-shape:round;border-radius:999px;flex:none;justify-content:center;align-items:center;min-width:18px;height:18px;margin-left:auto;padding:0 5px;font-size:11px;font-weight:600;line-height:18px;display:inline-flex}.d0xfxa_railButton .d0xfxa_inboxBadge{margin-left:0;position:absolute;top:0;right:0}.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[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;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;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);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;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}";
10320
- const tagId$1 = "@wowyuarm/dsh-agent-team/sidebar.module.css";
10321
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
10322
- const tag = document.createElement("style");
10323
- tag.dataset.plugin = "@wowyuarm/dsh-agent-team";
10324
- tag.dataset.pluginCss = tagId$1;
10325
- tag.textContent = css$1;
10326
- document.head.appendChild(tag);
10327
- }
10328
- var sidebar_module_css_default = {
10329
- "agentAvatar": "d0xfxa_agentAvatar",
10330
- "agentAvatarBadge": "d0xfxa_agentAvatarBadge",
10331
- "agentCopy": "d0xfxa_agentCopy",
10332
- "agentList": "d0xfxa_agentList",
10333
- "agentRow": "d0xfxa_agentRow",
10334
- "agentSelect": "d0xfxa_agentSelect",
10335
- "channelList": "d0xfxa_channelList",
10336
- "channelName": "d0xfxa_channelName",
10337
- "channelRow": "d0xfxa_channelRow",
10338
- "channelSelect": "d0xfxa_channelSelect",
10339
- "editChannelName": "d0xfxa_editChannelName",
10340
- "editDescription": "d0xfxa_editDescription",
10341
- "editHint": "d0xfxa_editHint",
10342
- "editMemberCopy": "d0xfxa_editMemberCopy",
10343
- "editMemberList": "d0xfxa_editMemberList",
10344
- "editMemberRow": "d0xfxa_editMemberRow",
10345
- "editMemberRowChannels": "d0xfxa_editMemberRowChannels",
10346
- "emptyState": "d0xfxa_emptyState",
10347
- "iconButton": "d0xfxa_iconButton",
10348
- "inboxBadge": "d0xfxa_inboxBadge",
10349
- "inboxCard": "d0xfxa_inboxCard",
10350
- "inboxCardLabel": "d0xfxa_inboxCardLabel",
10351
- "menuHint": "d0xfxa_menuHint",
10352
- "panel": "d0xfxa_panel",
10353
- "railButton": "d0xfxa_railButton",
10354
- "railWorkspace": "d0xfxa_railWorkspace",
10355
- "retryError": "d0xfxa_retryError",
10356
- "rowAlert": "d0xfxa_rowAlert",
10357
- "rowError": "d0xfxa_rowError",
10358
- "rowMenu": "d0xfxa_rowMenu",
10359
- "rowMenuButton": "d0xfxa_rowMenuButton",
10360
- "section": "d0xfxa_section",
10361
- "sectionActions": "d0xfxa_sectionActions",
10362
- "sectionChevron": "d0xfxa_sectionChevron",
10363
- "sectionHeader": "d0xfxa_sectionHeader",
10364
- "sectionTitle": "d0xfxa_sectionTitle",
10365
- "sectionToggle": "d0xfxa_sectionToggle",
10366
- "sidebarRowDragging": "d0xfxa_sidebarRowDragging",
10367
- "sidebarRowDropAfter": "d0xfxa_sidebarRowDropAfter",
10368
- "sidebarRowDropBefore": "d0xfxa_sidebarRowDropBefore",
10369
- "textButton": "d0xfxa_textButton",
10370
- "unavailableDot": "d0xfxa_unavailableDot",
10371
- "workspaceBrowser": "d0xfxa_workspaceBrowser",
10372
- "workspaceCopy": "d0xfxa_workspaceCopy",
10373
- "workspaceIcon": "d0xfxa_workspaceIcon",
10374
- "workspaceList": "d0xfxa_workspaceList",
10375
- "workspaceRow": "d0xfxa_workspaceRow",
10376
- "workspaceSection": "d0xfxa_workspaceSection"
10377
- };
10378
- //#endregion
10379
10924
  //#region src/client/TeamWorkspaceRow.tsx
10380
10925
  function TeamWorkspaceRow({ workspaceId, title, path, selected, current, onSelect }) {
10381
10926
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
@@ -10510,32 +11055,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10510
11055
  for (const listener of listeners$1) listener();
10511
11056
  }
10512
11057
  //#endregion
10513
- //#region src/client/TeamMemberAvatar.tsx
10514
- /**
10515
- * Sidebar Member avatar reusing the conversation identity language: the
10516
- * deterministic member hue and handle initial, with the presence indicator
10517
- * overlaid at the bottom-right so one glyph carries identity and state.
10518
- */
10519
- function TeamMemberAvatar({ status, t }) {
10520
- const label = presenceLabel(status, t);
10521
- const state = presenceDotState(status.presence);
10522
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
10523
- label,
10524
- delayMs: 300,
10525
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
10526
- className: sidebar_module_css_default.agentAvatar,
10527
- style: { "--team-avatar-hue": memberHue(status.member.memberId) },
10528
- role: "img",
10529
- "aria-label": label,
10530
- children: [status.member.handle.replace("@", "").slice(0, 1).toUpperCase(), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10531
- className: sidebar_module_css_default.agentAvatarBadge,
10532
- "aria-hidden": "true",
10533
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamStateDot, { state })
10534
- })]
10535
- })
10536
- });
10537
- }
10538
- //#endregion
10539
11058
  //#region src/client/sidebar-drag.tsx
10540
11059
  /**
10541
11060
  * Native whole-row drag for the Team sidebar lists. Unlike the Harness
@@ -10848,7 +11367,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10848
11367
  }
10849
11368
  //#endregion
10850
11369
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/create.module.css.mjs
10851
- 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}}";
11370
+ const css = "._1henIG_form{gap:16px;display:grid}._1henIG_modeSwitch{margin-bottom:16px}._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_notice{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:18px}._1henIG_state{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}._1henIG_roster{gap:2px;display:grid}._1henIG_failure{justify-items:start;gap:8px;display:grid}._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}}";
10852
11371
  const tagId = "@wowyuarm/dsh-agent-team/create.module.css";
10853
11372
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
10854
11373
  const tag = document.createElement("style");
@@ -10862,14 +11381,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10862
11381
  "chevronOpen": "_1henIG_chevronOpen",
10863
11382
  "dialogContent": "_1henIG_dialogContent",
10864
11383
  "error": "_1henIG_error",
11384
+ "failure": "_1henIG_failure",
10865
11385
  "field": "_1henIG_field",
10866
11386
  "form": "_1henIG_form",
10867
11387
  "input": "_1henIG_input",
10868
11388
  "memberOption": "_1henIG_memberOption",
10869
11389
  "memberPicker": "_1henIG_memberPicker",
10870
11390
  "menuCap": "_1henIG_menuCap",
11391
+ "modeSwitch": "_1henIG_modeSwitch",
11392
+ "notice": "_1henIG_notice",
11393
+ "roster": "_1henIG_roster",
10871
11394
  "selectTrigger": "_1henIG_selectTrigger",
10872
11395
  "selectValue": "_1henIG_selectValue",
11396
+ "state": "_1henIG_state",
10873
11397
  "unavailableDot": "_1henIG_unavailableDot"
10874
11398
  };
10875
11399
  //#endregion
@@ -11141,12 +11665,117 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11141
11665
  return left.provider === right.provider && left.model === right.model && left.reasoningEffort === right.reasoningEffort;
11142
11666
  }
11143
11667
  //#endregion
11668
+ //#region src/client/TeamAgentImport.tsx
11669
+ /** Selection is a Host join, not a new Agent or a copied Session. */
11670
+ function TeamAgentImport({ workspaceId, loadMembers, joinWorkspace, onJoined, onPending, t }) {
11671
+ const [members, setMembers] = (0, react.useState)([]);
11672
+ const [loading, setLoading] = (0, react.useState)(true);
11673
+ const [error, setError] = (0, react.useState)();
11674
+ const [pending, setPending] = (0, react.useState)();
11675
+ const retry = (0, react.useRef)();
11676
+ const busy = (0, react.useRef)(false);
11677
+ const generation = (0, react.useRef)(0);
11678
+ const load = (0, react.useCallback)(async () => {
11679
+ const current = ++generation.current;
11680
+ setLoading(true);
11681
+ setError(void 0);
11682
+ try {
11683
+ const result = await loadMembers({});
11684
+ if (current !== generation.current) return;
11685
+ if (!result.ok) throw new Error(result.error.message);
11686
+ setMembers(result.value.filter((status) => (status.member.state === "enabled" || status.member.state === "suspended") && !status.workspaceIds.includes(workspaceId)));
11687
+ } catch (cause) {
11688
+ if (current === generation.current) setError(cause instanceof Error ? cause.message : String(cause));
11689
+ } finally {
11690
+ if (current === generation.current) setLoading(false);
11691
+ }
11692
+ }, [loadMembers, workspaceId]);
11693
+ (0, react.useEffect)(() => {
11694
+ load();
11695
+ return () => {
11696
+ generation.current++;
11697
+ };
11698
+ }, [load]);
11699
+ const join = async (status) => {
11700
+ if (busy.current) return;
11701
+ busy.current = true;
11702
+ setPending(status.member.memberId);
11703
+ onPending(true);
11704
+ setError(void 0);
11705
+ const request = retry.current?.memberId === status.member.memberId ? retry.current : {
11706
+ requestId: mintRequestId(),
11707
+ workspaceId,
11708
+ memberId: status.member.memberId
11709
+ };
11710
+ retry.current = request;
11711
+ try {
11712
+ const result = await joinWorkspace(request);
11713
+ if (!result.ok) throw new Error(result.error.message);
11714
+ await onJoined();
11715
+ } catch (cause) {
11716
+ setError(cause instanceof Error ? cause.message : String(cause));
11717
+ } finally {
11718
+ busy.current = false;
11719
+ setPending(void 0);
11720
+ onPending(false);
11721
+ }
11722
+ };
11723
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11724
+ className: create_module_css_default.form,
11725
+ children: [
11726
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11727
+ className: create_module_css_default.notice,
11728
+ children: t("importAgentNotice")
11729
+ }),
11730
+ loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11731
+ className: create_module_css_default.state,
11732
+ role: "status",
11733
+ children: t("loadingAgents")
11734
+ }),
11735
+ !loading && error === void 0 && members.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11736
+ className: create_module_css_default.state,
11737
+ children: t("emptyImportAgents")
11738
+ }),
11739
+ !loading && members.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11740
+ className: create_module_css_default.roster,
11741
+ children: members.map((status) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberRow, {
11742
+ status,
11743
+ t,
11744
+ action: {
11745
+ label: pending === status.member.memberId ? t("importingAgent") : t("importAgent"),
11746
+ disabled: pending !== void 0,
11747
+ onSelect: () => {
11748
+ join(status);
11749
+ }
11750
+ }
11751
+ }, status.member.memberId))
11752
+ }),
11753
+ error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11754
+ className: create_module_css_default.failure,
11755
+ role: "alert",
11756
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11757
+ className: create_module_css_default.error,
11758
+ children: error
11759
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
11760
+ disabled: pending !== void 0,
11761
+ variant: "outline",
11762
+ onClick: () => {
11763
+ load();
11764
+ },
11765
+ children: t("retry")
11766
+ })]
11767
+ })
11768
+ ]
11769
+ });
11770
+ }
11771
+ //#endregion
11144
11772
  //#region src/client/TeamAgentsPanel.tsx
11145
- function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, archiveMember, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }) {
11773
+ function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, addMember, updateMember, recoverMember, archiveMember, joinWorkspace, leaveWorkspace, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }) {
11146
11774
  const [members, setMembers] = (0, react.useState)([]);
11147
11775
  const [loading, setLoading] = (0, react.useState)(true);
11148
11776
  const [error, setError] = (0, react.useState)();
11149
11777
  const [formOpen, setFormOpen] = (0, react.useState)(false);
11778
+ const [importing, setImporting] = (0, react.useState)(false);
11150
11779
  const [handle, setHandle] = (0, react.useState)("");
11151
11780
  const [description, setDescription] = (0, react.useState)("");
11152
11781
  const [model, setModel] = (0, react.useState)(void 0);
@@ -11260,9 +11889,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11260
11889
  try {
11261
11890
  const result = await addMember(request);
11262
11891
  if (result.ok) {
11892
+ const committed = {
11893
+ ...result.value.status,
11894
+ workspaceIds: [result.value.status.member.workspaceId]
11895
+ };
11263
11896
  setMembers((current) => {
11264
- const retained = current.filter((status) => status.member.memberId !== result.value.status.member.memberId);
11265
- return result.value.status.member.state === "inactive" || result.value.status.member.state === "archived" ? retained : [...retained, result.value.status];
11897
+ const retained = current.filter((status) => status.member.memberId !== committed.member.memberId);
11898
+ return committed.member.state === "inactive" || committed.member.state === "archived" ? retained : [...retained, committed];
11266
11899
  });
11267
11900
  setHandle("");
11268
11901
  setDescription("");
@@ -11302,7 +11935,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11302
11935
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11303
11936
  className: sidebar_module_css_default.panel,
11304
11937
  children: [
11305
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
11938
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
11306
11939
  open: formOpen,
11307
11940
  onClose: closeForm,
11308
11941
  title: t("addAgent"),
@@ -11313,14 +11946,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11313
11946
  disabled: creating,
11314
11947
  onClick: closeForm,
11315
11948
  children: t("cancel")
11316
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
11949
+ }), !importing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
11317
11950
  type: "submit",
11318
11951
  form: "team-agent-create-form",
11319
11952
  variant: "primary",
11320
11953
  disabled: creating || handle.trim().length === 0,
11321
11954
  children: creating ? t("creatingAgent") : t("createAgent")
11322
11955
  })] }),
11323
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
11956
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
11957
+ className: create_module_css_default.modeSwitch,
11958
+ variant: "outline",
11959
+ disabled: creating,
11960
+ "aria-expanded": importing,
11961
+ onClick: () => {
11962
+ setImporting((value) => !value);
11963
+ setError(void 0);
11964
+ },
11965
+ children: importing ? t("createAgent") : t("importAgentTitle")
11966
+ }), formOpen && importing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamAgentImport, {
11967
+ workspaceId,
11968
+ loadMembers,
11969
+ joinWorkspace,
11970
+ onPending: setCreating,
11971
+ onJoined: async () => {
11972
+ await refresh();
11973
+ setFormOpen(false);
11974
+ queueMicrotask(() => {
11975
+ triggerRef.current?.focus();
11976
+ });
11977
+ },
11978
+ t
11979
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
11324
11980
  id: "team-agent-create-form",
11325
11981
  className: create_module_css_default.form,
11326
11982
  onSubmit: submit,
@@ -11367,7 +12023,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11367
12023
  children: error
11368
12024
  })
11369
12025
  ]
11370
- })
12026
+ })]
11371
12027
  }),
11372
12028
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(TeamSidebarSection, {
11373
12029
  title: t("agents"),
@@ -11385,6 +12041,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11385
12041
  "aria-label": t("addAgent"),
11386
12042
  onClick: () => {
11387
12043
  setError(void 0);
12044
+ setImporting(false);
11388
12045
  setFormOpen(true);
11389
12046
  },
11390
12047
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 })
@@ -11395,7 +12052,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11395
12052
  className: sidebar_module_css_default.emptyState,
11396
12053
  children: t("loadingAgents")
11397
12054
  }),
11398
- !loading && members.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12055
+ !loading && error === void 0 && members.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11399
12056
  className: sidebar_module_css_default.emptyState,
11400
12057
  children: t("emptyAgents")
11401
12058
  }),
@@ -11405,6 +12062,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11405
12062
  drag,
11406
12063
  orderKey: status.member.memberId,
11407
12064
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AgentRow, {
12065
+ workspaceId,
12066
+ leaveWorkspace,
11408
12067
  status,
11409
12068
  ...memberSessionId === void 0 ? {} : { current: status.member.sessionId === memberSessionId },
11410
12069
  updateMember,
@@ -11412,9 +12071,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11412
12071
  archiveMember,
11413
12072
  loadModels,
11414
12073
  openMemberSession,
11415
- onUpdated: () => {
11416
- refresh();
11417
- },
12074
+ onUpdated: refresh,
11418
12075
  t
11419
12076
  })
11420
12077
  }, status.member.memberId))
@@ -11442,11 +12099,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11442
12099
  * conversation page, the avatar carries identity plus the presence badge, and
11443
12100
  * the row menu opens the editor.
11444
12101
  */
11445
- function AgentRow({ status, current, updateMember, recoverMember, archiveMember, loadModels, openMemberSession, onUpdated, t }) {
12102
+ function AgentRow({ workspaceId, leaveWorkspace, status, current, updateMember, recoverMember, archiveMember, loadModels, openMemberSession, onUpdated, t }) {
11446
12103
  const [menuOpen, setMenuOpen] = (0, react.useState)(false);
11447
12104
  const [editing, setEditing] = (0, react.useState)(false);
11448
12105
  const [archiving, setArchiving] = (0, react.useState)(false);
11449
12106
  const [rowAlert, setRowAlert] = (0, react.useState)();
12107
+ const [archivePending, setArchivePending] = (0, react.useState)(false);
12108
+ const archiveRequest = (0, react.useRef)();
12109
+ const withdrawing = workspaceId !== status.member.workspaceId;
11450
12110
  const recover = async () => {
11451
12111
  try {
11452
12112
  const result = await recoverMember({
@@ -11475,22 +12135,35 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11475
12135
  }
11476
12136
  };
11477
12137
  const archive = async () => {
12138
+ if (archivePending) return;
12139
+ setArchivePending(true);
12140
+ setRowAlert(void 0);
12141
+ archiveRequest.current ??= mintRequestId();
12142
+ const request = {
12143
+ requestId: archiveRequest.current,
12144
+ memberId: status.member.memberId
12145
+ };
11478
12146
  try {
11479
- const result = await archiveMember({
11480
- requestId: mintRequestId(),
11481
- memberId: status.member.memberId
11482
- });
12147
+ const result = withdrawing ? await leaveWorkspace({
12148
+ ...request,
12149
+ workspaceId
12150
+ }) : await archiveMember(request);
12151
+ if (!result.ok) throw new Error(result.error.message);
12152
+ setArchiving(false);
12153
+ archiveRequest.current = void 0;
11483
12154
  await onUpdated();
11484
- if (!result.ok) setRowAlert(t("archiveAgentFailed", { message: result.error.message }));
11485
12155
  } catch (cause) {
11486
- setRowAlert(t("archiveAgentFailed", { message: cause instanceof Error ? cause.message : String(cause) }));
12156
+ setRowAlert(cause instanceof Error ? cause.message : String(cause));
12157
+ } finally {
12158
+ setArchivePending(false);
11487
12159
  }
11488
12160
  };
11489
12161
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
11490
12162
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11491
12163
  className: sidebar_module_css_default.agentRow,
12164
+ "data-agent-row": true,
11492
12165
  "data-menu-open": menuOpen || void 0,
11493
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
12166
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
11494
12167
  type: "button",
11495
12168
  className: sidebar_module_css_default.agentSelect,
11496
12169
  "aria-label": t("openAgentSession", { name: status.member.handle }),
@@ -11499,13 +12172,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11499
12172
  onClick: () => {
11500
12173
  openMemberSession(status.member.sessionId);
11501
12174
  },
11502
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberAvatar, {
12175
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberIdentity, {
11503
12176
  status,
11504
- t
11505
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
12177
+ name: status.member.handle.replace(/^@/, ""),
11506
12178
  className: sidebar_module_css_default.agentCopy,
11507
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: status.member.handle }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: status.member.description })]
11508
- })]
12179
+ t
12180
+ })
11509
12181
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
11510
12182
  className: sidebar_module_css_default.rowMenu,
11511
12183
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamRowMenu, {
@@ -11528,7 +12200,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11528
12200
  }] : [],
11529
12201
  {
11530
12202
  id: "archive",
11531
- label: t("archiveAgent"),
12203
+ label: t(withdrawing ? "withdrawAgent" : "archiveAgent"),
11532
12204
  icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconArchiveOutline20, { size: 16 }),
11533
12205
  danger: true
11534
12206
  }
@@ -11542,37 +12214,46 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11542
12214
  })
11543
12215
  })]
11544
12216
  }),
11545
- rowAlert !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
12217
+ !archiving && rowAlert !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11546
12218
  className: sidebar_module_css_default.rowAlert,
11547
12219
  role: "alert",
11548
12220
  children: rowAlert
11549
12221
  }),
11550
- archiving && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
12222
+ archiving && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
11551
12223
  open: true,
11552
12224
  onClose: () => {
11553
- setArchiving(false);
12225
+ if (!archivePending) setArchiving(false);
11554
12226
  },
11555
- title: t("archiveAgentTitle", { name: status.member.handle }),
12227
+ title: t(withdrawing ? "withdrawAgentTitle" : "archiveAgentTitle", { name: status.member.handle }),
11556
12228
  closeLabel: t("close"),
11557
12229
  contentClassName: create_module_css_default.dialogContent,
11558
12230
  footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
11559
12231
  variant: "outline",
12232
+ disabled: archivePending,
11560
12233
  onClick: () => {
11561
12234
  setArchiving(false);
11562
12235
  },
11563
12236
  children: t("cancel")
11564
12237
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
11565
12238
  variant: "primary",
12239
+ disabled: archivePending,
11566
12240
  onClick: () => {
11567
- setArchiving(false);
11568
12241
  archive();
11569
12242
  },
11570
- children: t("archiveAgentConfirm")
12243
+ children: t(withdrawing ? "withdrawAgent" : "archiveAgentConfirm")
11571
12244
  })] }),
11572
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11573
- className: create_module_css_default.error,
11574
- children: t("archiveAgentNotice", { name: status.member.handle })
11575
- })
12245
+ children: [
12246
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12247
+ className: create_module_css_default.error,
12248
+ children: t(withdrawing ? "withdrawAgentNotice" : "archiveAgentNotice", { name: status.member.handle })
12249
+ }),
12250
+ !withdrawing && status.workspaceIds.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("archiveOtherWorkspaces", { count: status.workspaceIds.length - 1 }) }),
12251
+ rowAlert !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12252
+ className: create_module_css_default.error,
12253
+ role: "alert",
12254
+ children: rowAlert
12255
+ })
12256
+ ]
11576
12257
  }),
11577
12258
  editing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AgentEditorDialog, {
11578
12259
  status,
@@ -11896,7 +12577,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11896
12577
  className: sidebar_module_css_default.emptyState,
11897
12578
  children: t("loadingChannels")
11898
12579
  }),
11899
- !loading && (view?.channels.length ?? 0) === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12580
+ !loading && error === void 0 && view !== void 0 && view.channels.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11900
12581
  className: sidebar_module_css_default.emptyState,
11901
12582
  children: t("emptyChannels")
11902
12583
  }),
@@ -12132,39 +12813,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12132
12813
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", { children: t("channelMembersSection") }), members.map((status) => {
12133
12814
  const joined = joinedIds.has(status.member.memberId);
12134
12815
  const rowPending = membership.pending.has(status.member.memberId);
12135
- const disabled = rowPending || !joined && status.presence === "unavailable";
12816
+ const disabled = rowPending || !joined && status.availability !== "active";
12136
12817
  const rowError = membership.errors.get(status.member.memberId);
12137
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12138
- className: sidebar_module_css_default.editMemberRow,
12139
- children: [
12140
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamPresenceDot, {
12141
- status,
12142
- t
12143
- }),
12144
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
12145
- className: sidebar_module_css_default.editMemberCopy,
12146
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: ["@", status.member.handle] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: status.member.description })]
12147
- }),
12148
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
12149
- size: "sm",
12150
- variant: "outline",
12151
- disabled,
12152
- onClick: () => {
12153
- membership.change({
12154
- workspaceId: channel.workspaceId,
12155
- channelRef: channel.channelRef,
12156
- memberId: status.member.memberId,
12157
- joined
12158
- });
12159
- },
12160
- children: rowPending ? t("membershipUpdating") : joined ? t("removeFromChannel") : t("addToChannel")
12161
- }),
12162
- rowError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12163
- className: sidebar_module_css_default.rowError,
12164
- role: "alert",
12165
- children: rowError
12166
- })
12167
- ]
12818
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMemberRow, {
12819
+ status,
12820
+ action: {
12821
+ label: rowPending ? t("membershipUpdating") : joined ? t("removeFromChannel") : t("addToChannel"),
12822
+ disabled,
12823
+ onSelect: () => {
12824
+ membership.change({
12825
+ workspaceId: channel.workspaceId,
12826
+ channelRef: channel.channelRef,
12827
+ memberId: status.member.memberId,
12828
+ joined
12829
+ });
12830
+ }
12831
+ },
12832
+ ...rowError === void 0 ? {} : { error: rowError },
12833
+ t
12168
12834
  }, status.member.memberId);
12169
12835
  })]
12170
12836
  }),
@@ -12179,26 +12845,44 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12179
12845
  }
12180
12846
  //#endregion
12181
12847
  //#region src/client/TeamWorkspaceBrowser.tsx
12182
- 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 }) {
12848
+ /**
12849
+ * The Inbox entry's icon with its unread mark. The quantity left this surface
12850
+ * and lives in the control's accessible name: the sidebar answers whether
12851
+ * anything is waiting at a glance, and the number — which moves on every fact —
12852
+ * is what a reader asks for on purpose. The mark hangs off the icon rather than
12853
+ * off the control, so the wide card and the 36px rail button put the same dot
12854
+ * on the same corner of the same glyph.
12855
+ */
12856
+ function InboxMark({ unread }) {
12857
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
12858
+ className: sidebar_module_css_default.inboxMark,
12859
+ 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", {
12860
+ className: sidebar_module_css_default.inboxDot,
12861
+ "data-team-inbox-dot": true,
12862
+ "aria-hidden": "true"
12863
+ })]
12864
+ });
12865
+ }
12866
+ function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, selectInbox, t, useWorkspaces, loadMembers, loadInbox, subscribeChanges, subscribeReads, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, archiveMember, joinWorkspace, leaveWorkspace, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
12183
12867
  const navigationState = (0, react.useSyncExternalStore)(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
12184
12868
  const workspaces = useWorkspaces((state) => state.items);
12185
12869
  const selected = navigationState.workspaceId;
12186
12870
  const selectedId = selected !== void 0 && workspaces.some((workspace) => workspace.workspaceId === selected) ? selected : workspaces[0]?.workspaceId;
12187
12871
  const overviewIsCurrent = navigationState.channelRef === void 0 && navigationState.memberSessionId === void 0 && navigationState.inbox !== true;
12188
- const inboxIsCurrent = navigationState.inbox === true;
12872
+ const inboxIsCurrent = navigationState.inbox === true && navigationState.memberSessionId === void 0;
12189
12873
  const [creatingAgents, setCreatingAgents] = (0, react.useState)([]);
12190
12874
  const [pendingSection, setPendingSection] = (0, react.useState)();
12191
12875
  const channelsRef = (0, react.useRef)(null);
12192
12876
  const agentsRef = (0, react.useRef)(null);
12193
12877
  const workspacesOpen = useSidebarSectionOpen(void 0, "workspaces");
12194
12878
  const [inboxTotal, setInboxTotal] = (0, react.useState)(0);
12879
+ const inboxLabel = inboxTotal > 0 ? t("inboxTitleWithCount", { count: inboxTotal }) : t("inboxTitle");
12195
12880
  (0, react.useEffect)(() => {
12196
12881
  let disposed = false;
12197
12882
  let scheduled;
12198
12883
  const refresh = async () => {
12199
12884
  const results = await Promise.all(workspaces.map((workspace) => loadInbox({
12200
12885
  workspaceId: workspace.workspaceId,
12201
- directOnly: true,
12202
12886
  limit: 1
12203
12887
  })));
12204
12888
  if (disposed) return;
@@ -12251,22 +12935,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12251
12935
  "aria-label": t("workspaceSections"),
12252
12936
  children: [
12253
12937
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
12254
- label: t("mentionsOfMe"),
12938
+ label: inboxLabel,
12255
12939
  side: "right",
12256
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
12940
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
12257
12941
  type: "button",
12258
12942
  className: sidebar_module_css_default.railButton,
12259
- "aria-label": inboxTotal > 0 ? t("mentionsOfMeWithCount", { count: inboxTotal }) : t("mentionsOfMe"),
12943
+ "aria-label": inboxLabel,
12260
12944
  "aria-current": inboxIsCurrent ? "page" : void 0,
12261
12945
  onClick: () => {
12262
12946
  selectInbox();
12263
12947
  expandSidebar();
12264
12948
  },
12265
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQueueOutline14, { size: 16 }), inboxTotal > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12266
- className: sidebar_module_css_default.inboxBadge,
12267
- "aria-hidden": "true",
12268
- children: inboxTotal > 99 ? "99+" : inboxTotal
12269
- })]
12949
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InboxMark, { unread: inboxTotal })
12270
12950
  })
12271
12951
  }),
12272
12952
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
@@ -12306,21 +12986,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12306
12986
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
12307
12987
  type: "button",
12308
12988
  className: sidebar_module_css_default.inboxCard,
12309
- "aria-label": inboxTotal > 0 ? t("mentionsOfMeWithCount", { count: inboxTotal }) : t("mentionsOfMe"),
12989
+ "aria-label": inboxLabel,
12310
12990
  "aria-current": inboxIsCurrent ? "page" : void 0,
12311
12991
  onClick: selectInbox,
12312
- children: [
12313
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQueueOutline14, { size: 16 }),
12314
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12315
- className: sidebar_module_css_default.inboxCardLabel,
12316
- children: t("mentionsOfMe")
12317
- }),
12318
- inboxTotal > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12319
- className: sidebar_module_css_default.inboxBadge,
12320
- "aria-hidden": "true",
12321
- children: inboxTotal > 99 ? "99+" : inboxTotal
12322
- })
12323
- ]
12992
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InboxMark, { unread: inboxTotal }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12993
+ className: sidebar_module_css_default.inboxCardLabel,
12994
+ children: t("inboxTitle")
12995
+ })]
12324
12996
  }),
12325
12997
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamSidebarSection, {
12326
12998
  title: t("workspaces"),
@@ -12372,6 +13044,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12372
13044
  updateMember,
12373
13045
  recoverMember,
12374
13046
  archiveMember,
13047
+ joinWorkspace,
13048
+ leaveWorkspace,
12375
13049
  loadModels,
12376
13050
  ...navigationState.memberSessionId === void 0 ? {} : { memberSessionId: navigationState.memberSessionId },
12377
13051
  openMemberSession,
@@ -12399,6 +13073,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12399
13073
  teamMode: "团队模式",
12400
13074
  workspaceSections: "工作区内容",
12401
13075
  addAgent: "添加 Agent",
13076
+ importAgentTitle: "从其他 Workspace 引入",
13077
+ importAgent: "引入",
13078
+ importingAgent: "引入中…",
13079
+ importAgentNotice: "选择已有 Agent 加入当前 Workspace。身份、记忆与会话保持不变;Channel 仍需另行加入。",
13080
+ emptyImportAgents: "没有可引入的 Agent。",
13081
+ withdrawAgent: "从此 Workspace 撤回",
13082
+ withdrawAgentTitle: "撤回 {name}?",
13083
+ withdrawAgentNotice: "仅撤出当前 Workspace:退出此处所有 Channel、释放活跃 Claim 并清除 Attention。其他 Workspace 的工作、会话和私有记忆不受影响。",
13084
+ archiveOtherWorkspaces: "同时从其他 {count} 个 Workspace 收起。",
12402
13085
  cancel: "取消",
12403
13086
  close: "关闭",
12404
13087
  copyCode: "复制",
@@ -12416,14 +13099,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12416
13099
  statusError: "错误",
12417
13100
  statusUnavailable: "不可用",
12418
13101
  addChannel: "新建频道",
12419
- mentionsOfMe: "提到我",
12420
- mentionsOfMeWithCount: "提到我,{count} 条未读提及",
12421
- loadingInbox: "正在加载提到我…",
12422
- inboxEmptyTitle: "还没有人提到你",
12423
- inboxEmptyHint: "需要你知道或做决定时,成员会提到你",
12424
- inboxTimeToday: "今天",
13102
+ inboxTitle: "收件箱",
13103
+ inboxTitleWithCount: "收件箱,{count} 条未读",
13104
+ loadingInbox: "正在加载收件箱…",
13105
+ inboxEmptyTitle: "收件箱是空的",
13106
+ inboxEmptyHint: "你参与的 Thread 有新活动、或有人提到你时,会出现在这里",
12425
13107
  inboxTimeYesterday: "昨天",
12426
- inboxHeaderMeta: "{threads} 个 Thread · {mentions} 条提及,按最新提及排序",
13108
+ inboxHeaderThreads: "{count} 个 Thread",
13109
+ inboxHeaderUnread: "{count} 条未读",
13110
+ inboxHeaderMentions: "{count} 条提及",
13111
+ inboxRowUnread: "{count} 条未读",
13112
+ inboxRowUnreadMentions: "{count} 条未读,其中 {mentions} 条提及",
13113
+ inboxRowActor: "最新来自 {name}",
13114
+ inboxSectionNeedsMe: "需要我",
13115
+ inboxSectionRecent: "最近活跃",
12427
13116
  channelName: "名称",
12428
13117
  channelDescription: "说明",
12429
13118
  initialMembers: "初始成员",
@@ -12489,12 +13178,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12489
13178
  taskStatusInReview: "待验收",
12490
13179
  taskStatusDone: "已完成",
12491
13180
  taskStatusClosed: "已关闭",
12492
- taskMessageCount: "{count} 条消息",
12493
13181
  taskLabel: "Task #{number}",
12494
13182
  taskPending: "Task …",
12495
13183
  openTask: "打开 Task #{number}",
12496
13184
  openThread: "打开讨论",
13185
+ openTaskUnread: "打开 Task #{number}({count} 条新动态)",
13186
+ openThreadUnread: "打开讨论({count} 条新动态)",
12497
13187
  threadLabel: "讨论",
13188
+ recentActivity: "最近活动 {time}",
13189
+ replyAction: "回复",
13190
+ claimers: "由 {names} 处理",
12498
13191
  asTask: "作为任务",
12499
13192
  promoteToTask: "转为 Task",
12500
13193
  promotingTask: "正在转为 Task…",
@@ -12556,6 +13249,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12556
13249
  teamMode: "Team mode",
12557
13250
  workspaceSections: "Workspace sections",
12558
13251
  addAgent: "Add Agent",
13252
+ importAgentTitle: "Bring in from another Workspace",
13253
+ importAgent: "Bring in",
13254
+ importingAgent: "Joining…",
13255
+ importAgentNotice: "Choose an existing Agent to join this Workspace. Identity, memory, and session stay unchanged; join Channels separately.",
13256
+ emptyImportAgents: "No Agents available to bring in.",
13257
+ withdrawAgent: "Withdraw from this Workspace",
13258
+ withdrawAgentTitle: "Withdraw {name}?",
13259
+ withdrawAgentNotice: "Leave only this Workspace: exit its Channels, release active Claims, and clear Attention. Work elsewhere, the session, and private memory stay unchanged.",
13260
+ archiveOtherWorkspaces: "Also hides this Agent in {count} other Workspace(s).",
12559
13261
  cancel: "Cancel",
12560
13262
  close: "Close",
12561
13263
  copyCode: "Copy",
@@ -12573,14 +13275,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12573
13275
  statusError: "Error",
12574
13276
  statusUnavailable: "Unavailable",
12575
13277
  addChannel: "New Channel",
12576
- mentionsOfMe: "Mentions of me",
12577
- mentionsOfMeWithCount: "Mentions of me, {count} unread mention(s)",
12578
- loadingInbox: "Loading mentions…",
12579
- inboxEmptyTitle: "Nobody has mentioned you yet",
12580
- inboxEmptyHint: "Members will mention you when you must know or decide",
12581
- inboxTimeToday: "Today",
13278
+ inboxTitle: "Inbox",
13279
+ inboxTitleWithCount: "Inbox, {count} unread",
13280
+ loadingInbox: "Loading Inbox…",
13281
+ inboxEmptyTitle: "Your Inbox is empty",
13282
+ inboxEmptyHint: "Threads you take part in appear here when they have new activity or mention you",
12582
13283
  inboxTimeYesterday: "Yesterday",
12583
- inboxHeaderMeta: "{threads} Thread(s) · {mentions} mention(s), newest first",
13284
+ inboxHeaderThreads: "{count} Thread(s)",
13285
+ inboxHeaderUnread: "{count} unread",
13286
+ inboxHeaderMentions: "{count} mention(s)",
13287
+ inboxRowUnread: "{count} unread",
13288
+ inboxRowUnreadMentions: "{count} unread, {mentions} mention(s)",
13289
+ inboxRowActor: "Latest from {name}",
13290
+ inboxSectionNeedsMe: "Needs me",
13291
+ inboxSectionRecent: "Recently active",
12584
13292
  channelName: "Name",
12585
13293
  channelDescription: "Description",
12586
13294
  initialMembers: "Initial members",
@@ -12646,12 +13354,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12646
13354
  taskStatusInReview: "In review",
12647
13355
  taskStatusDone: "Done",
12648
13356
  taskStatusClosed: "Closed",
12649
- taskMessageCount: "{count} messages",
12650
13357
  taskLabel: "Task #{number}",
12651
13358
  taskPending: "Task …",
12652
13359
  openTask: "Open Task #{number}",
12653
13360
  openThread: "Open thread",
13361
+ openTaskUnread: "Open Task #{number} ({count} new updates)",
13362
+ openThreadUnread: "Open thread ({count} new updates)",
12654
13363
  threadLabel: "Thread",
13364
+ recentActivity: "Last activity {time}",
13365
+ replyAction: "Reply",
13366
+ claimers: "Handled by {names}",
12655
13367
  asTask: "As task",
12656
13368
  promoteToTask: "Convert to Task",
12657
13369
  promotingTask: "Converting to Task…",
@@ -12738,6 +13450,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12738
13450
  recoverMember: (request) => ctx.remote.agentTeam.recoverMember(request),
12739
13451
  clearMemberContext: (request) => ctx.remote.agentTeam.clearMemberContext(request),
12740
13452
  archiveMember: (request) => ctx.remote.agentTeam.archiveMember(request),
13453
+ joinWorkspace: (request) => ctx.remote.agentTeam.joinWorkspace(request),
13454
+ leaveWorkspace: (request) => ctx.remote.agentTeam.leaveWorkspace(request),
12741
13455
  loadModels: () => ctx.remote.session.modelCatalog(),
12742
13456
  openMemberSession: openMemberSessionImpl
12743
13457
  };
@@ -12826,7 +13540,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12826
13540
  restore();
12827
13541
  };
12828
13542
  }, "agent-team: member session restore");
12829
- const changes = new TeamChangeStream((request, signal) => ctx.remote.agentTeam.changes(request, signal));
13543
+ const changes = new TeamChangeStream(ctx.remote);
13544
+ ctx.effect(() => () => changes.dispose(), "agent-team: change subscriptions");
13545
+ ctx.on("connection/reset", () => {
13546
+ changes.recover();
13547
+ });
12830
13548
  const reads = new TeamReadStream();
12831
13549
  const loadMemberGroups = async () => {
12832
13550
  const workspaces = ctx.workspaces.list.getSnapshot().items;
@@ -12852,13 +13570,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12852
13570
  leaveTeam: () => {
12853
13571
  navigation.actions().exitMemberSession();
12854
13572
  navigation.actions().leaveTeam();
12855
- },
12856
- loadMemberGroups
13573
+ }
12857
13574
  })
12858
13575
  }, TeamFooterAction));
12859
13576
  registerModeShadow(ctx, navigation, changes, reads, drafts, "sidebar.workspaces", TeamWorkspaceBrowser);
12860
13577
  registerModeShadow(ctx, navigation, changes, reads, drafts, "main", TeamConversation, void 0, "conversation");
12861
- registerModeShadow(ctx, navigation, changes, reads, drafts, "sidebar.settings", TeamSettings, () => ({ loadMemberGroups }));
13578
+ registerModeShadow(ctx, navigation, changes, reads, drafts, "sidebar.settings", TeamMembersAction, () => ({ loadMemberGroups }));
12862
13579
  }
12863
13580
  async function apply(ctx) {
12864
13581
  const disposeRemote = await ctx.remote.$mount(TYPERT_REMOTE);