@visorcraft/idlehands 1.3.9 → 1.3.11

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 (47) hide show
  1. package/dist/agent/formatting.js +27 -3
  2. package/dist/agent/formatting.js.map +1 -1
  3. package/dist/agent/tool-loop-detection.js +38 -13
  4. package/dist/agent/tool-loop-detection.js.map +1 -1
  5. package/dist/agent/tool-loop-guard.js +12 -5
  6. package/dist/agent/tool-loop-guard.js.map +1 -1
  7. package/dist/agent.js +12 -11
  8. package/dist/agent.js.map +1 -1
  9. package/dist/anton/controller.js +62 -20
  10. package/dist/anton/controller.js.map +1 -1
  11. package/dist/anton/prompt.js +7 -6
  12. package/dist/anton/prompt.js.map +1 -1
  13. package/dist/anton/reporter.js +22 -2
  14. package/dist/anton/reporter.js.map +1 -1
  15. package/dist/anton/session.js +4 -1
  16. package/dist/anton/session.js.map +1 -1
  17. package/dist/anton/verifier.js +152 -5
  18. package/dist/anton/verifier.js.map +1 -1
  19. package/dist/bot/auto-continue.js +19 -4
  20. package/dist/bot/auto-continue.js.map +1 -1
  21. package/dist/bot/command-logic.js +77 -26
  22. package/dist/bot/command-logic.js.map +1 -1
  23. package/dist/bot/commands.js +6 -3
  24. package/dist/bot/commands.js.map +1 -1
  25. package/dist/bot/discord.js +3 -1
  26. package/dist/bot/discord.js.map +1 -1
  27. package/dist/bot/session-manager.js +5 -0
  28. package/dist/bot/session-manager.js.map +1 -1
  29. package/dist/bot/telegram.js +1 -1
  30. package/dist/bot/ux/actions.js +161 -0
  31. package/dist/bot/ux/actions.js.map +1 -0
  32. package/dist/bot/ux/events.js +5 -2
  33. package/dist/bot/ux/events.js.map +1 -1
  34. package/dist/bot/ux/progress-throttle.js +241 -0
  35. package/dist/bot/ux/progress-throttle.js.map +1 -0
  36. package/dist/bot/ux/renderer.js +391 -0
  37. package/dist/bot/ux/renderer.js.map +1 -0
  38. package/dist/bot/ux/state.js +157 -0
  39. package/dist/bot/ux/state.js.map +1 -0
  40. package/dist/cli/commands/anton.js +2 -2
  41. package/dist/cli/commands/anton.js.map +1 -1
  42. package/dist/config.js +16 -3
  43. package/dist/config.js.map +1 -1
  44. package/dist/git.js +9 -0
  45. package/dist/git.js.map +1 -1
  46. package/dist/tui/controller.js +1 -1
  47. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/bot/ux/events.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/bot/ux/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Unified rate-limiting and heartbeat behavior for IdleHands UX.
3
+ *
4
+ * This module provides shared throttling logic for progress updates and
5
+ * heartbeat signals across all bot platforms (Telegram, Discord, TUI, etc.).
6
+ * It ensures consistent behavior while avoiding message spam and respecting
7
+ * platform-specific constraints.
8
+ */
9
+ // ---------------------------------------------------------------------------
10
+ // Throttle Configuration
11
+ // ---------------------------------------------------------------------------
12
+ /**
13
+ * Default interval for progress updates (milliseconds).
14
+ * Progress messages should not be sent more frequently than this.
15
+ */
16
+ export const DEFAULT_PROGRESS_INTERVAL_MS = 3000;
17
+ /**
18
+ * Default interval for heartbeat signals (milliseconds).
19
+ * Heartbeat keeps "typing..." indicators alive on platforms like Telegram.
20
+ */
21
+ export const DEFAULT_HEARTBEAT_INTERVAL_MS = 4000;
22
+ /**
23
+ * Maximum number of progress updates without user activity before warning.
24
+ */
25
+ export const MAX_PROGRESS_SILENT_INTERVALS = 3;
26
+ // ---------------------------------------------------------------------------
27
+ // Throttle Management
28
+ // ---------------------------------------------------------------------------
29
+ /**
30
+ * Create a new throttle state for a session.
31
+ */
32
+ export function createProgressThrottleState(config) {
33
+ const now = config?.now?.() ?? Date.now();
34
+ return {
35
+ lastProgressAt: now,
36
+ lastHeartbeatAt: now,
37
+ lastUserActivityAt: now,
38
+ silentIntervals: 0,
39
+ isThrottled: false,
40
+ heartbeatRequired: false,
41
+ };
42
+ }
43
+ /**
44
+ * Check if a progress update should be allowed based on throttle state.
45
+ */
46
+ export function checkProgressThrottle(state, config = {}) {
47
+ const now = config.now?.() ?? Date.now();
48
+ const progressInterval = config.progressIntervalMs ?? DEFAULT_PROGRESS_INTERVAL_MS;
49
+ const heartbeatInterval = config.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
50
+ const _maxSilent = config.maxSilentIntervals ?? MAX_PROGRESS_SILENT_INTERVALS;
51
+ // If user is active, allow progress updates
52
+ const timeSinceUserActivity = now - state.lastUserActivityAt;
53
+ if (timeSinceUserActivity < heartbeatInterval) {
54
+ return {
55
+ allow: true,
56
+ reason: 'user_active',
57
+ };
58
+ }
59
+ // Check if we need to send a heartbeat
60
+ const timeSinceHeartbeat = now - state.lastHeartbeatAt;
61
+ if (timeSinceHeartbeat >= heartbeatInterval) {
62
+ return {
63
+ allow: true,
64
+ reason: 'heartbeat_required',
65
+ };
66
+ }
67
+ // Check progress throttle
68
+ const timeSinceProgress = now - state.lastProgressAt;
69
+ if (timeSinceProgress >= progressInterval) {
70
+ return {
71
+ allow: true,
72
+ reason: 'allowed',
73
+ };
74
+ }
75
+ // Throttled
76
+ const retryAfter = progressInterval - timeSinceProgress;
77
+ return {
78
+ allow: false,
79
+ reason: 'throttled',
80
+ retryAfter,
81
+ };
82
+ }
83
+ /**
84
+ * Check if a heartbeat signal should be sent.
85
+ */
86
+ export function checkHeartbeatRequired(state, config = {}) {
87
+ const now = config.now?.() ?? Date.now();
88
+ const heartbeatInterval = config.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
89
+ const timeSinceHeartbeat = now - state.lastHeartbeatAt;
90
+ return timeSinceHeartbeat >= heartbeatInterval;
91
+ }
92
+ /**
93
+ * Update throttle state after a progress update.
94
+ */
95
+ export function recordProgressUpdate(state, config = {}) {
96
+ const now = config.now?.() ?? Date.now();
97
+ state.lastProgressAt = now;
98
+ state.silentIntervals = 0;
99
+ state.isThrottled = false;
100
+ }
101
+ /**
102
+ * Update throttle state after sending a heartbeat signal.
103
+ */
104
+ export function recordHeartbeat(state, config = {}) {
105
+ const now = config.now?.() ?? Date.now();
106
+ state.lastHeartbeatAt = now;
107
+ state.heartbeatRequired = false;
108
+ }
109
+ /**
110
+ * Update throttle state when user activity is detected.
111
+ */
112
+ export function recordUserActivity(state, config = {}) {
113
+ const now = config.now?.() ?? Date.now();
114
+ state.lastUserActivityAt = now;
115
+ state.silentIntervals = 0;
116
+ state.isThrottled = false;
117
+ }
118
+ /**
119
+ * Increment silent interval counter (called periodically).
120
+ */
121
+ export function incrementSilentInterval(state, config = {}) {
122
+ const now = config.now?.() ?? Date.now();
123
+ const heartbeatInterval = config.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
124
+ const maxSilent = config.maxSilentIntervals ?? MAX_PROGRESS_SILENT_INTERVALS;
125
+ // Only count silent intervals when user is not active
126
+ const timeSinceUserActivity = now - state.lastUserActivityAt;
127
+ if (timeSinceUserActivity >= heartbeatInterval) {
128
+ state.silentIntervals += 1;
129
+ if (state.silentIntervals >= maxSilent) {
130
+ state.isThrottled = true;
131
+ }
132
+ }
133
+ }
134
+ /**
135
+ * Reset throttle state for a new session.
136
+ */
137
+ export function resetThrottleState(state, config = {}) {
138
+ const now = config.now?.() ?? Date.now();
139
+ state.lastProgressAt = now;
140
+ state.lastHeartbeatAt = now;
141
+ state.lastUserActivityAt = now;
142
+ state.silentIntervals = 0;
143
+ state.isThrottled = false;
144
+ state.heartbeatRequired = false;
145
+ }
146
+ // ---------------------------------------------------------------------------
147
+ // Throttled Progress Updater
148
+ // ---------------------------------------------------------------------------
149
+ /**
150
+ * Helper class for managing throttled progress updates.
151
+ */
152
+ export class ThrottledProgressUpdater {
153
+ state;
154
+ config;
155
+ heartbeatTimer = null;
156
+ silentIntervalTimer = null;
157
+ constructor(config = {}) {
158
+ this.config = config;
159
+ this.state = createProgressThrottleState(config);
160
+ }
161
+ /**
162
+ * Start the throttling timers.
163
+ */
164
+ start() {
165
+ const heartbeatInterval = this.config.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
166
+ const progressInterval = this.config.progressIntervalMs ?? DEFAULT_PROGRESS_INTERVAL_MS;
167
+ // Heartbeat timer - keeps "typing..." indicators alive
168
+ this.heartbeatTimer = setInterval(() => {
169
+ if (checkHeartbeatRequired(this.state, this.config)) {
170
+ this.state.heartbeatRequired = true;
171
+ }
172
+ }, heartbeatInterval);
173
+ // Silent interval counter - tracks inactivity
174
+ this.silentIntervalTimer = setInterval(() => {
175
+ incrementSilentInterval(this.state, this.config);
176
+ }, progressInterval);
177
+ }
178
+ /**
179
+ * Stop all timers.
180
+ */
181
+ stop() {
182
+ if (this.heartbeatTimer) {
183
+ clearInterval(this.heartbeatTimer);
184
+ this.heartbeatTimer = null;
185
+ }
186
+ if (this.silentIntervalTimer) {
187
+ clearInterval(this.silentIntervalTimer);
188
+ this.silentIntervalTimer = null;
189
+ }
190
+ }
191
+ /**
192
+ * Check if a progress update should be allowed.
193
+ */
194
+ checkProgress() {
195
+ return checkProgressThrottle(this.state, this.config);
196
+ }
197
+ /**
198
+ * Check if a heartbeat signal is required.
199
+ */
200
+ checkHeartbeat() {
201
+ return checkHeartbeatRequired(this.state, this.config);
202
+ }
203
+ /**
204
+ * Record a progress update.
205
+ */
206
+ recordProgress() {
207
+ recordProgressUpdate(this.state, this.config);
208
+ }
209
+ /**
210
+ * Record a heartbeat signal.
211
+ */
212
+ recordHeartbeat() {
213
+ recordHeartbeat(this.state, this.config);
214
+ }
215
+ /**
216
+ * Record user activity.
217
+ */
218
+ recordUserActivity() {
219
+ recordUserActivity(this.state, this.config);
220
+ }
221
+ /**
222
+ * Get current throttle state.
223
+ */
224
+ getState() {
225
+ return { ...this.state };
226
+ }
227
+ /**
228
+ * Reset state for a new session.
229
+ */
230
+ reset() {
231
+ resetThrottleState(this.state, this.config);
232
+ }
233
+ }
234
+ // ---------------------------------------------------------------------------
235
+ // Configuration constants (also exported at module level)
236
+ // ---------------------------------------------------------------------------
237
+ // ---------------------------------------------------------------------------
238
+ // DEFAULT_PROGRESS_INTERVAL_MS = 3000
239
+ // DEFAULT_HEARTBEAT_INTERVAL_MS = 4000
240
+ // MAX_PROGRESS_SILENT_INTERVALS = 3
241
+ //# sourceMappingURL=progress-throttle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-throttle.js","sourceRoot":"","sources":["../../../src/bot/ux/progress-throttle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,391 @@
1
+ /**
2
+ * Platform-agnostic UX event renderer.
3
+ *
4
+ * Converts the canonical event model into text blocks suitable for
5
+ * Discord, Telegram, and other platforms without duplicating formatting logic.
6
+ */
7
+ // ---------------------------------------------------------------------------
8
+ // Renderer Functions
9
+ // ---------------------------------------------------------------------------
10
+ /**
11
+ * Render an ACK event into text blocks.
12
+ */
13
+ export function renderACK(event) {
14
+ const blocks = [];
15
+ // Main message
16
+ blocks.push({
17
+ type: 'message',
18
+ category: 'ACK',
19
+ content: {
20
+ type: 'text',
21
+ content: event.message,
22
+ format: { bold: true },
23
+ },
24
+ format: {
25
+ prefix: '✅',
26
+ icon: 'ack',
27
+ },
28
+ });
29
+ // Optional metadata
30
+ if (event.estimatedDurationSec !== undefined) {
31
+ blocks.push({
32
+ type: 'section',
33
+ content: {
34
+ type: 'text',
35
+ content: `⏱️ Estimated duration: ${event.estimatedDurationSec}s`,
36
+ },
37
+ });
38
+ }
39
+ if (event.model !== undefined) {
40
+ blocks.push({
41
+ type: 'section',
42
+ content: {
43
+ type: 'text',
44
+ content: `🤖 Model: ${event.model}`,
45
+ },
46
+ });
47
+ }
48
+ return blocks;
49
+ }
50
+ /**
51
+ * Render a PROGRESS event into text blocks.
52
+ */
53
+ export function renderPROGRESS(event) {
54
+ const blocks = [];
55
+ // Progress bar if progress is available
56
+ if (event.progress !== undefined) {
57
+ blocks.push({
58
+ type: 'progress',
59
+ progress: event.progress,
60
+ message: event.message,
61
+ phase: event.phase,
62
+ });
63
+ }
64
+ // Status message
65
+ blocks.push({
66
+ type: 'message',
67
+ category: 'PROGRESS',
68
+ content: {
69
+ type: 'text',
70
+ content: event.message,
71
+ },
72
+ format: {
73
+ prefix: '⏳',
74
+ icon: 'progress',
75
+ },
76
+ });
77
+ // Optional metadata
78
+ if (event.phase !== undefined) {
79
+ blocks.push({
80
+ type: 'section',
81
+ title: 'Phase',
82
+ content: {
83
+ type: 'text',
84
+ content: event.phase,
85
+ format: { italic: true },
86
+ },
87
+ });
88
+ }
89
+ if (event.toolName !== undefined) {
90
+ blocks.push({
91
+ type: 'section',
92
+ title: 'Tool',
93
+ content: {
94
+ type: 'text',
95
+ content: event.toolName,
96
+ format: { monospace: true },
97
+ },
98
+ });
99
+ }
100
+ if (event.toolId !== undefined) {
101
+ blocks.push({
102
+ type: 'section',
103
+ title: 'Tool ID',
104
+ content: {
105
+ type: 'text',
106
+ content: event.toolId,
107
+ format: { monospace: true },
108
+ },
109
+ });
110
+ }
111
+ return blocks;
112
+ }
113
+ /**
114
+ * Render a WARNING event into text blocks.
115
+ */
116
+ export function renderWARNING(event) {
117
+ const blocks = [];
118
+ blocks.push({
119
+ type: 'message',
120
+ category: 'WARNING',
121
+ content: {
122
+ type: 'text',
123
+ content: event.message,
124
+ format: { italic: true },
125
+ },
126
+ format: {
127
+ prefix: '⚠️',
128
+ icon: 'warning',
129
+ color: 'yellow',
130
+ },
131
+ });
132
+ if (event.code !== undefined) {
133
+ blocks.push({
134
+ type: 'section',
135
+ title: 'Code',
136
+ content: {
137
+ type: 'text',
138
+ content: event.code,
139
+ format: { monospace: true },
140
+ },
141
+ });
142
+ }
143
+ if (event.hint !== undefined) {
144
+ blocks.push({
145
+ type: 'section',
146
+ title: 'Hint',
147
+ content: {
148
+ type: 'text',
149
+ content: event.hint,
150
+ },
151
+ });
152
+ }
153
+ return blocks;
154
+ }
155
+ /**
156
+ * Render an ERROR event into text blocks.
157
+ */
158
+ export function renderERROR(event) {
159
+ const blocks = [];
160
+ blocks.push({
161
+ type: 'message',
162
+ category: 'ERROR',
163
+ content: {
164
+ type: 'text',
165
+ content: event.message,
166
+ format: { bold: true, color: 'red' },
167
+ },
168
+ format: {
169
+ prefix: '❌',
170
+ icon: 'error',
171
+ color: 'red',
172
+ },
173
+ });
174
+ if (event.code !== undefined) {
175
+ blocks.push({
176
+ type: 'section',
177
+ title: 'Code',
178
+ content: {
179
+ type: 'text',
180
+ content: event.code,
181
+ format: { monospace: true },
182
+ },
183
+ });
184
+ }
185
+ if (event.details !== undefined) {
186
+ blocks.push({
187
+ type: 'code',
188
+ content: event.details,
189
+ });
190
+ }
191
+ if (event.retryable === true) {
192
+ blocks.push({
193
+ type: 'section',
194
+ content: {
195
+ type: 'text',
196
+ content: 'This error is retryable.',
197
+ format: { italic: true },
198
+ },
199
+ });
200
+ }
201
+ if (event.guidance !== undefined) {
202
+ blocks.push({
203
+ type: 'section',
204
+ title: 'Guidance',
205
+ content: {
206
+ type: 'text',
207
+ content: event.guidance,
208
+ },
209
+ });
210
+ }
211
+ return blocks;
212
+ }
213
+ /**
214
+ * Render a RESULT event into text blocks.
215
+ */
216
+ export function renderRESULT(event) {
217
+ const blocks = [];
218
+ blocks.push({
219
+ type: 'message',
220
+ category: 'RESULT',
221
+ content: {
222
+ type: 'text',
223
+ content: event.summary,
224
+ format: { bold: true },
225
+ },
226
+ format: {
227
+ prefix: event.success !== false ? '✅' : '❌',
228
+ icon: 'result',
229
+ color: event.success !== false ? 'green' : 'red',
230
+ },
231
+ });
232
+ if (event.data !== undefined) {
233
+ blocks.push({
234
+ type: 'code',
235
+ content: JSON.stringify(event.data, null, 2),
236
+ });
237
+ }
238
+ if (event.stats !== undefined) {
239
+ const statsLines = [];
240
+ if (event.stats.durationMs !== undefined) {
241
+ statsLines.push(`Duration: ${event.stats.durationMs}ms`);
242
+ }
243
+ if (event.stats.tokensUsed !== undefined) {
244
+ statsLines.push(`Tokens: ${event.stats.tokensUsed}`);
245
+ }
246
+ if (event.stats.toolsCalled !== undefined) {
247
+ statsLines.push(`Tools: ${event.stats.toolsCalled}`);
248
+ }
249
+ if (statsLines.length > 0) {
250
+ blocks.push({
251
+ type: 'section',
252
+ title: 'Stats',
253
+ content: {
254
+ type: 'text',
255
+ content: statsLines.join(', '),
256
+ },
257
+ });
258
+ }
259
+ }
260
+ return blocks;
261
+ }
262
+ /**
263
+ * Render an ACTIONS event into text blocks.
264
+ */
265
+ export function renderACTIONS(event) {
266
+ const blocks = [];
267
+ if (event.message !== undefined) {
268
+ blocks.push({
269
+ type: 'message',
270
+ category: 'ACTIONS',
271
+ content: {
272
+ type: 'text',
273
+ content: event.message,
274
+ },
275
+ format: {
276
+ prefix: '🔧',
277
+ icon: 'actions',
278
+ },
279
+ });
280
+ }
281
+ blocks.push({
282
+ type: 'actions',
283
+ actions: event.actions,
284
+ message: event.message,
285
+ });
286
+ return blocks;
287
+ }
288
+ // ---------------------------------------------------------------------------
289
+ // Main Renderer
290
+ // ---------------------------------------------------------------------------
291
+ /**
292
+ * Render any UX event into canonical text blocks.
293
+ */
294
+ export function renderEvent(event) {
295
+ switch (event.category) {
296
+ case 'ACK':
297
+ return renderACK(event);
298
+ case 'PROGRESS':
299
+ return renderPROGRESS(event);
300
+ case 'WARNING':
301
+ return renderWARNING(event);
302
+ case 'ERROR':
303
+ return renderERROR(event);
304
+ case 'RESULT':
305
+ return renderRESULT(event);
306
+ case 'ACTIONS':
307
+ return renderACTIONS(event);
308
+ default:
309
+ // Fallback for unknown categories - this should never happen
310
+ return [
311
+ {
312
+ type: 'message',
313
+ category: 'ACK',
314
+ content: {
315
+ type: 'text',
316
+ content: `Unknown event category: ${event.category}`,
317
+ format: { color: 'orange' },
318
+ },
319
+ },
320
+ ];
321
+ }
322
+ }
323
+ // ---------------------------------------------------------------------------
324
+ // Utility Functions
325
+ // ---------------------------------------------------------------------------
326
+ /**
327
+ * Format a progress bar string.
328
+ */
329
+ export function formatProgressBar(progress, width = 20) {
330
+ const filled = Math.round(progress * width);
331
+ const empty = width - filled;
332
+ return `[${'█'.repeat(filled)}${'░'.repeat(empty)}] ${Math.round(progress * 100)}%`;
333
+ }
334
+ /**
335
+ * Format a timestamp into a human-readable string.
336
+ */
337
+ export function formatTimestamp(timestamp) {
338
+ const date = new Date(timestamp);
339
+ return date.toLocaleString();
340
+ }
341
+ /**
342
+ * Format a duration in milliseconds into a human-readable string.
343
+ */
344
+ export function formatDuration(ms) {
345
+ if (ms < 1000)
346
+ return `${ms}ms`;
347
+ if (ms < 60000)
348
+ return `${(ms / 1000).toFixed(1)}s`;
349
+ if (ms < 3600000)
350
+ return `${(ms / 60000).toFixed(1)}m`;
351
+ return `${(ms / 3600000).toFixed(1)}h`;
352
+ }
353
+ /**
354
+ * Extract plain text from a block (for platforms that don't support rich formatting).
355
+ */
356
+ export function blockToPlainText(block) {
357
+ switch (block.type) {
358
+ case 'text':
359
+ return block.content;
360
+ case 'section':
361
+ const content = Array.isArray(block.content)
362
+ ? block.content.map(blockToPlainText).join('\n')
363
+ : blockToPlainText(block.content);
364
+ return block.title ? `${block.title}:\n${content}` : content;
365
+ case 'message':
366
+ const msgContent = Array.isArray(block.content)
367
+ ? block.content.map(blockToPlainText).join('\n')
368
+ : blockToPlainText(block.content);
369
+ return msgContent;
370
+ case 'actions':
371
+ return block.actions
372
+ .map((a) => `${a.label}${a.payload ? `: ${JSON.stringify(a.payload)}` : ''}`)
373
+ .filter(Boolean)
374
+ .join('\n');
375
+ case 'progress':
376
+ return `${block.message || ''} ${formatProgressBar(block.progress)}`;
377
+ case 'divider':
378
+ return '---';
379
+ case 'code':
380
+ return `\`\`\`\n${block.content}\n\`\`\``;
381
+ default:
382
+ return '';
383
+ }
384
+ }
385
+ /**
386
+ * Convert all blocks to plain text.
387
+ */
388
+ export function blocksToPlainText(blocks) {
389
+ return blocks.map(blockToPlainText).join('\n\n');
390
+ }
391
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../../src/bot/ux/renderer.ts"],"names":[],"mappings":"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"}