@wowyuarm/dsh-agent-team 0.1.0 → 0.1.2

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 (91) hide show
  1. package/README.md +14 -2
  2. package/README.zh.md +10 -2
  3. package/package.json +32 -24
  4. package/packages/agent-team/lib/attachments.js +157 -0
  5. package/packages/agent-team/lib/index.js +280 -22
  6. package/packages/agent-team/lib/ledger.js +98 -22
  7. package/packages/agent-team/lib/recovery.js +87 -0
  8. package/packages/agent-team/lib/spec.js +27 -5
  9. package/packages/agent-team/lib/typert.host.js +313 -26
  10. package/packages/agent-team/lib/typert.remote-client.d.ts +9 -1
  11. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  12. package/packages/agent-team/lib/typert.remote-client.js +234 -17
  13. package/packages/agent-team/lib/types/attachments.d.ts +69 -0
  14. package/packages/agent-team/lib/types/attachments.d.ts.map +1 -0
  15. package/packages/agent-team/lib/types/index.d.ts +68 -6
  16. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  17. package/packages/agent-team/lib/types/ledger.d.ts +17 -1
  18. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  19. package/packages/agent-team/lib/types/recovery.d.ts +42 -0
  20. package/packages/agent-team/lib/types/recovery.d.ts.map +1 -0
  21. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  22. package/packages/agent-team/lib/types/types.d.ts +94 -3
  23. package/packages/agent-team/lib/types/types.d.ts.map +1 -1
  24. package/packages/agent-team/preset/team-member/agent.cordis.yml +2 -2
  25. package/packages/client-agent-team/README.md +4 -3
  26. package/packages/client-agent-team/README.zh.md +4 -3
  27. package/packages/client-agent-team/lib/client.js +1791 -322
  28. package/packages/client-agent-team/lib/client.js.map +1 -1
  29. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +5 -2
  30. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  31. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +108 -59
  32. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +7 -1
  33. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  34. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +80 -19
  35. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
  36. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +38 -19
  37. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts +4 -1
  38. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
  39. package/packages/client-agent-team/lib/types/client/TeamComposer.js +61 -4
  40. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
  41. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
  42. package/packages/client-agent-team/lib/types/client/TeamConversation.js +3 -3
  43. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts +12 -2
  44. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
  45. package/packages/client-agent-team/lib/types/client/TeamMessage.js +152 -14
  46. package/packages/client-agent-team/lib/types/client/TeamRunDivider.d.ts +10 -0
  47. package/packages/client-agent-team/lib/types/client/TeamRunDivider.d.ts.map +1 -0
  48. package/packages/client-agent-team/lib/types/client/TeamRunDivider.js +12 -0
  49. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +7 -0
  50. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  51. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +93 -16
  52. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  53. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  54. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +6 -5
  55. package/packages/client-agent-team/lib/types/client/attachment-preview.d.ts +22 -0
  56. package/packages/client-agent-team/lib/types/client/attachment-preview.d.ts.map +1 -0
  57. package/packages/client-agent-team/lib/types/client/attachment-preview.js +35 -0
  58. package/packages/client-agent-team/lib/types/client/drafts.d.ts +41 -0
  59. package/packages/client-agent-team/lib/types/client/drafts.d.ts.map +1 -0
  60. package/packages/client-agent-team/lib/types/client/drafts.js +144 -0
  61. package/packages/client-agent-team/lib/types/client/index.d.ts +2 -0
  62. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  63. package/packages/client-agent-team/lib/types/client/index.js +50 -10
  64. package/packages/client-agent-team/lib/types/client/locales.d.ts +34 -0
  65. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  66. package/packages/client-agent-team/lib/types/client/locales.js +34 -0
  67. package/packages/client-agent-team/lib/types/client/multi-menu-field.d.ts +33 -0
  68. package/packages/client-agent-team/lib/types/client/multi-menu-field.d.ts.map +1 -0
  69. package/packages/client-agent-team/lib/types/client/multi-menu-field.js +30 -0
  70. package/packages/client-agent-team/lib/types/client/navigation.d.ts +16 -1
  71. package/packages/client-agent-team/lib/types/client/navigation.d.ts.map +1 -1
  72. package/packages/client-agent-team/lib/types/client/navigation.js +45 -8
  73. package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts +35 -0
  74. package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts.map +1 -0
  75. package/packages/client-agent-team/lib/types/client/sidebar-drag.js +70 -0
  76. package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts +27 -0
  77. package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts.map +1 -0
  78. package/packages/client-agent-team/lib/types/client/sidebar-order.js +170 -0
  79. package/packages/client-agent-team/lib/types/client/slots.d.ts +18 -2
  80. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  81. package/packages/client-agent-team/lib/types/client/task-refs.d.ts +20 -0
  82. package/packages/client-agent-team/lib/types/client/task-refs.d.ts.map +1 -0
  83. package/packages/client-agent-team/lib/types/client/task-refs.js +58 -0
  84. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +15 -0
  85. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  86. package/packages/client-agent-team/lib/types/client/team-formatters.js +30 -2
  87. package/packages/client-agent-team/lib/types/client/team-separators.d.ts +8 -0
  88. package/packages/client-agent-team/lib/types/client/team-separators.d.ts.map +1 -1
  89. package/packages/client-agent-team/lib/types/client/team-separators.js +14 -0
  90. package/packages/tool-agent-team/lib/index.js +10 -6
  91. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
@@ -1007,7 +1007,7 @@ window.__ModuleLoader__.load({
1007
1007
  };
1008
1008
  //#endregion
1009
1009
  //#region ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.js
1010
- const version = {
1010
+ const version$1 = {
1011
1011
  major: 4,
1012
1012
  minor: 4,
1013
1013
  patch: 3
@@ -1019,7 +1019,7 @@ window.__ModuleLoader__.load({
1019
1019
  inst ?? (inst = {});
1020
1020
  inst._zod.def = def;
1021
1021
  inst._zod.bag = inst._zod.bag || {};
1022
- inst._zod.version = version;
1022
+ inst._zod.version = version$1;
1023
1023
  const checks = [...inst._zod.def.checks ?? []];
1024
1024
  if (inst._zod.traits.has("$ZodCheck")) checks.unshift(inst);
1025
1025
  for (const ch of checks) for (const fn of ch._zod.onattach) fn(inst);
@@ -4089,7 +4089,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4089
4089
  "presetId": string().readonly(),
4090
4090
  "model": object({
4091
4091
  "provider": string().readonly(),
4092
- "model": string().readonly()
4092
+ "model": string().readonly(),
4093
+ "reasoningEffort": intersection(string(), unknown()).readonly().optional()
4093
4094
  }).readonly().optional(),
4094
4095
  "channelRefs": array(intersection(string(), unknown())).readonly()
4095
4096
  });
@@ -4109,7 +4110,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4109
4110
  "presetId": string().readonly(),
4110
4111
  "model": union([_undefined(), object({
4111
4112
  "provider": string().readonly(),
4112
- "model": string().readonly()
4113
+ "model": string().readonly(),
4114
+ "reasoningEffort": intersection(string(), unknown()).readonly().optional()
4113
4115
  })]).readonly().optional(),
4114
4116
  "privateMemoryPath": string().readonly(),
4115
4117
  "state": union([
@@ -4218,6 +4220,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4218
4220
  literal("reopen")
4219
4221
  ]).readonly(),
4220
4222
  "releasedClaimRefs": union([_undefined(), array(intersection(string(), unknown()))]).readonly().optional(),
4223
+ "completedClaimRefs": union([_undefined(), array(intersection(string(), unknown()))]).readonly().optional(),
4221
4224
  "activityRef": intersection(string(), unknown()).readonly(),
4222
4225
  "taskRef": intersection(string(), unknown()).readonly(),
4223
4226
  "threadRef": intersection(string(), unknown()).readonly(),
@@ -4298,6 +4301,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4298
4301
  }).readonly(),
4299
4302
  "memberIds": array(intersection(string(), unknown())).readonly()
4300
4303
  });
4304
+ const _wowyuarm_dsh_agent_team_agentTeam_getAttachment_parameter_0$schema = object({ "attachmentId": intersection(string(), unknown()).readonly() });
4305
+ const _wowyuarm_dsh_agent_team_agentTeam_getAttachment_result$schema = object({
4306
+ "name": string().readonly(),
4307
+ "mediaType": string().readonly(),
4308
+ "byteSize": number().readonly(),
4309
+ "bytesBase64": string().readonly()
4310
+ });
4301
4311
  const _wowyuarm_dsh_agent_team_agentTeam_inbox_parameter_0$schema = object({
4302
4312
  "workspaceId": intersection(string(), unknown()).readonly(),
4303
4313
  "limit": number().readonly().optional()
@@ -4366,7 +4376,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4366
4376
  "presetId": string().readonly(),
4367
4377
  "model": union([_undefined(), object({
4368
4378
  "provider": string().readonly(),
4369
- "model": string().readonly()
4379
+ "model": string().readonly(),
4380
+ "reasoningEffort": intersection(string(), unknown()).readonly().optional()
4370
4381
  })]).readonly().optional(),
4371
4382
  "state": union([
4372
4383
  literal("enabled"),
@@ -4388,6 +4399,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4388
4399
  ]).readonly(),
4389
4400
  "diagnostic": string().readonly().optional()
4390
4401
  }));
4402
+ const _wowyuarm_dsh_agent_team_agentTeam_putAttachment_parameter_0$schema = object({
4403
+ "requestId": intersection(string(), unknown()).readonly(),
4404
+ "workspaceId": intersection(string(), unknown()).readonly(),
4405
+ "name": string().readonly(),
4406
+ "mediaType": union([_undefined(), string()]).readonly().optional(),
4407
+ "bytesBase64": string().readonly()
4408
+ });
4409
+ const _wowyuarm_dsh_agent_team_agentTeam_putAttachment_result$schema = object({
4410
+ "attachmentId": intersection(string(), unknown()).readonly(),
4411
+ "path": string().readonly(),
4412
+ "name": string().readonly(),
4413
+ "byteSize": number().readonly(),
4414
+ "mediaType": string().readonly()
4415
+ });
4391
4416
  const _wowyuarm_dsh_agent_team_agentTeam_readThread_parameter_0$schema = object({
4392
4417
  "requestId": intersection(string(), unknown()).readonly(),
4393
4418
  "workspaceId": intersection(string(), unknown()).readonly(),
@@ -4441,6 +4466,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4441
4466
  "taskRef": intersection(string(), unknown()).readonly(),
4442
4467
  "sender": intersection(string(), unknown()).readonly(),
4443
4468
  "body": string().readonly(),
4469
+ "attachments": union([_undefined(), array(object({
4470
+ "attachmentId": intersection(string(), unknown()).readonly(),
4471
+ "name": string().readonly(),
4472
+ "byteSize": number().readonly(),
4473
+ "mediaType": string().readonly()
4474
+ }))]).readonly().optional(),
4444
4475
  "topLevel": boolean().readonly(),
4445
4476
  "sequence": number().readonly(),
4446
4477
  "occurredAt": string().readonly()
@@ -4457,6 +4488,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4457
4488
  "taskRef": intersection(string(), unknown()).readonly(),
4458
4489
  "sender": intersection(string(), unknown()).readonly(),
4459
4490
  "body": string().readonly(),
4491
+ "attachments": union([_undefined(), array(object({
4492
+ "attachmentId": intersection(string(), unknown()).readonly(),
4493
+ "name": string().readonly(),
4494
+ "byteSize": number().readonly(),
4495
+ "mediaType": string().readonly()
4496
+ }))]).readonly().optional(),
4460
4497
  "topLevel": boolean().readonly(),
4461
4498
  "sequence": number().readonly(),
4462
4499
  "occurredAt": string().readonly()
@@ -4473,6 +4510,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4473
4510
  literal("reopen")
4474
4511
  ]).readonly(),
4475
4512
  "releasedClaimRefs": union([_undefined(), array(intersection(string(), unknown()))]).readonly().optional(),
4513
+ "completedClaimRefs": union([_undefined(), array(intersection(string(), unknown()))]).readonly().optional(),
4476
4514
  "activityRef": intersection(string(), unknown()).readonly(),
4477
4515
  "taskRef": intersection(string(), unknown()).readonly(),
4478
4516
  "threadRef": intersection(string(), unknown()).readonly(),
@@ -4521,6 +4559,45 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4521
4559
  "sequence": number().readonly()
4522
4560
  })).readonly()
4523
4561
  });
4562
+ const _wowyuarm_dsh_agent_team_agentTeam_recoverMember_parameter_0$schema = object({
4563
+ "requestId": intersection(string(), unknown()).readonly(),
4564
+ "workspaceId": intersection(string(), unknown()).readonly(),
4565
+ "memberId": intersection(string(), unknown()).readonly()
4566
+ });
4567
+ const _wowyuarm_dsh_agent_team_agentTeam_recoverMember_result$schema = object({ "status": object({
4568
+ "member": object({
4569
+ "memberId": intersection(string(), unknown()).readonly(),
4570
+ "sessionId": intersection(string(), unknown()).readonly(),
4571
+ "workspaceId": intersection(string(), unknown()).readonly(),
4572
+ "handle": string().readonly(),
4573
+ "description": string().readonly(),
4574
+ "presetId": string().readonly(),
4575
+ "model": union([_undefined(), object({
4576
+ "provider": string().readonly(),
4577
+ "model": string().readonly(),
4578
+ "reasoningEffort": intersection(string(), unknown()).readonly().optional()
4579
+ })]).readonly().optional(),
4580
+ "privateMemoryPath": string().readonly(),
4581
+ "state": union([
4582
+ literal("enabled"),
4583
+ literal("suspended"),
4584
+ literal("inactive")
4585
+ ]).readonly()
4586
+ }).readonly(),
4587
+ "availability": union([
4588
+ literal("suspended"),
4589
+ literal("inactive"),
4590
+ literal("active"),
4591
+ literal("unavailable")
4592
+ ]).readonly(),
4593
+ "presence": union([
4594
+ literal("unavailable"),
4595
+ literal("available"),
4596
+ literal("working"),
4597
+ literal("error")
4598
+ ]).readonly(),
4599
+ "diagnostic": string().readonly().optional()
4600
+ }).readonly() });
4524
4601
  const _wowyuarm_dsh_agent_team_agentTeam_removeChannelMember_parameter_0$schema = object({
4525
4602
  "requestId": intersection(string(), unknown()).readonly(),
4526
4603
  "workspaceId": intersection(string(), unknown()).readonly(),
@@ -4560,6 +4637,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4560
4637
  "body": string().readonly(),
4561
4638
  "baseRevision": number().readonly(),
4562
4639
  "recipients": array(intersection(string(), unknown())).readonly().optional(),
4640
+ "attachmentPaths": union([_undefined(), array(string())]).readonly().optional(),
4641
+ "attachments": union([_undefined(), array(intersection(string(), unknown()))]).readonly().optional(),
4563
4642
  "confirmationToken": intersection(string(), unknown()).readonly().optional()
4564
4643
  });
4565
4644
  const _wowyuarm_dsh_agent_team_agentTeam_reply_result$schema = union([
@@ -4611,6 +4690,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4611
4690
  "taskRef": intersection(string(), unknown()).readonly(),
4612
4691
  "sender": intersection(string(), unknown()).readonly(),
4613
4692
  "body": string().readonly(),
4693
+ "attachments": union([_undefined(), array(object({
4694
+ "attachmentId": intersection(string(), unknown()).readonly(),
4695
+ "name": string().readonly(),
4696
+ "byteSize": number().readonly(),
4697
+ "mediaType": string().readonly()
4698
+ }))]).readonly().optional(),
4614
4699
  "topLevel": boolean().readonly(),
4615
4700
  "sequence": number().readonly(),
4616
4701
  "occurredAt": string().readonly()
@@ -4651,12 +4736,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4651
4736
  })).readonly()
4652
4737
  })
4653
4738
  ]);
4739
+ const _wowyuarm_dsh_agent_team_agentTeam_resolveTaskRefs_parameter_0$schema = object({
4740
+ "workspaceId": intersection(string(), unknown()).readonly(),
4741
+ "taskRefs": array(intersection(string(), unknown())).readonly()
4742
+ });
4743
+ const _wowyuarm_dsh_agent_team_agentTeam_resolveTaskRefs_result$schema = object({ "resolved": array(object({
4744
+ "taskRef": intersection(string(), unknown()).readonly(),
4745
+ "channelRef": intersection(string(), unknown()).readonly(),
4746
+ "threadRef": intersection(string(), unknown()).readonly(),
4747
+ "taskNumber": number().readonly()
4748
+ })).readonly() });
4654
4749
  const _wowyuarm_dsh_agent_team_agentTeam_sendMessage_parameter_0$schema = object({
4655
4750
  "requestId": intersection(string(), unknown()).readonly(),
4656
4751
  "workspaceId": intersection(string(), unknown()).readonly(),
4657
4752
  "channelRef": intersection(string(), unknown()).readonly(),
4658
4753
  "body": string().readonly(),
4659
4754
  "recipients": array(intersection(string(), unknown())).readonly().optional(),
4755
+ "attachments": union([_undefined(), array(intersection(string(), unknown()))]).readonly().optional(),
4756
+ "attachmentPaths": union([_undefined(), array(string())]).readonly().optional(),
4660
4757
  "confirmationToken": intersection(string(), unknown()).readonly().optional()
4661
4758
  });
4662
4759
  const _wowyuarm_dsh_agent_team_agentTeam_sendMessage_result$schema = union([
@@ -4674,6 +4771,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4674
4771
  "taskRef": intersection(string(), unknown()).readonly(),
4675
4772
  "sender": intersection(string(), unknown()).readonly(),
4676
4773
  "body": string().readonly(),
4774
+ "attachments": union([_undefined(), array(object({
4775
+ "attachmentId": intersection(string(), unknown()).readonly(),
4776
+ "name": string().readonly(),
4777
+ "byteSize": number().readonly(),
4778
+ "mediaType": string().readonly()
4779
+ }))]).readonly().optional(),
4677
4780
  "topLevel": boolean().readonly(),
4678
4781
  "sequence": number().readonly(),
4679
4782
  "occurredAt": string().readonly()
@@ -4769,6 +4872,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4769
4872
  "taskRef": intersection(string(), unknown()).readonly(),
4770
4873
  "sender": intersection(string(), unknown()).readonly(),
4771
4874
  "body": string().readonly(),
4875
+ "attachments": union([_undefined(), array(object({
4876
+ "attachmentId": intersection(string(), unknown()).readonly(),
4877
+ "name": string().readonly(),
4878
+ "byteSize": number().readonly(),
4879
+ "mediaType": string().readonly()
4880
+ }))]).readonly().optional(),
4772
4881
  "topLevel": boolean().readonly(),
4773
4882
  "sequence": number().readonly(),
4774
4883
  "occurredAt": string().readonly()
@@ -4797,6 +4906,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4797
4906
  "taskRef": intersection(string(), unknown()).readonly(),
4798
4907
  "sender": intersection(string(), unknown()).readonly(),
4799
4908
  "body": string().readonly(),
4909
+ "attachments": union([_undefined(), array(object({
4910
+ "attachmentId": intersection(string(), unknown()).readonly(),
4911
+ "name": string().readonly(),
4912
+ "byteSize": number().readonly(),
4913
+ "mediaType": string().readonly()
4914
+ }))]).readonly().optional(),
4800
4915
  "topLevel": boolean().readonly(),
4801
4916
  "sequence": number().readonly(),
4802
4917
  "occurredAt": string().readonly()
@@ -4813,6 +4928,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4813
4928
  literal("reopen")
4814
4929
  ]).readonly(),
4815
4930
  "releasedClaimRefs": union([_undefined(), array(intersection(string(), unknown()))]).readonly().optional(),
4931
+ "completedClaimRefs": union([_undefined(), array(intersection(string(), unknown()))]).readonly().optional(),
4816
4932
  "activityRef": intersection(string(), unknown()).readonly(),
4817
4933
  "taskRef": intersection(string(), unknown()).readonly(),
4818
4934
  "threadRef": intersection(string(), unknown()).readonly(),
@@ -4886,7 +5002,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4886
5002
  "description": string().readonly(),
4887
5003
  "model": object({
4888
5004
  "provider": string().readonly(),
4889
- "model": string().readonly()
5005
+ "model": string().readonly(),
5006
+ "reasoningEffort": intersection(string(), unknown()).readonly().optional()
4890
5007
  }).readonly().optional()
4891
5008
  });
4892
5009
  const _wowyuarm_dsh_agent_team_agentTeam_updateMember_result$schema = object({
@@ -4905,7 +5022,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4905
5022
  "presetId": string().readonly(),
4906
5023
  "model": union([_undefined(), object({
4907
5024
  "provider": string().readonly(),
4908
- "model": string().readonly()
5025
+ "model": string().readonly(),
5026
+ "reasoningEffort": intersection(string(), unknown()).readonly().optional()
4909
5027
  })]).readonly().optional(),
4910
5028
  "privateMemoryPath": string().readonly(),
4911
5029
  "state": union([
@@ -4986,6 +5104,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4986
5104
  "taskRef": intersection(string(), unknown()).readonly(),
4987
5105
  "sender": intersection(string(), unknown()).readonly(),
4988
5106
  "body": string().readonly(),
5107
+ "attachments": union([_undefined(), array(object({
5108
+ "attachmentId": intersection(string(), unknown()).readonly(),
5109
+ "name": string().readonly(),
5110
+ "byteSize": number().readonly(),
5111
+ "mediaType": string().readonly()
5112
+ }))]).readonly().optional(),
4989
5113
  "topLevel": boolean().readonly(),
4990
5114
  "sequence": number().readonly(),
4991
5115
  "occurredAt": string().readonly()
@@ -5037,6 +5161,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5037
5161
  literal("reopen")
5038
5162
  ]).readonly(),
5039
5163
  "releasedClaimRefs": union([_undefined(), array(intersection(string(), unknown()))]).readonly().optional(),
5164
+ "completedClaimRefs": union([_undefined(), array(intersection(string(), unknown()))]).readonly().optional(),
5040
5165
  "activityRef": intersection(string(), unknown()).readonly(),
5041
5166
  "taskRef": intersection(string(), unknown()).readonly(),
5042
5167
  "threadRef": intersection(string(), unknown()).readonly(),
@@ -5095,7 +5220,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5095
5220
  },
5096
5221
  sourceLocation: {
5097
5222
  "file": "packages/agent-team/src/index.ts",
5098
- "line": 284,
5223
+ "line": 342,
5099
5224
  "column": 9
5100
5225
  }
5101
5226
  },
@@ -5122,7 +5247,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5122
5247
  },
5123
5248
  sourceLocation: {
5124
5249
  "file": "packages/agent-team/src/index.ts",
5125
- "line": 428,
5250
+ "line": 644,
5126
5251
  "column": 9
5127
5252
  }
5128
5253
  },
@@ -5150,7 +5275,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5150
5275
  },
5151
5276
  sourceLocation: {
5152
5277
  "file": "packages/agent-team/src/index.ts",
5153
- "line": 221,
5278
+ "line": 279,
5154
5279
  "column": 9
5155
5280
  }
5156
5281
  },
@@ -5177,7 +5302,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5177
5302
  },
5178
5303
  sourceLocation: {
5179
5304
  "file": "packages/agent-team/src/index.ts",
5180
- "line": 376,
5305
+ "line": 524,
5181
5306
  "column": 9
5182
5307
  }
5183
5308
  },
@@ -5204,7 +5329,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5204
5329
  },
5205
5330
  sourceLocation: {
5206
5331
  "file": "packages/agent-team/src/index.ts",
5207
- "line": 262,
5332
+ "line": 320,
5333
+ "column": 9
5334
+ }
5335
+ },
5336
+ {
5337
+ id: "@wowyuarm/dsh-agent-team#agentTeam/getAttachment",
5338
+ service: "agentTeam",
5339
+ namespace: "agentTeam",
5340
+ method: "getAttachment",
5341
+ invocation: { kind: "direct" },
5342
+ parameters: [{
5343
+ name: "request",
5344
+ wire: "request",
5345
+ source: "json",
5346
+ codec: {
5347
+ mode: "strict",
5348
+ typeSymbol: "@wowyuarm/dsh-agent-team/types#AgentTeamGetAttachmentRequest",
5349
+ schema: _wowyuarm_dsh_agent_team_agentTeam_getAttachment_parameter_0$schema
5350
+ }
5351
+ }],
5352
+ result: {
5353
+ mode: "strict",
5354
+ typeSymbol: "@wowyuarm/dsh-agent-team/types#AgentTeamGetAttachmentResult",
5355
+ schema: _wowyuarm_dsh_agent_team_agentTeam_getAttachment_result$schema
5356
+ },
5357
+ sourceLocation: {
5358
+ "file": "packages/agent-team/src/index.ts",
5359
+ "line": 621,
5208
5360
  "column": 9
5209
5361
  }
5210
5362
  },
@@ -5231,7 +5383,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5231
5383
  },
5232
5384
  sourceLocation: {
5233
5385
  "file": "packages/agent-team/src/index.ts",
5234
- "line": 438,
5386
+ "line": 654,
5235
5387
  "column": 3
5236
5388
  }
5237
5389
  },
@@ -5258,7 +5410,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5258
5410
  },
5259
5411
  sourceLocation: {
5260
5412
  "file": "packages/agent-team/src/index.ts",
5261
- "line": 386,
5413
+ "line": 534,
5262
5414
  "column": 9
5263
5415
  }
5264
5416
  },
@@ -5286,10 +5438,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5286
5438
  },
5287
5439
  sourceLocation: {
5288
5440
  "file": "packages/agent-team/src/index.ts",
5289
- "line": 212,
5441
+ "line": 270,
5290
5442
  "column": 3
5291
5443
  }
5292
5444
  },
5445
+ {
5446
+ id: "@wowyuarm/dsh-agent-team#agentTeam/putAttachment",
5447
+ service: "agentTeam",
5448
+ namespace: "agentTeam",
5449
+ method: "putAttachment",
5450
+ invocation: { kind: "direct" },
5451
+ parameters: [{
5452
+ name: "request",
5453
+ wire: "request",
5454
+ source: "json",
5455
+ codec: {
5456
+ mode: "strict",
5457
+ typeSymbol: "@wowyuarm/dsh-agent-team/types#AgentTeamPutAttachmentRequest",
5458
+ schema: _wowyuarm_dsh_agent_team_agentTeam_putAttachment_parameter_0$schema
5459
+ }
5460
+ }],
5461
+ result: {
5462
+ mode: "strict",
5463
+ typeSymbol: "@wowyuarm/dsh-agent-team/types#AgentTeamPutAttachmentResult",
5464
+ schema: _wowyuarm_dsh_agent_team_agentTeam_putAttachment_result$schema
5465
+ },
5466
+ sourceLocation: {
5467
+ "file": "packages/agent-team/src/index.ts",
5468
+ "line": 608,
5469
+ "column": 9
5470
+ }
5471
+ },
5293
5472
  {
5294
5473
  id: "@wowyuarm/dsh-agent-team#agentTeam/readThread",
5295
5474
  service: "agentTeam",
@@ -5313,7 +5492,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5313
5492
  },
5314
5493
  sourceLocation: {
5315
5494
  "file": "packages/agent-team/src/index.ts",
5316
- "line": 445,
5495
+ "line": 661,
5496
+ "column": 9
5497
+ }
5498
+ },
5499
+ {
5500
+ id: "@wowyuarm/dsh-agent-team#agentTeam/recoverMember",
5501
+ service: "agentTeam",
5502
+ namespace: "agentTeam",
5503
+ method: "recoverMember",
5504
+ invocation: { kind: "direct" },
5505
+ parameters: [{
5506
+ name: "request",
5507
+ wire: "request",
5508
+ source: "json",
5509
+ codec: {
5510
+ mode: "strict",
5511
+ typeSymbol: "@wowyuarm/dsh-agent-team/types#AgentTeamRecoverMemberRequest",
5512
+ schema: _wowyuarm_dsh_agent_team_agentTeam_recoverMember_parameter_0$schema
5513
+ }
5514
+ }],
5515
+ result: {
5516
+ mode: "strict",
5517
+ typeSymbol: "@wowyuarm/dsh-agent-team/types#AgentTeamRecoverMemberResult",
5518
+ schema: _wowyuarm_dsh_agent_team_agentTeam_recoverMember_result$schema
5519
+ },
5520
+ sourceLocation: {
5521
+ "file": "packages/agent-team/src/index.ts",
5522
+ "line": 400,
5317
5523
  "column": 9
5318
5524
  }
5319
5525
  },
@@ -5340,7 +5546,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5340
5546
  },
5341
5547
  sourceLocation: {
5342
5548
  "file": "packages/agent-team/src/index.ts",
5343
- "line": 398,
5549
+ "line": 546,
5344
5550
  "column": 9
5345
5551
  }
5346
5552
  },
@@ -5367,10 +5573,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5367
5573
  },
5368
5574
  sourceLocation: {
5369
5575
  "file": "packages/agent-team/src/index.ts",
5370
- "line": 418,
5576
+ "line": 629,
5371
5577
  "column": 9
5372
5578
  }
5373
5579
  },
5580
+ {
5581
+ id: "@wowyuarm/dsh-agent-team#agentTeam/resolveTaskRefs",
5582
+ service: "agentTeam",
5583
+ namespace: "agentTeam",
5584
+ method: "resolveTaskRefs",
5585
+ invocation: { kind: "direct" },
5586
+ parameters: [{
5587
+ name: "request",
5588
+ wire: "request",
5589
+ source: "json",
5590
+ codec: {
5591
+ mode: "strict",
5592
+ typeSymbol: "@wowyuarm/dsh-agent-team/types#AgentTeamResolveTaskRefsRequest",
5593
+ schema: _wowyuarm_dsh_agent_team_agentTeam_resolveTaskRefs_parameter_0$schema
5594
+ }
5595
+ }],
5596
+ result: {
5597
+ mode: "strict",
5598
+ typeSymbol: "@wowyuarm/dsh-agent-team/types#AgentTeamResolveTaskRefsResult",
5599
+ schema: _wowyuarm_dsh_agent_team_agentTeam_resolveTaskRefs_result$schema
5600
+ },
5601
+ sourceLocation: {
5602
+ "file": "packages/agent-team/src/index.ts",
5603
+ "line": 258,
5604
+ "column": 3
5605
+ }
5606
+ },
5374
5607
  {
5375
5608
  id: "@wowyuarm/dsh-agent-team#agentTeam/sendMessage",
5376
5609
  service: "agentTeam",
@@ -5394,7 +5627,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5394
5627
  },
5395
5628
  sourceLocation: {
5396
5629
  "file": "packages/agent-team/src/index.ts",
5397
- "line": 408,
5630
+ "line": 556,
5398
5631
  "column": 9
5399
5632
  }
5400
5633
  },
@@ -5421,7 +5654,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5421
5654
  },
5422
5655
  sourceLocation: {
5423
5656
  "file": "packages/agent-team/src/index.ts",
5424
- "line": 462,
5657
+ "line": 678,
5425
5658
  "column": 3
5426
5659
  }
5427
5660
  },
@@ -5448,7 +5681,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5448
5681
  },
5449
5682
  sourceLocation: {
5450
5683
  "file": "packages/agent-team/src/index.ts",
5451
- "line": 455,
5684
+ "line": 671,
5452
5685
  "column": 3
5453
5686
  }
5454
5687
  },
@@ -5475,7 +5708,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5475
5708
  },
5476
5709
  sourceLocation: {
5477
5710
  "file": "packages/agent-team/src/index.ts",
5478
- "line": 274,
5711
+ "line": 332,
5479
5712
  "column": 9
5480
5713
  }
5481
5714
  },
@@ -5502,7 +5735,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5502
5735
  },
5503
5736
  sourceLocation: {
5504
5737
  "file": "packages/agent-team/src/index.ts",
5505
- "line": 341,
5738
+ "line": 487,
5506
5739
  "column": 9
5507
5740
  }
5508
5741
  },
@@ -5529,7 +5762,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5529
5762
  },
5530
5763
  sourceLocation: {
5531
5764
  "file": "packages/agent-team/src/index.ts",
5532
- "line": 469,
5765
+ "line": 685,
5533
5766
  "column": 3
5534
5767
  }
5535
5768
  }
@@ -5537,14 +5770,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5537
5770
  };
5538
5771
  //#endregion
5539
5772
  //#region src/client/navigation.ts
5540
- const STORAGE_KEY = "dsh.agent-team.navigation";
5773
+ const STORAGE_KEY$2 = "dsh.agent-team.navigation";
5541
5774
  function readSnapshot() {
5542
5775
  if (typeof localStorage === "undefined") return { mode: "conversation" };
5543
5776
  try {
5544
5777
  const parsed = JSON.parse(localStorage.getItem("dsh.agent-team.navigation") ?? "");
5778
+ const hasThread = typeof parsed.taskRef === "string" && typeof parsed.threadRef === "string";
5545
5779
  return {
5546
5780
  mode: parsed.mode === "team" ? "team" : "conversation",
5547
- ...typeof parsed.workspaceId === "string" ? { workspaceId: parsed.workspaceId } : {}
5781
+ ...typeof parsed.workspaceId === "string" ? { workspaceId: parsed.workspaceId } : {},
5782
+ ...typeof parsed.channelRef === "string" ? { channelRef: parsed.channelRef } : {},
5783
+ ...hasThread ? {
5784
+ taskRef: parsed.taskRef,
5785
+ threadRef: parsed.threadRef,
5786
+ ...typeof parsed.taskNumber === "number" && Number.isInteger(parsed.taskNumber) && parsed.taskNumber > 0 ? { taskNumber: parsed.taskNumber } : {}
5787
+ } : {}
5548
5788
  };
5549
5789
  } catch {
5550
5790
  return { mode: "conversation" };
@@ -5553,10 +5793,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5553
5793
  function persistSnapshot(snapshot) {
5554
5794
  if (typeof localStorage === "undefined") return;
5555
5795
  try {
5556
- const { mode, workspaceId } = snapshot;
5557
- localStorage.setItem(STORAGE_KEY, JSON.stringify({
5796
+ const { mode, workspaceId, channelRef, taskRef, threadRef, taskNumber } = snapshot;
5797
+ localStorage.setItem(STORAGE_KEY$2, JSON.stringify({
5558
5798
  mode,
5559
- ...workspaceId === void 0 ? {} : { workspaceId }
5799
+ ...workspaceId === void 0 ? {} : { workspaceId },
5800
+ ...channelRef === void 0 ? {} : { channelRef },
5801
+ ...taskRef === void 0 ? {} : { taskRef },
5802
+ ...threadRef === void 0 ? {} : { threadRef },
5803
+ ...taskNumber === void 0 ? {} : { taskNumber }
5560
5804
  }));
5561
5805
  } catch {}
5562
5806
  }
@@ -5574,25 +5818,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5574
5818
  actions() {
5575
5819
  return {
5576
5820
  enterTeam: () => {
5821
+ this.clearMemberSession();
5577
5822
  this.setMode("team");
5578
5823
  },
5579
5824
  leaveTeam: () => {
5580
5825
  this.setMode("conversation");
5581
5826
  },
5582
5827
  selectWorkspace: (workspaceId) => {
5828
+ this.clearMemberSession();
5583
5829
  this.setWorkspace(workspaceId);
5584
5830
  },
5585
5831
  selectChannel: (channelRef) => {
5832
+ this.clearMemberSession();
5586
5833
  this.setChannel(channelRef);
5587
5834
  },
5588
5835
  selectThread: (taskRef, threadRef, channelRef, taskNumber) => {
5836
+ this.clearMemberSession();
5589
5837
  this.setThread(taskRef, threadRef, channelRef, taskNumber);
5590
5838
  },
5591
5839
  backToWorkspace: () => {
5840
+ this.clearMemberSession();
5592
5841
  this.setThread(void 0);
5593
5842
  },
5594
5843
  backToChannels: () => {
5844
+ this.clearMemberSession();
5595
5845
  this.clearChannel();
5846
+ },
5847
+ enterMemberSession: (sessionId, returnToSessionId) => {
5848
+ this.setMemberSession(sessionId, returnToSessionId);
5849
+ },
5850
+ exitMemberSession: () => {
5851
+ this.clearMemberSession();
5596
5852
  }
5597
5853
  };
5598
5854
  }
@@ -5607,6 +5863,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5607
5863
  };
5608
5864
  this.commit();
5609
5865
  }
5866
+ setMemberSession(sessionId, returnToSessionId) {
5867
+ if (this.snapshot.memberSessionId === sessionId && this.snapshot.mode === "team") return;
5868
+ const { memberSessionId: _memberSessionId, ...base } = this.snapshot;
5869
+ this.snapshot = {
5870
+ ...base,
5871
+ mode: "team",
5872
+ memberSessionId: sessionId,
5873
+ ...returnToSessionId === void 0 ? {} : { returnToSessionId }
5874
+ };
5875
+ this.commit();
5876
+ }
5877
+ /** Any explicit Team navigation or the footer leave closes a Member view. */
5878
+ clearMemberSession() {
5879
+ if (this.snapshot.memberSessionId === void 0 && this.snapshot.returnToSessionId === void 0) return;
5880
+ const { memberSessionId: _memberSessionId, returnToSessionId: _returnToSessionId, ...base } = this.snapshot;
5881
+ this.snapshot = base;
5882
+ this.commit();
5883
+ }
5610
5884
  setWorkspace(workspaceId) {
5611
5885
  if (this.snapshot.workspaceId === workspaceId) return;
5612
5886
  const { channelRef: _channelRef, taskRef: _taskRef, threadRef: _threadRef, taskNumber: _taskNumber, ...base } = this.snapshot;
@@ -5730,6 +6004,136 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5730
6004
  }
5731
6005
  };
5732
6006
  //#endregion
6007
+ //#region src/client/drafts.ts
6008
+ const STORAGE_KEY$1 = "dsh.agent-team.drafts.v1";
6009
+ /** Retention ceiling; the oldest savedAt entries fall out first. */
6010
+ const LIMIT = 50;
6011
+ const EMPTY = Object.freeze({
6012
+ draft: "",
6013
+ recipients: /* @__PURE__ */ new Set()
6014
+ });
6015
+ function isTeamDraftKey(value) {
6016
+ return value.startsWith("channel:") || value.startsWith("thread:");
6017
+ }
6018
+ function readStored() {
6019
+ if (typeof localStorage === "undefined") return /* @__PURE__ */ new Map();
6020
+ try {
6021
+ const parsed = JSON.parse(localStorage.getItem("dsh.agent-team.drafts.v1") ?? "");
6022
+ const restored = /* @__PURE__ */ new Map();
6023
+ for (const [key, value] of Object.entries(parsed)) {
6024
+ if (!isTeamDraftKey(key) || typeof value !== "object" || value === null) continue;
6025
+ const candidate = value;
6026
+ if (typeof candidate.draft !== "string" || !Array.isArray(candidate.recipientIds) || typeof candidate.savedAt !== "number") continue;
6027
+ if (!candidate.recipientIds.every((id) => typeof id === "string")) continue;
6028
+ restored.set(key, {
6029
+ draft: candidate.draft,
6030
+ recipientIds: candidate.recipientIds,
6031
+ savedAt: candidate.savedAt
6032
+ });
6033
+ }
6034
+ return restored;
6035
+ } catch {
6036
+ return /* @__PURE__ */ new Map();
6037
+ }
6038
+ }
6039
+ function persistStored(entries) {
6040
+ if (typeof localStorage === "undefined") return;
6041
+ try {
6042
+ const payload = Object.fromEntries([...entries].map(([key, entry]) => [key, entry]));
6043
+ localStorage.setItem(STORAGE_KEY$1, JSON.stringify(payload));
6044
+ } catch {}
6045
+ }
6046
+ /**
6047
+ * Root-scoped draft cache, one instance per Client context (created in
6048
+ * `applyUi` and injected like the navigation service — never a module
6049
+ * singleton). Slot lifetimes subscribe per key.
6050
+ */
6051
+ var TeamDraftStore = class {
6052
+ entries = readStored();
6053
+ snapshots = /* @__PURE__ */ new Map();
6054
+ listeners = /* @__PURE__ */ new Set();
6055
+ subscribe = (listener) => {
6056
+ this.listeners.add(listener);
6057
+ return () => {
6058
+ this.listeners.delete(listener);
6059
+ };
6060
+ };
6061
+ /** Release listeners when the owning Client context disposes. */
6062
+ dispose() {
6063
+ this.listeners.clear();
6064
+ }
6065
+ /** Stable per-key snapshot identity for useSyncExternalStore. */
6066
+ getSnapshot = (key) => {
6067
+ const cached = this.snapshots.get(key);
6068
+ if (cached !== void 0) return cached;
6069
+ const entry = this.entries.get(key);
6070
+ if (entry === void 0) return EMPTY;
6071
+ const snapshot = Object.freeze({
6072
+ draft: entry.draft,
6073
+ recipients: new Set(entry.recipientIds)
6074
+ });
6075
+ this.snapshots.set(key, snapshot);
6076
+ return snapshot;
6077
+ };
6078
+ writeDraft(key, draft) {
6079
+ this.write(key, { draft });
6080
+ }
6081
+ writeRecipients(key, recipients) {
6082
+ this.write(key, { recipientIds: [...recipients] });
6083
+ }
6084
+ /** Drop one key entirely — the success path after a committed send. */
6085
+ clear(key) {
6086
+ if (!this.entries.delete(key)) return;
6087
+ this.snapshots.delete(key);
6088
+ persistStored(this.entries);
6089
+ for (const listener of this.listeners) listener();
6090
+ }
6091
+ /** Test seam: forget everything, including what localStorage still holds. */
6092
+ reset() {
6093
+ this.entries = /* @__PURE__ */ new Map();
6094
+ this.snapshots.clear();
6095
+ if (typeof localStorage !== "undefined") localStorage.removeItem(STORAGE_KEY$1);
6096
+ for (const listener of this.listeners) listener();
6097
+ }
6098
+ /** Re-read persisted content — what a fresh page load starts from. */
6099
+ reload() {
6100
+ this.entries = readStored();
6101
+ this.snapshots.clear();
6102
+ for (const listener of this.listeners) listener();
6103
+ }
6104
+ write(key, patch) {
6105
+ const previous = this.entries.get(key);
6106
+ const next = {
6107
+ draft: patch.draft ?? previous?.draft ?? "",
6108
+ recipientIds: patch.recipientIds ?? previous?.recipientIds ?? [],
6109
+ savedAt: Date.now()
6110
+ };
6111
+ if (previous !== void 0 && previous.draft === next.draft && previous.recipientIds.length === next.recipientIds.length && previous.recipientIds.every((id, index) => id === next.recipientIds[index])) return;
6112
+ if (next.draft === "" && next.recipientIds.length === 0) {
6113
+ this.clear(key);
6114
+ return;
6115
+ }
6116
+ this.entries.set(key, next);
6117
+ this.evict();
6118
+ this.snapshots.delete(key);
6119
+ persistStored(this.entries);
6120
+ for (const listener of this.listeners) listener();
6121
+ }
6122
+ evict() {
6123
+ while (this.entries.size > LIMIT) {
6124
+ let oldestKey;
6125
+ let oldestSavedAt = Number.POSITIVE_INFINITY;
6126
+ for (const [key, entry] of this.entries) if (entry.savedAt < oldestSavedAt) {
6127
+ oldestSavedAt = entry.savedAt;
6128
+ oldestKey = key;
6129
+ }
6130
+ if (oldestKey === void 0) return;
6131
+ this.entries.delete(oldestKey);
6132
+ this.snapshots.delete(oldestKey);
6133
+ }
6134
+ }
6135
+ };
6136
+ //#endregion
5733
6137
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/team.module.css.mjs
5734
6138
  const css$8 = ".YvAbSa_footerStack{flex:none;width:100%;height:42px;margin:8px 0 0;display:flex}.YvAbSa_footerAction,.YvAbSa_settingsAction{box-sizing:border-box;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:8px;width:calc(100% + 4px);height:42px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.YvAbSa_footerAction{margin:0 -2px}.YvAbSa_settingsAction{margin:4px -2px}.YvAbSa_footerAction:hover,.YvAbSa_footerAction:focus-visible,.YvAbSa_settingsAction:hover,.YvAbSa_settingsAction:focus-visible{background:var(--dsw-alias-interactive-bg-hover);outline:none}.YvAbSa_footerAction.YvAbSa_rail,.YvAbSa_settingsAction.YvAbSa_rail{border-radius:50%;justify-content:center;width:36px;height:36px;padding:0}.YvAbSa_footerAction.YvAbSa_rail{margin:0}.YvAbSa_settingsAction.YvAbSa_rail{margin:8px 0 10px}.YvAbSa_railStack{align-items:center;width:36px;height:36px;margin:0}";
5735
6139
  const tagId$8 = "@wowyuarm/dsh-agent-team/team.module.css";
@@ -5781,7 +6185,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5781
6185
  }
5782
6186
  //#endregion
5783
6187
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/presence.module.css.mjs
5784
- const css$7 = ".-\\36 lQ-q_target{flex:0 0 14px;justify-content:center;align-items:center;display:inline-flex}.-\\36 lQ-q_unavailableDot{background:var(--dsw-alias-text-disabled);border-radius:50%;width:7px;height:7px;display:inline-block}";
6188
+ const css$7 = ".-\\36 lQ-q_target{flex:0 0 14px;justify-content:center;align-items:center;display:inline-flex}.-\\36 lQ-q_unavailableDot{background:var(--dsw-alias-label-tertiary);border-radius:50%;width:7px;height:7px;display:inline-block}";
5785
6189
  const tagId$7 = "@wowyuarm/dsh-agent-team/presence.module.css";
5786
6190
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$7) + "]") === null) {
5787
6191
  const tag = document.createElement("style");
@@ -5823,7 +6227,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5823
6227
  }
5824
6228
  //#endregion
5825
6229
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/members.module.css.mjs
5826
- const css$6 = ".UkovOW_body{max-height:min(65vh,560px);overflow-y:auto}.UkovOW_content{outline:none;gap:12px;display:grid}.UkovOW_group{gap:3px;display:grid}.UkovOW_group+.UkovOW_group{border-top:1px solid var(--dsw-alias-border-subtle);padding-top:10px}.UkovOW_group h3{color:var(--dsw-alias-text-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-text-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-text-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-text-tertiary)}.UkovOW_error{color:var(--dsw-alias-state-error-primary)}@media (width<=600px){.UkovOW_body{max-height:calc(100vh - 160px)}}";
6230
+ const css$6 = ".UkovOW_body{max-height:min(65vh,560px);overflow-y:auto}.UkovOW_content{outline:none;gap:12px;display:grid}.UkovOW_group{gap:3px;display:grid}.UkovOW_group+.UkovOW_group{border-top:1px solid var(--dsw-alias-border-l2);padding-top:10px}.UkovOW_group h3{color:var(--dsw-alias-label-secondary);margin:0 0 3px;font-size:12px;font-weight:600;line-height:18px}.UkovOW_member{border-radius:6px;grid-template-columns:14px minmax(0,1fr);align-items:center;gap:0 8px;min-height:36px;padding:4px 6px;display:grid}.UkovOW_member:hover{background:var(--dsw-alias-interactive-bg-hover)}.UkovOW_copy{min-width:0;display:grid}.UkovOW_copy strong{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:500;line-height:18px;overflow:hidden}.UkovOW_copy small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:14px;overflow:hidden}.UkovOW_state,.UkovOW_error{margin:0;padding:6px 0;font-size:12px;line-height:18px}.UkovOW_state{color:var(--dsw-alias-label-tertiary)}.UkovOW_error{color:var(--dsw-alias-state-error-primary)}@media (width<=600px){.UkovOW_body{max-height:calc(100vh - 160px)}}";
5827
6231
  const tagId$6 = "@wowyuarm/dsh-agent-team/members.module.css";
5828
6232
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
5829
6233
  const tag = document.createElement("style");
@@ -5941,8 +6345,40 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5941
6345
  });
5942
6346
  }
5943
6347
  //#endregion
6348
+ //#region src/client/attachment-preview.ts
6349
+ /** Base64 one file payload in chunks so large uploads stay off the call-stack limit. */
6350
+ function bytesToBase64(bytes) {
6351
+ let binary = "";
6352
+ const chunk = 32768;
6353
+ for (let start = 0; start < bytes.length; start += chunk) binary += String.fromCharCode(...bytes.subarray(start, start + chunk));
6354
+ return btoa(binary);
6355
+ }
6356
+ /**
6357
+ * Thumbnail data URLs live in one session-wide cache: message lists re-render
6358
+ * often, and each miss costs a Host round-trip plus a base64 decode. Failed
6359
+ * loads (bytes already GC'd) are cached as `null` so the chip fallback is stable.
6360
+ */
6361
+ const dataUrlCache = /* @__PURE__ */ new Map();
6362
+ function cachedAttachmentDataUrl(attachmentId) {
6363
+ return dataUrlCache.get(attachmentId);
6364
+ }
6365
+ async function loadAttachmentDataUrl(getAttachment, attachment) {
6366
+ const cached = dataUrlCache.get(attachment.attachmentId);
6367
+ if (cached !== void 0) return cached;
6368
+ const result = await getAttachment({ attachmentId: attachment.attachmentId });
6369
+ const url = result.ok && attachment.mediaType.startsWith("image/") ? `data:${attachment.mediaType};base64,${result.value.bytesBase64}` : null;
6370
+ dataUrlCache.set(attachment.attachmentId, url);
6371
+ return url;
6372
+ }
6373
+ /** Human-readable byte size for attachment chips. */
6374
+ function formatByteSize(byteSize) {
6375
+ if (byteSize < 1024) return `${byteSize} B`;
6376
+ if (byteSize < 1024 * 1024) return `${(byteSize / 1024).toFixed(0)} KB`;
6377
+ return `${(byteSize / (1024 * 1024)).toFixed(1)} MB`;
6378
+ }
6379
+ //#endregion
5944
6380
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/composer.module.css.mjs
5945
- const css$5 = ".x9jGQq_root{padding:0 var(--dsh-composer-side-clearance,16px) 8px;flex-direction:column;align-items:center;display:flex}.x9jGQq_card{box-sizing:border-box;width:100%;max-width:var(--dsh-composer-card-max-width,780px);border:1px solid var(--dsw-alias-border-l2-darkmode-thin);background:var(--dsw-specific-input-major,var(--dsw-alias-surface-primary));box-shadow:var(--dsw-shadow-lv2);border-radius:22px;flex-direction:column;gap:6px;padding:10px 0 0;display:flex;position:relative}.x9jGQq_card:focus-within{border-color:var(--dsw-alias-state-business-primary)}.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-text-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-text-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-text-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_mentionDescription{min-width:0;color:var(--dsw-alias-label-tertiary,var(--dsw-alias-text-tertiary));text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.x9jGQq_toolbar{justify-content:flex-end;align-items:center;min-height:34px;padding:2px 8px 6px;display:flex}.x9jGQq_sendButton{background:var(--dsw-alias-button-info-fill,var(--dsw-alias-button-primary-fill));color:#fff;cursor:pointer;border:0;border-radius:50%;justify-content:center;align-items:center;width:34px;height:34px;padding:0;transition:background-color .1s,opacity .1s;display:inline-flex}.x9jGQq_sendButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover,var(--dsw-alias-button-primary-hover))}.x9jGQq_sendButton:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.x9jGQq_sendButton:disabled{cursor:not-allowed;opacity:.4}.x9jGQq_confirmation{color:var(--dsw-alias-text-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-text-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}}";
6381
+ const css$5 = ".x9jGQq_root{padding:0 var(--dsh-composer-side-clearance,16px) 8px;flex-direction:column;align-items:center;display:flex}.x9jGQq_card{box-sizing:border-box;width:100%;max-width:var(--dsh-composer-card-max-width,780px);border:1px solid var(--dsw-alias-border-l2-darkmode-thin);background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1));box-shadow:var(--dsw-shadow-lv2);border-radius:22px;flex-direction:column;gap:6px;padding:10px 0 0;display:flex;position:relative}.x9jGQq_inputArea{min-height:28px;position:relative}.x9jGQq_inputArea textarea{box-sizing:border-box;resize:none;width:100%;min-height:28px;max-height:336px;color:var(--dsw-alias-label-primary,var(--dsw-alias-label-primary));font:inherit;white-space:pre-wrap;overflow-wrap:anywhere;background:0 0;border:0;outline:0;padding:4px 12px 0 16px;font-size:15px;line-height:24px;display:block;overflow-y:auto}.x9jGQq_inputArea textarea::placeholder{color:var(--dsw-alias-label-caption,var(--dsw-alias-label-tertiary))}.x9jGQq_inputArea textarea:disabled{cursor:not-allowed;opacity:.55}.x9jGQq_mentionMenu{z-index:10;border:1px solid var(--dsw-alias-border-inverted);background:var(--dsw-specific-menu);max-height:min(320px,40vh);box-shadow:var(--dsw-shadow-lv3);border-radius:12px;padding:4px;position:absolute;bottom:calc(100% + 12px);left:0;right:0;overflow-y:auto}.x9jGQq_mentionOption{width:100%;min-height:40px;color:var(--dsw-alias-label-primary,var(--dsw-alias-label-primary));cursor:pointer;text-align:left;background:0 0;border:0;border-radius:10px;grid-template-columns:16px minmax(0,auto) minmax(0,1fr);align-items:center;gap:8px;padding:8px 10px;font-size:14px;line-height:22px;display:grid}.x9jGQq_mentionOption:hover,.x9jGQq_mentionOption[aria-selected=true]{background:var(--dsw-alias-interactive-bg-hover)}.x9jGQq_mentionName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.x9jGQq_mentionDescription{min-width:0;color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-tertiary));text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.x9jGQq_toolbar{justify-content:flex-end;align-items:center;gap:6px;min-height:34px;padding:2px 8px 6px;display:flex}.x9jGQq_attachButton{background:var(--dsw-specific-selector);color:var(--dsw-alias-label-primary);cursor:pointer;border:0;border-radius:999px;flex:none;place-items:center;width:28px;height:28px;margin-right:auto;display:grid}.x9jGQq_attachButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.x9jGQq_attachButton:disabled{cursor:default;opacity:.5}.x9jGQq_attachButton:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,var(--dsw-specific-selector));outline-offset:1px}.x9jGQq_fileInput{display:none}.x9jGQq_fileChips{flex-wrap:wrap;gap:4px;margin:0;padding:4px 8px 0;list-style:none;display:flex}.x9jGQq_fileChip{background:var(--dsw-alias-interactive-bg-hover);border-radius:6px;align-items:center;gap:4px;max-width:100%;padding:2px 4px 2px 8px;display:inline-flex}.x9jGQq_fileChipSize{color:var(--dsw-alias-label-tertiary);margin-left:6px}.x9jGQq_imageChip{align-items:center;display:flex}.x9jGQq_imageChipPreview{border:1px solid var(--dsw-alias-border-l2);object-fit:cover;border-radius:4px;width:56px;height:40px}.x9jGQq_fileChipName{text-overflow:ellipsis;white-space:nowrap;max-width:220px;font-size:11px;line-height:16px;overflow:hidden}.x9jGQq_fileChipRemove{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;justify-content:center;align-items:center;width:16px;height:16px;padding:0;font-size:12px;display:inline-flex}.x9jGQq_fileChipRemove:hover,.x9jGQq_fileChipRemove:focus-visible{color:var(--dsw-alias-label-primary);outline:none}.x9jGQq_sendButton{background:var(--dsw-alias-button-info-fill,var(--dsw-alias-button-primary-fill));color:#fff;cursor:pointer;border:0;border-radius:50%;justify-content:center;align-items:center;width:34px;height:34px;padding:0;transition:background-color .1s,opacity .1s;display:inline-flex}.x9jGQq_sendButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover,var(--dsw-alias-button-primary-hover))}.x9jGQq_sendButton:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.x9jGQq_sendButton:disabled{cursor:not-allowed;opacity:.4}.x9jGQq_confirmation{color:var(--dsw-alias-label-tertiary);align-self:stretch;margin:0;padding:0 16px;font-size:12px;line-height:18px}.x9jGQq_notifyRow{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-tertiary));overflow-wrap:anywhere;margin:0;padding:0 16px;font-size:12px;line-height:18px}.x9jGQq_error{color:var(--dsw-alias-state-error-primary);align-self:stretch;margin:0;padding:0 4px 2px;font-size:12px;line-height:18px}@media (width<=600px){.x9jGQq_mentionOption{grid-template-columns:16px minmax(0,1fr);min-height:36px;padding-block:6px}.x9jGQq_mentionDescription{display:none}}@media (prefers-reduced-motion:reduce){.x9jGQq_sendButton{transition:none}}";
5946
6382
  const tagId$5 = "@wowyuarm/dsh-agent-team/composer.module.css";
5947
6383
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
5948
6384
  const tag = document.createElement("style");
@@ -5952,9 +6388,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5952
6388
  document.head.appendChild(tag);
5953
6389
  }
5954
6390
  var composer_module_css_default = {
6391
+ "attachButton": "x9jGQq_attachButton",
5955
6392
  "card": "x9jGQq_card",
5956
6393
  "confirmation": "x9jGQq_confirmation",
5957
6394
  "error": "x9jGQq_error",
6395
+ "fileChip": "x9jGQq_fileChip",
6396
+ "fileChipName": "x9jGQq_fileChipName",
6397
+ "fileChipRemove": "x9jGQq_fileChipRemove",
6398
+ "fileChipSize": "x9jGQq_fileChipSize",
6399
+ "fileChips": "x9jGQq_fileChips",
6400
+ "fileInput": "x9jGQq_fileInput",
6401
+ "imageChip": "x9jGQq_imageChip",
6402
+ "imageChipPreview": "x9jGQq_imageChipPreview",
5958
6403
  "inputArea": "x9jGQq_inputArea",
5959
6404
  "mentionDescription": "x9jGQq_mentionDescription",
5960
6405
  "mentionMenu": "x9jGQq_mentionMenu",
@@ -5991,8 +6436,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5991
6436
  const normalized = query.toLocaleLowerCase();
5992
6437
  return members.filter((status) => status.presence !== "unavailable" && status.member.state !== "inactive" && status.member.handle.toLocaleLowerCase().startsWith(normalized));
5993
6438
  }
5994
- function TeamComposer({ members, recipients, draft, pending, confirmation, error, onDraftChange, onRecipientsChange, onSubmit, t }) {
6439
+ /** One object URL per draft file; revoked when the draft is removed. */
6440
+ const draftPreviewUrls = /* @__PURE__ */ new WeakMap();
6441
+ function draftPreviewUrl(file) {
6442
+ if (!file.type.startsWith("image/")) return void 0;
6443
+ let url = draftPreviewUrls.get(file);
6444
+ if (url === void 0) {
6445
+ url = URL.createObjectURL(file);
6446
+ draftPreviewUrls.set(file, url);
6447
+ }
6448
+ return url;
6449
+ }
6450
+ function TeamComposer({ members, recipients, draft, pending, confirmation, error, onDraftChange, onRecipientsChange, onSubmit, pendingFiles, onFilesChange, t }) {
5995
6451
  const inputRef = (0, react.useRef)(null);
6452
+ const fileInputRef = (0, react.useRef)(null);
5996
6453
  const rootRef = (0, react.useRef)(null);
5997
6454
  const menuRef = (0, react.useRef)(null);
5998
6455
  const composingRef = (0, react.useRef)(false);
@@ -6019,6 +6476,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6019
6476
  }
6020
6477
  setHighlight((current) => Math.min(current, candidates.length - 1));
6021
6478
  }, [mention, candidates.length]);
6479
+ (0, react.useEffect)(() => {
6480
+ const active = document.activeElement;
6481
+ if (active !== document.body && active?.closest("[aria-current=\"page\"]") === null) return;
6482
+ inputRef.current?.focus({ preventScroll: true });
6483
+ }, []);
6484
+ (0, react.useEffect)(() => {
6485
+ if (confirmation === void 0 || pending) return;
6486
+ inputRef.current?.focus({ preventScroll: true });
6487
+ }, [confirmation, pending]);
6022
6488
  const pruneRecipients = (nextDraft) => {
6023
6489
  const knownMembers = new Map(members.map((status) => [status.member.memberId, status.member]));
6024
6490
  const next = new Set([...recipients].filter((memberId) => {
@@ -6027,6 +6493,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6027
6493
  }));
6028
6494
  if (next.size !== recipients.size) onRecipientsChange(next);
6029
6495
  };
6496
+ (0, react.useEffect)(() => {
6497
+ if (members.length === 0) return;
6498
+ pruneRecipients(draft);
6499
+ }, [
6500
+ draft,
6501
+ recipients,
6502
+ members
6503
+ ]);
6030
6504
  const updateMention = (nextDraft, caret) => {
6031
6505
  const match = findMention(nextDraft, caret);
6032
6506
  setMention(match);
@@ -6090,6 +6564,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6090
6564
  ref: rootRef,
6091
6565
  className: composer_module_css_default.root,
6092
6566
  onSubmit: (event) => {
6567
+ console.log("DBG composer submit pending=%s draft=%j", pending, draft);
6093
6568
  event.preventDefault();
6094
6569
  if (!pending && draft.trim() !== "") onSubmit();
6095
6570
  },
@@ -6148,7 +6623,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6148
6623
  "aria-activedescendant": menuOpen && activeCandidate !== void 0 ? `${listId}-${activeCandidate.member.memberId}` : void 0,
6149
6624
  "aria-expanded": menuOpen,
6150
6625
  value: draft,
6151
- disabled: pending,
6626
+ readOnly: pending,
6152
6627
  placeholder: t("messagePlaceholder"),
6153
6628
  rows: 1,
6154
6629
  onChange,
@@ -6171,15 +6646,78 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6171
6646
  "data-team-notify": true,
6172
6647
  children: t("composerNotify", { ids: [...recipients].sort().map((memberId) => `@${members.find((candidate) => candidate.member.memberId === memberId)?.member.handle ?? memberId}`).join(", ") })
6173
6648
  }),
6174
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6649
+ onFilesChange !== void 0 && pendingFiles !== void 0 && pendingFiles.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
6650
+ className: composer_module_css_default.fileChips,
6651
+ "aria-label": t("attachFiles"),
6652
+ children: pendingFiles.map((file, index) => {
6653
+ const previewUrl = draftPreviewUrl(file);
6654
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
6655
+ className: `${composer_module_css_default.fileChip} ${previewUrl !== void 0 ? composer_module_css_default.imageChip : ""}`,
6656
+ children: [
6657
+ previewUrl !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
6658
+ src: previewUrl,
6659
+ alt: "",
6660
+ className: composer_module_css_default.imageChipPreview
6661
+ }),
6662
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6663
+ className: composer_module_css_default.fileChipName,
6664
+ title: file.name,
6665
+ children: [file.name, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6666
+ className: composer_module_css_default.fileChipSize,
6667
+ children: formatByteSize(file.size)
6668
+ })]
6669
+ }),
6670
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6671
+ type: "button",
6672
+ className: composer_module_css_default.fileChipRemove,
6673
+ "aria-label": t("removeFile", { name: file.name }),
6674
+ disabled: pending,
6675
+ onClick: () => {
6676
+ const url = draftPreviewUrls.get(file);
6677
+ if (url !== void 0) URL.revokeObjectURL(url);
6678
+ onFilesChange(pendingFiles.filter((_, candidate) => candidate !== index));
6679
+ },
6680
+ children: "×"
6681
+ })
6682
+ ]
6683
+ }, `${file.name}-${index}`);
6684
+ })
6685
+ }),
6686
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6175
6687
  className: composer_module_css_default.toolbar,
6176
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6688
+ children: [onFilesChange !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6689
+ ref: fileInputRef,
6690
+ type: "file",
6691
+ multiple: true,
6692
+ className: composer_module_css_default.fileInput,
6693
+ "aria-hidden": "true",
6694
+ tabIndex: -1,
6695
+ onChange: (event) => {
6696
+ const chosen = [...event.target.files ?? []];
6697
+ if (chosen.length > 0 && pendingFiles !== void 0) onFilesChange([...pendingFiles, ...chosen]);
6698
+ event.target.value = "";
6699
+ }
6700
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6701
+ type: "button",
6702
+ className: composer_module_css_default.attachButton,
6703
+ "aria-label": t("attachFiles"),
6704
+ title: t("attachFiles"),
6705
+ disabled: pending,
6706
+ onClick: () => {
6707
+ fileInputRef.current?.click();
6708
+ },
6709
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 })
6710
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6177
6711
  type: "submit",
6178
6712
  className: composer_module_css_default.sendButton,
6179
6713
  "aria-label": pending ? t("sendingMessage") : t("sendMessage"),
6180
6714
  disabled: pending || draft.trim() === "",
6715
+ onMouseDown: (event) => {
6716
+ event.preventDefault();
6717
+ inputRef.current?.focus({ preventScroll: true });
6718
+ },
6181
6719
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSendOutline16, { size: 16 })
6182
- })
6720
+ })]
6183
6721
  })
6184
6722
  ]
6185
6723
  }), error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -6190,6 +6728,56 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6190
6728
  });
6191
6729
  }
6192
6730
  //#endregion
6731
+ //#region src/client/task-refs.ts
6732
+ const resolved = /* @__PURE__ */ new Map();
6733
+ const pending = /* @__PURE__ */ new Set();
6734
+ /** Refs the Host did not recognize; never re-queried (no retry loops). */
6735
+ const unresolvable = /* @__PURE__ */ new Set();
6736
+ const listeners$1 = /* @__PURE__ */ new Set();
6737
+ let version = 0;
6738
+ const emit = () => {
6739
+ version += 1;
6740
+ for (const listener of listeners$1) listener();
6741
+ };
6742
+ const subscribe = (listener) => {
6743
+ listeners$1.add(listener);
6744
+ return () => {
6745
+ listeners$1.delete(listener);
6746
+ };
6747
+ };
6748
+ /** Stable snapshot token; the map is read directly after this changes. */
6749
+ const getSnapshot = () => version;
6750
+ /** React binding: re-renders the caller when any ref resolution lands. */
6751
+ const useResolvedTaskRefVersion = () => (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6752
+ const cachedResolvedTaskRef = (taskRef) => resolved.get(taskRef);
6753
+ /** Store one resolution (click path) and wake every rendered link. */
6754
+ const rememberResolvedTaskRef = (entry) => {
6755
+ resolved.set(entry.taskRef, entry);
6756
+ pending.delete(entry.taskRef);
6757
+ emit();
6758
+ };
6759
+ /**
6760
+ * Batch-resolve unknown refs through the Host lookup. Concurrent callers
6761
+ * deduplicate through the pending set; failures just clear the pending mark
6762
+ * so a later interaction can retry.
6763
+ */
6764
+ const resolveUnknownTaskRefs = async (refs, lookup) => {
6765
+ const missing = refs.filter((taskRef) => !resolved.has(taskRef) && !pending.has(taskRef) && !unresolvable.has(taskRef));
6766
+ if (missing.length === 0) return;
6767
+ for (const taskRef of missing) pending.add(taskRef);
6768
+ try {
6769
+ const entries = await lookup(missing);
6770
+ for (const entry of entries) {
6771
+ resolved.set(entry.taskRef, entry);
6772
+ pending.delete(entry.taskRef);
6773
+ }
6774
+ for (const taskRef of missing) if (!resolved.has(taskRef)) unresolvable.add(taskRef);
6775
+ if (entries.length > 0) emit();
6776
+ } finally {
6777
+ for (const taskRef of missing) pending.delete(taskRef);
6778
+ }
6779
+ };
6780
+ //#endregion
6193
6781
  //#region src/client/team-formatters.ts
6194
6782
  function formatTaskStatus(status, t) {
6195
6783
  return t({
@@ -6233,6 +6821,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6233
6821
  for (let index = 0; index < memberId.length; index += 1) hash = (hash * 31 + memberId.charCodeAt(index)) % 360;
6234
6822
  return hash;
6235
6823
  }
6824
+ const BRANDED_REF_PATTERN = /\b(task|channel|thread):[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi;
6825
+ /**
6826
+ * Split a literal text run into plain and branded-ref segments. The pattern
6827
+ * anchors on the fixed ref prefixes plus the UUID shape, so ordinary prose
6828
+ * containing a colon never linkifies. Refs render as navigation links; text
6829
+ * without any ref comes back as one untouched segment.
6830
+ */
6831
+ function splitBrandedRefs(text) {
6832
+ const segments = [];
6833
+ let cursor = 0;
6834
+ for (const match of text.matchAll(BRANDED_REF_PATTERN)) {
6835
+ const start = match.index ?? 0;
6836
+ if (start > cursor) segments.push({ text: text.slice(cursor, start) });
6837
+ segments.push({
6838
+ text: match[0],
6839
+ ref: match[0]
6840
+ });
6841
+ cursor = start + match[0].length;
6842
+ }
6843
+ if (cursor < text.length) segments.push({ text: text.slice(cursor) });
6844
+ return segments;
6845
+ }
6236
6846
  function escapeRegExp(value) {
6237
6847
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6238
6848
  }
@@ -6313,7 +6923,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6313
6923
  }
6314
6924
  function formatActivity(activity, options) {
6315
6925
  const actor = options.actorName(activity.actor);
6316
- if (activity.kind === "accept") return options.t("activityAccepted", { actor });
6926
+ if (activity.kind === "accept") return activity.completedClaimRefs !== void 0 && activity.completedClaimRefs.length > 0 ? options.t("activityAcceptedWithClaims", {
6927
+ actor,
6928
+ count: activity.completedClaimRefs.length
6929
+ }) : options.t("activityAccepted", { actor });
6317
6930
  if (activity.kind === "close") return options.t("activityClosed", { actor });
6318
6931
  if (activity.kind === "reopen") return options.t("activityReopened", { actor });
6319
6932
  const direction = "claimRef" in activity ? options.claims.find((claim) => claim.claimRef === activity.claimRef)?.direction ?? options.t("claims") : options.t("claims");
@@ -6335,9 +6948,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6335
6948
  });
6336
6949
  throw new Error(`unknown Team Activity kind: ${activity.kind}`);
6337
6950
  }
6951
+ /** Remove the machine-facing `[attachment] <path>` prompt lines from a body before display. */
6952
+ function stripAttachmentLines(body) {
6953
+ return body.replaceAll(/^\[attachment\] .*$(\n)?/gm, "").replace(/\n+$/, "");
6954
+ }
6338
6955
  //#endregion
6339
6956
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/conversation.module.css.mjs
6340
- const css$4 = ".omcBaG_surface{grid-template-rows:auto minmax(0,1fr) auto;min-width:0;height:100%;min-height:0;display:grid;overflow:hidden}.omcBaG_surfaceHeader{border-bottom:1px solid var(--dsw-alias-border-subtle);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-text-primary);overflow-wrap:anywhere;margin:0;font-size:20px;font-weight:600;line-height:28px}.omcBaG_headerCopy p{color:var(--dsw-alias-text-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{margin-top:0}.omcBaG_messageIdentity{background:hsl(var(--team-avatar-hue,212) 42% 46%);color:#fff;border-radius:50%;flex:0 0 28px;justify-content:center;align-items:center;height:28px;font-size:12px;font-weight:600;display:flex}.omcBaG_messageRow[data-human] .omcBaG_messageIdentity{background:var(--dsw-alias-state-business-primary)}.omcBaG_messageRow[data-grouped] .omcBaG_messageIdentity{visibility:hidden}.omcBaG_messageBody{min-width:0}.omcBaG_nameRow{flex-wrap:wrap;align-items:baseline;gap:8px;display:flex}.omcBaG_nameRow strong{color:var(--dsw-alias-text-primary);font-size:13px;font-weight:600;line-height:20px}.omcBaG_messageTime{color:var(--dsw-alias-text-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_messageBody .omcBaG_messageMarkdown{font-size:14px;line-height:22px}.omcBaG_messageBody>.omcBaG_messageMarkdown>div:first-child{color:var(--dsw-alias-text-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-text-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-text-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-fill-tertiary);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-text-tertiary);text-transform:uppercase;font-size:12px;line-height:18px}.omcBaG_welcome h1{color:var(--dsw-alias-text-primary);margin:8px 0;font-size:24px;font-weight:600;line-height:32px}.omcBaG_welcome p{color:var(--dsw-alias-text-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{border:1px solid #0000;border-radius:10px;margin:2px -10px;padding:3px 10px;transition:border-color .12s}.omcBaG_messageRun:hover{border-color:var(--dsw-alias-border-default)}.omcBaG_messageRow[data-grouped]:has(.omcBaG_messageBody>button){border-top:1px solid var(--dsw-alias-border-subtle);margin-top:3px;padding-top:7px}.omcBaG_mention{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 12%, transparent);color:var(--dsw-alias-state-business-primary);border-radius:5px;padding:0 4px;font-weight:500;box-shadow:0 1px 2px #00000014}.omcBaG_mentionsRow{gap:4px;width:fit-content;margin-top:3px;font-size:.85em;display:flex}@media (width<=600px){.omcBaG_messageRun{margin:2px -6px;padding:3px 6px}}@media (prefers-reduced-motion:reduce){.omcBaG_messageRun{transition:none}}";
6957
+ const css$4 = ".omcBaG_surface{grid-template-rows:auto minmax(0,1fr) auto;min-width:0;height:100%;min-height:0;display:grid;overflow:hidden}.omcBaG_surfaceHeader{border-bottom:1px solid var(--dsw-alias-border-l2);min-width:0;padding:14px clamp(18px,3vw,36px) 12px}.omcBaG_headerRow{justify-content:space-between;align-items:flex-start;gap:16px;min-width:0;max-width:880px;margin:0 auto;display:flex}.omcBaG_headerCopy{min-width:0}.omcBaG_headerCopy h1{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;font-size:20px;font-weight:600;line-height:28px}.omcBaG_headerCopy p{color:var(--dsw-alias-label-secondary);margin:3px 0 0;font-size:13px;line-height:20px}.omcBaG_headerActions{flex:none;align-items:center;gap:6px;display:flex}.omcBaG_backRow{max-width:880px;margin:0 auto 8px}.omcBaG_timeline{overscroll-behavior:contain;scrollbar-gutter:stable;min-height:0;padding:12px clamp(18px,3vw,36px) 24px;overflow:hidden auto}.omcBaG_timelineContent{flex-direction:column;min-width:0;max-width:880px;min-height:100%;margin:0 auto;display:flex}.omcBaG_emptySurface{margin:auto;padding:32px 0}.omcBaG_emptySurface .omcBaG_emptyState{text-align:center;justify-items:center}.omcBaG_timelineAction{justify-content:center;padding:2px 0 8px;display:flex}.omcBaG_messageRow{gap:10px;padding:10px 0;display:flex}.omcBaG_messageRow[data-grouped]{padding-top:2px}.omcBaG_messageRow[data-grouped] .omcBaG_messageBody>:first-child{margin-top:0}.omcBaG_messageIdentity{background:hsl(var(--team-avatar-hue,212) 42% 46%);color:#fff;border-radius:50%;flex:0 0 28px;justify-content:center;align-items:center;height:28px;font-size:12px;font-weight:600;display:flex}.omcBaG_messageRow[data-human] .omcBaG_messageIdentity{background:var(--dsw-alias-state-business-primary)}.omcBaG_messageRow[data-grouped] .omcBaG_messageIdentity{visibility:hidden}.omcBaG_messageBody{min-width:0}.omcBaG_nameRow{flex-wrap:wrap;align-items:baseline;gap:8px;display:flex}.omcBaG_nameRow strong{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600;line-height:20px}.omcBaG_messageTime{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:20px}.omcBaG_messageText{white-space:pre-wrap;word-break:break-word;margin:6px 0;font-size:14px;line-height:22px}.omcBaG_messageBody .omcBaG_messageMarkdown{font-size:14px;line-height:22px}.omcBaG_messageBody>.omcBaG_messageMarkdown>div:first-child{color:var(--dsw-alias-label-primary);font:inherit}.omcBaG_messageBody .omcBaG_messageMarkdown p{margin:6px 0}.omcBaG_messageBody .omcBaG_messageMarkdown :where(ul,ol){margin:6px 0;padding-left:22px}.omcBaG_messageBody .omcBaG_messageMarkdown li+li{margin-top:2px}.omcBaG_messageBody .omcBaG_messageMarkdown strong{font-weight:600}.omcBaG_messageBody .omcBaG_messageMarkdown :where(h1,h2,h3,h4,h5,h6){margin:12px 0 4px}.omcBaG_messageBody .omcBaG_messageMarkdown :where(h1){font-size:17px;line-height:26px}.omcBaG_messageBody .omcBaG_messageMarkdown :where(h2){font-size:16px;line-height:24px}.omcBaG_messageBody .omcBaG_messageMarkdown :where(h3,h4,h5,h6){font-size:15px;line-height:22px}.omcBaG_messageBody .omcBaG_messageMarkdown pre{margin:8px 0;padding:10px 12px;font-size:13px}.omcBaG_messageBody .omcBaG_messageMarkdown blockquote{margin:6px 0}.omcBaG_messageBody .omcBaG_messageMarkdown :where(th,td){padding-block:5px}.omcBaG_emptyState,.omcBaG_loadingState{color:var(--dsw-alias-label-tertiary);margin:0;padding:14px 0;font-size:13px;line-height:20px}.omcBaG_emptyState{gap:3px;display:grid}.omcBaG_emptyState strong{color:var(--dsw-alias-label-secondary);font-weight:500}.omcBaG_emptyState span{font-size:12px}.omcBaG_loadingState{align-items:center;gap:8px;display:flex}.omcBaG_loadingMark{background:var(--dsw-alias-bg-skeleton);border-radius:50%;width:8px;height:8px;animation:1.2s ease-in-out infinite omcBaG_pulse}.omcBaG_error,.omcBaG_errorState{color:var(--dsw-alias-state-error-primary);max-width:880px;margin:0 auto;padding-top:6px;font-size:12px;line-height:18px}.omcBaG_errorState{justify-content:space-between;align-items:center;gap:8px;display:flex}.omcBaG_welcomeSurface{justify-content:center;align-items:center;min-width:0;height:100%;padding:32px;display:flex}.omcBaG_welcome{text-align:center;max-width:420px}.omcBaG_welcomeEyebrow{color:var(--dsw-alias-label-tertiary);text-transform:uppercase;font-size:12px;line-height:18px}.omcBaG_welcome h1{color:var(--dsw-alias-label-primary);margin:8px 0;font-size:24px;font-weight:600;line-height:32px}.omcBaG_welcome p{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px;line-height:20px}@keyframes omcBaG_pulse{0%,to{opacity:.35}50%{opacity:1}}@media (width<=600px){.omcBaG_surfaceHeader{padding:12px 12px 10px}.omcBaG_headerRow{flex-direction:column;align-items:stretch;gap:8px}.omcBaG_headerActions{flex-wrap:wrap}.omcBaG_backRow{margin-bottom:6px}.omcBaG_timeline{scrollbar-gutter:auto;padding:8px 12px 16px}.omcBaG_messageRow{padding:8px 0}}@media (prefers-reduced-motion:reduce){.omcBaG_loadingMark{animation:none}}.omcBaG_messageRun{margin:2px 0;padding:3px 0}.omcBaG_messageRow[data-grouped]:has(.omcBaG_messageBody>button){border-top:1px solid var(--dsw-alias-border-l2);margin-top:3px;padding-top:7px}.omcBaG_runDivider{border-top:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);margin:2px 0 0;padding:5px 0 0 38px;font-size:11px;line-height:16px}.omcBaG_runDivider+.omcBaG_messageRow[data-grouped]:has(.omcBaG_messageBody>button){border-top:0;margin-top:0}.omcBaG_mention{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 12%, transparent);color:var(--dsw-alias-state-business-primary);border-radius:5px;padding:0 4px;font-weight:500;box-shadow:0 1px 2px #00000014}.omcBaG_mentionsRow{gap:4px;width:fit-content;margin-top:3px;font-size:.85em;display:flex}.omcBaG_attachmentStrip{flex-wrap:wrap;gap:6px;margin-top:4px;display:flex}.omcBaG_attachmentThumb{cursor:zoom-in;border:0;border-radius:8px;padding:0}.omcBaG_attachmentThumb img{object-fit:cover;border-radius:8px;width:128px;height:96px;display:block}.omcBaG_attachmentThumb:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,currentColor);outline-offset:1px}.omcBaG_confirmBody{margin:0 0 8px}.omcBaG_confirmList{gap:6px;margin:0;padding-left:18px;display:grid}.omcBaG_refLink{color:var(--dsw-alias-state-business-primary);cursor:pointer;font:inherit;text-align:left;text-underline-offset:3px;background:0 0;border:none;border-radius:4px;padding:0;text-decoration:underline}.omcBaG_refLink:hover{text-decoration-thickness:2px}.omcBaG_refLink:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}.omcBaG_attachmentModal{width:min(1100px,92vw)}.omcBaG_attachmentZoom{object-fit:contain;border-radius:12px;max-width:100%;max-height:78vh;margin:0 auto;display:block}.omcBaG_attachmentChip{background:var(--dsw-alias-interactive-bg-hover);border-radius:6px;align-items:baseline;gap:6px;max-width:100%;padding:3px 8px;display:inline-flex}.omcBaG_attachmentChipName{text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:17px;overflow:hidden}.omcBaG_attachmentChipSize{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:11px;line-height:17px}";
6341
6958
  const tagId$4 = "@wowyuarm/dsh-agent-team/conversation.module.css";
6342
6959
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
6343
6960
  const tag = document.createElement("style");
@@ -6347,7 +6964,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6347
6964
  document.head.appendChild(tag);
6348
6965
  }
6349
6966
  var conversation_module_css_default = {
6967
+ "attachmentChip": "omcBaG_attachmentChip",
6968
+ "attachmentChipName": "omcBaG_attachmentChipName",
6969
+ "attachmentChipSize": "omcBaG_attachmentChipSize",
6970
+ "attachmentModal": "omcBaG_attachmentModal",
6971
+ "attachmentStrip": "omcBaG_attachmentStrip",
6972
+ "attachmentThumb": "omcBaG_attachmentThumb",
6973
+ "attachmentZoom": "omcBaG_attachmentZoom",
6350
6974
  "backRow": "omcBaG_backRow",
6975
+ "confirmBody": "omcBaG_confirmBody",
6976
+ "confirmList": "omcBaG_confirmList",
6351
6977
  "emptyState": "omcBaG_emptyState",
6352
6978
  "emptySurface": "omcBaG_emptySurface",
6353
6979
  "error": "omcBaG_error",
@@ -6368,6 +6994,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6368
6994
  "messageTime": "omcBaG_messageTime",
6369
6995
  "nameRow": "omcBaG_nameRow",
6370
6996
  "pulse": "omcBaG_pulse",
6997
+ "refLink": "omcBaG_refLink",
6998
+ "runDivider": "omcBaG_runDivider",
6371
6999
  "surface": "omcBaG_surface",
6372
7000
  "surfaceHeader": "omcBaG_surfaceHeader",
6373
7001
  "timeline": "omcBaG_timeline",
@@ -6380,10 +7008,61 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6380
7008
  //#endregion
6381
7009
  //#region src/client/TeamMessage.tsx
6382
7010
  /** One chat message row with identity chrome and sender-appropriate rendering. */
6383
- function TeamMessage({ senderName, memberId, human, body, occurredAt, mentionNames, senderTitle, grouped, children }) {
7011
+ function TeamMessage({ senderName, memberId, human, body, occurredAt, mentionNames, senderTitle, grouped, attachments, loadAttachment, t, onOpenRef, onResolveTaskRefs, children }) {
6384
7012
  const avatarStyle = human ? void 0 : { "--team-avatar-hue": memberHue(memberId) };
6385
- const inline = (human || isPlainTextBody(body)) && mentionNames !== void 0 && mentionNames.length > 0 ? splitMentionNames(body, mentionNames) : void 0;
7013
+ const displayBody = stripAttachmentLines(body) === "" ? body : stripAttachmentLines(body);
7014
+ const inline = (human || isPlainTextBody(displayBody)) && mentionNames !== void 0 && mentionNames.length > 0 ? splitMentionNames(displayBody, mentionNames) : void 0;
6386
7015
  const fallbackNames = inline === void 0 ? mentionNames ?? [] : inline.unmatched;
7016
+ const richAgentBody = !human && !isPlainTextBody(displayBody);
7017
+ const fallbackRefs = richAgentBody && onOpenRef !== void 0 ? splitBrandedRefs(displayBody).filter((segment) => segment.ref !== void 0 && !segment.ref.startsWith("task:")).map((segment) => segment.ref) : [];
7018
+ const refVersion = useResolvedTaskRefVersion();
7019
+ const bodyTaskRefs = onOpenRef === void 0 || richAgentBody ? [] : splitBrandedRefs(displayBody).filter((segment) => segment.ref !== void 0 && segment.ref.startsWith("task:")).map((segment) => segment.ref);
7020
+ const bodyTaskRefKey = bodyTaskRefs.join(",");
7021
+ (0, react.useEffect)(() => {
7022
+ if (onResolveTaskRefs === void 0 || bodyTaskRefKey === "") return;
7023
+ resolveUnknownTaskRefs(bodyTaskRefs, onResolveTaskRefs);
7024
+ }, [
7025
+ onResolveTaskRefs,
7026
+ bodyTaskRefKey,
7027
+ refVersion
7028
+ ]);
7029
+ const taskLabel = (0, react.useCallback)((taskNumber) => t?.("taskLabel", { number: taskNumber }) ?? `Task #${taskNumber}`, [t]);
7030
+ const markdownRef = (0, react.useRef)(null);
7031
+ (0, react.useLayoutEffect)(() => {
7032
+ const root = markdownRef.current;
7033
+ if (!richAgentBody || root === null || onOpenRef === void 0) return;
7034
+ const textNodes = markdownProseTextNodes(root);
7035
+ const taskRefs = [...new Set(textNodes.flatMap((node) => splitBrandedRefs(node.data).filter((segment) => segment.ref?.startsWith("task:") === true).map((segment) => segment.ref)))];
7036
+ if (onResolveTaskRefs !== void 0 && taskRefs.length > 0) resolveUnknownTaskRefs(taskRefs, onResolveTaskRefs);
7037
+ for (const node of textNodes) renderResolvedMarkdownTaskRefs(node, taskLabel);
7038
+ for (const button of root.querySelectorAll("button[data-task-ref]")) {
7039
+ const taskRef = button.dataset.taskRef;
7040
+ const hit = taskRef === void 0 ? void 0 : cachedResolvedTaskRef(taskRef);
7041
+ if (taskRef !== void 0 && hit !== void 0) button.textContent = taskLabel(hit.taskNumber);
7042
+ }
7043
+ }, [
7044
+ richAgentBody,
7045
+ onOpenRef,
7046
+ onResolveTaskRefs,
7047
+ refVersion,
7048
+ taskLabel
7049
+ ]);
7050
+ (0, react.useEffect)(() => {
7051
+ const root = markdownRef.current;
7052
+ if (!richAgentBody || root === null || onOpenRef === void 0) return;
7053
+ const openTask = (event) => {
7054
+ const target = event.target;
7055
+ if (!(target instanceof Element)) return;
7056
+ const button = target.closest("button[data-task-ref]");
7057
+ if (button === null || !root.contains(button)) return;
7058
+ const taskRef = button instanceof HTMLElement ? button.dataset.taskRef : void 0;
7059
+ if (taskRef !== void 0) onOpenRef(taskRef);
7060
+ };
7061
+ root.addEventListener("click", openTask);
7062
+ return () => {
7063
+ root.removeEventListener("click", openTask);
7064
+ };
7065
+ }, [richAgentBody, onOpenRef]);
6387
7066
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
6388
7067
  className: conversation_module_css_default.messageRow,
6389
7068
  "data-human": human || void 0,
@@ -6411,26 +7090,185 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6411
7090
  children: inline.segments.map((segment, index) => segment.mention ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6412
7091
  className: conversation_module_css_default.mention,
6413
7092
  children: segment.text
6414
- }, index) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: segment.text }, index))
6415
- }) : human ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7093
+ }, index) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderRefs(segment.text, onOpenRef, taskLabel) }, index))
7094
+ }) : human || onOpenRef !== void 0 && isPlainTextBody(displayBody) && splitBrandedRefs(displayBody).some((segment) => segment.ref !== void 0) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6416
7095
  className: conversation_module_css_default.messageText,
6417
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MessageText, { text: body })
7096
+ children: onOpenRef === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MessageText, { text: displayBody }) : renderRefs(displayBody, onOpenRef, taskLabel)
6418
7097
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7098
+ ref: markdownRef,
6419
7099
  className: conversation_module_css_default.messageMarkdown,
6420
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, { text: body })
7100
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, { text: displayBody }, `${displayBody}:${onOpenRef === void 0 ? "literal" : "refs"}`)
6421
7101
  }),
6422
- fallbackNames.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7102
+ (fallbackNames.length > 0 || fallbackRefs.length > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6423
7103
  className: conversation_module_css_default.mentionsRow,
6424
- children: fallbackNames.map((name) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7104
+ children: [fallbackNames.map((name) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6425
7105
  className: conversation_module_css_default.mention,
6426
7106
  children: ["@", name]
6427
- }, name))
7107
+ }, name)), fallbackRefs.map((ref) => {
7108
+ const resolved = cachedResolvedTaskRef(ref);
7109
+ const label = resolved !== void 0 && ref.startsWith("task:") ? taskLabel(resolved.taskNumber) : ref;
7110
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7111
+ type: "button",
7112
+ className: conversation_module_css_default.refLink,
7113
+ title: ref,
7114
+ onClick: () => {
7115
+ onOpenRef(ref);
7116
+ },
7117
+ children: label
7118
+ }, ref);
7119
+ })]
7120
+ }),
7121
+ attachments !== void 0 && attachments.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamAttachmentStrip, {
7122
+ attachments,
7123
+ ...loadAttachment === void 0 ? {} : { loadAttachment },
7124
+ ...t === void 0 ? {} : { t }
6428
7125
  }),
6429
7126
  children
6430
7127
  ]
6431
7128
  })]
6432
7129
  });
6433
7130
  }
7131
+ /** Text nodes that Markdown rendered as prose rather than code or a link. */
7132
+ function markdownProseTextNodes(root) {
7133
+ const nodes = [];
7134
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
7135
+ for (let node = walker.nextNode(); node !== null; node = walker.nextNode()) {
7136
+ const parent = node.parentElement;
7137
+ if (parent !== null && parent.closest("code, pre, a, button") === null) nodes.push(node);
7138
+ }
7139
+ return nodes;
7140
+ }
7141
+ /** Replace resolved refs in one prose text node without changing Markdown structure. */
7142
+ function renderResolvedMarkdownTaskRefs(node, taskLabel) {
7143
+ const segments = splitBrandedRefs(node.data);
7144
+ if (!segments.some((segment) => segment.ref?.startsWith("task:") === true && cachedResolvedTaskRef(segment.ref) !== void 0)) return;
7145
+ const fragment = document.createDocumentFragment();
7146
+ for (const segment of segments) {
7147
+ const taskRef = segment.ref?.startsWith("task:") === true ? segment.ref : void 0;
7148
+ if (taskRef === void 0) {
7149
+ fragment.append(segment.text);
7150
+ continue;
7151
+ }
7152
+ const resolved = cachedResolvedTaskRef(taskRef);
7153
+ if (resolved === void 0) {
7154
+ fragment.append(segment.text);
7155
+ continue;
7156
+ }
7157
+ const button = document.createElement("button");
7158
+ button.type = "button";
7159
+ if (conversation_module_css_default.refLink !== void 0) button.className = conversation_module_css_default.refLink;
7160
+ button.dataset.taskRef = taskRef;
7161
+ button.title = taskRef;
7162
+ button.textContent = taskLabel(resolved.taskNumber);
7163
+ fragment.append(button);
7164
+ }
7165
+ node.replaceWith(fragment);
7166
+ }
7167
+ /** Render one literal text run, linkifying branded refs when navigation is available. */
7168
+ function renderRefs(text, onOpenRef, taskLabel) {
7169
+ if (onOpenRef === void 0) return text;
7170
+ return splitBrandedRefs(text).map((segment, index) => {
7171
+ if (segment.ref === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: segment.text }, index);
7172
+ const resolved = cachedResolvedTaskRef(segment.ref);
7173
+ const label = resolved !== void 0 && segment.ref.startsWith("task:") ? taskLabel(resolved.taskNumber) : segment.ref;
7174
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7175
+ type: "button",
7176
+ className: conversation_module_css_default.refLink,
7177
+ title: segment.ref,
7178
+ onClick: () => {
7179
+ onOpenRef(segment.ref);
7180
+ },
7181
+ children: label
7182
+ }, index);
7183
+ });
7184
+ }
7185
+ /** One message's attachment strip: image thumbnails with a large view, or name chips when bytes are gone. */
7186
+ function TeamAttachmentStrip({ attachments, loadAttachment, t }) {
7187
+ const [zoomed, setZoomed] = (0, react.useState)();
7188
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7189
+ className: conversation_module_css_default.attachmentStrip,
7190
+ children: [attachments.map((attachment) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamAttachment, {
7191
+ attachment,
7192
+ ...loadAttachment === void 0 ? {} : { loadAttachment },
7193
+ ...t === void 0 ? {} : { t },
7194
+ onZoom: setZoomed
7195
+ }, attachment.attachmentId)), zoomed !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
7196
+ open: true,
7197
+ ...conversation_module_css_default.attachmentModal === void 0 ? {} : { className: conversation_module_css_default.attachmentModal },
7198
+ title: zoomed.name,
7199
+ onClose: () => {
7200
+ setZoomed(void 0);
7201
+ },
7202
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
7203
+ className: conversation_module_css_default.attachmentZoom,
7204
+ src: cachedAttachmentDataUrl(zoomed.attachmentId) ?? void 0,
7205
+ alt: zoomed.name
7206
+ })
7207
+ })]
7208
+ });
7209
+ }
7210
+ function TeamAttachment({ attachment, loadAttachment, t, onZoom }) {
7211
+ const wantsPreview = loadAttachment !== void 0 && attachment.mediaType.startsWith("image/");
7212
+ const [dataUrl, setDataUrl] = (0, react.useState)(wantsPreview ? cachedAttachmentDataUrl(attachment.attachmentId) : null);
7213
+ (0, react.useEffect)(() => {
7214
+ if (!wantsPreview || dataUrl !== void 0) return;
7215
+ let mounted = true;
7216
+ loadAttachmentDataUrl(loadAttachment, attachment).then((url) => {
7217
+ if (mounted) setDataUrl(url);
7218
+ });
7219
+ return () => {
7220
+ mounted = false;
7221
+ };
7222
+ }, [
7223
+ wantsPreview,
7224
+ dataUrl,
7225
+ loadAttachment,
7226
+ attachment
7227
+ ]);
7228
+ const expired = t?.("attachmentExpired") ?? "File no longer cached";
7229
+ if (wantsPreview && dataUrl !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7230
+ type: "button",
7231
+ className: conversation_module_css_default.attachmentThumb,
7232
+ "aria-label": t?.("viewImage", { name: attachment.name }) ?? attachment.name,
7233
+ title: attachment.name,
7234
+ onClick: () => {
7235
+ onZoom(attachment);
7236
+ },
7237
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
7238
+ src: dataUrl,
7239
+ alt: attachment.name
7240
+ })
7241
+ });
7242
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7243
+ className: conversation_module_css_default.attachmentChip,
7244
+ title: wantsPreview ? expired : `${attachment.name} · ${formatByteSize(attachment.byteSize)}`,
7245
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7246
+ className: conversation_module_css_default.attachmentChipName,
7247
+ children: attachment.name
7248
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7249
+ className: conversation_module_css_default.attachmentChipSize,
7250
+ children: wantsPreview ? expired : formatByteSize(attachment.byteSize)
7251
+ })]
7252
+ });
7253
+ }
7254
+ //#endregion
7255
+ //#region src/client/TeamRunDivider.tsx
7256
+ /**
7257
+ * Explicit boundary between two same-sender Messages of one run separated by
7258
+ * a real waiting gap: the hairline restores the block boundary that grouping
7259
+ * removed, and the label below it restores the instant that the suppressed
7260
+ * identity chrome would have shown.
7261
+ */
7262
+ function TeamRunDivider({ occurredAt }) {
7263
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7264
+ className: conversation_module_css_default.runDivider,
7265
+ role: "separator",
7266
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
7267
+ dateTime: occurredAt,
7268
+ children: formatMessageTime(occurredAt)
7269
+ })
7270
+ });
7271
+ }
6434
7272
  //#endregion
6435
7273
  //#region src/client/team-membership.ts
6436
7274
  /**
@@ -6538,8 +7376,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6538
7376
  jumpToLatest
6539
7377
  };
6540
7378
  }
6541
- //#endregion
6542
- //#region src/client/team-separators.ts
7379
+ /**
7380
+ * Whether two adjacent same-sender run items are separated by a real waiting
7381
+ * gap: only such gaps earn an explicit time divider, while rapid bursts stay
7382
+ * merged into one seamless run.
7383
+ */
7384
+ function isRunGap(previousOccurredAt, occurredAt) {
7385
+ if (previousOccurredAt === void 0 || occurredAt === void 0) return false;
7386
+ const previous = Date.parse(previousOccurredAt);
7387
+ const at = Date.parse(occurredAt);
7388
+ return !Number.isNaN(previous) && !Number.isNaN(at) && at - previous >= 5 * 6e4;
7389
+ }
6543
7390
  const pad = (value) => String(value).padStart(2, "0");
6544
7391
  /** Local-calendar day key for one wall-clock instant; shared by bespoke loops. */
6545
7392
  function timelineDayKey(occurredAt) {
@@ -6599,7 +7446,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6599
7446
  }
6600
7447
  //#endregion
6601
7448
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/channel.module.css.mjs
6602
- const css$3 = ".MYaRJa_headerMeta{color:var(--dsw-alias-text-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-subtle);color:var(--dsw-alias-text-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-default);color:var(--dsw-alias-text-primary)}.MYaRJa_taskFooter:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.MYaRJa_taskNumber{color:var(--dsw-alias-text-primary);font-size:12px;font-weight:600;line-height:18px}.MYaRJa_taskStatus,.MYaRJa_taskCount{color:var(--dsw-alias-text-tertiary);font-size:11px;line-height:18px}.MYaRJa_taskDot{flex:none;align-items:center;width:8px;display:inline-flex}.MYaRJa_taskDotQuiet{border-radius:50%;flex:none;width:8px;height:8px;position:relative}.MYaRJa_taskDotQuiet[data-variant=todo]{border:1px solid var(--dsw-alias-text-tertiary)}.MYaRJa_taskDotQuiet[data-variant=closed]{color:var(--dsw-alias-text-tertiary)}.MYaRJa_taskDotQuiet[data-variant=closed]:before{content:\"\";opacity:.1;background:currentColor;border-radius:50%;position:absolute;inset:0}.MYaRJa_taskDotQuiet[data-variant=closed]:after{content:\"\";background:currentColor;border-radius:50%;position:absolute;inset:20%}.MYaRJa_taskArrow{color:var(--dsw-alias-text-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-text-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-text-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_headerMeta span+span:before{display:none}.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}}";
7449
+ const css$3 = ".MYaRJa_headerMeta{color:var(--dsw-alias-label-tertiary);flex-wrap:wrap;align-items:center;gap:6px;margin-top:7px;font-size:12px;line-height:18px;display:flex}.MYaRJa_headerMeta span+span:before{content:\"·\";margin-right:6px}.MYaRJa_taskFooter{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left;background:0 0;border-radius:999px;align-items:center;gap:6px;max-width:100%;margin:6px 0 0;padding:2px 10px;transition:background-color .12s,border-color .12s,color .12s;display:inline-flex}.MYaRJa_taskFooter:hover,.MYaRJa_taskFooter:focus-visible{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary)}.MYaRJa_taskFooter:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.MYaRJa_taskNumber{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:600;line-height:18px}.MYaRJa_taskStatus,.MYaRJa_taskCount{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:18px}.MYaRJa_taskDot{flex:none;align-items:center;width:8px;display:inline-flex}.MYaRJa_taskDotQuiet{border-radius:50%;flex:none;width:8px;height:8px;position:relative}.MYaRJa_taskDotQuiet[data-variant=todo]{border:1px solid var(--dsw-alias-label-tertiary)}.MYaRJa_taskDotQuiet[data-variant=closed]{color:var(--dsw-alias-label-tertiary)}.MYaRJa_taskDotQuiet[data-variant=closed]:before{content:\"\";opacity:.1;background:currentColor;border-radius:50%;position:absolute;inset:0}.MYaRJa_taskDotQuiet[data-variant=closed]:after{content:\"\";background:currentColor;border-radius:50%;position:absolute;inset:20%}.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_headerMeta span+span:before{display:none}.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}}";
6603
7450
  const tagId$3 = "@wowyuarm/dsh-agent-team/channel.module.css";
6604
7451
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
6605
7452
  const tag = document.createElement("style");
@@ -6626,7 +7473,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6626
7473
  };
6627
7474
  //#endregion
6628
7475
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/thread.module.css.mjs
6629
- 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-subtle);max-width:880px;margin:12px auto 0;padding-top:8px}.-Qiwua_riskSection{border-top:1px solid var(--dsw-alias-border-subtle);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-text-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-text-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;font-weight:500;line-height:18px;overflow:hidden}.-Qiwua_claimDirection{color:var(--dsw-alias-text-primary);overflow-wrap:anywhere;min-width:0;font-size:12px;line-height:18px}.-Qiwua_claimState{color:var(--dsw-alias-text-tertiary);white-space:nowrap;font-size:11px;line-height:18px}.-Qiwua_emptyClaims{color:var(--dsw-alias-text-tertiary);margin:0;padding:5px 6px;font-size:11px;line-height:18px}.-Qiwua_activityRow{color:var(--dsw-alias-text-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-default);border-radius:50%;flex:0 0 5px;width:5px;height:5px}.-Qiwua_historySection{border-bottom:1px solid var(--dsw-alias-border-subtle);max-width:100%;margin:0 auto 12px;padding-bottom:10px}.-Qiwua_historySection h2{color:var(--dsw-alias-text-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-text-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-default);content:\"\";flex:1;height:1px}.-Qiwua_unreadBoundary span{flex:none}.-Qiwua_daySeparator{color:var(--dsw-alias-text-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-subtle);content:\"\";flex:1;height:1px}.-Qiwua_daySeparator span{flex:none}.-Qiwua_newUpdates{background:var(--dsw-specific-input-major,var(--dsw-alias-surface-primary));border:1px solid var(--dsw-alias-border-l2-darkmode-thin);box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-text-secondary);z-index:2;border-radius:999px;justify-content:center;align-items:center;gap:8px;width:fit-content;margin:8px auto;padding:4px 6px 4px 12px;font-size:12px;line-height:18px;display:flex;position:sticky;bottom:8px}.-Qiwua_taskTitle{color:var(--dsw-alias-text-secondary);text-overflow:ellipsis;white-space:nowrap;margin:2px 0 0;font-size:13px;line-height:20px;overflow:hidden}.-Qiwua_closedBar{flex-direction:column;align-items:center;display:flex}.-Qiwua_closedNotice{color:var(--dsw-alias-text-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_claimDirection{grid-column:2/-1}.-Qiwua_activityRow{padding-inline:0}.-Qiwua_newUpdates{max-width:calc(100% - 16px)}}";
7476
+ const css$2 = ".-Qiwua_titleLine{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.-Qiwua_titleLine h1{margin:0}.-Qiwua_workSection{border-top:1px solid var(--dsw-alias-border-l2);max-width:880px;margin:12px auto 0;padding-top:8px}.-Qiwua_riskSection{border-top:1px solid var(--dsw-alias-border-l2);max-width:880px;margin:12px auto 0;padding-top:10px}.-Qiwua_riskSection h2{color:var(--dsw-alias-state-error-primary);margin:0 0 5px;font-size:12px;font-weight:600;line-height:18px}.-Qiwua_riskRow{color:var(--dsw-alias-label-secondary);align-items:center;gap:8px;margin:3px 0;font-size:12px;line-height:18px;display:flex}.-Qiwua_claimList{gap:4px;padding:4px 0 2px 22px;display:grid}.-Qiwua_claimRow{border-radius:6px;grid-template-columns:14px minmax(96px,auto) minmax(0,1fr) auto auto;align-items:center;gap:4px 8px;min-height:36px;padding:4px 6px;display:grid}.-Qiwua_claimRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.-Qiwua_claimOwner{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;font-weight:500;line-height:18px;overflow:hidden}.-Qiwua_claimDirection{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;min-width:0;font-size:12px;line-height:18px}.-Qiwua_claimState{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:11px;line-height:18px}.-Qiwua_emptyClaims{color:var(--dsw-alias-label-tertiary);margin:0;padding:5px 6px;font-size:11px;line-height:18px}.-Qiwua_activityRow{color:var(--dsw-alias-label-tertiary);text-align:center;justify-content:center;align-items:center;gap:8px;max-width:100%;margin:4px auto;padding:5px 12px;font-size:11px;line-height:18px;display:flex}.-Qiwua_activityText{overflow-wrap:anywhere;min-width:0}.-Qiwua_activityMark{background:var(--dsw-alias-border-l3);border-radius:50%;flex:0 0 5px;width:5px;height:5px}.-Qiwua_historySection{border-bottom:1px solid var(--dsw-alias-border-l2);max-width:100%;margin:0 auto 12px;padding-bottom:10px}.-Qiwua_historySection h2{color:var(--dsw-alias-label-tertiary);letter-spacing:.02em;text-transform:uppercase;margin:0 0 4px;font-size:11px;font-weight:600;line-height:16px}.-Qiwua_publicSection{min-width:0}.-Qiwua_unreadBoundary{color:var(--dsw-alias-label-tertiary);align-items:center;gap:10px;margin:10px 0 6px;font-size:11px;line-height:16px;display:flex}.-Qiwua_unreadBoundary:before,.-Qiwua_unreadBoundary:after{background:var(--dsw-alias-border-l3);content:\"\";flex:1;height:1px}.-Qiwua_unreadBoundary span{flex:none}.-Qiwua_daySeparator{color:var(--dsw-alias-label-tertiary);letter-spacing:.02em;align-items:center;gap:10px;margin:12px 0 4px;font-size:11px;line-height:16px;display:flex}.-Qiwua_daySeparator:before,.-Qiwua_daySeparator:after{background:var(--dsw-alias-border-l2);content:\"\";flex:1;height:1px}.-Qiwua_daySeparator span{flex:none}.-Qiwua_newUpdates{background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1));border:1px solid var(--dsw-alias-border-l2-darkmode-thin);box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-label-secondary);z-index:2;border-radius:999px;justify-content:center;align-items:center;gap:8px;width:fit-content;margin:8px auto;padding:4px 6px 4px 12px;font-size:12px;line-height:18px;display:flex;position:sticky;bottom:8px}.-Qiwua_taskTitle{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;margin:2px 0 0;font-size:13px;line-height:20px;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_claimDirection{grid-column:2/-1}.-Qiwua_activityRow{padding-inline:0}.-Qiwua_newUpdates{max-width:calc(100% - 16px)}}";
6630
7477
  const tagId$2 = "@wowyuarm/dsh-agent-team/thread.module.css";
6631
7478
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
6632
7479
  const tag = document.createElement("style");
@@ -6674,22 +7521,52 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6674
7521
  hasMore: fresh.hasMore || current.cursor < fresh.cursor
6675
7522
  };
6676
7523
  }
6677
- function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscribeChanges, loadMembers, sendMessage, joinChannel, removeChannelMember, selectThread, backToChannels, t }) {
7524
+ function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscribeChanges, loadMembers, drafts, putAttachment, getAttachment, sendMessage, joinChannel, removeChannelMember, selectThread, selectChannel, backToChannels, resolveTaskRefs, t }) {
6678
7525
  const [view, setView] = (0, react.useState)();
6679
7526
  const [members, setMembers] = (0, react.useState)([]);
6680
- const [draft, setDraft] = (0, react.useState)("");
6681
7527
  const [error, setError] = (0, react.useState)();
7528
+ const [pendingFiles, setPendingFiles] = (0, react.useState)([]);
6682
7529
  const [statusMessage, setStatusMessage] = (0, react.useState)();
6683
7530
  const [loading, setLoading] = (0, react.useState)(true);
6684
7531
  const [pending, setPending] = (0, react.useState)(false);
6685
7532
  const [loadingOlder, setLoadingOlder] = (0, react.useState)(false);
6686
- const [recipients, setRecipients] = (0, react.useState)(/* @__PURE__ */ new Set());
6687
7533
  const [managingMembers, setManagingMembers] = (0, react.useState)(false);
7534
+ const draftKey = `channel:${channelRef}`;
7535
+ const { draft, recipients } = (0, react.useSyncExternalStore)(drafts.subscribe, () => drafts.getSnapshot(draftKey));
6688
7536
  const manageTriggerRef = (0, react.useRef)(null);
6689
7537
  const memberListRef = (0, react.useRef)(null);
6690
7538
  const mountedRef = (0, react.useRef)(false);
6691
7539
  const refreshSequenceRef = (0, react.useRef)(0);
6692
7540
  const channelLastItem = view?.items[view.items.length - 1];
7541
+ const openRef = (ref) => {
7542
+ if (ref.startsWith("channel:")) {
7543
+ if (ref !== channelRef) selectChannel(ref);
7544
+ return;
7545
+ }
7546
+ if (ref.startsWith("task:")) {
7547
+ const match = view?.items.find((item) => item.task.taskRef === ref);
7548
+ if (match !== void 0) {
7549
+ selectThread(match.task.taskRef, match.thread.threadRef, channelRef, match.taskNumber);
7550
+ return;
7551
+ }
7552
+ resolveTaskRefs({
7553
+ workspaceId,
7554
+ taskRefs: [ref]
7555
+ }).then((result) => {
7556
+ if (!result.ok) return;
7557
+ const hit = result.value.resolved[0];
7558
+ if (hit !== void 0) selectThread(hit.taskRef, hit.threadRef, hit.channelRef, hit.taskNumber);
7559
+ });
7560
+ }
7561
+ };
7562
+ const lookupTaskRefs = (taskRefs) => resolveTaskRefs({
7563
+ workspaceId,
7564
+ taskRefs
7565
+ }).then((result) => {
7566
+ if (!result.ok) return [];
7567
+ for (const entry of result.value.resolved) rememberResolvedTaskRef(entry);
7568
+ return result.value.resolved;
7569
+ });
6693
7570
  const timeline = useTimelineScroll(`${view?.items.length ?? 0}:${channelLastItem?.message.messageRef ?? ""}`);
6694
7571
  const channel = view?.channels.find((item) => item.channelRef === channelRef);
6695
7572
  const channelMemberIds = new Set(view?.members.filter((item) => item.channelRef === channelRef).map((item) => item.memberId) ?? []);
@@ -6744,7 +7621,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6744
7621
  setView(void 0);
6745
7622
  setError(void 0);
6746
7623
  setLoading(true);
6747
- setRecipients(/* @__PURE__ */ new Set());
6748
7624
  setManagingMembers(false);
6749
7625
  refresh();
6750
7626
  const disposers = [subscribeChanges({
@@ -6819,30 +7695,47 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6819
7695
  });
6820
7696
  const pendingSendId = (0, react.useRef)();
6821
7697
  const send = async () => {
7698
+ console.log("DBG send entry pending=%s draft=%j files=%d", pending, draft, pendingFiles.length);
6822
7699
  if (pending || draft.trim() === "") return;
6823
7700
  const recipientIds = [...recipients].sort();
6824
7701
  const requestId = pendingSendId.current ?? crypto.randomUUID();
6825
7702
  pendingSendId.current = requestId;
6826
- const request = {
6827
- requestId,
6828
- workspaceId,
6829
- channelRef,
6830
- body: draft.trim(),
6831
- recipients: recipientIds
6832
- };
6833
7703
  setPending(true);
6834
7704
  setError(void 0);
6835
7705
  setStatusMessage(void 0);
6836
7706
  try {
6837
- const result = await sendMessage(request);
7707
+ const attachmentIds = [];
7708
+ for (const file of pendingFiles) {
7709
+ const uploaded = await putAttachment({
7710
+ requestId: crypto.randomUUID(),
7711
+ workspaceId,
7712
+ name: file.name,
7713
+ mediaType: file.type === "" ? void 0 : file.type,
7714
+ bytesBase64: bytesToBase64(new Uint8Array(await file.arrayBuffer()))
7715
+ });
7716
+ if (!uploaded.ok) {
7717
+ pendingSendId.current = void 0;
7718
+ setError(uploaded.error.message);
7719
+ return;
7720
+ }
7721
+ attachmentIds.push(uploaded.value.attachmentId);
7722
+ }
7723
+ const result = await sendMessage({
7724
+ requestId,
7725
+ workspaceId,
7726
+ channelRef,
7727
+ body: draft.trim(),
7728
+ recipients: recipientIds,
7729
+ ...attachmentIds.length === 0 ? {} : { attachments: attachmentIds }
7730
+ });
6838
7731
  if (!result.ok) {
6839
7732
  pendingSendId.current = void 0;
6840
7733
  setError(result.error.message);
6841
7734
  } else if (result.value.kind === "committed") {
6842
7735
  pendingSendId.current = void 0;
6843
7736
  await refresh();
6844
- setDraft("");
6845
- setRecipients(/* @__PURE__ */ new Set());
7737
+ drafts.clear(draftKey);
7738
+ setPendingFiles([]);
6846
7739
  setStatusMessage(void 0);
6847
7740
  } else if (result.value.kind === "confirmation_required") setStatusMessage(t("mentionConfirmation"));
6848
7741
  else {
@@ -7008,13 +7901,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7008
7901
  children: block.items.map((item, index) => {
7009
7902
  const senderStatus = members.find((member) => member.member.memberId === item.message.sender);
7010
7903
  const human = item.message.sender === view.humanMemberId;
7011
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMessage, {
7012
- senderName: human ? t("human") : senderStatus?.member.handle ?? item.message.sender,
7904
+ const sender = human ? t("human") : senderStatus?.member.handle ?? item.message.sender;
7905
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [isRunGap(index > 0 ? block.items[index - 1].message.occurredAt : void 0, item.message.occurredAt) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamRunDivider, { occurredAt: item.message.occurredAt }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamMessage, {
7906
+ senderName: sender,
7013
7907
  memberId: item.message.sender,
7014
7908
  human,
7015
7909
  body: item.message.body,
7910
+ attachments: item.message.attachments,
7911
+ loadAttachment: getAttachment,
7912
+ t,
7016
7913
  occurredAt: item.message.occurredAt,
7017
7914
  mentionNames: mentionNamesOf(item.mentions, mentionHandlesMap),
7915
+ onOpenRef: openRef,
7916
+ onResolveTaskRefs: lookupTaskRefs,
7018
7917
  grouped: index > 0,
7019
7918
  ...senderStatus === void 0 ? {} : { senderTitle: senderStatus.member.description },
7020
7919
  children: item.message.topLevel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
@@ -7057,7 +7956,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7057
7956
  })
7058
7957
  ]
7059
7958
  })
7060
- }, item.message.messageRef);
7959
+ })] }, item.message.messageRef);
7061
7960
  })
7062
7961
  }, `run-${block.items[0].message.messageRef}`))
7063
7962
  ]
@@ -7071,18 +7970,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7071
7970
  ...statusMessage === void 0 ? {} : { confirmation: statusMessage },
7072
7971
  ...error === void 0 ? {} : { error },
7073
7972
  onDraftChange: (next) => {
7074
- setDraft(next);
7973
+ drafts.writeDraft(draftKey, next);
7075
7974
  setStatusMessage(void 0);
7076
7975
  },
7077
7976
  onRecipientsChange: (next) => {
7078
- setRecipients(next);
7977
+ drafts.writeRecipients(draftKey, next);
7079
7978
  setStatusMessage(void 0);
7080
7979
  },
7081
7980
  onSubmit: () => {
7082
7981
  send();
7083
7982
  },
7983
+ pendingFiles,
7984
+ onFilesChange: setPendingFiles,
7084
7985
  t
7085
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {})
7986
+ }, draftKey) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {})
7086
7987
  ]
7087
7988
  });
7088
7989
  }
@@ -7111,7 +8012,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7111
8012
  return new Map(facts.map((fact) => [factKey(fact.fact), fact]));
7112
8013
  }
7113
8014
  function TeamThreadPage(props) {
7114
- const { workspaceId, channelRef, taskRef, threadRef, taskNumber, backToWorkspace, loadChannels, readThread, loadThreadHistory, subscribeChanges, loadMembers, reply, changeTask, t } = props;
8015
+ const { workspaceId, channelRef, taskRef, threadRef, taskNumber, backToWorkspace, selectChannel, selectThread, resolveTaskRefs, putAttachment, loadChannels, readThread, loadThreadHistory, subscribeChanges, loadMembers, drafts, getAttachment, reply, changeTask, t } = props;
7115
8016
  const [projection, setProjection] = (0, react.useState)();
7116
8017
  const [channelView, setChannelView] = (0, react.useState)();
7117
8018
  const [members, setMembers] = (0, react.useState)([]);
@@ -7122,9 +8023,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7122
8023
  const [historyHasMore, setHistoryHasMore] = (0, react.useState)(false);
7123
8024
  const [remainingUnreadCount, setRemainingUnreadCount] = (0, react.useState)(0);
7124
8025
  const [newFactsCount, setNewFactsCount] = (0, react.useState)(0);
7125
- const [draft, setDraft] = (0, react.useState)("");
7126
- const [recipients, setRecipients] = (0, react.useState)(/* @__PURE__ */ new Set());
8026
+ const draftKey = `thread:${threadRef}`;
8027
+ const { draft, recipients } = (0, react.useSyncExternalStore)(drafts.subscribe, () => drafts.getSnapshot(draftKey));
7127
8028
  const [claimsOpen, setClaimsOpen] = (0, react.useState)(false);
8029
+ const [confirmingAccept, setConfirmingAccept] = (0, react.useState)(false);
8030
+ (0, react.useEffect)(() => {
8031
+ if (confirmingAccept && projection?.task.resolution === "accepted") setConfirmingAccept(false);
8032
+ }, [confirmingAccept, projection?.task.resolution]);
7128
8033
  const [replyRequestId, setReplyRequestId] = (0, react.useState)();
7129
8034
  const [confirmation, setConfirmation] = (0, react.useState)();
7130
8035
  const [statusMessage, setStatusMessage] = (0, react.useState)();
@@ -7369,6 +8274,26 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7369
8274
  return status === void 0 ? t("memberUnknown") : `@${status.member.handle}`;
7370
8275
  };
7371
8276
  const messageSender = (fact) => fact.kind === "message" ? fact.message.sender : void 0;
8277
+ const [pendingFiles, setPendingFiles] = (0, react.useState)([]);
8278
+ const openRef = (ref) => {
8279
+ if (ref.startsWith("channel:") && ref !== channelRef) selectChannel(ref);
8280
+ if (ref.startsWith("task:") && ref !== taskRef) resolveTaskRefs({
8281
+ workspaceId,
8282
+ taskRefs: [ref]
8283
+ }).then((result) => {
8284
+ if (!result.ok) return;
8285
+ const hit = result.value.resolved[0];
8286
+ if (hit !== void 0) selectThread(hit.taskRef, hit.threadRef, hit.channelRef, hit.taskNumber);
8287
+ });
8288
+ };
8289
+ const lookupTaskRefs = (refs) => resolveTaskRefs({
8290
+ workspaceId,
8291
+ taskRefs: refs
8292
+ }).then((result) => {
8293
+ if (!result.ok) return [];
8294
+ for (const entry of result.value.resolved) rememberResolvedTaskRef(entry);
8295
+ return result.value.resolved;
8296
+ });
7372
8297
  const renderFact = (fact, grouped = false) => {
7373
8298
  if (fact.kind === "message") {
7374
8299
  const sender = memberName(fact.message.sender);
@@ -7378,8 +8303,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7378
8303
  memberId: fact.message.sender,
7379
8304
  human: fact.message.sender === channelView?.humanMemberId,
7380
8305
  body: fact.message.body,
8306
+ attachments: fact.message.attachments,
8307
+ loadAttachment: getAttachment,
8308
+ t,
7381
8309
  occurredAt: fact.message.occurredAt,
7382
8310
  mentionNames: mentionNamesOf(fact.mentions, mentionHandlesMap),
8311
+ onOpenRef: openRef,
8312
+ onResolveTaskRefs: lookupTaskRefs,
7383
8313
  grouped,
7384
8314
  ...senderStatus === void 0 ? {} : { senderTitle: senderStatus.member.description }
7385
8315
  }, factKey(fact));
@@ -7407,7 +8337,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7407
8337
  const flushRun = () => {
7408
8338
  if (run.length > 0) nodes.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7409
8339
  className: conversation_module_css_default.messageRun,
7410
- children: run.map((entry, entryIndex) => renderFact(entry, entryIndex > 0))
8340
+ children: run.map((entry, entryIndex) => {
8341
+ const previous = entryIndex > 0 ? run[entryIndex - 1] : void 0;
8342
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [entry.kind === "message" && isRunGap(previous?.kind === "message" ? previous.message.occurredAt : void 0, entry.message.occurredAt) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamRunDivider, { occurredAt: entry.message.occurredAt }), renderFact(entry, entryIndex > 0)] }, factKey(entry));
8343
+ })
7411
8344
  }, `run-${factKey(run[0])}`));
7412
8345
  run = [];
7413
8346
  };
@@ -7508,6 +8441,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7508
8441
  setPending(true);
7509
8442
  setError(void 0);
7510
8443
  try {
8444
+ const attachmentIds = [];
8445
+ for (const file of pendingFiles) {
8446
+ const uploaded = await putAttachment({
8447
+ requestId: crypto.randomUUID(),
8448
+ workspaceId,
8449
+ name: file.name,
8450
+ mediaType: file.type === "" ? void 0 : file.type,
8451
+ bytesBase64: bytesToBase64(new Uint8Array(await file.arrayBuffer()))
8452
+ });
8453
+ if (!uploaded.ok) {
8454
+ setError(uploaded.error.message);
8455
+ return;
8456
+ }
8457
+ attachmentIds.push(uploaded.value.attachmentId);
8458
+ }
7511
8459
  const result = await reply({
7512
8460
  requestId: id,
7513
8461
  workspaceId,
@@ -7515,6 +8463,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7515
8463
  body: draft.trim(),
7516
8464
  baseRevision: thread.revision,
7517
8465
  recipients: [...recipients].sort(),
8466
+ ...attachmentIds.length === 0 ? {} : { attachments: attachmentIds },
7518
8467
  ...confirmation === void 0 ? {} : { confirmationToken: confirmation }
7519
8468
  });
7520
8469
  if (!result.ok) {
@@ -7538,8 +8487,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7538
8487
  task: committed.task,
7539
8488
  thread: committed.thread
7540
8489
  });
7541
- setDraft("");
7542
- setRecipients(/* @__PURE__ */ new Set());
8490
+ drafts.clear(draftKey);
8491
+ setPendingFiles([]);
7543
8492
  setReplyRequestId(void 0);
7544
8493
  setConfirmation(void 0);
7545
8494
  setStatusMessage(void 0);
@@ -7610,15 +8559,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7610
8559
  })]
7611
8560
  }), task !== void 0 && thread !== void 0 && task.resolution !== "closed" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7612
8561
  className: conversation_module_css_default.headerActions,
7613
- children: [task.status === "in_review" && task.resolution === "open" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
7614
- size: "sm",
7615
- variant: "primary",
7616
- disabled: pending,
7617
- onClick: () => {
7618
- mutateTask("accept");
7619
- },
7620
- children: t("acceptTask")
7621
- }), task.resolution === "open" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8562
+ children: [(() => {
8563
+ const activeClaims = projection?.claims.filter((claim) => claim.taskRef === task.taskRef && claim.state === "active") ?? [];
8564
+ const earlyAccept = task.resolution === "open" && task.status === "in_progress" && activeClaims.length > 0;
8565
+ if (!(task.status === "in_review" || earlyAccept) || task.resolution !== "open") return null;
8566
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8567
+ size: "sm",
8568
+ variant: "primary",
8569
+ disabled: pending,
8570
+ onClick: () => {
8571
+ if (earlyAccept) setConfirmingAccept(true);
8572
+ else mutateTask("accept");
8573
+ },
8574
+ children: t("acceptTask")
8575
+ });
8576
+ })(), task.resolution === "open" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
7622
8577
  size: "sm",
7623
8578
  variant: "outline",
7624
8579
  disabled: pending,
@@ -7655,6 +8610,43 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7655
8610
  ] })]
7656
8611
  }, claim.claimRef))]
7657
8612
  }),
8613
+ task !== void 0 && thread !== void 0 && (() => {
8614
+ const activeClaims = projection?.claims.filter((claim) => claim.taskRef === task.taskRef && claim.state === "active") ?? [];
8615
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
8616
+ open: confirmingAccept,
8617
+ onClose: () => {
8618
+ if (!pending) setConfirmingAccept(false);
8619
+ },
8620
+ title: t("acceptEarlyTitle"),
8621
+ closeLabel: t("cancel"),
8622
+ 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, {
8623
+ variant: "outline",
8624
+ disabled: pending,
8625
+ onClick: () => {
8626
+ setConfirmingAccept(false);
8627
+ },
8628
+ children: t("cancel")
8629
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8630
+ variant: "primary",
8631
+ disabled: pending,
8632
+ onClick: () => {
8633
+ mutateTask("accept");
8634
+ },
8635
+ children: pending ? t("acceptingTask") : t("acceptTask")
8636
+ })] }),
8637
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8638
+ className: conversation_module_css_default.confirmBody,
8639
+ children: t("acceptEarlyBody", { count: activeClaims.length })
8640
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
8641
+ className: conversation_module_css_default.confirmList,
8642
+ children: activeClaims.map((claim) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
8643
+ memberName(claim.owner),
8644
+ " · ",
8645
+ claim.direction
8646
+ ] }, claim.claimRef))
8647
+ })]
8648
+ });
8649
+ })(),
7658
8650
  task !== void 0 && thread !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
7659
8651
  className: thread_module_css_default.workSection,
7660
8652
  "aria-label": t("claims"),
@@ -7807,13 +8799,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7807
8799
  ...statusMessage === void 0 ? {} : { confirmation: statusMessage },
7808
8800
  ...error === void 0 ? {} : { error },
7809
8801
  onDraftChange: (next) => {
7810
- setDraft(next);
8802
+ drafts.writeDraft(draftKey, next);
7811
8803
  setConfirmation(void 0);
7812
8804
  setReplyRequestId(void 0);
7813
8805
  setStatusMessage(void 0);
7814
8806
  },
7815
8807
  onRecipientsChange: (next) => {
7816
- setRecipients(next);
8808
+ drafts.writeRecipients(draftKey, next);
7817
8809
  setConfirmation(void 0);
7818
8810
  setReplyRequestId(void 0);
7819
8811
  setStatusMessage(void 0);
@@ -7821,23 +8813,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7821
8813
  onSubmit: () => {
7822
8814
  sendReply();
7823
8815
  },
8816
+ pendingFiles,
8817
+ onFilesChange: setPendingFiles,
7824
8818
  t
7825
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {})
8819
+ }, draftKey) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {})
7826
8820
  ]
7827
8821
  });
7828
8822
  }
7829
8823
  //#endregion
7830
8824
  //#region src/client/TeamConversation.tsx
7831
- function TeamConversation({ t, useWorkspaces, navigation, loadChannels, readThread, loadThreadHistory, subscribeChanges, loadMembers, sendMessage, joinChannel, removeChannelMember, reply, changeTask, selectThread, backToWorkspace, backToChannels }) {
8825
+ function TeamConversation({ t, useWorkspaces, navigation, drafts, putAttachment, getAttachment, loadChannels, readThread, loadThreadHistory, subscribeChanges, loadMembers, sendMessage, joinChannel, removeChannelMember, reply, changeTask, selectThread, selectChannel, backToWorkspace, backToChannels, resolveTaskRefs }) {
7832
8826
  const navigationState = (0, react.useSyncExternalStore)(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
7833
8827
  const current = useWorkspaces((state) => state.items).find((workspace) => workspace.workspaceId === navigationState.workspaceId);
7834
8828
  if (current !== void 0 && navigationState.taskRef !== void 0 && navigationState.threadRef !== void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamThreadPage, {
7835
8829
  workspaceId: current.workspaceId,
8830
+ putAttachment,
7836
8831
  taskRef: navigationState.taskRef,
7837
8832
  threadRef: navigationState.threadRef,
7838
8833
  backToWorkspace,
8834
+ selectChannel,
8835
+ selectThread,
8836
+ resolveTaskRefs,
7839
8837
  ...navigationState.channelRef === void 0 ? {} : { channelRef: navigationState.channelRef },
7840
8838
  ...navigationState.taskNumber === void 0 ? {} : { taskNumber: navigationState.taskNumber },
8839
+ drafts,
8840
+ getAttachment,
7841
8841
  readThread,
7842
8842
  loadChannels,
7843
8843
  loadThreadHistory,
@@ -7850,6 +8850,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7850
8850
  if (current !== void 0 && navigationState.channelRef !== void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamChannelPage, {
7851
8851
  workspaceId: current.workspaceId,
7852
8852
  channelRef: navigationState.channelRef,
8853
+ drafts,
8854
+ putAttachment,
8855
+ getAttachment,
7853
8856
  loadChannels,
7854
8857
  subscribeChanges,
7855
8858
  loadMembers,
@@ -7857,7 +8860,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7857
8860
  joinChannel,
7858
8861
  removeChannelMember,
7859
8862
  selectThread,
8863
+ selectChannel,
7860
8864
  backToChannels,
8865
+ resolveTaskRefs,
7861
8866
  t
7862
8867
  }, navigationState.channelRef);
7863
8868
  const welcome = current === void 0 ? {
@@ -7887,7 +8892,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7887
8892
  }
7888
8893
  //#endregion
7889
8894
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/sidebar.module.css.mjs
7890
- 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_workspaceHeader{color:var(--dsw-alias-label-tertiary);justify-content:space-between;align-items:center;min-height:28px;padding:0 4px 0 8px;font-size:13px;font-weight:600;line-height:20px;display:flex}.d0xfxa_railButton{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0;display:inline-flex}.d0xfxa_railButton:hover,.d0xfxa_railButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);outline:none}.d0xfxa_workspaceList{flex-direction:column;gap:2px;padding-bottom:2px;display:flex}.d0xfxa_workspaceRow{color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;background:0 0;border:0;border-radius:8px;align-items:center;gap:6px;width:100%;height:34px;padding:0 8px;display:flex}.d0xfxa_workspaceRow:hover,.d0xfxa_workspaceRow:focus-visible,.d0xfxa_workspaceRow[aria-current=page]{background:var(--dsw-alias-interactive-bg-hover);outline:none}.d0xfxa_workspaceRow:focus-visible{box-shadow:inset 0 0 0 1px var(--dsw-alias-border-default)}.d0xfxa_workspaceIcon{color:var(--dsw-alias-label-tertiary);flex:0 0 16px;justify-content:center;align-items:center;height:20px;display:inline-flex}.d0xfxa_workspaceRow[data-selected] .d0xfxa_workspaceIcon{color:var(--dsw-alias-state-business-primary)}.d0xfxa_workspaceCopy{min-width:0;display:flex}.d0xfxa_workspaceCopy strong{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:400;line-height:20px;overflow:hidden}.d0xfxa_emptyState{color:var(--dsw-alias-label-tertiary);margin:8px;font-size:12px;line-height:18px}.d0xfxa_railWorkspace{flex-direction:column;align-items:center;gap:8px;padding-top:8px;display:flex}.d0xfxa_railButton{border-radius:50%;width:36px;height:36px}.d0xfxa_railButton[data-active]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.d0xfxa_workspaceSection{flex-direction:column;flex:1;gap:4px;min-height:0;margin-top:2px;display:flex;overflow-y:auto}.d0xfxa_section{flex-direction:column;display:flex}.d0xfxa_sectionHeader{align-items:center;min-height:26px;padding-right:2px;display:flex}.d0xfxa_sectionToggle{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;align-items:center;gap:4px;min-width:0;min-height:24px;padding:0 6px;font-size:12px;line-height:18px;display:inline-flex}.d0xfxa_sectionToggle:focus-visible{outline:none}.d0xfxa_sectionToggle:hover .d0xfxa_sectionChevron,.d0xfxa_sectionToggle:focus-visible .d0xfxa_sectionChevron{color:var(--dsw-alias-label-primary)}.d0xfxa_sectionChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .12s,color .12s}.d0xfxa_sectionToggle[aria-expanded=false] .d0xfxa_sectionChevron{transform:rotate(-90deg)}.d0xfxa_sectionTitle{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.d0xfxa_sectionActions{align-items:center;margin-left:auto;display:inline-flex}.d0xfxa_panel{flex-direction:column;display:flex}.d0xfxa_iconButton{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:50%;justify-content:center;align-items:center;width:24px;height:24px;padding:0;display:inline-flex}.d0xfxa_iconButton:hover,.d0xfxa_iconButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);outline:none}.d0xfxa_textButton{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:2px 5px;font-size:11px;line-height:18px}.d0xfxa_textButton:hover,.d0xfxa_textButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);outline:none}.d0xfxa_textButton:disabled{cursor:not-allowed;opacity:.4}.d0xfxa_channelList,.d0xfxa_agentList{flex-direction:column;gap:1px;padding:0 4px 4px;display:flex}.d0xfxa_channelRow{color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;min-height:30px;display:flex;position:relative}.d0xfxa_channelSelect{box-sizing:border-box;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;flex:1;align-items:center;min-width:0;min-height:30px;padding:3px 4px 3px 8px;display:flex}.d0xfxa_channelSelect:focus-visible{outline:none}.d0xfxa_channelName{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:400;line-height:18px;overflow:hidden}.d0xfxa_agentRow{color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;min-height:38px;display:flex;position:relative}.d0xfxa_agentSelect{box-sizing:border-box;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;flex:1;grid-template-columns:24px minmax(0,1fr);align-items:center;gap:0 8px;min-width:0;min-height:38px;padding:3px 4px 3px 8px;display:grid}.d0xfxa_agentSelect:focus-visible{outline:none}.d0xfxa_agentAvatar{background:hsl(var(--team-avatar-hue,212) 42% 46%);color:#fff;cursor:default;border-radius:50%;flex:0 0 24px;justify-content:center;align-items:center;width:24px;height:24px;font-size:11px;font-weight:600;display:inline-flex;position:relative}.d0xfxa_agentAvatarBadge{background:var(--dsw-specific-sidebar-fill);box-shadow:0 0 0 1px var(--dsw-specific-sidebar-fill);border-radius:50%;justify-content:center;align-items:center;width:12px;height:12px;padding:1px;line-height:0;display:inline-flex;position:absolute;bottom:-3px;right:-3px}.d0xfxa_agentCopy{flex-direction:column;min-width:0;display:flex}.d0xfxa_agentCopy strong{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:400;line-height:17px;overflow:hidden}.d0xfxa_agentCopy small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:13px;overflow:hidden}.d0xfxa_unavailableDot{background:var(--dsw-alias-text-disabled);border-radius:50%;width:7px;height:7px;display:inline-block}.d0xfxa_rowMenu{flex:none;align-items:center;padding-right:4px;display:none}.d0xfxa_channelRow:hover .d0xfxa_rowMenu,.d0xfxa_channelRow:focus-within .d0xfxa_rowMenu,.d0xfxa_channelRow[data-menu-open] .d0xfxa_rowMenu,.d0xfxa_agentRow:hover .d0xfxa_rowMenu,.d0xfxa_agentRow:focus-within .d0xfxa_rowMenu,.d0xfxa_agentRow[data-menu-open] .d0xfxa_rowMenu{display:inline-flex}.d0xfxa_channelRow[data-menu-open],.d0xfxa_agentRow[data-menu-open],.d0xfxa_channelRow:hover,.d0xfxa_agentRow:hover,.d0xfxa_channelRow:focus-within,.d0xfxa_agentRow:focus-within,.d0xfxa_channelRow[aria-current=page]{background:var(--dsw-alias-interactive-bg-hover)}.d0xfxa_rowMenuButton{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;justify-content:center;align-items:center;width:20px;height:20px;padding:0;display:inline-flex}.d0xfxa_rowMenuButton:hover,.d0xfxa_rowMenuButton:focus-visible{color:var(--dsw-alias-label-primary);outline:none}.d0xfxa_retryError{color:var(--dsw-alias-state-error-primary);justify-content:space-between;align-items:center;gap:8px;padding:8px;font-size:11px;display:flex}.d0xfxa_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-text-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-text-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_rowError{color:var(--dsw-alias-state-error-primary);grid-column:1/-1;margin:2px 0;font-size:11px;line-height:16px}";
8895
+ 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_workspaceHeader{color:var(--dsw-alias-label-tertiary);justify-content:space-between;align-items:center;min-height:28px;padding:0 4px 0 8px;font-size:13px;font-weight:600;line-height:20px;display:flex}.d0xfxa_railButton{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0;display:inline-flex}.d0xfxa_railButton:hover,.d0xfxa_railButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);outline:none}.d0xfxa_workspaceList{flex-direction:column;gap:2px;padding-bottom:2px;display:flex}.d0xfxa_workspaceRow{color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;background:0 0;border:0;border-radius:8px;align-items:center;gap:6px;width:100%;height:34px;padding:0 8px;display:flex}.d0xfxa_workspaceRow:hover,.d0xfxa_workspaceRow:focus-visible,.d0xfxa_workspaceRow[aria-current=page]{background:var(--dsw-alias-interactive-bg-hover);outline:none}.d0xfxa_workspaceRow:focus-visible{box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l3)}.d0xfxa_workspaceIcon{color:var(--dsw-alias-label-tertiary);flex:0 0 16px;justify-content:center;align-items:center;height:20px;display:inline-flex}.d0xfxa_workspaceRow[data-selected] .d0xfxa_workspaceIcon{color:var(--dsw-alias-state-business-primary)}.d0xfxa_workspaceCopy{min-width:0;display:flex}.d0xfxa_workspaceCopy strong{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:400;line-height:20px;overflow:hidden}.d0xfxa_emptyState{color:var(--dsw-alias-label-tertiary);margin:8px;font-size:12px;line-height:18px}.d0xfxa_railWorkspace{flex-direction:column;align-items:center;gap:8px;padding-top:8px;display:flex}.d0xfxa_railButton{border-radius:50%;width:36px;height:36px}.d0xfxa_railButton[data-active]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.d0xfxa_workspaceSection{flex-direction:column;flex:1;gap:4px;min-height:0;margin-top:2px;display:flex;overflow-y:auto}.d0xfxa_section{flex-direction:column;display:flex}.d0xfxa_sectionHeader{align-items:center;min-height:26px;padding-right:2px;display:flex}.d0xfxa_sectionToggle{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;align-items:center;gap:4px;min-width:0;min-height:24px;padding:0 6px;font-size:12px;line-height:18px;display:inline-flex}.d0xfxa_sectionToggle:focus-visible{outline:none}.d0xfxa_sectionToggle:hover .d0xfxa_sectionChevron,.d0xfxa_sectionToggle:focus-visible .d0xfxa_sectionChevron{color:var(--dsw-alias-label-primary)}.d0xfxa_sectionChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .12s,color .12s}.d0xfxa_sectionToggle[aria-expanded=false] .d0xfxa_sectionChevron{transform:rotate(-90deg)}.d0xfxa_sectionTitle{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.d0xfxa_sectionActions{align-items:center;margin-left:auto;display:inline-flex}.d0xfxa_panel{flex-direction:column;display:flex}.d0xfxa_iconButton{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:50%;justify-content:center;align-items:center;width:24px;height:24px;padding:0;display:inline-flex}.d0xfxa_iconButton:hover,.d0xfxa_iconButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);outline:none}.d0xfxa_textButton{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:2px 5px;font-size:11px;line-height:18px}.d0xfxa_textButton:hover,.d0xfxa_textButton:focus-visible{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);outline:none}.d0xfxa_textButton:disabled{cursor:not-allowed;opacity:.4}.d0xfxa_channelList,.d0xfxa_agentList{flex-direction:column;gap:1px;padding:0 4px 4px;display:flex}.d0xfxa_sidebarRowDragging{opacity:.5}.d0xfxa_sidebarRowDropBefore,.d0xfxa_sidebarRowDropAfter{position:relative}.d0xfxa_sidebarRowDropBefore:before,.d0xfxa_sidebarRowDropAfter:after{content:\"\";z-index:1;background:linear-gradient(55deg, transparent calc(50% - 1px), var(--dsw-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 0 / 5px 7px no-repeat, linear-gradient(125deg, transparent calc(50% - 1px), var(--dsw-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 5px / 5px 7px no-repeat, linear-gradient(var(--dsw-alias-state-business-primary) 0 0) 4px 5px / calc(100% - 4px) 2px no-repeat;pointer-events:none;height:12px;position:absolute;left:0;right:4px}.d0xfxa_sidebarRowDropBefore:before{top:-7px}.d0xfxa_sidebarRowDropAfter:after{bottom:-7px}.d0xfxa_channelRow{color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;min-height:30px;display:flex;position:relative}.d0xfxa_channelSelect{box-sizing:border-box;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;flex:1;align-items:center;min-width:0;min-height:30px;padding:3px 4px 3px 8px;display:flex}.d0xfxa_channelSelect:focus-visible{outline:none}.d0xfxa_channelName{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:400;line-height:18px;overflow:hidden}.d0xfxa_agentRow{color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;min-height:38px;display:flex;position:relative}.d0xfxa_agentSelect{box-sizing:border-box;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;flex:1;grid-template-columns:24px minmax(0,1fr);align-items:center;gap:0 8px;min-width:0;min-height:38px;padding:3px 4px 3px 8px;display:grid}.d0xfxa_agentSelect:focus-visible{outline:none}.d0xfxa_agentSelect[aria-current=page]{background:var(--dsw-alias-interactive-bg-hover);border-radius:8px}.d0xfxa_agentRow:hover .d0xfxa_agentSelect[aria-current=page],.d0xfxa_agentRow:focus-within .d0xfxa_agentSelect[aria-current=page],.d0xfxa_agentRow[data-menu-open] .d0xfxa_agentSelect[aria-current=page]{background:0 0}.d0xfxa_agentAvatar{background:hsl(var(--team-avatar-hue,212) 42% 46%);color:#fff;cursor:default;border-radius:50%;flex:0 0 24px;justify-content:center;align-items:center;width:24px;height:24px;font-size:11px;font-weight:600;display:inline-flex;position:relative}.d0xfxa_agentAvatarBadge{background:var(--dsw-specific-sidebar-fill);box-shadow:0 0 0 1px var(--dsw-specific-sidebar-fill);border-radius:50%;justify-content:center;align-items:center;width:12px;height:12px;padding:1px;line-height:0;display:inline-flex;position:absolute;bottom:-3px;right:-3px}.d0xfxa_agentCopy{flex-direction:column;min-width:0;display:flex}.d0xfxa_agentCopy strong{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:400;line-height:17px;overflow:hidden}.d0xfxa_agentCopy small{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:13px;overflow:hidden}.d0xfxa_unavailableDot{background:var(--dsw-alias-label-tertiary);border-radius:50%;width:7px;height:7px;display:inline-block}.d0xfxa_rowMenu{flex:none;align-items:center;padding-right:4px;display:none}.d0xfxa_channelRow:hover .d0xfxa_rowMenu,.d0xfxa_channelRow:focus-within .d0xfxa_rowMenu,.d0xfxa_channelRow[data-menu-open] .d0xfxa_rowMenu,.d0xfxa_agentRow:hover .d0xfxa_rowMenu,.d0xfxa_agentRow:focus-within .d0xfxa_rowMenu,.d0xfxa_agentRow[data-menu-open] .d0xfxa_rowMenu{display:inline-flex}.d0xfxa_channelRow[data-menu-open],.d0xfxa_agentRow[data-menu-open],.d0xfxa_channelRow:hover,.d0xfxa_agentRow:hover,.d0xfxa_channelRow:focus-within,.d0xfxa_agentRow:focus-within,.d0xfxa_channelRow[aria-current=page]{background:var(--dsw-alias-interactive-bg-hover)}.d0xfxa_rowMenuButton{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;justify-content:center;align-items:center;width:20px;height:20px;padding:0;display:inline-flex}.d0xfxa_rowMenuButton:hover,.d0xfxa_rowMenuButton:focus-visible{color:var(--dsw-alias-label-primary);outline:none}.d0xfxa_retryError{color:var(--dsw-alias-state-error-primary);justify-content:space-between;align-items:center;gap:8px;padding:8px;font-size:11px;display:flex}.d0xfxa_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}";
7891
8896
  const tagId$1 = "@wowyuarm/dsh-agent-team/sidebar.module.css";
7892
8897
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
7893
8898
  const tag = document.createElement("style");
@@ -7916,6 +8921,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7916
8921
  "editMemberRowChannels": "d0xfxa_editMemberRowChannels",
7917
8922
  "emptyState": "d0xfxa_emptyState",
7918
8923
  "iconButton": "d0xfxa_iconButton",
8924
+ "menuHint": "d0xfxa_menuHint",
7919
8925
  "panel": "d0xfxa_panel",
7920
8926
  "railButton": "d0xfxa_railButton",
7921
8927
  "railWorkspace": "d0xfxa_railWorkspace",
@@ -7929,6 +8935,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7929
8935
  "sectionHeader": "d0xfxa_sectionHeader",
7930
8936
  "sectionTitle": "d0xfxa_sectionTitle",
7931
8937
  "sectionToggle": "d0xfxa_sectionToggle",
8938
+ "sidebarRowDragging": "d0xfxa_sidebarRowDragging",
8939
+ "sidebarRowDropAfter": "d0xfxa_sidebarRowDropAfter",
8940
+ "sidebarRowDropBefore": "d0xfxa_sidebarRowDropBefore",
7932
8941
  "textButton": "d0xfxa_textButton",
7933
8942
  "unavailableDot": "d0xfxa_unavailableDot",
7934
8943
  "workspaceBrowser": "d0xfxa_workspaceBrowser",
@@ -7991,6 +9000,237 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7991
9000
  });
7992
9001
  }
7993
9002
  //#endregion
9003
+ //#region src/client/sidebar-drag.tsx
9004
+ /**
9005
+ * Native whole-row drag for the Team sidebar lists. Unlike the Harness
9006
+ * workspace list there is no document-level acceptance here: hovering another
9007
+ * row shows the before/after insertion marker and releasing on a row commits
9008
+ * exactly once per gesture, while a release outside any row — including over
9009
+ * the other sidebar list, whose panel never responds — just cancels without
9010
+ * committing.
9011
+ */
9012
+ /**
9013
+ * One drag gesture per panel instance. `onCommit` receives the moved ref,
9014
+ * the drop target and the insertion side exactly once per completed gesture;
9015
+ * releases outside the list never reach it.
9016
+ */
9017
+ function useSidebarRowDrag({ refs, onCommit }) {
9018
+ const [state, setState] = (0, react.useState)(null);
9019
+ const committed = (0, react.useRef)(false);
9020
+ const half = (event) => {
9021
+ const rect = event.currentTarget.getBoundingClientRect();
9022
+ return event.clientY - rect.top < rect.height / 2 ? "before" : "after";
9023
+ };
9024
+ return { rowProps: (orderKey) => ({
9025
+ draggable: true,
9026
+ className: state === null ? void 0 : state.active === orderKey ? sidebar_module_css_default.sidebarRowDragging : state.over === orderKey ? state.marker === "before" ? sidebar_module_css_default.sidebarRowDropBefore : sidebar_module_css_default.sidebarRowDropAfter : void 0,
9027
+ onDragStart: (event) => {
9028
+ if (event.dataTransfer === null) return;
9029
+ event.dataTransfer.effectAllowed = "move";
9030
+ event.dataTransfer.setData("text/plain", orderKey);
9031
+ committed.current = false;
9032
+ setState({
9033
+ active: orderKey,
9034
+ over: orderKey,
9035
+ marker: "after"
9036
+ });
9037
+ },
9038
+ onDragEnd: () => {
9039
+ setState(null);
9040
+ },
9041
+ onDragOver: (event) => {
9042
+ if (state === null || !refs.includes(orderKey)) return;
9043
+ event.preventDefault();
9044
+ if (event.dataTransfer !== null) event.dataTransfer.dropEffect = "move";
9045
+ const marker = half(event);
9046
+ if (state.over !== orderKey || state.marker !== marker) setState({
9047
+ ...state,
9048
+ over: orderKey,
9049
+ marker
9050
+ });
9051
+ },
9052
+ onDrop: (event) => {
9053
+ if (state === null || !refs.includes(orderKey)) return;
9054
+ event.preventDefault();
9055
+ if (committed.current) return;
9056
+ committed.current = true;
9057
+ onCommit(state.active, orderKey, half(event));
9058
+ }
9059
+ }) };
9060
+ }
9061
+ /**
9062
+ * Transparent wrapper that owns the drop-marker styling for one draggable
9063
+ * sidebar row. It adds no layout of its own; the styled row stays inside so
9064
+ * hover/focus descendant selectors keep working.
9065
+ */
9066
+ function SortableRow({ drag, orderKey, children }) {
9067
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9068
+ ...drag.rowProps(orderKey),
9069
+ children
9070
+ });
9071
+ }
9072
+ //#endregion
9073
+ //#region src/client/sidebar-order.ts
9074
+ /**
9075
+ * Human presentation preference for the Team sidebar: the row order of the
9076
+ * Channels and Agents lists. The order lives in this browser only — it is UI
9077
+ * taste, never a shared Team fact, so nothing here touches the ledger.
9078
+ *
9079
+ * One deep module owns the whole concern: storage, reconcile against the
9080
+ * current Remote order (drop removed refs, keep the user's relative order,
9081
+ * append newcomers in default order), the single `moveSidebarItem` mutation
9082
+ * behind whole-row drag, and a small subscription hook with snapshot-stable
9083
+ * results for `useSyncExternalStore`.
9084
+ */
9085
+ const STORAGE_KEY = "dsh.agent-team.sidebar-order";
9086
+ function listKey(workspaceId, kind) {
9087
+ return workspaceId === void 0 ? void 0 : `${workspaceId}|${kind}`;
9088
+ }
9089
+ const MEMORY_ONLY = Symbol("sidebar-order.memory");
9090
+ /**
9091
+ * Read-through parse cache over the raw persisted payload: repeated snapshots
9092
+ * skip re-validating an unchanged payload, while anything written outside this
9093
+ * module — another tab, devtools, a cleared store — is picked up because the
9094
+ * raw comparison misses.
9095
+ */
9096
+ let cachedRaw;
9097
+ let cachedOrders = {};
9098
+ /**
9099
+ * Parse persisted orders defensively: private mode, quota errors, and stale
9100
+ * or corrupted payloads all degrade to "no preference" instead of breaking
9101
+ * the sidebar.
9102
+ */
9103
+ function storedOrders() {
9104
+ let raw = null;
9105
+ try {
9106
+ raw = typeof localStorage === "undefined" ? null : localStorage.getItem(STORAGE_KEY);
9107
+ } catch {
9108
+ raw = null;
9109
+ }
9110
+ if (cachedRaw !== void 0 && raw !== null && raw === cachedRaw) return cachedOrders;
9111
+ if (raw === null) {
9112
+ if (cachedRaw === MEMORY_ONLY) return cachedOrders;
9113
+ cachedRaw = raw;
9114
+ cachedOrders = {};
9115
+ return cachedOrders;
9116
+ }
9117
+ try {
9118
+ const parsed = JSON.parse(raw);
9119
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("not an object");
9120
+ const clean = {};
9121
+ for (const [key, value] of Object.entries(parsed)) {
9122
+ if (!Array.isArray(value) || !value.every((entry) => typeof entry === "string")) continue;
9123
+ clean[key] = value;
9124
+ }
9125
+ cachedRaw = raw;
9126
+ cachedOrders = clean;
9127
+ return cachedOrders;
9128
+ } catch {
9129
+ return {};
9130
+ }
9131
+ }
9132
+ function saveOrder(key, refs) {
9133
+ const next = {
9134
+ ...structuredClone(storedOrders()),
9135
+ [key]: refs
9136
+ };
9137
+ cachedOrders = next;
9138
+ try {
9139
+ if (typeof localStorage !== "undefined") {
9140
+ const raw = JSON.stringify(next);
9141
+ localStorage.setItem(STORAGE_KEY, raw);
9142
+ cachedRaw = raw;
9143
+ return;
9144
+ }
9145
+ } catch {}
9146
+ cachedRaw = MEMORY_ONLY;
9147
+ }
9148
+ /**
9149
+ * Merge the saved personal order into the current Remote order: kept refs
9150
+ * stay in the user's relative order with duplicates collapsed, removed refs
9151
+ * disappear, and new refs join in their Remote default positions after the
9152
+ * known ones.
9153
+ */
9154
+ function reconcileSidebarOrder(saved, current) {
9155
+ const present = new Set(current);
9156
+ const seen = /* @__PURE__ */ new Set();
9157
+ const merged = [];
9158
+ for (const ref of saved) {
9159
+ if (seen.has(ref) || !present.has(ref)) continue;
9160
+ seen.add(ref);
9161
+ merged.push(ref);
9162
+ }
9163
+ for (const ref of current) {
9164
+ if (seen.has(ref)) continue;
9165
+ seen.add(ref);
9166
+ merged.push(ref);
9167
+ }
9168
+ return merged;
9169
+ }
9170
+ let revision = 0;
9171
+ const listeners = /* @__PURE__ */ new Set();
9172
+ const snapshots = /* @__PURE__ */ new Map();
9173
+ function savedFingerprint(key) {
9174
+ const saved = storedOrders()[key];
9175
+ return saved === void 0 ? "" : `f${saved.length}:${saved.join(",")}`;
9176
+ }
9177
+ function emitChange() {
9178
+ revision += 1;
9179
+ for (const listener of listeners) listener();
9180
+ }
9181
+ function orderedSnapshot(workspaceId, kind, refs) {
9182
+ const key = listKey(workspaceId, kind);
9183
+ if (key === void 0) return refs;
9184
+ const signature = refs.join("\0");
9185
+ const fingerprint = savedFingerprint(key);
9186
+ const hit = snapshots.get(key);
9187
+ if (hit !== void 0 && hit.atRevision === revision && hit.signature === signature && hit.savedFingerprint === fingerprint) return hit.result;
9188
+ const result = reconcileSidebarOrder(storedOrders()[key] ?? [], refs);
9189
+ snapshots.set(key, {
9190
+ atRevision: revision,
9191
+ signature,
9192
+ savedFingerprint: fingerprint,
9193
+ result
9194
+ });
9195
+ return result;
9196
+ }
9197
+ /**
9198
+ * Effective row order for one sidebar list: the user's saved order folded
9199
+ * into the given Remote default order. Identity-stable across renders while
9200
+ * neither the data nor this browser's preference changes.
9201
+ */
9202
+ function useSidebarOrder(workspaceId, kind, refs) {
9203
+ return (0, react.useSyncExternalStore)((0, react.useCallback)((listener) => {
9204
+ listeners.add(listener);
9205
+ return () => {
9206
+ listeners.delete(listener);
9207
+ };
9208
+ }, []), () => orderedSnapshot(workspaceId, kind, refs), () => orderedSnapshot(workspaceId, kind, refs));
9209
+ }
9210
+ /**
9211
+ * The only mutation path: move `movedRef` to the given side of `targetRef`
9212
+ * inside the list's current effective order. Returns the new order, or
9213
+ * `undefined` when the request cannot change anything (unknown refs, dropping
9214
+ * a row onto itself, or an adjacent marker that would put it right back).
9215
+ * Persistence and subscriber notification happen here.
9216
+ */
9217
+ function moveSidebarItem(workspaceId, kind, refs, movedRef, targetRef, marker) {
9218
+ const key = listKey(workspaceId, kind);
9219
+ const from = refs.indexOf(movedRef);
9220
+ const nextFromTarget = refs.indexOf(targetRef);
9221
+ if (key === void 0 || from < 0 || nextFromTarget < 0 || movedRef === targetRef) return void 0;
9222
+ const next = [...refs];
9223
+ const [item] = next.splice(from, 1);
9224
+ if (item === void 0) return void 0;
9225
+ const insertAt = next.indexOf(targetRef) + (marker === "after" ? 1 : 0);
9226
+ if (insertAt === from) return void 0;
9227
+ next.splice(insertAt, 0, item);
9228
+ saveOrder(key, next);
9229
+ snapshots.delete(key);
9230
+ emitChange();
9231
+ return next;
9232
+ }
9233
+ //#endregion
7994
9234
  //#region src/client/TeamRowMenu.tsx
7995
9235
  /**
7996
9236
  * Row-level overflow menu shared by sidebar Channel and Agent rows, mirroring
@@ -8062,7 +9302,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8062
9302
  }
8063
9303
  //#endregion
8064
9304
  //#region \0dsh-css:/home/yu/projects/dsh-agent-team/packages/client-agent-team/src/client/create.module.css.mjs
8065
- 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{width:100%}._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-text-disabled);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}}";
9305
+ const css = "._1henIG_form{gap:16px;display:grid}._1henIG_field{color:var(--dsw-alias-label-secondary);gap:6px;font-size:12px;line-height:18px;display:grid}._1henIG_input{box-sizing:border-box;width:100%}._1henIG_menuCap{max-height:min(320px,56vh)}._1henIG_selectTrigger{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);box-sizing:border-box;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;border-radius:8px;justify-content:space-between;align-items:center;gap:8px;min-height:32px;padding:4px 10px;font-size:14px;line-height:22px;display:flex}._1henIG_selectTrigger:disabled{cursor:default;opacity:.6}._1henIG_selectTrigger:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}._1henIG_selectValue{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}._1henIG_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .12s;display:inline-flex}._1henIG_chevronOpen{transform:rotate(180deg)}._1henIG_memberPicker{border:0;gap:4px;max-height:220px;margin:0;padding:0;display:grid;overflow-y:auto}._1henIG_memberPicker legend{color:var(--dsw-alias-label-secondary);padding:0 0 6px;font-size:12px;line-height:18px}._1henIG_memberOption{color:var(--dsw-alias-label-primary);border-radius:6px;grid-template-columns:auto 14px minmax(0,1fr);align-items:center;gap:0 7px;min-height:32px;padding:3px 6px;display:grid}._1henIG_memberOption:hover{background:var(--dsw-alias-interactive-bg-hover)}._1henIG_memberOption input{margin:0}._1henIG_memberOption small{color:var(--dsw-alias-label-tertiary);grid-column:3;font-size:10px;line-height:14px}._1henIG_unavailableDot{background:var(--dsw-alias-label-tertiary);border-radius:50%;justify-self:center;width:7px;height:7px;display:inline-block}._1henIG_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}._1henIG_dialogContent{max-height:min(70vh,560px);overflow-y:auto}@media (width<=600px){._1henIG_dialogContent{max-height:calc(100vh - 180px)}._1henIG_memberPicker{max-height:180px}}";
8066
9306
  const tagId = "@wowyuarm/dsh-agent-team/create.module.css";
8067
9307
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
8068
9308
  const tag = document.createElement("style");
@@ -8081,13 +9321,77 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8081
9321
  "input": "_1henIG_input",
8082
9322
  "memberOption": "_1henIG_memberOption",
8083
9323
  "memberPicker": "_1henIG_memberPicker",
9324
+ "menuCap": "_1henIG_menuCap",
8084
9325
  "selectTrigger": "_1henIG_selectTrigger",
8085
9326
  "selectValue": "_1henIG_selectValue",
8086
9327
  "unavailableDot": "_1henIG_unavailableDot"
8087
9328
  };
8088
9329
  //#endregion
9330
+ //#region src/client/multi-menu-field.tsx
9331
+ /**
9332
+ * Render the labeled multi-select Menu field.
9333
+ * @param props.label - field caption; doubles as the trigger's accessible name.
9334
+ * @param props.options - selectable entries in display order.
9335
+ * @param props.selected - currently checked ids.
9336
+ * @param props.onToggle - invoked with an id when its row is clicked.
9337
+ * @param props.disabled - disables the trigger while a mutation is in flight.
9338
+ * @param props.emptyText - shown instead of the picker when there is nothing to pick.
9339
+ * @param props.triggerEmptyLabel - trigger caption when nothing is selected.
9340
+ * @param props.formatCount - builds the trigger caption for N selections.
9341
+ */
9342
+ function MultiMenuField({ label, options, selected, onToggle, disabled = false, emptyText, triggerEmptyLabel, formatCount }) {
9343
+ const [open, setOpen] = (0, react.useState)(false);
9344
+ const items = options.map((option) => ({
9345
+ id: option.id,
9346
+ label: option.hint === void 0 ? option.label : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [option.label, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
9347
+ className: sidebar_module_css_default.menuHint,
9348
+ children: ` ${option.hint}`
9349
+ })] }),
9350
+ ...option.disabled === true ? { disabled: true } : {},
9351
+ ...option.icon === void 0 ? {} : { icon: option.icon }
9352
+ }));
9353
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9354
+ className: create_module_css_default.field,
9355
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }), options.length === 0 && emptyText !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
9356
+ className: sidebar_module_css_default.editHint,
9357
+ children: emptyText
9358
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
9359
+ open,
9360
+ portal: true,
9361
+ className: create_module_css_default.menuCap,
9362
+ items,
9363
+ selectedIds: selected,
9364
+ onSelect: (id) => {
9365
+ onToggle(id);
9366
+ },
9367
+ onClose: () => {
9368
+ setOpen(false);
9369
+ },
9370
+ anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
9371
+ type: "button",
9372
+ className: create_module_css_default.selectTrigger,
9373
+ "aria-label": label,
9374
+ "aria-haspopup": "listbox",
9375
+ "aria-expanded": open,
9376
+ disabled,
9377
+ onClick: () => {
9378
+ setOpen((value) => !value);
9379
+ },
9380
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9381
+ className: create_module_css_default.selectValue,
9382
+ children: selected.length === 0 ? triggerEmptyLabel : formatCount(selected.length)
9383
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9384
+ className: `${create_module_css_default.chevron} ${open ? create_module_css_default.chevronOpen : ""}`,
9385
+ "aria-hidden": true,
9386
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})
9387
+ })]
9388
+ })
9389
+ })]
9390
+ });
9391
+ }
9392
+ //#endregion
8089
9393
  //#region src/client/TeamAgentsPanel.tsx
8090
- function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, loadChannels, addMember, updateMember, joinChannel, removeChannelMember, loadModels, openMemberSession, onCreatingChange, t }) {
9394
+ function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, loadChannels, addMember, updateMember, recoverMember, joinChannel, removeChannelMember, loadModels, memberSessionId, openMemberSession, onCreatingChange, t }) {
8091
9395
  const [members, setMembers] = (0, react.useState)([]);
8092
9396
  const [channels, setChannels] = (0, react.useState)([]);
8093
9397
  const [channelRefs, setChannelRefs] = (0, react.useState)([]);
@@ -8096,9 +9400,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8096
9400
  const [formOpen, setFormOpen] = (0, react.useState)(false);
8097
9401
  const [handle, setHandle] = (0, react.useState)("");
8098
9402
  const [description, setDescription] = (0, react.useState)("");
9403
+ const [model, setModel] = (0, react.useState)(void 0);
8099
9404
  const [creating, setCreating] = (0, react.useState)(false);
8100
9405
  const [retryRequest, setRetryRequest] = (0, react.useState)();
8101
9406
  const triggerRef = (0, react.useRef)(null);
9407
+ const orderedAgentRefs = useSidebarOrder(workspaceId, "agents", (0, react.useMemo)(() => members.map((status) => status.member.memberId), [members]));
9408
+ const orderedMembers = (0, react.useMemo)(() => {
9409
+ const byId = new Map(members.map((status) => [status.member.memberId, status]));
9410
+ return orderedAgentRefs.map((memberId) => byId.get(memberId)).filter((status) => status !== void 0);
9411
+ }, [orderedAgentRefs, members]);
9412
+ const applyMove = (movedRef, targetRef, marker) => {
9413
+ moveSidebarItem(workspaceId, "agents", orderedAgentRefs, movedRef, targetRef, marker);
9414
+ };
9415
+ const drag = useSidebarRowDrag({
9416
+ refs: orderedAgentRefs,
9417
+ onCommit: applyMove
9418
+ });
8102
9419
  const refresh = (0, react.useCallback)(async () => {
8103
9420
  setLoading(true);
8104
9421
  const result = await loadMembers({ workspaceId });
@@ -8159,6 +9476,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8159
9476
  });
8160
9477
  setHandle("");
8161
9478
  setDescription("");
9479
+ setModel(void 0);
8162
9480
  setChannelRefs([]);
8163
9481
  setFormOpen(false);
8164
9482
  if (result.value.status.presence === "unavailable") setError(result.value.status.diagnostic ?? t("statusUnavailable"));
@@ -8181,15 +9499,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8181
9499
  event.preventDefault();
8182
9500
  const normalizedHandle = handle.trim();
8183
9501
  const normalizedDescription = description.trim();
8184
- if (normalizedHandle.length === 0 || normalizedDescription.length === 0 || creating) return;
8185
- if (channelRefs.length === 0) return;
8186
- provision(retryRequest !== void 0 && retryRequest.workspaceId === workspaceId && retryRequest.handle === normalizedHandle && retryRequest.description === normalizedDescription && retryRequest.channelRefs.length === channelRefs.length && retryRequest.channelRefs.every((ref) => channelRefs.includes(ref)) ? retryRequest : {
9502
+ if (normalizedHandle.length === 0 || creating) return;
9503
+ provision(retryRequest !== void 0 && retryRequest.workspaceId === workspaceId && retryRequest.handle === normalizedHandle && retryRequest.description === normalizedDescription && sameModel(retryRequest.model, model) && retryRequest.channelRefs.length === channelRefs.length && retryRequest.channelRefs.every((ref) => channelRefs.includes(ref)) ? retryRequest : {
8187
9504
  requestId: crypto.randomUUID(),
8188
9505
  workspaceId,
8189
9506
  handle: normalizedHandle,
8190
9507
  description: normalizedDescription,
8191
9508
  presetId: "team-member",
8192
- channelRefs
9509
+ channelRefs,
9510
+ ...model === void 0 ? {} : { model }
8193
9511
  });
8194
9512
  };
8195
9513
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -8210,7 +9528,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8210
9528
  type: "submit",
8211
9529
  form: "team-agent-create-form",
8212
9530
  variant: "primary",
8213
- disabled: creating || handle.trim().length === 0 || description.trim().length === 0 || channelRefs.length === 0,
9531
+ disabled: creating || handle.trim().length === 0,
8214
9532
  children: creating ? t("creatingAgent") : t("createAgent")
8215
9533
  })] }),
8216
9534
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
@@ -8233,9 +9551,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8233
9551
  }),
8234
9552
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
8235
9553
  className: create_module_css_default.field,
8236
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("agentDescription") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
9554
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [t("agentDescription"), t("optionalSuffix")] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
8237
9555
  className: create_module_css_default.input,
8238
9556
  value: description,
9557
+ placeholder: t("agentDescriptionPlaceholder"),
8239
9558
  onChange: (event) => {
8240
9559
  setDescription(event.target.value);
8241
9560
  setRetryRequest(void 0);
@@ -8243,21 +9562,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8243
9562
  disabled: creating
8244
9563
  })]
8245
9564
  }),
8246
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
8247
- className: create_module_css_default.field,
8248
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", { children: t("initialChannels") }), channels.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("noChannelsForAgent") }) : channels.map((channel) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
8249
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
8250
- type: "checkbox",
8251
- checked: channelRefs.includes(channel.channelRef),
8252
- disabled: creating,
8253
- onChange: (event) => {
8254
- setChannelRefs((current) => event.target.checked ? [...current, channel.channelRef] : current.filter((ref) => ref !== channel.channelRef));
8255
- setRetryRequest(void 0);
8256
- }
8257
- }),
8258
- " ",
8259
- channel.name
8260
- ] }, channel.channelRef))]
9565
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelPickerField, {
9566
+ model,
9567
+ onModelChange: (choice) => {
9568
+ setModel(choice);
9569
+ setRetryRequest(void 0);
9570
+ },
9571
+ loadModels,
9572
+ disabled: creating,
9573
+ t
9574
+ }),
9575
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MultiMenuField, {
9576
+ label: `${t("initialChannels")}${t("optionalSuffix")}`,
9577
+ disabled: creating,
9578
+ options: channels.map((channel) => ({
9579
+ id: channel.channelRef,
9580
+ label: channel.name
9581
+ })),
9582
+ selected: channelRefs,
9583
+ onToggle: (ref) => {
9584
+ setChannelRefs((current) => current.includes(ref) ? current.filter((item) => item !== ref) : [...current, ref]);
9585
+ setRetryRequest(void 0);
9586
+ },
9587
+ emptyText: t("noChannelsForAgent"),
9588
+ triggerEmptyLabel: t("channelsPickerEmpty"),
9589
+ formatCount: (count) => t("channelsPickerCount", { count })
8261
9590
  }),
8262
9591
  formOpen && error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8263
9592
  className: create_module_css_default.error,
@@ -8295,19 +9624,25 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8295
9624
  }),
8296
9625
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8297
9626
  className: sidebar_module_css_default.agentList,
8298
- children: members.map((status) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AgentRow, {
8299
- status,
8300
- channels,
8301
- loadChannels,
8302
- updateMember,
8303
- joinChannel,
8304
- removeChannelMember,
8305
- loadModels,
8306
- openMemberSession,
8307
- onUpdated: () => {
8308
- refresh();
8309
- },
8310
- t
9627
+ children: orderedMembers.map((status) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SortableRow, {
9628
+ drag,
9629
+ orderKey: status.member.memberId,
9630
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AgentRow, {
9631
+ status,
9632
+ ...memberSessionId === void 0 ? {} : { current: status.member.sessionId === memberSessionId },
9633
+ channels,
9634
+ loadChannels,
9635
+ updateMember,
9636
+ recoverMember,
9637
+ joinChannel,
9638
+ removeChannelMember,
9639
+ loadModels,
9640
+ openMemberSession,
9641
+ onUpdated: () => {
9642
+ refresh();
9643
+ },
9644
+ t
9645
+ })
8311
9646
  }, status.member.memberId))
8312
9647
  })
8313
9648
  ]
@@ -8333,9 +9668,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8333
9668
  * conversation page, the avatar carries identity plus the presence badge, and
8334
9669
  * the row menu opens the editor.
8335
9670
  */
8336
- function AgentRow({ status, channels, loadChannels, updateMember, joinChannel, removeChannelMember, loadModels, openMemberSession, onUpdated, t }) {
9671
+ function AgentRow({ status, current, channels, loadChannels, updateMember, recoverMember, joinChannel, removeChannelMember, loadModels, openMemberSession, onUpdated, t }) {
8337
9672
  const [menuOpen, setMenuOpen] = (0, react.useState)(false);
8338
9673
  const [editing, setEditing] = (0, react.useState)(false);
9674
+ const resume = async () => {
9675
+ await recoverMember({
9676
+ requestId: crypto.randomUUID(),
9677
+ workspaceId: status.member.workspaceId,
9678
+ memberId: status.member.memberId
9679
+ });
9680
+ await onUpdated();
9681
+ };
8339
9682
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8340
9683
  className: sidebar_module_css_default.agentRow,
8341
9684
  "data-menu-open": menuOpen || void 0,
@@ -8343,6 +9686,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8343
9686
  type: "button",
8344
9687
  className: sidebar_module_css_default.agentSelect,
8345
9688
  "aria-label": t("openAgentSession", { name: status.member.handle }),
9689
+ "aria-current": current ? "page" : void 0,
9690
+ disabled: status.availability !== "active",
8346
9691
  onClick: () => {
8347
9692
  openMemberSession(status.member.sessionId);
8348
9693
  },
@@ -8361,9 +9706,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8361
9706
  id: "edit",
8362
9707
  label: t("editAgent"),
8363
9708
  icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, {})
8364
- }],
8365
- onSelect: () => {
8366
- setEditing(true);
9709
+ }, ...status.presence === "error" ? [{
9710
+ id: "resume",
9711
+ label: t("resumeAgent"),
9712
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlayOutline16, {})
9713
+ }] : []],
9714
+ onSelect: (id) => {
9715
+ if (id === "resume") resume();
9716
+ else setEditing(true);
8367
9717
  },
8368
9718
  onOpenChange: setMenuOpen
8369
9719
  })
@@ -8388,23 +9738,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8388
9738
  return `${provider}\u0000${model}`;
8389
9739
  }
8390
9740
  /**
8391
- * Agent editor: handle, description, and per-Member model selection commit
8392
- * through one durable update; Channel membership below keeps its own
8393
- * immediate add/remove flow.
9741
+ * Shared provider/model dropdown for the create and edit forms. The option
9742
+ * list rides the shared Menu primitive (one leading "follow Host default"
9743
+ * row, then non-selectable provider headings) with a capped, internally
9744
+ * scrolling card so growing model catalogs cannot stretch the dialog.
8394
9745
  */
8395
- function AgentEditorDialog({ status, channels, loadChannels, updateMember, joinChannel, removeChannelMember, loadModels, onCommitted, onClose, t }) {
8396
- const memberId = status.member.memberId;
8397
- const [handle, setHandle] = (0, react.useState)(status.member.handle);
8398
- const [description, setDescription] = (0, react.useState)(status.member.description);
8399
- const [model, setModel] = (0, react.useState)(status.member.model === void 0 ? void 0 : [status.member.model.provider, status.member.model.model]);
9746
+ function ModelPickerField({ model, onModelChange, loadModels, disabled, t }) {
8400
9747
  const [groups, setGroups] = (0, react.useState)();
8401
9748
  const [modelsError, setModelsError] = (0, react.useState)();
8402
- const [modelOpen, setModelOpen] = (0, react.useState)(false);
8403
- const [saving, setSaving] = (0, react.useState)(false);
8404
- const [error, setError] = (0, react.useState)();
8405
- const pendingRequest = (0, react.useRef)();
8406
- const [memberships, setMemberships] = (0, react.useState)();
8407
- const [loadError, setLoadError] = (0, react.useState)();
9749
+ const [open, setModelOpen] = (0, react.useState)(false);
9750
+ const [effortOpen, setEffortOpen] = (0, react.useState)(false);
8408
9751
  (0, react.useEffect)(() => {
8409
9752
  let mounted = true;
8410
9753
  loadModels().then((result) => {
@@ -8418,6 +9761,150 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8418
9761
  mounted = false;
8419
9762
  };
8420
9763
  }, [loadModels]);
9764
+ const items = [{
9765
+ id: "",
9766
+ label: t("modelFollowDefault")
9767
+ }];
9768
+ const byKey = /* @__PURE__ */ new Map();
9769
+ for (const group of groups ?? []) {
9770
+ items.push({
9771
+ type: "label",
9772
+ id: `model-group:${group.id}`,
9773
+ text: group.name
9774
+ });
9775
+ for (const entry of group.models) {
9776
+ const key = modelKey(group.id, entry.id);
9777
+ byKey.set(key, {
9778
+ provider: group.id,
9779
+ id: entry.id,
9780
+ name: entry.name,
9781
+ efforts: entry.reasoning?.efforts ?? []
9782
+ });
9783
+ items.push({
9784
+ id: key,
9785
+ label: entry.name
9786
+ });
9787
+ }
9788
+ }
9789
+ const selectedModelKey = model === void 0 ? "" : modelKey(model.provider, model.model);
9790
+ const triggerLabel = model === void 0 ? t("modelFollowDefault") : byKey.get(selectedModelKey)?.name ?? `${model.provider} / ${model.model}`;
9791
+ const efforts = model === void 0 ? [] : byKey.get(selectedModelKey)?.efforts ?? [];
9792
+ const effortItems = [{
9793
+ id: "",
9794
+ label: t("effortFollowDefault")
9795
+ }, ...efforts.map((effort) => ({
9796
+ id: effort.id,
9797
+ label: effort.name
9798
+ }))];
9799
+ const selectedEffort = model?.reasoningEffort ?? "";
9800
+ const effortTriggerLabel = model === void 0 || selectedEffort === "" ? t("effortFollowDefault") : efforts.find((effort) => effort.id === selectedEffort)?.name ?? selectedEffort;
9801
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9802
+ className: create_module_css_default.field,
9803
+ children: [
9804
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("memberModel") }),
9805
+ groups === void 0 && modelsError === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
9806
+ className: sidebar_module_css_default.editHint,
9807
+ children: t("modelsLoading")
9808
+ }),
9809
+ modelsError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
9810
+ className: sidebar_module_css_default.editHint,
9811
+ children: t("modelsLoadFailed", { message: modelsError })
9812
+ }),
9813
+ groups !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
9814
+ open,
9815
+ portal: true,
9816
+ className: create_module_css_default.menuCap,
9817
+ items,
9818
+ selectedId: selectedModelKey,
9819
+ onSelect: (key) => {
9820
+ setModelOpen(false);
9821
+ const choice = byKey.get(key);
9822
+ onModelChange(choice === void 0 ? void 0 : {
9823
+ provider: choice.provider,
9824
+ model: choice.id
9825
+ });
9826
+ },
9827
+ onClose: () => {
9828
+ setModelOpen(false);
9829
+ },
9830
+ anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
9831
+ type: "button",
9832
+ className: create_module_css_default.selectTrigger,
9833
+ "aria-label": t("memberModel"),
9834
+ "aria-haspopup": "listbox",
9835
+ "aria-expanded": open,
9836
+ disabled,
9837
+ onClick: () => {
9838
+ setModelOpen((value) => !value);
9839
+ },
9840
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9841
+ className: create_module_css_default.selectValue,
9842
+ children: triggerLabel
9843
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9844
+ className: `${create_module_css_default.chevron} ${open ? create_module_css_default.chevronOpen : ""}`,
9845
+ "aria-hidden": true,
9846
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})
9847
+ })]
9848
+ })
9849
+ }),
9850
+ model !== void 0 && efforts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
9851
+ open: effortOpen,
9852
+ portal: true,
9853
+ className: create_module_css_default.menuCap,
9854
+ items: effortItems,
9855
+ selectedId: selectedEffort,
9856
+ onSelect: (key) => {
9857
+ setEffortOpen(false);
9858
+ onModelChange(key === "" ? {
9859
+ provider: model.provider,
9860
+ model: model.model
9861
+ } : {
9862
+ provider: model.provider,
9863
+ model: model.model,
9864
+ reasoningEffort: key
9865
+ });
9866
+ },
9867
+ onClose: () => {
9868
+ setEffortOpen(false);
9869
+ },
9870
+ anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
9871
+ type: "button",
9872
+ className: create_module_css_default.selectTrigger,
9873
+ "aria-label": t("reasoningEffort"),
9874
+ "aria-haspopup": "listbox",
9875
+ "aria-expanded": effortOpen,
9876
+ disabled,
9877
+ onClick: () => {
9878
+ setEffortOpen((value) => !value);
9879
+ },
9880
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9881
+ className: create_module_css_default.selectValue,
9882
+ children: `${t("reasoningEffort")} · ${effortTriggerLabel}`
9883
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9884
+ className: `${create_module_css_default.chevron} ${effortOpen ? create_module_css_default.chevronOpen : ""}`,
9885
+ "aria-hidden": true,
9886
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})
9887
+ })]
9888
+ })
9889
+ })
9890
+ ]
9891
+ });
9892
+ }
9893
+ /**
9894
+ * Agent editor: handle, description, and per-Member model selection commit
9895
+ * through one durable update; Channel membership below keeps its own
9896
+ * immediate add/remove flow.
9897
+ */
9898
+ function AgentEditorDialog({ status, channels, loadChannels, updateMember, joinChannel, removeChannelMember, loadModels, onCommitted, onClose, t }) {
9899
+ const memberId = status.member.memberId;
9900
+ const [handle, setHandle] = (0, react.useState)(status.member.handle);
9901
+ const [description, setDescription] = (0, react.useState)(status.member.description);
9902
+ const [model, setModel] = (0, react.useState)(status.member.model);
9903
+ const [saving, setSaving] = (0, react.useState)(false);
9904
+ const [error, setError] = (0, react.useState)();
9905
+ const pendingRequest = (0, react.useRef)();
9906
+ const [memberships, setMemberships] = (0, react.useState)();
9907
+ const [loadError, setLoadError] = (0, react.useState)();
8421
9908
  (0, react.useEffect)(() => {
8422
9909
  let mounted = true;
8423
9910
  loadChannels({
@@ -8449,54 +9936,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8449
9936
  });
8450
9937
  });
8451
9938
  const joinedChannels = new Set((memberships ?? []).filter((item) => item.memberId === memberId).map((item) => item.channelRef));
8452
- const modelChoices = (() => {
8453
- const items = [{
8454
- id: "",
8455
- label: t("modelFollowDefault")
8456
- }];
8457
- const byKey = /* @__PURE__ */ new Map();
8458
- for (const group of groups ?? []) {
8459
- items.push({
8460
- type: "label",
8461
- id: `model-group:${group.id}`,
8462
- text: group.name
8463
- });
8464
- for (const entry of group.models) {
8465
- const key = modelKey(group.id, entry.id);
8466
- byKey.set(key, {
8467
- provider: group.id,
8468
- id: entry.id,
8469
- name: entry.name
8470
- });
8471
- items.push({
8472
- id: key,
8473
- label: entry.name
8474
- });
8475
- }
8476
- }
8477
- return {
8478
- items,
8479
- byKey
8480
- };
8481
- })();
8482
- const selectedModelKey = model === void 0 ? "" : modelKey(model[0], model[1]);
8483
- const modelTriggerLabel = model === void 0 ? t("modelFollowDefault") : modelChoices.byKey.get(selectedModelKey)?.name ?? `${model[0]} / ${model[1]}`;
8484
- const dirty = handle.trim() !== status.member.handle || description.trim() !== status.member.description || !sameModel(model, status.member.model === void 0 ? void 0 : [status.member.model.provider, status.member.model.model]);
9939
+ const dirty = handle.trim() !== status.member.handle || description.trim() !== status.member.description || !sameModel(model, status.member.model);
8485
9940
  const submit = async (event) => {
8486
9941
  event.preventDefault();
8487
9942
  const normalizedHandle = handle.trim();
8488
9943
  const normalizedDescription = description.trim();
8489
- if (saving || !dirty || normalizedHandle.length === 0 || normalizedDescription.length === 0) return;
9944
+ if (saving || !dirty || normalizedHandle.length === 0) return;
8490
9945
  const payload = {
8491
9946
  memberId,
8492
9947
  handle: normalizedHandle,
8493
9948
  description: normalizedDescription,
8494
- ...model === void 0 ? {} : { model: {
8495
- provider: model[0],
8496
- model: model[1]
8497
- } }
9949
+ ...model === void 0 ? {} : { model }
8498
9950
  };
8499
- const request = pendingRequest.current !== void 0 && pendingRequest.current.memberId === payload.memberId && pendingRequest.current.handle === payload.handle && pendingRequest.current.description === payload.description && sameModel(pendingRequest.current.model === void 0 ? void 0 : [pendingRequest.current.model.provider, pendingRequest.current.model.model], model) ? pendingRequest.current : {
9951
+ const request = pendingRequest.current !== void 0 && pendingRequest.current.memberId === payload.memberId && pendingRequest.current.handle === payload.handle && pendingRequest.current.description === payload.description && sameModel(pendingRequest.current.model, model) ? pendingRequest.current : {
8500
9952
  requestId: crypto.randomUUID(),
8501
9953
  ...payload
8502
9954
  };
@@ -8532,7 +9984,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8532
9984
  type: "submit",
8533
9985
  form: "team-agent-edit-form",
8534
9986
  variant: "primary",
8535
- disabled: saving || !dirty || handle.trim().length === 0 || description.trim().length === 0,
9987
+ disabled: saving || !dirty || handle.trim().length === 0,
8536
9988
  children: saving ? t("editSaving") : t("editSave")
8537
9989
  })] }),
8538
9990
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
@@ -8557,9 +10009,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8557
10009
  }),
8558
10010
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
8559
10011
  className: create_module_css_default.field,
8560
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("agentDescription") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
10012
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [t("agentDescription"), t("optionalSuffix")] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
8561
10013
  className: create_module_css_default.input,
8562
10014
  value: description,
10015
+ placeholder: t("agentDescriptionPlaceholder"),
8563
10016
  onChange: (event) => {
8564
10017
  setDescription(event.target.value);
8565
10018
  pendingRequest.current = void 0;
@@ -8567,53 +10020,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8567
10020
  disabled: saving
8568
10021
  })]
8569
10022
  }),
8570
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8571
- className: create_module_css_default.field,
8572
- children: [
8573
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("memberModel") }),
8574
- groups === void 0 && modelsError === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
8575
- className: sidebar_module_css_default.editHint,
8576
- children: t("modelsLoading")
8577
- }),
8578
- modelsError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
8579
- className: sidebar_module_css_default.editHint,
8580
- children: t("modelsLoadFailed", { message: modelsError })
8581
- }),
8582
- groups !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
8583
- open: modelOpen,
8584
- portal: true,
8585
- items: modelChoices.items,
8586
- selectedId: selectedModelKey,
8587
- onSelect: (key) => {
8588
- setModelOpen(false);
8589
- pendingRequest.current = void 0;
8590
- const choice = modelChoices.byKey.get(key);
8591
- setModel(choice === void 0 ? void 0 : [choice.provider, choice.id]);
8592
- },
8593
- onClose: () => {
8594
- setModelOpen(false);
8595
- },
8596
- anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8597
- type: "button",
8598
- className: create_module_css_default.selectTrigger,
8599
- "aria-label": t("memberModel"),
8600
- "aria-haspopup": "listbox",
8601
- "aria-expanded": modelOpen,
8602
- disabled: saving,
8603
- onClick: () => {
8604
- setModelOpen((value) => !value);
8605
- },
8606
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8607
- className: create_module_css_default.selectValue,
8608
- children: modelTriggerLabel
8609
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8610
- className: `${create_module_css_default.chevron} ${modelOpen ? create_module_css_default.chevronOpen : ""}`,
8611
- "aria-hidden": true,
8612
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})
8613
- })]
8614
- })
8615
- })
8616
- ]
10023
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelPickerField, {
10024
+ model,
10025
+ onModelChange: (choice) => {
10026
+ pendingRequest.current = void 0;
10027
+ setModel(choice);
10028
+ },
10029
+ loadModels,
10030
+ disabled: saving,
10031
+ t
8617
10032
  }),
8618
10033
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
8619
10034
  className: create_module_css_default.memberPicker,
@@ -8674,7 +10089,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8674
10089
  function sameModel(left, right) {
8675
10090
  if (left === void 0 && right === void 0) return true;
8676
10091
  if (left === void 0 || right === void 0) return false;
8677
- return left[0] === right[0] && left[1] === right[1];
10092
+ return left.provider === right.provider && left.model === right.model && left.reasoningEffort === right.reasoningEffort;
8678
10093
  }
8679
10094
  //#endregion
8680
10095
  //#region src/client/TeamChannelsPanel.tsx
@@ -8692,6 +10107,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8692
10107
  const [pendingCreate, setPendingCreate] = (0, react.useState)();
8693
10108
  const previousCreatingKey = (0, react.useRef)(creatingAgents.map((request) => request.requestId).join(","));
8694
10109
  const triggerRef = (0, react.useRef)(null);
10110
+ const orderedChannelRefs = useSidebarOrder(workspaceId, "channels", (0, react.useMemo)(() => view?.channels.map((channel) => channel.channelRef) ?? [], [view]));
10111
+ const orderedChannels = (0, react.useMemo)(() => {
10112
+ const byRef = new Map((view?.channels ?? []).map((channel) => [channel.channelRef, channel]));
10113
+ return orderedChannelRefs.map((channelRef) => byRef.get(channelRef)).filter((channel) => channel !== void 0);
10114
+ }, [orderedChannelRefs, view]);
10115
+ const applyMove = (movedRef, targetRef, marker) => {
10116
+ moveSidebarItem(workspaceId, "channels", orderedChannelRefs, movedRef, targetRef, marker);
10117
+ };
10118
+ const drag = useSidebarRowDrag({
10119
+ refs: orderedChannelRefs,
10120
+ onCommit: applyMove
10121
+ });
8695
10122
  const refresh = (0, react.useCallback)(async () => {
8696
10123
  setLoading(true);
8697
10124
  const [channelResult, memberResult] = await Promise.all([loadChannels({
@@ -8754,7 +10181,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8754
10181
  };
8755
10182
  const submit = async (event) => {
8756
10183
  event.preventDefault();
8757
- if (mutating || name.trim() === "" || description.trim() === "") return;
10184
+ if (mutating || name.trim() === "") return;
8758
10185
  const payload = {
8759
10186
  workspaceId,
8760
10187
  name: name.trim(),
@@ -8805,7 +10232,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8805
10232
  type: "submit",
8806
10233
  form: "team-channel-create-form",
8807
10234
  variant: "primary",
8808
- disabled: mutating || name.trim() === "" || description.trim() === "",
10235
+ disabled: mutating || name.trim() === "",
8809
10236
  children: mutating ? t("creatingChannel") : t("createChannel")
8810
10237
  })] }),
8811
10238
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
@@ -8830,9 +10257,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8830
10257
  }),
8831
10258
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
8832
10259
  className: create_module_css_default.field,
8833
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("channelDescription") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
10260
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [t("channelDescription"), t("optionalSuffix")] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
8834
10261
  className: create_module_css_default.input,
8835
10262
  value: description,
10263
+ placeholder: t("agentDescriptionPlaceholder"),
8836
10264
  disabled: mutating,
8837
10265
  onChange: (event) => {
8838
10266
  setDescription(event.target.value);
@@ -8840,64 +10268,38 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8840
10268
  }
8841
10269
  })]
8842
10270
  }),
8843
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
8844
- className: create_module_css_default.memberPicker,
10271
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MultiMenuField, {
10272
+ label: t("initialMembers"),
8845
10273
  disabled: mutating,
8846
- children: [
8847
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", { children: t("initialMembers") }),
8848
- creatingAgents.map((request) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
8849
- className: create_module_css_default.memberOption,
8850
- children: [
8851
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
8852
- type: "checkbox",
8853
- disabled: true,
8854
- "aria-describedby": `creating-member-reason-${request.requestId}`
8855
- }),
8856
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8857
- className: create_module_css_default.unavailableDot,
8858
- "aria-hidden": "true"
8859
- }),
8860
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: request.handle }),
8861
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
8862
- id: `creating-member-reason-${request.requestId}`,
8863
- children: t("memberCreatingReason")
8864
- })
8865
- ]
8866
- }, request.requestId)),
8867
- members.map((status) => {
8868
- const disabled = status.presence === "unavailable";
8869
- const reasonId = `initial-member-reason-${status.member.memberId}`;
8870
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
8871
- className: create_module_css_default.memberOption,
8872
- children: [
8873
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
8874
- type: "checkbox",
8875
- disabled,
8876
- "aria-describedby": disabled ? reasonId : void 0,
8877
- checked: selected.has(status.member.memberId),
8878
- onChange: (event) => {
8879
- setSelected((current) => {
8880
- const next = new Set(current);
8881
- if (event.target.checked) next.add(status.member.memberId);
8882
- else next.delete(status.member.memberId);
8883
- return next;
8884
- });
8885
- setPendingCreate(void 0);
8886
- }
8887
- }),
8888
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamPresenceDot, {
8889
- status,
8890
- t
8891
- }),
8892
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: status.member.handle }),
8893
- disabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
8894
- id: reasonId,
8895
- children: t("memberUnavailableReason")
8896
- })
8897
- ]
8898
- }, status.member.memberId);
10274
+ options: [...creatingAgents.map((request) => ({
10275
+ id: request.requestId,
10276
+ label: request.handle,
10277
+ disabled: true,
10278
+ hint: t("memberCreatingReason")
10279
+ })), ...members.map((status) => ({
10280
+ id: status.member.memberId,
10281
+ label: status.member.handle,
10282
+ ...status.presence === "unavailable" ? {
10283
+ disabled: true,
10284
+ hint: t("memberUnavailableReason")
10285
+ } : {},
10286
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TeamPresenceDot, {
10287
+ status,
10288
+ t
8899
10289
  })
8900
- ]
10290
+ }))],
10291
+ selected: [...selected],
10292
+ onToggle: (id) => {
10293
+ setSelected((current) => {
10294
+ const next = new Set(current);
10295
+ if (next.has(id)) next.delete(id);
10296
+ else next.add(id);
10297
+ return next;
10298
+ });
10299
+ setPendingCreate(void 0);
10300
+ },
10301
+ triggerEmptyLabel: t("membersPickerEmpty"),
10302
+ formatCount: (count) => t("membersPickerCount", { count })
8901
10303
  }),
8902
10304
  error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8903
10305
  className: create_module_css_default.error,
@@ -8935,20 +10337,25 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8935
10337
  }),
8936
10338
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8937
10339
  className: sidebar_module_css_default.channelList,
8938
- children: view?.channels.map((channel) => {
8939
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChannelRow, {
8940
- channel,
8941
- members,
8942
- joinedIds: membership.get(channel.channelRef) ?? /* @__PURE__ */ new Set(),
8943
- selected: selectedChannelRef === channel.channelRef,
8944
- updateChannel,
8945
- joinChannel: props.joinChannel,
8946
- removeChannelMember: props.removeChannelMember,
8947
- onCommitted: () => {
8948
- refresh();
8949
- },
8950
- selectChannel,
8951
- t
10340
+ children: orderedChannels.map((channel) => {
10341
+ const joined = membership.get(channel.channelRef) ?? /* @__PURE__ */ new Set();
10342
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SortableRow, {
10343
+ drag,
10344
+ orderKey: channel.channelRef,
10345
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChannelRow, {
10346
+ channel,
10347
+ members,
10348
+ joinedIds: joined,
10349
+ selected: selectedChannelRef === channel.channelRef,
10350
+ updateChannel,
10351
+ joinChannel: props.joinChannel,
10352
+ removeChannelMember: props.removeChannelMember,
10353
+ onCommitted: () => {
10354
+ refresh();
10355
+ },
10356
+ selectChannel,
10357
+ t
10358
+ })
8952
10359
  }, channel.channelRef);
8953
10360
  })
8954
10361
  })
@@ -9034,7 +10441,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9034
10441
  event.preventDefault();
9035
10442
  const normalizedName = name.trim();
9036
10443
  const normalizedDescription = description.trim();
9037
- if (saving || !dirty || normalizedName === "" || normalizedDescription === "") return;
10444
+ if (saving || !dirty || normalizedName === "") return;
9038
10445
  const request = pendingRequest.current !== void 0 && pendingRequest.current.channelRef === channel.channelRef && pendingRequest.current.name === normalizedName && pendingRequest.current.description === normalizedDescription ? pendingRequest.current : {
9039
10446
  requestId: crypto.randomUUID(),
9040
10447
  workspaceId: channel.workspaceId,
@@ -9074,7 +10481,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9074
10481
  type: "submit",
9075
10482
  form: "team-channel-edit-form",
9076
10483
  variant: "primary",
9077
- disabled: saving || !dirty || name.trim() === "" || description.trim() === "",
10484
+ disabled: saving || !dirty || name.trim() === "",
9078
10485
  children: saving ? t("editSaving") : t("editSave")
9079
10486
  })] }),
9080
10487
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
@@ -9099,9 +10506,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9099
10506
  }),
9100
10507
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
9101
10508
  className: create_module_css_default.field,
9102
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("channelDescription") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
10509
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [t("channelDescription"), t("optionalSuffix")] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
9103
10510
  className: create_module_css_default.input,
9104
10511
  value: description,
10512
+ placeholder: t("agentDescriptionPlaceholder"),
9105
10513
  onChange: (event) => {
9106
10514
  setDescription(event.target.value);
9107
10515
  pendingRequest.current = void 0;
@@ -9162,12 +10570,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9162
10570
  }
9163
10571
  //#endregion
9164
10572
  //#region src/client/TeamWorkspaceBrowser.tsx
9165
- function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, t, useWorkspaces, loadMembers, subscribeChanges, addMember, loadChannels, createChannel, updateChannel, updateMember, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
10573
+ function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, t, useWorkspaces, loadMembers, subscribeChanges, addMember, loadChannels, createChannel, updateChannel, updateMember, recoverMember, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
9166
10574
  const navigationState = (0, react.useSyncExternalStore)(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
9167
10575
  const workspaces = useWorkspaces((state) => state.items);
9168
10576
  const selected = navigationState.workspaceId;
9169
10577
  const selectedId = selected !== void 0 && workspaces.some((workspace) => workspace.workspaceId === selected) ? selected : workspaces[0]?.workspaceId;
9170
- const overviewIsCurrent = navigationState.channelRef === void 0;
10578
+ const overviewIsCurrent = navigationState.channelRef === void 0 && navigationState.memberSessionId === void 0;
9171
10579
  const [creatingAgents, setCreatingAgents] = (0, react.useState)([]);
9172
10580
  const [pendingSection, setPendingSection] = (0, react.useState)();
9173
10581
  const channelsRef = (0, react.useRef)(null);
@@ -9255,7 +10663,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9255
10663
  joinChannel,
9256
10664
  removeChannelMember,
9257
10665
  creatingAgents: creatingAgents.filter((request) => request.workspaceId === selectedId),
9258
- ...navigationState.channelRef === void 0 ? {} : { selectedChannelRef: navigationState.channelRef },
10666
+ ...navigationState.memberSessionId !== void 0 || navigationState.channelRef === void 0 ? {} : { selectedChannelRef: navigationState.channelRef },
9259
10667
  selectChannel,
9260
10668
  t
9261
10669
  }, selectedId)
@@ -9268,9 +10676,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9268
10676
  loadChannels,
9269
10677
  addMember,
9270
10678
  updateMember,
10679
+ recoverMember,
9271
10680
  joinChannel,
9272
10681
  removeChannelMember,
9273
10682
  loadModels,
10683
+ ...navigationState.memberSessionId === void 0 ? {} : { memberSessionId: navigationState.memberSessionId },
9274
10684
  openMemberSession,
9275
10685
  onCreatingChange: (request, creating) => {
9276
10686
  setCreatingAgents((current) => creating ? [...current.filter((item) => item.requestId !== request.requestId), request] : current.filter((item) => item.requestId !== request.requestId));
@@ -9322,6 +10732,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9322
10732
  manageMembers: "管理成员",
9323
10733
  editChannel: "编辑频道",
9324
10734
  editAgent: "编辑 Agent",
10735
+ resumeAgent: "恢复",
10736
+ optionalSuffix: "(可选)",
10737
+ agentDescriptionPlaceholder: "留空则暂无描述",
10738
+ channelsPickerEmpty: "选择初始频道",
10739
+ channelsPickerCount: "已选 {count} 个频道",
10740
+ membersPickerEmpty: "选择初始成员",
10741
+ membersPickerCount: "已选 {count} 个成员",
10742
+ reasoningEffort: "推理强度",
10743
+ effortFollowDefault: "跟随模型默认",
10744
+ attachFiles: "添加附件",
10745
+ removeFile: "移除 {name}",
10746
+ attachmentExpired: "文件已过期清理",
10747
+ viewImage: "查看大图 {name}",
9325
10748
  actionsChannel: "{name} 的操作",
9326
10749
  actionsAgent: "{name} 的操作",
9327
10750
  editSave: "保存",
@@ -9387,6 +10810,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9387
10810
  activityClaimReleased: "{actor} 释放了「{direction}」",
9388
10811
  activityClaimsReleased: "{actor} 因成员权限变化释放了 {count} 个 Claim",
9389
10812
  activityAccepted: "{actor} 验收了此 Task",
10813
+ activityAcceptedWithClaims: "{actor} 验收了此 Task,并一并完成了 {count} 个未完成 Claim",
10814
+ acceptEarlyTitle: "提前验收任务",
10815
+ acceptEarlyBody: "将验收本 Task,并把以下 {count} 个未完成的 Claim 一并标记为完成:",
10816
+ acceptingTask: "验收中…",
9390
10817
  activityClosed: "{actor} 关闭了此 Task",
9391
10818
  activityReopened: "{actor} 重新打开了此 Task",
9392
10819
  mentionConfirmation: "提及未关注成员需要确认,再次发送以继续",
@@ -9433,6 +10860,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9433
10860
  manageMembers: "Manage members",
9434
10861
  editChannel: "Edit Channel",
9435
10862
  editAgent: "Edit Agent",
10863
+ resumeAgent: "Resume",
10864
+ optionalSuffix: " (optional)",
10865
+ agentDescriptionPlaceholder: "Leave empty if not needed",
10866
+ channelsPickerEmpty: "Choose initial channels",
10867
+ channelsPickerCount: "{count} selected",
10868
+ membersPickerEmpty: "Choose initial members",
10869
+ membersPickerCount: "{count} selected",
10870
+ reasoningEffort: "Reasoning effort",
10871
+ effortFollowDefault: "Follow model default",
10872
+ attachFiles: "Add attachments",
10873
+ removeFile: "Remove {name}",
10874
+ attachmentExpired: "File expired and cleaned up",
10875
+ viewImage: "View image {name}",
9436
10876
  actionsChannel: "{name} actions",
9437
10877
  actionsAgent: "{name} actions",
9438
10878
  editSave: "Save",
@@ -9498,6 +10938,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9498
10938
  activityClaimReleased: "{actor} released “{direction}”",
9499
10939
  activityClaimsReleased: "{actor} released {count} Claim(s) after a membership change",
9500
10940
  activityAccepted: "{actor} accepted this Task",
10941
+ activityAcceptedWithClaims: "{actor} accepted this Task and completed {count} unfinished Claims with it",
10942
+ acceptEarlyTitle: "Accept Task early",
10943
+ acceptEarlyBody: "This accepts the Task and marks the following {count} unfinished Claims as done:",
10944
+ acceptingTask: "Accepting…",
9501
10945
  activityClosed: "{actor} closed this Task",
9502
10946
  activityReopened: "{actor} reopened this Task",
9503
10947
  mentionConfirmation: "Mentioning an unfollowed member requires confirmation; send again to continue",
@@ -9517,27 +10961,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9517
10961
  "sessions",
9518
10962
  "connection"
9519
10963
  ];
9520
- function registerModeShadow(ctx, navigation, changes, name, component, extraInject) {
10964
+ function registerModeShadow(ctx, navigation, changes, drafts, name, component, extraInject) {
9521
10965
  const sharedRemotes = {
9522
10966
  loadChannels: (request) => ctx.remote.agentTeam.view(request),
9523
10967
  subscribeChanges: (scope, listener) => changes.subscribe(scope, listener),
10968
+ drafts,
9524
10969
  loadMembers: (request) => ctx.remote.agentTeam.members(request),
9525
10970
  joinChannel: (request) => ctx.remote.agentTeam.joinChannel(request),
9526
10971
  removeChannelMember: (request) => ctx.remote.agentTeam.removeChannelMember(request),
9527
10972
  updateChannel: (request) => ctx.remote.agentTeam.updateChannel(request),
9528
10973
  updateMember: (request) => ctx.remote.agentTeam.updateMember(request),
10974
+ recoverMember: (request) => ctx.remote.agentTeam.recoverMember(request),
9529
10975
  loadModels: async () => {
9530
10976
  return (await ctx.get("connection").api.llm.models({})).result;
9531
10977
  },
9532
10978
  openMemberSession: (sessionId) => {
9533
- navigation.actions().leaveTeam();
9534
- ctx.sessions.open(sessionId);
10979
+ const sessions = ctx.sessions;
10980
+ const snapshot = navigation.getSnapshot();
10981
+ const current = sessions.list.getSnapshot().current;
10982
+ const returnTo = snapshot.memberSessionId === void 0 && current !== void 0 && current !== sessionId ? current : void 0;
10983
+ navigation.actions().enterMemberSession(sessionId, returnTo);
10984
+ sessions.open(sessionId);
9535
10985
  }
9536
10986
  };
9537
10987
  ctx.slots.inject(name, () => {
9538
10988
  let dispose;
9539
10989
  const reconcile = () => {
9540
- const active = navigation.getSnapshot().mode === "team";
10990
+ const snapshot = navigation.getSnapshot();
10991
+ const active = snapshot.mode === "team" && !(name === "conversation" && snapshot.memberSessionId !== void 0);
9541
10992
  if (active && dispose === void 0) dispose = ctx.slots.register({
9542
10993
  name,
9543
10994
  priority: -100,
@@ -9551,8 +11002,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9551
11002
  readThread: (request) => ctx.remote.agentTeam.readThread(request),
9552
11003
  loadThreadHistory: (request) => ctx.remote.agentTeam.threadHistory(request),
9553
11004
  sendMessage: (request) => ctx.remote.agentTeam.sendMessage(request),
11005
+ putAttachment: (request) => ctx.remote.agentTeam.putAttachment(request),
11006
+ getAttachment: (request) => ctx.remote.agentTeam.getAttachment(request),
9554
11007
  reply: (request) => ctx.remote.agentTeam.reply(request),
9555
- changeTask: (request) => ctx.remote.agentTeam.changeTask(request)
11008
+ changeTask: (request) => ctx.remote.agentTeam.changeTask(request),
11009
+ resolveTaskRefs: (request) => ctx.remote.agentTeam.resolveTaskRefs(request)
9556
11010
  } : {},
9557
11011
  ...name === "sidebar.workspaces" ? {
9558
11012
  addMember: (request) => ctx.remote.agentTeam.addMember(request),
@@ -9581,9 +11035,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9581
11035
  }), "agent-team: dictionaries");
9582
11036
  const navigation = new TeamNavigation();
9583
11037
  const disposeNavigation = ctx.reflect.provide("teamNavigation", navigation);
11038
+ const drafts = new TeamDraftStore();
11039
+ const disposeDrafts = ctx.reflect.provide("teamDrafts", drafts);
9584
11040
  ctx.effect(() => () => {
9585
11041
  navigation.dispose();
11042
+ drafts.dispose();
9586
11043
  disposeNavigation();
11044
+ disposeDrafts();
9587
11045
  }, "agent-team: navigation service");
9588
11046
  const changes = new TeamChangeStream((request, signal) => ctx.remote.agentTeam.changes(request, signal));
9589
11047
  const loadMemberGroups = async () => {
@@ -9606,12 +11064,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9606
11064
  inject: () => ({
9607
11065
  navigation,
9608
11066
  ...navigation.actions(),
11067
+ leaveTeam: () => {
11068
+ const snapshot = navigation.getSnapshot();
11069
+ if (snapshot.memberSessionId === void 0) {
11070
+ navigation.actions().leaveTeam();
11071
+ return;
11072
+ }
11073
+ const returnTo = snapshot.returnToSessionId;
11074
+ navigation.actions().exitMemberSession();
11075
+ if (returnTo !== void 0) ctx.sessions.open(returnTo);
11076
+ navigation.actions().leaveTeam();
11077
+ },
9609
11078
  loadMemberGroups
9610
11079
  })
9611
11080
  }, TeamFooterAction));
9612
- registerModeShadow(ctx, navigation, changes, "sidebar.workspaces", TeamWorkspaceBrowser);
9613
- registerModeShadow(ctx, navigation, changes, "conversation", TeamConversation);
9614
- registerModeShadow(ctx, navigation, changes, "sidebar.settings", TeamSettings, () => ({ loadMemberGroups }));
11081
+ registerModeShadow(ctx, navigation, changes, drafts, "sidebar.workspaces", TeamWorkspaceBrowser);
11082
+ registerModeShadow(ctx, navigation, changes, drafts, "conversation", TeamConversation);
11083
+ registerModeShadow(ctx, navigation, changes, drafts, "sidebar.settings", TeamSettings, () => ({ loadMemberGroups }));
9615
11084
  }
9616
11085
  async function apply(ctx) {
9617
11086
  const disposeRemote = await ctx.remote.$mount(TYPERT_REMOTE);