@cubeai/dsh-feishu-channels 0.0.0-stage → 0.2.0

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 (65) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +15 -0
  3. package/README.md +56 -2
  4. package/client.js +4189 -0
  5. package/cordis.patch.yml +4 -0
  6. package/docs/coexistence.md +112 -0
  7. package/docs/dsh-feishu-channels-plan.md +1406 -0
  8. package/docs/ui-revamp-plan.md +263 -0
  9. package/docs/verification.md +120 -0
  10. package/icon.svg +17 -0
  11. package/locale/en.json +6 -0
  12. package/locale/zh.json +6 -0
  13. package/package.json +76 -4
  14. package/src/channels/connection-state.js +12 -0
  15. package/src/channels/diagnostics.js +77 -0
  16. package/src/channels/factory.js +20 -0
  17. package/src/channels/feishu-app.js +267 -0
  18. package/src/channels/feishu.js +399 -0
  19. package/src/channels/media.js +9 -0
  20. package/src/channels/meta.js +24 -0
  21. package/src/channels/qr/feishu.js +84 -0
  22. package/src/channels/qr/hub.js +229 -0
  23. package/src/channels/qr/render.js +8 -0
  24. package/src/channels/qr/shared.js +50 -0
  25. package/src/engine/abort.js +35 -0
  26. package/src/engine/access.js +23 -0
  27. package/src/engine/agent-options.js +19 -0
  28. package/src/engine/approval.js +70 -0
  29. package/src/engine/assistant-settings.js +38 -0
  30. package/src/engine/assistant-text.js +11 -0
  31. package/src/engine/atomic-file.js +45 -0
  32. package/src/engine/chat-commands.js +752 -0
  33. package/src/engine/choice-delivery.js +20 -0
  34. package/src/engine/choices.js +103 -0
  35. package/src/engine/command-locale.js +70 -0
  36. package/src/engine/command-messages.js +434 -0
  37. package/src/engine/command-permissions.js +38 -0
  38. package/src/engine/command-replies.js +59 -0
  39. package/src/engine/credentials.js +54 -0
  40. package/src/engine/deferred-delivery.js +260 -0
  41. package/src/engine/delivery-history.js +39 -0
  42. package/src/engine/file-delivery.js +215 -0
  43. package/src/engine/file-input.js +52 -0
  44. package/src/engine/file-log.js +25 -0
  45. package/src/engine/gateway.js +1337 -0
  46. package/src/engine/image-input.js +31 -0
  47. package/src/engine/json-state.js +25 -0
  48. package/src/engine/keyed-queue.js +20 -0
  49. package/src/engine/merge.js +56 -0
  50. package/src/engine/message-progress.js +274 -0
  51. package/src/engine/question.js +201 -0
  52. package/src/engine/quiet-logger.js +25 -0
  53. package/src/engine/reply-stream.js +86 -0
  54. package/src/engine/router.js +713 -0
  55. package/src/engine/secure-file.js +8 -0
  56. package/src/engine/seen-store.js +43 -0
  57. package/src/engine/session-export.js +64 -0
  58. package/src/engine/session-history.js +30 -0
  59. package/src/engine/session-id.js +62 -0
  60. package/src/engine/session-store.js +109 -0
  61. package/src/engine/session-title.js +29 -0
  62. package/src/engine/split.js +291 -0
  63. package/src/engine/workspace-path.js +9 -0
  64. package/src/index.js +62 -0
  65. package/src/manager.js +1325 -0
@@ -0,0 +1,86 @@
1
+ export function isAssistantTextDelta(chunk) {
2
+ if (!chunk || typeof chunk.text !== 'string' || chunk.text.length === 0)
3
+ return false;
4
+ return !chunk.type || chunk.type === 'text' || chunk.type === 'text-delta';
5
+ }
6
+ export class ReplyStreamHub {
7
+ streams = new Map();
8
+ texts = new Map();
9
+ tails = new Map();
10
+ delivered = new Set();
11
+ // 在增量排队时记录归属,开流尚未完成也能按会话取消。
12
+ owners = new Map();
13
+ // 回合纪元:reset 时自增,迟到的旧回合增量据此丢弃,不会重建流
14
+ generations = new Map();
15
+ onTextDelta(key, delta, start, sessionId) {
16
+ if (sessionId !== undefined) {
17
+ const owner = this.owners.get(key);
18
+ if (owner !== undefined && owner !== sessionId)
19
+ this.reset(key);
20
+ this.owners.set(key, sessionId);
21
+ }
22
+ const generation = this.generations.get(key) ?? 0;
23
+ const prev = this.tails.get(key) ?? Promise.resolve();
24
+ const next = prev.catch(() => undefined).then(async () => {
25
+ if (generation !== (this.generations.get(key) ?? 0))
26
+ return;
27
+ let stream = this.streams.get(key);
28
+ if (!stream) {
29
+ stream = await start();
30
+ // start 期间可能刚被 reset(模型切换等),旧回合的流不再入表
31
+ if (generation !== (this.generations.get(key) ?? 0))
32
+ return;
33
+ if (!stream)
34
+ return;
35
+ this.streams.set(key, stream);
36
+ this.texts.set(key, '');
37
+ this.delivered.delete(key);
38
+ }
39
+ const acc = (this.texts.get(key) ?? '') + delta;
40
+ this.texts.set(key, acc);
41
+ await stream.update(acc);
42
+ });
43
+ this.tails.set(key, next);
44
+ return next;
45
+ }
46
+ async take(key, sessionId) {
47
+ if (sessionId !== undefined && this.owners.has(key) && this.owners.get(key) !== sessionId)
48
+ return { text: '' };
49
+ const generation = this.generations.get(key) ?? 0;
50
+ await (this.tails.get(key) ?? Promise.resolve()).catch(() => undefined);
51
+ if (generation !== (this.generations.get(key) ?? 0))
52
+ return { text: '', invalidated: true };
53
+ const stream = this.streams.get(key);
54
+ const text = this.texts.get(key) ?? '';
55
+ this.streams.delete(key);
56
+ this.texts.delete(key);
57
+ this.tails.delete(key);
58
+ return { stream, text };
59
+ }
60
+ markDelivered(key, sessionId) {
61
+ if (sessionId !== undefined) {
62
+ const owner = this.owners.get(key);
63
+ if (owner !== undefined && owner !== sessionId)
64
+ return;
65
+ this.owners.set(key, sessionId);
66
+ }
67
+ this.delivered.add(key);
68
+ }
69
+ consumeDelivered(key, sessionId) {
70
+ if (sessionId !== undefined && this.owners.get(key) !== sessionId)
71
+ return false;
72
+ return this.delivered.delete(key);
73
+ }
74
+ reset(key, sessionId) {
75
+ // 清理其他历史登记不能取消当前会话的流;普通新回合仍可无条件重置。
76
+ if (sessionId !== undefined && this.owners.get(key) !== sessionId)
77
+ return;
78
+ // 新回合开始:清掉上一回合可能残留的流与累计文本,避免新内容拼进旧卡片
79
+ this.generations.set(key, (this.generations.get(key) ?? 0) + 1);
80
+ this.streams.delete(key);
81
+ this.texts.delete(key);
82
+ this.tails.delete(key);
83
+ this.delivered.delete(key);
84
+ this.owners.delete(key);
85
+ }
86
+ }