@khorsheed/dsh-room 0.2.2 → 0.2.3

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 (109) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.en.md +29 -62
  3. package/README.i18n.yaml +2 -2
  4. package/README.md +28 -61
  5. package/lib/client.js +13097 -4182
  6. package/lib/index.js +4045 -730
  7. package/lib/journal-B4FOGO6S.js +482 -0
  8. package/lib/journal-Rid9AAnD.js +485 -0
  9. package/lib/tool.js +112 -166
  10. package/lib/typert.host.js +2031 -374
  11. package/lib/typert.remote-client.d.ts +34 -10
  12. package/lib/typert.remote-client.js +1599 -210
  13. package/lib/types/agent-setup.d.ts +1 -1
  14. package/lib/types/client/InviteAgentAction.js +4 -16
  15. package/lib/types/client/InviteDialog.d.ts +28 -6
  16. package/lib/types/client/InviteDialog.js +76 -12
  17. package/lib/types/client/MemberCard.d.ts +5 -1
  18. package/lib/types/client/MemberCard.js +4 -4
  19. package/lib/types/client/MembersView.d.ts +1 -1
  20. package/lib/types/client/MembersView.js +58 -22
  21. package/lib/types/client/RemoveMemberConfirm.d.ts +40 -0
  22. package/lib/types/client/RemoveMemberConfirm.js +85 -0
  23. package/lib/types/client/RoomApprovalView.d.ts +11 -0
  24. package/lib/types/client/RoomApprovalView.js +28 -0
  25. package/lib/types/client/RoomComposer.d.ts +1 -1
  26. package/lib/types/client/RoomComposer.js +195 -29
  27. package/lib/types/client/RoomDecisionView.d.ts +22 -0
  28. package/lib/types/client/RoomDecisionView.js +35 -0
  29. package/lib/types/client/RoomHelpView.d.ts +17 -0
  30. package/lib/types/client/RoomHelpView.js +56 -0
  31. package/lib/types/client/RoomInboxView.d.ts +10 -0
  32. package/lib/types/client/RoomInboxView.js +14 -0
  33. package/lib/types/client/RoomQuestionView.d.ts +13 -0
  34. package/lib/types/client/RoomQuestionView.js +61 -0
  35. package/lib/types/client/RoomRelayView.js +1 -1
  36. package/lib/types/client/RoomRunView.d.ts +3 -1
  37. package/lib/types/client/RoomRunView.js +12 -5
  38. package/lib/types/client/RoomSettingsView.d.ts +19 -0
  39. package/lib/types/client/RoomSettingsView.js +30 -0
  40. package/lib/types/client/RoomSpeechView.d.ts +22 -8
  41. package/lib/types/client/RoomSpeechView.js +94 -11
  42. package/lib/types/client/RoomStatsLine.d.ts +26 -5
  43. package/lib/types/client/RoomStatsLine.js +53 -7
  44. package/lib/types/client/RoomTaskCapsule.d.ts +19 -0
  45. package/lib/types/client/RoomTaskCapsule.js +37 -0
  46. package/lib/types/client/TasksTab.d.ts +41 -0
  47. package/lib/types/client/TasksTab.js +43 -0
  48. package/lib/types/client/TasksView.d.ts +44 -0
  49. package/lib/types/client/TasksView.js +149 -0
  50. package/lib/types/client/TeamView.d.ts +33 -0
  51. package/lib/types/client/TeamView.js +210 -0
  52. package/lib/types/client/at-menu.d.ts +127 -0
  53. package/lib/types/client/at-menu.js +173 -0
  54. package/lib/types/client/draft-chips.d.ts +67 -0
  55. package/lib/types/client/draft-chips.js +95 -0
  56. package/lib/types/client/executions.d.ts +0 -30
  57. package/lib/types/client/executions.js +4 -34
  58. package/lib/types/client/icons-local.d.ts +25 -0
  59. package/lib/types/client/icons-local.js +10 -0
  60. package/lib/types/client/icons.d.ts +2 -1
  61. package/lib/types/client/icons.js +1 -0
  62. package/lib/types/client/index.js +276 -72
  63. package/lib/types/client/locales.d.ts +482 -52
  64. package/lib/types/client/locales.js +490 -60
  65. package/lib/types/client/nodes.d.ts +112 -17
  66. package/lib/types/client/nodes.js +197 -26
  67. package/lib/types/client/slots.d.ts +117 -47
  68. package/lib/types/client/task-tag.d.ts +32 -0
  69. package/lib/types/client/task-tag.js +33 -0
  70. package/lib/types/client/tasks.d.ts +50 -0
  71. package/lib/types/client/tasks.js +82 -0
  72. package/lib/types/client/team.d.ts +73 -0
  73. package/lib/types/client/team.js +187 -0
  74. package/lib/types/decisions.d.ts +49 -0
  75. package/lib/types/decisions.js +101 -0
  76. package/lib/types/deliveries.d.ts +17 -1
  77. package/lib/types/deliveries.js +82 -6
  78. package/lib/types/dispatch.d.ts +92 -4
  79. package/lib/types/dispatch.js +477 -109
  80. package/lib/types/help.d.ts +137 -0
  81. package/lib/types/help.js +216 -0
  82. package/lib/types/helps.d.ts +26 -0
  83. package/lib/types/helps.js +47 -0
  84. package/lib/types/index.d.ts +292 -52
  85. package/lib/types/index.js +1415 -199
  86. package/lib/types/jobs.d.ts +22 -0
  87. package/lib/types/jobs.js +77 -0
  88. package/lib/types/journal.d.ts +17 -27
  89. package/lib/types/journal.js +120 -43
  90. package/lib/types/messaging.d.ts +65 -0
  91. package/lib/types/messaging.js +160 -0
  92. package/lib/types/plan-service.js +7 -1
  93. package/lib/types/report-gate.d.ts +81 -0
  94. package/lib/types/report-gate.js +89 -0
  95. package/lib/types/tool-definition.d.ts +43 -20
  96. package/lib/types/tool-definition.js +145 -212
  97. package/lib/types/tool.d.ts +2 -2
  98. package/lib/types/tool.js +3 -2
  99. package/lib/types/types.d.ts +755 -78
  100. package/locale/zh.json +1 -1
  101. package/package.json +3 -3
  102. package/lib/types/client/RoomActivityDock.d.ts +0 -19
  103. package/lib/types/client/RoomActivityDock.js +0 -105
  104. package/lib/types/client/RoomDockCapsules.d.ts +0 -64
  105. package/lib/types/client/RoomDockCapsules.js +0 -277
  106. package/lib/types/client/RoomPlanTab.d.ts +0 -15
  107. package/lib/types/client/RoomPlanTab.js +0 -13
  108. package/lib/types/client/RoomTaskLineView.d.ts +0 -13
  109. package/lib/types/client/RoomTaskLineView.js +0 -21
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Cross-session help: a member of a room asks another session for help. The
3
+ * helper stays where it is — its own session, queue, model and context — and
4
+ * the room carries the thread both ways:
5
+ *
6
+ * - the request lands in the helper's session as an ordinary follow-up (the
7
+ * host's own queue: it waits for the helper's current turn), carrying a
8
+ * `room-help` source the chat renders as a card pointing back to the room;
9
+ * - while a thread is open the helper's agent carries two agent-local tools,
10
+ * `room_help_reply` (final answer plus a short handoff) and `room_help_ask`
11
+ * (a question back to the asker), registered on that agent only;
12
+ * - the helper's messages reach the asking member as report-origin dispatches
13
+ * (the same path a member's report takes: joins a running turn, wakes an
14
+ * idle one); a helper turn that ends without the reply tool hands over its
15
+ * last answer instead, so a thread never hangs on a forgotten call.
16
+ *
17
+ * The room journals the thread as `room/help` + `room/help-message` +
18
+ * `room/help-state`.
19
+ * @module @khorsheed/dsh-room/help
20
+ */
21
+ import type { Agent } from '@deepseek-ai/dsh-agent';
22
+ import { type ContextFormed, type MessageSource } from '@deepseek-ai/dsh-llm';
23
+ import type { SessionEvent } from '@deepseek-ai/dsh-session/types';
24
+ import type { RoomHelp, RoomHelpMessageEvent } from './types.ts';
25
+ export { replayHelps } from './helps.ts';
26
+ /** The producer-owned source kind of a help message in the helper's session. */
27
+ export declare const HELP_KIND = "room-help";
28
+ declare module '@deepseek-ai/dsh-llm' {
29
+ interface MessageSourceMap {
30
+ /** room producer: a help request (or a follow-up on it) from a member of another session's room. */
31
+ 'room-help': {
32
+ kind: 'room-help';
33
+ plugin: '@khorsheed/dsh-room';
34
+ /** The help thread. */
35
+ help: string;
36
+ /** The asking room's session and title. */
37
+ room: string;
38
+ roomTitle: string;
39
+ /** The asking member's name. */
40
+ from: string;
41
+ /** `request`: the thread's first message; `message`: the asker writing again. */
42
+ op: 'request' | 'message';
43
+ /** The asker's own words (the card shows these; the content adds the model-facing framing). */
44
+ text: string;
45
+ } & ContextFormed;
46
+ }
47
+ }
48
+ /** The fields of a help source. */
49
+ export interface HelpSource {
50
+ readonly help: string;
51
+ readonly room: string;
52
+ readonly roomTitle: string;
53
+ readonly from: string;
54
+ readonly op: 'request' | 'message';
55
+ readonly text: string;
56
+ }
57
+ /** The source a help message carries into the helper's session. */
58
+ export declare function helpSource(fields: HelpSource): MessageSource;
59
+ /** A message source's help fields, when it is one. */
60
+ export declare function readHelpSource(source: unknown): HelpSource | undefined;
61
+ /**
62
+ * The session ids a log's human messages @-referenced (the host's
63
+ * `@[title](dsh-session:…)` mentions): the human pointing at a session is
64
+ * consent for the room to ask it.
65
+ * @param events - the room's events.
66
+ * @returns the referenced session ids.
67
+ */
68
+ export declare function referencedSessions(events: readonly SessionEvent[]): Set<string>;
69
+ /**
70
+ * The session ids a text's `dsh-session:` mentions name.
71
+ * @param text - message or argument text.
72
+ * @returns the ids, in order.
73
+ */
74
+ export declare function mentionedSessions(text: string): string[];
75
+ /**
76
+ * The member a 「成员(房间)」 label names (the label the @ menu writes for a
77
+ * room member, inside an `@[…](dsh-session:…)` mention or typed as text).
78
+ * @param name - the session argument as given.
79
+ * @param roomTitle - the room's resolved title.
80
+ * @returns the member name, or undefined when the label names the room itself.
81
+ */
82
+ export declare function memberFromLabel(name: string | undefined, roomTitle: string): string | undefined;
83
+ /**
84
+ * The help threads a helper's session has received (newest last), from the
85
+ * help sources in its own log.
86
+ * @param events - the helper's session events.
87
+ * @returns one entry per thread.
88
+ */
89
+ export declare function receivedHelps(events: readonly SessionEvent[]): HelpSource[];
90
+ /**
91
+ * The answer a helper's turn ended with: the last assistant text after the
92
+ * help message was claimed and before the next message from anyone else.
93
+ * @param events - the helper's session events.
94
+ * @param messageId - the help message.
95
+ * @returns the text, '' when the turn produced none (or never ran).
96
+ */
97
+ export declare function turnAnswer(events: readonly SessionEvent[], messageId: string): string;
98
+ /** Whether the helper's log holds the help message (it was claimed from the queue). */
99
+ export declare function claimed(events: readonly SessionEvent[], messageId: string): boolean;
100
+ /** The request as the helper's model reads it. */
101
+ export declare function requestPrompt(help: {
102
+ id: string;
103
+ fromName: string;
104
+ text: string;
105
+ }, roomTitle: string): string;
106
+ /** The asker writing again on a thread, as the helper reads it. */
107
+ export declare function messagePrompt(help: {
108
+ id: string;
109
+ fromName: string;
110
+ }, roomTitle: string, text: string): string;
111
+ /** A helper's message as the asking member reads it. */
112
+ export declare function askerPrompt(help: RoomHelp, message: Pick<RoomHelpMessageEvent, 'kind' | 'text' | 'handoff' | 'fallback'>): string;
113
+ /** What the helper tools need from the room. */
114
+ export interface HelperBackend {
115
+ /** Record the helper's question or reply on a thread and carry it to the asker. */
116
+ helperMessage(agent: Agent, request: {
117
+ help?: string;
118
+ kind: 'question' | 'reply';
119
+ text: string;
120
+ handoff?: string;
121
+ }): Promise<string>;
122
+ }
123
+ /**
124
+ * The two helper tools, registered on one helper agent only.
125
+ * @param backend - the room service.
126
+ * @returns the tool definitions.
127
+ */
128
+ export declare function helperTools(backend: HelperBackend): import("@deepseek-ai/dsh-tools").ToolDefinition[];
129
+ /** Build a help message for the helper's session. */
130
+ export declare function helpMessage(text: string, source: HelpSource): {
131
+ content: {
132
+ type: "text";
133
+ text: string;
134
+ }[];
135
+ source: MessageSource;
136
+ } & Pick<import("@deepseek-ai/dsh-llm").UserMessage, "id" | "role">;
137
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1,216 @@
1
+ import { createUserMessage } from '@deepseek-ai/dsh-llm';
2
+ import { defineTool } from '@deepseek-ai/dsh-tools';
3
+ export { replayHelps } from './helps.js';
4
+ /** The producer-owned source kind of a help message in the helper's session. */
5
+ export const HELP_KIND = 'room-help';
6
+ const PACKAGE_NAME = '@khorsheed/dsh-room';
7
+ /** The source a help message carries into the helper's session. */
8
+ export function helpSource(fields) {
9
+ return Object.freeze({ kind: HELP_KIND, plugin: PACKAGE_NAME, ...fields });
10
+ }
11
+ /** A message source's help fields, when it is one. */
12
+ export function readHelpSource(source) {
13
+ const value = source;
14
+ if (value?.kind !== HELP_KIND || typeof value.help !== 'string' || typeof value.room !== 'string')
15
+ return undefined;
16
+ return {
17
+ help: value.help, room: value.room,
18
+ roomTitle: typeof value.roomTitle === 'string' ? value.roomTitle : '',
19
+ from: typeof value.from === 'string' ? value.from : '',
20
+ op: value.op === 'message' ? 'message' : 'request',
21
+ text: typeof value.text === 'string' ? value.text : '',
22
+ };
23
+ }
24
+ /**
25
+ * The session ids a log's human messages @-referenced (the host's
26
+ * `@[title](dsh-session:…)` mentions): the human pointing at a session is
27
+ * consent for the room to ask it.
28
+ * @param events - the room's events.
29
+ * @returns the referenced session ids.
30
+ */
31
+ export function referencedSessions(events) {
32
+ const ids = new Set();
33
+ for (const event of events) {
34
+ if (event.type !== 'user/message' || event.data.source.kind !== 'user')
35
+ continue;
36
+ for (const block of event.data.content) {
37
+ if (block.type === 'text')
38
+ for (const id of mentionedSessions(block.text))
39
+ ids.add(id);
40
+ }
41
+ }
42
+ return ids;
43
+ }
44
+ /**
45
+ * The session ids a text's `dsh-session:` mentions name.
46
+ * @param text - message or argument text.
47
+ * @returns the ids, in order.
48
+ */
49
+ export function mentionedSessions(text) {
50
+ return [...text.matchAll(/dsh-session:([A-Za-z0-9_-]+)/gu)].flatMap((match) => {
51
+ const id = decodeSessionUri(match[1]);
52
+ return id === undefined ? [] : [id];
53
+ });
54
+ }
55
+ /**
56
+ * The member a 「成员(房间)」 label names (the label the @ menu writes for a
57
+ * room member, inside an `@[…](dsh-session:…)` mention or typed as text).
58
+ * @param name - the session argument as given.
59
+ * @param roomTitle - the room's resolved title.
60
+ * @returns the member name, or undefined when the label names the room itself.
61
+ */
62
+ export function memberFromLabel(name, roomTitle) {
63
+ if (name === undefined)
64
+ return undefined;
65
+ const label = /@\[((?:\\.|[^\\\]])*)\]\(dsh-session:/u.exec(name)?.[1]?.replace(/\\(.)/gu, '$1') ?? name.trim();
66
+ const suffix = `(${roomTitle})`;
67
+ if (!label.endsWith(suffix) || label === suffix)
68
+ return undefined;
69
+ return label.slice(0, -suffix.length).replace(/^@/u, '').trim() || undefined;
70
+ }
71
+ /** The session id inside a `dsh-session:` payload (base64url JSON string), if well-formed. */
72
+ function decodeSessionUri(payload) {
73
+ try {
74
+ const parsed = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));
75
+ return typeof parsed === 'string' ? parsed : undefined;
76
+ }
77
+ catch {
78
+ return undefined;
79
+ }
80
+ }
81
+ /**
82
+ * The help threads a helper's session has received (newest last), from the
83
+ * help sources in its own log.
84
+ * @param events - the helper's session events.
85
+ * @returns one entry per thread.
86
+ */
87
+ export function receivedHelps(events) {
88
+ const seen = new Map();
89
+ for (const event of events) {
90
+ if (event.type !== 'user/message')
91
+ continue;
92
+ const source = readHelpSource(event.data.source);
93
+ if (source !== undefined && !seen.has(source.help))
94
+ seen.set(source.help, source);
95
+ }
96
+ return [...seen.values()];
97
+ }
98
+ /**
99
+ * The answer a helper's turn ended with: the last assistant text after the
100
+ * help message was claimed and before the next message from anyone else.
101
+ * @param events - the helper's session events.
102
+ * @param messageId - the help message.
103
+ * @returns the text, '' when the turn produced none (or never ran).
104
+ */
105
+ export function turnAnswer(events, messageId) {
106
+ const start = events.findIndex(event => event.type === 'user/message' && String(event.data.id) === messageId);
107
+ if (start < 0)
108
+ return '';
109
+ let answer = '';
110
+ for (const event of events.slice(start + 1)) {
111
+ if (event.type === 'user/message' && readHelpSource(event.data.source) === undefined && event.data.source.kind === 'user')
112
+ break;
113
+ if (event.type === 'assistant/message') {
114
+ const text = event.data.message.content.flatMap(block => block.type === 'text' ? [block.text] : []).join('\n').trim();
115
+ if (text !== '')
116
+ answer = text;
117
+ }
118
+ }
119
+ return answer;
120
+ }
121
+ /** Whether the helper's log holds the help message (it was claimed from the queue). */
122
+ export function claimed(events, messageId) {
123
+ return events.some(event => event.type === 'user/message' && String(event.data.id) === messageId);
124
+ }
125
+ /** The request as the helper's model reads it. */
126
+ export function requestPrompt(help, roomTitle) {
127
+ return [
128
+ `[Help request from ${help.fromName} in the room "${roomTitle}" · help ${help.id}]`,
129
+ help.text,
130
+ '',
131
+ `${help.fromName} works in another session and is asking you for help. Work on it here as usual.`
132
+ + ' When you are done, call room_help_reply with your final answer and a short handoff (two or three lines: what you'
133
+ + ' found or changed, where, what they should do next) — the room hands both to them. If you need something from them'
134
+ + ' first, call room_help_ask; their answer arrives as a new message. If you change code for them, do it on a git'
135
+ + ' worktree branch so their checkout is untouched.',
136
+ ].join('\n');
137
+ }
138
+ /** The asker writing again on a thread, as the helper reads it. */
139
+ export function messagePrompt(help, roomTitle, text) {
140
+ return [
141
+ `[${help.fromName} in the room "${roomTitle}" · help ${help.id}]`,
142
+ text,
143
+ '',
144
+ 'Continue the help. Call room_help_reply when you are done, or room_help_ask if you need more from them.',
145
+ ].join('\n');
146
+ }
147
+ /** A helper's message as the asking member reads it. */
148
+ export function askerPrompt(help, message) {
149
+ if (message.kind === 'question') {
150
+ return [
151
+ `[Question from "${help.target.title}" about your help request · help ${help.id}]`,
152
+ message.text,
153
+ '',
154
+ `Answer with room_help (help: "${help.id}"). Answer it yourself from what you know; ask the human only if you cannot.`,
155
+ ].join('\n');
156
+ }
157
+ return [
158
+ `[Help reply from "${help.target.title}" · help ${help.id}]`,
159
+ message.text,
160
+ ...message.handoff === undefined ? [] : ['', `Handoff: ${message.handoff}`],
161
+ '',
162
+ 'Carry on with this in the room. To ask them more, call room_help again with this help id.',
163
+ ].join('\n');
164
+ }
165
+ /** Tag a helper tool with this package as its origin (AGENTS.md § Tool origin tagging). */
166
+ const tagged = (def) => Object.assign(def, { [Symbol.for('dsh.tool.origin')]: { channel: 'plugin', owner: PACKAGE_NAME } });
167
+ /**
168
+ * The two helper tools, registered on one helper agent only.
169
+ * @param backend - the room service.
170
+ * @returns the tool definitions.
171
+ */
172
+ export function helperTools(backend) {
173
+ const helpParam = {
174
+ type: 'string',
175
+ description: 'The help id from the request (e.g. the id after "help" in its first line). Omit when you were asked once.',
176
+ };
177
+ return [
178
+ tagged(defineTool({
179
+ name: 'room_help_reply',
180
+ description: 'Answer a help request another session sent you: your final answer plus a short handoff. The room hands both to '
181
+ + 'whoever asked. Call it once you are done (you can reply again later if they ask more).',
182
+ parameters: {
183
+ help: helpParam,
184
+ text: { type: 'string', required: true, description: 'Your final answer: what you found, what you did, the result.' },
185
+ handoff: { type: 'string', required: true, description: 'Two or three lines for them: what changed, where (branch, files), what to do next.' },
186
+ },
187
+ output: { schema: { type: 'object', additionalProperties: false, properties: { text: { type: 'string', required: true } } }, render: (_args, value) => [{ type: 'text', text: value.text }] },
188
+ isConcurrencySafe: () => true,
189
+ async execute(args, exec) {
190
+ if (exec.agent === undefined)
191
+ return { text: 'room_help_reply requires a calling agent.' };
192
+ return { text: await backend.helperMessage(exec.agent, { ...args.help === undefined ? {} : { help: args.help }, kind: 'reply', text: args.text, handoff: args.handoff }) };
193
+ },
194
+ })),
195
+ tagged(defineTool({
196
+ name: 'room_help_ask',
197
+ description: 'Ask whoever sent you a help request a question before you can finish it. Their answer arrives as a new message; '
198
+ + 'end your turn after asking.',
199
+ parameters: {
200
+ help: helpParam,
201
+ question: { type: 'string', required: true, description: 'What you need to know.' },
202
+ },
203
+ output: { schema: { type: 'object', additionalProperties: false, properties: { text: { type: 'string', required: true } } }, render: (_args, value) => [{ type: 'text', text: value.text }] },
204
+ isConcurrencySafe: () => true,
205
+ async execute(args, exec) {
206
+ if (exec.agent === undefined)
207
+ return { text: 'room_help_ask requires a calling agent.' };
208
+ return { text: await backend.helperMessage(exec.agent, { ...args.help === undefined ? {} : { help: args.help }, kind: 'question', text: args.question }) };
209
+ },
210
+ })),
211
+ ];
212
+ }
213
+ /** Build a help message for the helper's session. */
214
+ export function helpMessage(text, source) {
215
+ return createUserMessage({ content: [{ type: 'text', text }], source: helpSource(source) });
216
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Cross-session help threads, folded from a room's log (pure: the room
3
+ * state replay and the client both read it). See help.ts for the flow.
4
+ * @module @khorsheed/dsh-room/helps
5
+ */
6
+ import type { SessionEvent } from '@deepseek-ai/dsh-session/types';
7
+ import type { RoomHelp, RoomLinkedSession } from './types.ts';
8
+ /**
9
+ * Fold a room's help threads from its log.
10
+ * @param events - the room's events.
11
+ * @returns the threads, oldest first.
12
+ */
13
+ export declare function replayHelps(events: readonly SessionEvent[]): RoomHelp[];
14
+ /**
15
+ * The outside sessions this room keeps on its member list (「加入房间成员」),
16
+ * and the sessions whose join hint the human dismissed.
17
+ * @param events - the room's events.
18
+ * @returns linked sessions (oldest first) and dismissed hints.
19
+ */
20
+ export declare function replayLinks(events: readonly SessionEvent[]): {
21
+ readonly linked: RoomLinkedSession[];
22
+ readonly nudgesDismissed: string[];
23
+ };
24
+ /** Asks of one session after which its reply row suggests 加入房间成员. */
25
+ export declare const NUDGE_AFTER = 3;
26
+ //# sourceMappingURL=helps.d.ts.map
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Fold a room's help threads from its log.
3
+ * @param events - the room's events.
4
+ * @returns the threads, oldest first.
5
+ */
6
+ export function replayHelps(events) {
7
+ const helps = new Map();
8
+ for (const event of events) {
9
+ if (event.type === 'room/help') {
10
+ helps.set(event.data.id, { ...event.data, state: 'queued', since: event.time, messages: [], time: event.time });
11
+ }
12
+ else if (event.type === 'room/help-message') {
13
+ const help = helps.get(event.data.help);
14
+ if (help !== undefined)
15
+ helps.set(help.id, { ...help, messages: [...help.messages, { ...event.data, time: event.time }] });
16
+ }
17
+ else if (event.type === 'room/help-state') {
18
+ const help = helps.get(event.data.help);
19
+ if (help === undefined)
20
+ continue;
21
+ const { error: _old, ...rest } = help;
22
+ helps.set(help.id, { ...rest, state: event.data.state, since: help.state === event.data.state ? help.since : event.time, ...event.data.error === undefined ? {} : { error: event.data.error } });
23
+ }
24
+ }
25
+ return [...helps.values()];
26
+ }
27
+ /**
28
+ * The outside sessions this room keeps on its member list (「加入房间成员」),
29
+ * and the sessions whose join hint the human dismissed.
30
+ * @param events - the room's events.
31
+ * @returns linked sessions (oldest first) and dismissed hints.
32
+ */
33
+ export function replayLinks(events) {
34
+ const linked = new Map();
35
+ const dismissed = new Set();
36
+ for (const event of events) {
37
+ if (event.type === 'room/help-link')
38
+ linked.set(event.data.sessionId, { sessionId: event.data.sessionId, title: event.data.title, time: event.time });
39
+ else if (event.type === 'room/help-unlink')
40
+ linked.delete(event.data.sessionId);
41
+ else if (event.type === 'room/help-nudge-dismissed')
42
+ dismissed.add(event.data.sessionId);
43
+ }
44
+ return { linked: [...linked.values()], nudgesDismissed: [...dismissed] };
45
+ }
46
+ /** Asks of one session after which its reply row suggests 加入房间成员. */
47
+ export const NUDGE_AFTER = 3;