@a1hvdy/cc-openclaw 0.24.0 → 0.25.1

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 (96) hide show
  1. package/dist/src/channels/telegram-mirror/burst-accumulator.d.ts +96 -0
  2. package/dist/src/channels/telegram-mirror/burst-accumulator.js +130 -0
  3. package/dist/src/channels/telegram-mirror/burst-accumulator.js.map +1 -0
  4. package/dist/src/channels/telegram-mirror/callback-mapping.d.ts +61 -0
  5. package/dist/src/channels/telegram-mirror/callback-mapping.js +99 -0
  6. package/dist/src/channels/telegram-mirror/callback-mapping.js.map +1 -0
  7. package/dist/src/channels/telegram-mirror/card-renderer.d.ts +74 -0
  8. package/dist/src/channels/telegram-mirror/card-renderer.js +131 -0
  9. package/dist/src/channels/telegram-mirror/card-renderer.js.map +1 -0
  10. package/dist/src/channels/telegram-mirror/commands.d.ts +142 -0
  11. package/dist/src/channels/telegram-mirror/commands.js +389 -0
  12. package/dist/src/channels/telegram-mirror/commands.js.map +1 -0
  13. package/dist/src/channels/telegram-mirror/compose-buffer.d.ts +71 -0
  14. package/dist/src/channels/telegram-mirror/compose-buffer.js +110 -0
  15. package/dist/src/channels/telegram-mirror/compose-buffer.js.map +1 -0
  16. package/dist/src/channels/telegram-mirror/cost-views.d.ts +58 -0
  17. package/dist/src/channels/telegram-mirror/cost-views.js +121 -0
  18. package/dist/src/channels/telegram-mirror/cost-views.js.map +1 -0
  19. package/dist/src/channels/telegram-mirror/failure/callback-data-overflow.d.ts +21 -0
  20. package/dist/src/channels/telegram-mirror/failure/callback-data-overflow.js +30 -0
  21. package/dist/src/channels/telegram-mirror/failure/callback-data-overflow.js.map +1 -0
  22. package/dist/src/channels/telegram-mirror/failure/gateway-down.d.ts +15 -0
  23. package/dist/src/channels/telegram-mirror/failure/gateway-down.js +27 -0
  24. package/dist/src/channels/telegram-mirror/failure/gateway-down.js.map +1 -0
  25. package/dist/src/channels/telegram-mirror/failure/in-flight-conflict.d.ts +15 -0
  26. package/dist/src/channels/telegram-mirror/failure/in-flight-conflict.js +27 -0
  27. package/dist/src/channels/telegram-mirror/failure/in-flight-conflict.js.map +1 -0
  28. package/dist/src/channels/telegram-mirror/failure/index.d.ts +23 -0
  29. package/dist/src/channels/telegram-mirror/failure/index.js +35 -0
  30. package/dist/src/channels/telegram-mirror/failure/index.js.map +1 -0
  31. package/dist/src/channels/telegram-mirror/failure/model-5xx.d.ts +16 -0
  32. package/dist/src/channels/telegram-mirror/failure/model-5xx.js +24 -0
  33. package/dist/src/channels/telegram-mirror/failure/model-5xx.js.map +1 -0
  34. package/dist/src/channels/telegram-mirror/failure/network-blip.d.ts +17 -0
  35. package/dist/src/channels/telegram-mirror/failure/network-blip.js +25 -0
  36. package/dist/src/channels/telegram-mirror/failure/network-blip.js.map +1 -0
  37. package/dist/src/channels/telegram-mirror/failure/pool-exhausted-fallback.d.ts +15 -0
  38. package/dist/src/channels/telegram-mirror/failure/pool-exhausted-fallback.js +24 -0
  39. package/dist/src/channels/telegram-mirror/failure/pool-exhausted-fallback.js.map +1 -0
  40. package/dist/src/channels/telegram-mirror/failure/rate-limit.d.ts +16 -0
  41. package/dist/src/channels/telegram-mirror/failure/rate-limit.js +26 -0
  42. package/dist/src/channels/telegram-mirror/failure/rate-limit.js.map +1 -0
  43. package/dist/src/channels/telegram-mirror/failure/returning-after-24h.d.ts +14 -0
  44. package/dist/src/channels/telegram-mirror/failure/returning-after-24h.js +33 -0
  45. package/dist/src/channels/telegram-mirror/failure/returning-after-24h.js.map +1 -0
  46. package/dist/src/channels/telegram-mirror/failure/types.d.ts +30 -0
  47. package/dist/src/channels/telegram-mirror/failure/types.js +9 -0
  48. package/dist/src/channels/telegram-mirror/failure/types.js.map +1 -0
  49. package/dist/src/channels/telegram-mirror/inbound-handler.d.ts +52 -0
  50. package/dist/src/channels/telegram-mirror/inbound-handler.js +115 -0
  51. package/dist/src/channels/telegram-mirror/inbound-handler.js.map +1 -0
  52. package/dist/src/channels/telegram-mirror/index.d.ts +30 -0
  53. package/dist/src/channels/telegram-mirror/index.js +49 -0
  54. package/dist/src/channels/telegram-mirror/index.js.map +1 -0
  55. package/dist/src/channels/telegram-mirror/plan-attachment.d.ts +120 -0
  56. package/dist/src/channels/telegram-mirror/plan-attachment.js +138 -0
  57. package/dist/src/channels/telegram-mirror/plan-attachment.js.map +1 -0
  58. package/dist/src/channels/telegram-mirror/quota-reader.d.ts +41 -0
  59. package/dist/src/channels/telegram-mirror/quota-reader.js +29 -0
  60. package/dist/src/channels/telegram-mirror/quota-reader.js.map +1 -0
  61. package/dist/src/channels/telegram-mirror/sessions-keyboard.d.ts +84 -0
  62. package/dist/src/channels/telegram-mirror/sessions-keyboard.js +113 -0
  63. package/dist/src/channels/telegram-mirror/sessions-keyboard.js.map +1 -0
  64. package/dist/src/channels/telegram-mirror/soak-log.d.ts +98 -0
  65. package/dist/src/channels/telegram-mirror/soak-log.js +136 -0
  66. package/dist/src/channels/telegram-mirror/soak-log.js.map +1 -0
  67. package/dist/src/channels/telegram-mirror/state-machine.d.ts +102 -0
  68. package/dist/src/channels/telegram-mirror/state-machine.js +117 -0
  69. package/dist/src/channels/telegram-mirror/state-machine.js.map +1 -0
  70. package/dist/src/channels/telegram-mirror/sync-commands.d.ts +63 -0
  71. package/dist/src/channels/telegram-mirror/sync-commands.js +51 -0
  72. package/dist/src/channels/telegram-mirror/sync-commands.js.map +1 -0
  73. package/dist/src/channels/telegram-mirror/threshold-watcher.d.ts +54 -0
  74. package/dist/src/channels/telegram-mirror/threshold-watcher.js +77 -0
  75. package/dist/src/channels/telegram-mirror/threshold-watcher.js.map +1 -0
  76. package/dist/src/command-router/cc-handler.js +1 -1
  77. package/dist/src/command-router/cc-handler.js.map +1 -1
  78. package/dist/src/index.js +12 -8
  79. package/dist/src/index.js.map +1 -1
  80. package/dist/src/lib/auto-recovery.js +1 -1
  81. package/dist/src/lib/auto-recovery.js.map +1 -1
  82. package/dist/src/lib/drift-detector.js +1 -1
  83. package/dist/src/lib/drift-detector.js.map +1 -1
  84. package/dist/src/lib/error-renderer.d.ts +23 -0
  85. package/dist/src/lib/error-renderer.js +106 -0
  86. package/dist/src/lib/error-renderer.js.map +1 -0
  87. package/dist/src/lib/perf/speculative-bubble.d.ts +27 -0
  88. package/dist/src/lib/perf/speculative-bubble.js +36 -0
  89. package/dist/src/lib/perf/speculative-bubble.js.map +1 -0
  90. package/dist/src/lib/session-registry.d.ts +66 -0
  91. package/dist/src/lib/session-registry.js +188 -0
  92. package/dist/src/lib/session-registry.js.map +1 -0
  93. package/dist/src/lib/telegram-bot-api.d.ts +100 -0
  94. package/dist/src/lib/telegram-bot-api.js +204 -0
  95. package/dist/src/lib/telegram-bot-api.js.map +1 -0
  96. package/package.json +1 -1
@@ -0,0 +1,96 @@
1
+ /**
2
+ * src/channels/telegram-mirror/burst-accumulator.ts — v0.25.0 M8.
3
+ *
4
+ * Per-chat 5-second settle window for non-slash inbound messages. When
5
+ * the user fires multiple message bubbles within 5s of each other, the
6
+ * accumulator concatenates them into one user-message payload (joined by
7
+ * "\n\n") before delivery to the engine. A gap > 5s flushes the prior
8
+ * buffer immediately and starts a new one.
9
+ *
10
+ * Decision: ADR-007 — 5s is the empirical saddle point. <3s gaps are
11
+ * almost always related thoughts; >8s gaps are almost always new turns.
12
+ * 5s matches the WARMUP_COOLDOWN_MS in typing-prefetch.ts (consistency).
13
+ *
14
+ * Routing responsibility lives in the inbound dispatcher (later milestone):
15
+ * • Slash messages bypass this class — dispatched immediately via
16
+ * dispatchCommand (commands.ts).
17
+ * • Compose-active chats bypass this class — drafts go to ComposeBuffer
18
+ * (compose-buffer.ts). M7 takes priority over M8 per ADR-007.
19
+ * • Everything else flows through submit() here.
20
+ *
21
+ * The flush flow has TWO triggers:
22
+ * 1. A new submit() that arrives AFTER the settle window — that submit
23
+ * returns the prior buffer in `flushed` and starts a fresh buffer.
24
+ * 2. A periodic flushIfReady() check that runs on a timer when no new
25
+ * inbound has arrived since the window opened.
26
+ *
27
+ * Tests inject a deterministic clock; production passes Date.now.
28
+ */
29
+ export interface BurstAccumulatorOptions {
30
+ /** Settle window in milliseconds (default 5000 per ADR-007). */
31
+ settleMs?: number;
32
+ /** Injectable clock for tests; defaults to Date.now. */
33
+ now?: () => number;
34
+ /** Custom separator between concatenated drafts (default "\n\n"). */
35
+ separator?: string;
36
+ }
37
+ export interface SubmitResult {
38
+ /**
39
+ * When the new submit() arrives AFTER the prior buffer's settle window,
40
+ * the prior buffer is returned here for immediate delivery; the new
41
+ * message starts a fresh buffer in its place. Undefined otherwise.
42
+ */
43
+ flushed?: string;
44
+ }
45
+ export declare class BurstAccumulator {
46
+ private readonly sessions;
47
+ private readonly settleMs;
48
+ private readonly now;
49
+ private readonly separator;
50
+ constructor(opts?: BurstAccumulatorOptions);
51
+ /**
52
+ * Submit a non-slash inbound message. Returns `flushed` populated when
53
+ * the prior buffer for the chat had timed out and this submit forced
54
+ * its flush; in that case the new message starts a fresh buffer.
55
+ *
56
+ * The returned `flushed` payload is the only value the caller delivers
57
+ * to the engine — the new message itself stays buffered for at least
58
+ * `settleMs` more, so it gets a chance to coalesce with follow-ups.
59
+ */
60
+ submit(chatId: string, text: string): SubmitResult;
61
+ /**
62
+ * Periodic check — when the settle window has elapsed without any new
63
+ * inbound, returns the buffered payload and clears the session. When
64
+ * the window has NOT yet elapsed, returns undefined and leaves the
65
+ * buffer intact. Returns undefined for chats without an active buffer.
66
+ *
67
+ * Production wiring: call from a 1Hz interval timer per known chatId
68
+ * (or from the inbound dispatcher's idle-tick).
69
+ */
70
+ flushIfReady(chatId: string): string | undefined;
71
+ /**
72
+ * Force-flush the buffer for a chat regardless of timing. Used when an
73
+ * explicit signal arrives that the current buffer must deliver now —
74
+ * e.g. a slash command was typed (its dispatcher flushes burst first,
75
+ * then routes the slash, so the bursted text reaches the engine before
76
+ * the slash response).
77
+ */
78
+ flushNow(chatId: string): string | undefined;
79
+ /**
80
+ * True when a buffer exists for the chat (regardless of settle state).
81
+ * Used by the inbound dispatcher to decide whether a slash arrival
82
+ * should trigger flushNow before routing.
83
+ */
84
+ hasBuffer(chatId: string): boolean;
85
+ /**
86
+ * Number of drafts currently buffered for the chat. Useful for status
87
+ * surfaces and for tests asserting the buffer state.
88
+ */
89
+ draftCount(chatId: string): number;
90
+ /**
91
+ * Clear all sessions. Test helper.
92
+ */
93
+ clear(): void;
94
+ private fresh;
95
+ private format;
96
+ }
@@ -0,0 +1,130 @@
1
+ /**
2
+ * src/channels/telegram-mirror/burst-accumulator.ts — v0.25.0 M8.
3
+ *
4
+ * Per-chat 5-second settle window for non-slash inbound messages. When
5
+ * the user fires multiple message bubbles within 5s of each other, the
6
+ * accumulator concatenates them into one user-message payload (joined by
7
+ * "\n\n") before delivery to the engine. A gap > 5s flushes the prior
8
+ * buffer immediately and starts a new one.
9
+ *
10
+ * Decision: ADR-007 — 5s is the empirical saddle point. <3s gaps are
11
+ * almost always related thoughts; >8s gaps are almost always new turns.
12
+ * 5s matches the WARMUP_COOLDOWN_MS in typing-prefetch.ts (consistency).
13
+ *
14
+ * Routing responsibility lives in the inbound dispatcher (later milestone):
15
+ * • Slash messages bypass this class — dispatched immediately via
16
+ * dispatchCommand (commands.ts).
17
+ * • Compose-active chats bypass this class — drafts go to ComposeBuffer
18
+ * (compose-buffer.ts). M7 takes priority over M8 per ADR-007.
19
+ * • Everything else flows through submit() here.
20
+ *
21
+ * The flush flow has TWO triggers:
22
+ * 1. A new submit() that arrives AFTER the settle window — that submit
23
+ * returns the prior buffer in `flushed` and starts a fresh buffer.
24
+ * 2. A periodic flushIfReady() check that runs on a timer when no new
25
+ * inbound has arrived since the window opened.
26
+ *
27
+ * Tests inject a deterministic clock; production passes Date.now.
28
+ */
29
+ const DEFAULT_BURST_SETTLE_MS = 5_000;
30
+ export class BurstAccumulator {
31
+ sessions = new Map();
32
+ settleMs;
33
+ now;
34
+ separator;
35
+ constructor(opts = {}) {
36
+ this.settleMs = opts.settleMs ?? DEFAULT_BURST_SETTLE_MS;
37
+ this.now = opts.now ?? Date.now;
38
+ this.separator = opts.separator ?? '\n\n';
39
+ }
40
+ /**
41
+ * Submit a non-slash inbound message. Returns `flushed` populated when
42
+ * the prior buffer for the chat had timed out and this submit forced
43
+ * its flush; in that case the new message starts a fresh buffer.
44
+ *
45
+ * The returned `flushed` payload is the only value the caller delivers
46
+ * to the engine — the new message itself stays buffered for at least
47
+ * `settleMs` more, so it gets a chance to coalesce with follow-ups.
48
+ */
49
+ submit(chatId, text) {
50
+ const now = this.now();
51
+ const session = this.sessions.get(chatId);
52
+ if (session && now - session.lastTs > this.settleMs) {
53
+ // Gap exceeded — flush the prior buffer, then start a new one
54
+ // containing only the current message.
55
+ const flushed = this.format(session);
56
+ this.sessions.set(chatId, this.fresh(chatId, text, now));
57
+ return { flushed };
58
+ }
59
+ if (!session) {
60
+ this.sessions.set(chatId, this.fresh(chatId, text, now));
61
+ }
62
+ else {
63
+ session.pending.push({ text, ts: now });
64
+ session.lastTs = now;
65
+ }
66
+ return {};
67
+ }
68
+ /**
69
+ * Periodic check — when the settle window has elapsed without any new
70
+ * inbound, returns the buffered payload and clears the session. When
71
+ * the window has NOT yet elapsed, returns undefined and leaves the
72
+ * buffer intact. Returns undefined for chats without an active buffer.
73
+ *
74
+ * Production wiring: call from a 1Hz interval timer per known chatId
75
+ * (or from the inbound dispatcher's idle-tick).
76
+ */
77
+ flushIfReady(chatId) {
78
+ const session = this.sessions.get(chatId);
79
+ if (!session)
80
+ return undefined;
81
+ if (this.now() - session.lastTs <= this.settleMs)
82
+ return undefined;
83
+ const out = this.format(session);
84
+ this.sessions.delete(chatId);
85
+ return out;
86
+ }
87
+ /**
88
+ * Force-flush the buffer for a chat regardless of timing. Used when an
89
+ * explicit signal arrives that the current buffer must deliver now —
90
+ * e.g. a slash command was typed (its dispatcher flushes burst first,
91
+ * then routes the slash, so the bursted text reaches the engine before
92
+ * the slash response).
93
+ */
94
+ flushNow(chatId) {
95
+ const session = this.sessions.get(chatId);
96
+ if (!session)
97
+ return undefined;
98
+ const out = this.format(session);
99
+ this.sessions.delete(chatId);
100
+ return out;
101
+ }
102
+ /**
103
+ * True when a buffer exists for the chat (regardless of settle state).
104
+ * Used by the inbound dispatcher to decide whether a slash arrival
105
+ * should trigger flushNow before routing.
106
+ */
107
+ hasBuffer(chatId) {
108
+ return this.sessions.has(chatId);
109
+ }
110
+ /**
111
+ * Number of drafts currently buffered for the chat. Useful for status
112
+ * surfaces and for tests asserting the buffer state.
113
+ */
114
+ draftCount(chatId) {
115
+ return this.sessions.get(chatId)?.pending.length ?? 0;
116
+ }
117
+ /**
118
+ * Clear all sessions. Test helper.
119
+ */
120
+ clear() {
121
+ this.sessions.clear();
122
+ }
123
+ fresh(chatId, text, ts) {
124
+ return { chatId, pending: [{ text, ts }], lastTs: ts };
125
+ }
126
+ format(session) {
127
+ return session.pending.map((p) => p.text).join(this.separator);
128
+ }
129
+ }
130
+ //# sourceMappingURL=burst-accumulator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"burst-accumulator.js","sourceRoot":"","sources":["../../../../src/channels/telegram-mirror/burst-accumulator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * src/channels/telegram-mirror/callback-mapping.ts — v0.25.0 M3.
3
+ *
4
+ * ADR-004 — Telegram's callback_data is capped at 64 bytes UTF-8. For
5
+ * payloads larger than that (most action+slug combinations are), the bot
6
+ * writes a short opaque base36 id into callback_data and stashes the real
7
+ * payload here. TTL prevents unbounded memory growth as users tap through
8
+ * keyboards or never tap at all.
9
+ *
10
+ * Default TTL is 10 minutes per ADR-004 monitoring signal (callback miss
11
+ * rate > 2% in soak → revisit TTL). The class accepts an injectable clock
12
+ * so tests can fast-forward without setTimeout games.
13
+ *
14
+ * No I/O, no global state. Each subsystem that hands out callback_data
15
+ * owns its own CallbackMap instance — keeps ownership boundaries clean
16
+ * for M4 (per-command), M9 (plan keyboards), M11 (cost subview).
17
+ */
18
+ export interface CallbackMapOptions {
19
+ /** TTL in milliseconds (default 10 minutes per ADR-004). */
20
+ ttlMs?: number;
21
+ /** Injectable clock for tests; defaults to Date.now. */
22
+ now?: () => number;
23
+ /** Length of the opaque id string (default 8 base36 chars ≈ 41 bits entropy). */
24
+ idLength?: number;
25
+ }
26
+ export declare class CallbackMap {
27
+ private readonly entries;
28
+ private readonly ttlMs;
29
+ private readonly now;
30
+ private readonly idLength;
31
+ constructor(opts?: CallbackMapOptions);
32
+ /**
33
+ * Allocate a fresh opaque id and stash the payload behind it. Returns the
34
+ * id, which fits in a Telegram callback_data field with room to spare.
35
+ * Idempotent only at the data-shape level — calling create() with the
36
+ * same payload twice produces two distinct ids.
37
+ */
38
+ create(payload: unknown): string;
39
+ /**
40
+ * Resolve a callback id to its stashed payload. Returns undefined if the
41
+ * id was never minted OR if it has expired since. Stale entries are
42
+ * dropped lazily on access — no background timer needed.
43
+ */
44
+ get(id: string): unknown | undefined;
45
+ /**
46
+ * Manually evict an id (e.g., one-shot Approve/Reject buttons after the
47
+ * user taps once). Returns true if an entry was deleted.
48
+ */
49
+ delete(id: string): boolean;
50
+ /**
51
+ * Current entry count (after pruning expired). Useful for monitoring
52
+ * and the 2% callback-miss-rate signal in soak.
53
+ */
54
+ size(): number;
55
+ /**
56
+ * Drop everything. Test helper; production code never calls this.
57
+ */
58
+ clear(): void;
59
+ private prune;
60
+ private randomId;
61
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * src/channels/telegram-mirror/callback-mapping.ts — v0.25.0 M3.
3
+ *
4
+ * ADR-004 — Telegram's callback_data is capped at 64 bytes UTF-8. For
5
+ * payloads larger than that (most action+slug combinations are), the bot
6
+ * writes a short opaque base36 id into callback_data and stashes the real
7
+ * payload here. TTL prevents unbounded memory growth as users tap through
8
+ * keyboards or never tap at all.
9
+ *
10
+ * Default TTL is 10 minutes per ADR-004 monitoring signal (callback miss
11
+ * rate > 2% in soak → revisit TTL). The class accepts an injectable clock
12
+ * so tests can fast-forward without setTimeout games.
13
+ *
14
+ * No I/O, no global state. Each subsystem that hands out callback_data
15
+ * owns its own CallbackMap instance — keeps ownership boundaries clean
16
+ * for M4 (per-command), M9 (plan keyboards), M11 (cost subview).
17
+ */
18
+ import { randomBytes } from 'crypto';
19
+ const DEFAULT_TTL_MS = 10 * 60_000;
20
+ const DEFAULT_ID_LENGTH = 8;
21
+ export class CallbackMap {
22
+ entries = new Map();
23
+ ttlMs;
24
+ now;
25
+ idLength;
26
+ constructor(opts = {}) {
27
+ this.ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
28
+ this.now = opts.now ?? Date.now;
29
+ this.idLength = opts.idLength ?? DEFAULT_ID_LENGTH;
30
+ }
31
+ /**
32
+ * Allocate a fresh opaque id and stash the payload behind it. Returns the
33
+ * id, which fits in a Telegram callback_data field with room to spare.
34
+ * Idempotent only at the data-shape level — calling create() with the
35
+ * same payload twice produces two distinct ids.
36
+ */
37
+ create(payload) {
38
+ this.prune();
39
+ let id = this.randomId();
40
+ // Defensive — base36 ids of length 8 have ~3T possible values, so
41
+ // collisions are astronomically unlikely, but the loop is cheap.
42
+ while (this.entries.has(id)) {
43
+ id = this.randomId();
44
+ }
45
+ this.entries.set(id, { payload, expiresAt: this.now() + this.ttlMs });
46
+ return id;
47
+ }
48
+ /**
49
+ * Resolve a callback id to its stashed payload. Returns undefined if the
50
+ * id was never minted OR if it has expired since. Stale entries are
51
+ * dropped lazily on access — no background timer needed.
52
+ */
53
+ get(id) {
54
+ const entry = this.entries.get(id);
55
+ if (!entry)
56
+ return undefined;
57
+ if (entry.expiresAt <= this.now()) {
58
+ this.entries.delete(id);
59
+ return undefined;
60
+ }
61
+ return entry.payload;
62
+ }
63
+ /**
64
+ * Manually evict an id (e.g., one-shot Approve/Reject buttons after the
65
+ * user taps once). Returns true if an entry was deleted.
66
+ */
67
+ delete(id) {
68
+ return this.entries.delete(id);
69
+ }
70
+ /**
71
+ * Current entry count (after pruning expired). Useful for monitoring
72
+ * and the 2% callback-miss-rate signal in soak.
73
+ */
74
+ size() {
75
+ this.prune();
76
+ return this.entries.size;
77
+ }
78
+ /**
79
+ * Drop everything. Test helper; production code never calls this.
80
+ */
81
+ clear() {
82
+ this.entries.clear();
83
+ }
84
+ prune() {
85
+ const now = this.now();
86
+ for (const [id, entry] of this.entries) {
87
+ if (entry.expiresAt <= now)
88
+ this.entries.delete(id);
89
+ }
90
+ }
91
+ randomId() {
92
+ // 8 random bytes → 64 bits → BigInt → base36 → take left N chars.
93
+ // Leading zeroes are fine — base36 keeps id length bounded.
94
+ const hex = randomBytes(8).toString('hex');
95
+ const base36 = BigInt('0x' + hex).toString(36);
96
+ return base36.padStart(this.idLength, '0').slice(0, this.idLength);
97
+ }
98
+ }
99
+ //# sourceMappingURL=callback-mapping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callback-mapping.js","sourceRoot":"","sources":["../../../../src/channels/telegram-mirror/callback-mapping.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * src/channels/telegram-mirror/card-renderer.ts — v0.25.0 M2.
3
+ *
4
+ * Pure-function renderer: Turn (from state-machine.ts) → message body string
5
+ * suitable for sendMessage / editMessageText. Telegram-API HTTP wiring
6
+ * (sendTg / editTg) lands in a later milestone alongside the dispatch path
7
+ * — M2's exit criterion is just "render a single turn (working → done)",
8
+ * which is satisfied by this pure function.
9
+ *
10
+ * Aesthetic: terminal-mimic per ADR-001. Header glyph ("▶" working,
11
+ * "✓" done) + tool call list (each prefixed with status glyph) + assistant
12
+ * text. Compact enough to fit in a single Telegram message bubble.
13
+ *
14
+ * Tests live at tests/channels/telegram-mirror/m2-render-pipeline.test.ts.
15
+ */
16
+ import type { Turn, ToolCallRecord } from './state-machine.js';
17
+ /**
18
+ * Format one tool-call line for inclusion in the rendered card body.
19
+ * "✓ Bash · ls -la"
20
+ * "… Read · src/index.ts"
21
+ * "✗ Edit · …error glyph at left"
22
+ */
23
+ export declare function renderToolLine(tc: ToolCallRecord): string;
24
+ /**
25
+ * Render the thinking block (M6). Each line of the thinking text is
26
+ * prefixed with "> " to read as a block quote in plain-text Telegram
27
+ * bubbles — clearly visually distinct from the assistant text below it
28
+ * without depending on MarkdownV2 escapes. Empty thinking returns ''.
29
+ */
30
+ export declare function renderThinkingBlock(thinkingText: string): string;
31
+ /**
32
+ * Render the full turn into a Telegram-safe message body. The mirror keeps
33
+ * a single message per turn that gets edited in place — this function is
34
+ * idempotent for a given turn snapshot and produces the next body string.
35
+ *
36
+ * Body shape (lines separated by \n):
37
+ *
38
+ * ▶ Working ← or "✓ Done" when state==='done'
39
+ * ✓ Bash · ls -la ← one line per tool call, in arrival order
40
+ * … Read · src/x.ts
41
+ * <empty line>
42
+ * 💭 Thinking ← M6, only when thinkingText non-empty
43
+ * > reasoning line 1
44
+ * > reasoning line 2
45
+ * <empty line>
46
+ * <assistant text> ← present only when non-empty;
47
+ * ★ Insight ─ blocks preserved INLINE
48
+ * at their emission position (M6).
49
+ *
50
+ * Lines with no content (e.g. empty tool list, empty assistant text) are
51
+ * omitted entirely so the rendered body never has trailing whitespace.
52
+ */
53
+ export declare function renderTurn(turn: Turn): string;
54
+ /**
55
+ * A render action — abstraction the dispatch layer (added in a later
56
+ * milestone) consumes. M2 doesn't dispatch; it just builds the action so
57
+ * tests can assert against the planned message lifecycle.
58
+ *
59
+ * - 'send' on turn start (no prior messageId)
60
+ * - 'edit' on every subsequent state mutation
61
+ */
62
+ export interface RenderAction {
63
+ type: 'send' | 'edit';
64
+ chatId: string;
65
+ text: string;
66
+ /** Defined only when type === 'edit'. */
67
+ messageId?: number;
68
+ }
69
+ /**
70
+ * Decide whether the current turn snapshot should be sent (first render)
71
+ * or edited (subsequent renders). The dispatcher tracks the (chatId →
72
+ * messageId) map; this function just produces the action shape.
73
+ */
74
+ export declare function planRenderAction(turn: Turn, knownMessageId: number | undefined): RenderAction;
@@ -0,0 +1,131 @@
1
+ /**
2
+ * src/channels/telegram-mirror/card-renderer.ts — v0.25.0 M2.
3
+ *
4
+ * Pure-function renderer: Turn (from state-machine.ts) → message body string
5
+ * suitable for sendMessage / editMessageText. Telegram-API HTTP wiring
6
+ * (sendTg / editTg) lands in a later milestone alongside the dispatch path
7
+ * — M2's exit criterion is just "render a single turn (working → done)",
8
+ * which is satisfied by this pure function.
9
+ *
10
+ * Aesthetic: terminal-mimic per ADR-001. Header glyph ("▶" working,
11
+ * "✓" done) + tool call list (each prefixed with status glyph) + assistant
12
+ * text. Compact enough to fit in a single Telegram message bubble.
13
+ *
14
+ * Tests live at tests/channels/telegram-mirror/m2-render-pipeline.test.ts.
15
+ */
16
+ /**
17
+ * Glyph picked per tool-call status. Mirrors terminal "running / done /
18
+ * errored" iconography that A1 already reads in the live Claude Code TUI.
19
+ */
20
+ function toolGlyph(tc) {
21
+ if (tc.isError)
22
+ return '✗';
23
+ if (tc.result !== undefined)
24
+ return '✓';
25
+ return '…';
26
+ }
27
+ /**
28
+ * Render the input argument summary for a tool call. Kept tight — full
29
+ * input is in the result; the mirror line is meant to read at a glance.
30
+ */
31
+ function toolInputSummary(tc) {
32
+ const input = tc.input;
33
+ if (!input || typeof input !== 'object')
34
+ return '';
35
+ // Prefer common single-field shapes used by Bash/Read/Edit/Write.
36
+ const single = typeof input.command === 'string'
37
+ ? input.command
38
+ : typeof input.file_path === 'string'
39
+ ? input.file_path
40
+ : typeof input.path === 'string'
41
+ ? input.path
42
+ : typeof input.url === 'string'
43
+ ? input.url
44
+ : '';
45
+ if (single) {
46
+ return single.length > 60 ? single.slice(0, 57) + '...' : single;
47
+ }
48
+ return '';
49
+ }
50
+ /**
51
+ * Format one tool-call line for inclusion in the rendered card body.
52
+ * "✓ Bash · ls -la"
53
+ * "… Read · src/index.ts"
54
+ * "✗ Edit · …error glyph at left"
55
+ */
56
+ export function renderToolLine(tc) {
57
+ const glyph = toolGlyph(tc);
58
+ const summary = toolInputSummary(tc);
59
+ return summary ? `${glyph} ${tc.name} · ${summary}` : `${glyph} ${tc.name}`;
60
+ }
61
+ /**
62
+ * Render the thinking block (M6). Each line of the thinking text is
63
+ * prefixed with "> " to read as a block quote in plain-text Telegram
64
+ * bubbles — clearly visually distinct from the assistant text below it
65
+ * without depending on MarkdownV2 escapes. Empty thinking returns ''.
66
+ */
67
+ export function renderThinkingBlock(thinkingText) {
68
+ const trimmed = thinkingText.trim();
69
+ if (trimmed.length === 0)
70
+ return '';
71
+ const lines = trimmed.split('\n');
72
+ return ['💭 Thinking', ...lines.map((l) => `> ${l}`)].join('\n');
73
+ }
74
+ /**
75
+ * Render the full turn into a Telegram-safe message body. The mirror keeps
76
+ * a single message per turn that gets edited in place — this function is
77
+ * idempotent for a given turn snapshot and produces the next body string.
78
+ *
79
+ * Body shape (lines separated by \n):
80
+ *
81
+ * ▶ Working ← or "✓ Done" when state==='done'
82
+ * ✓ Bash · ls -la ← one line per tool call, in arrival order
83
+ * … Read · src/x.ts
84
+ * <empty line>
85
+ * 💭 Thinking ← M6, only when thinkingText non-empty
86
+ * > reasoning line 1
87
+ * > reasoning line 2
88
+ * <empty line>
89
+ * <assistant text> ← present only when non-empty;
90
+ * ★ Insight ─ blocks preserved INLINE
91
+ * at their emission position (M6).
92
+ *
93
+ * Lines with no content (e.g. empty tool list, empty assistant text) are
94
+ * omitted entirely so the rendered body never has trailing whitespace.
95
+ */
96
+ export function renderTurn(turn) {
97
+ const header = turn.state === 'done' ? '✓ Done' : '▶ Working';
98
+ const lines = [header];
99
+ if (turn.toolCalls.length > 0) {
100
+ for (const tc of turn.toolCalls) {
101
+ lines.push(renderToolLine(tc));
102
+ }
103
+ }
104
+ // Defensive default — Turn.thinkingText is required by the interface, but
105
+ // some test helpers and pre-M6 fixtures construct Turn-shaped objects
106
+ // without setting it. Treat absent / undefined as empty.
107
+ const thinking = renderThinkingBlock(turn.thinkingText ?? '');
108
+ if (thinking.length > 0) {
109
+ lines.push('');
110
+ lines.push(thinking);
111
+ }
112
+ const text = turn.assistantText.trim();
113
+ if (text.length > 0) {
114
+ lines.push('');
115
+ lines.push(text);
116
+ }
117
+ return lines.join('\n');
118
+ }
119
+ /**
120
+ * Decide whether the current turn snapshot should be sent (first render)
121
+ * or edited (subsequent renders). The dispatcher tracks the (chatId →
122
+ * messageId) map; this function just produces the action shape.
123
+ */
124
+ export function planRenderAction(turn, knownMessageId) {
125
+ const text = renderTurn(turn);
126
+ if (knownMessageId === undefined) {
127
+ return { type: 'send', chatId: turn.chatId, text };
128
+ }
129
+ return { type: 'edit', chatId: turn.chatId, text, messageId: knownMessageId };
130
+ }
131
+ //# sourceMappingURL=card-renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-renderer.js","sourceRoot":"","sources":["../../../../src/channels/telegram-mirror/card-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;;GAGG;AACH,SAAS,SAAS,CAAC,EAAkB;IACnC,IAAI,EAAE,CAAC,OAAO;QAAE,OAAO,GAAG,CAAC;IAC3B,IAAI,EAAE,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IACxC,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,EAAkB;IAC1C,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC;IACvB,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACnD,kEAAkE;IAClE,MAAM,MAAM,GACV,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;QAC/B,CAAC,CAAC,KAAK,CAAC,OAAO;QACf,CAAC,CAAC,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ;YACnC,CAAC,CAAC,KAAK,CAAC,SAAS;YACjB,CAAC,CAAC,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;gBAC9B,CAAC,CAAC,KAAK,CAAC,IAAI;gBACZ,CAAC,CAAC,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ;oBAC7B,CAAC,CAAC,KAAK,CAAC,GAAG;oBACX,CAAC,CAAC,EAAE,CAAC;IACf,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACnE,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,EAAkB;IAC/C,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;IAC5B,MAAM,OAAO,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACrC,OAAO,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC,IAAI,MAAM,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;AAC9E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,YAAoB;IACtD,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;IACpC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,OAAO,CAAC,aAAa,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,UAAU,CAAC,IAAU;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;IAC9D,MAAM,KAAK,GAAa,CAAC,MAAM,CAAC,CAAC;IAEjC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,sEAAsE;IACtE,yDAAyD;IACzD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IAC9D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;IACvC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAkBD;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAU,EAAE,cAAkC;IAC7E,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IACrD,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;AAChF,CAAC"}