pi-braid-telegram 0.1.6 → 0.1.7

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.
package/README.md CHANGED
@@ -2,77 +2,8 @@
2
2
 
3
3
  <!-- status: current -->
4
4
 
5
- Bidirectional Telegram channel for pi-braid.
6
-
7
- ```bash
8
- pi install npm:pi-braid-telegram
9
- ```
10
-
11
- One command, no clone, no build: `pi install` registers the package with pi and installs it under pi's npm directory.
12
-
13
- - **Outbound**: `telegram_send` tool - the agent sends text messages to the
14
- owner (or voice notes once a TTS source is configured). Messages are LONG by
15
- default: plain text sends verbatim up to the cap (`braid.telegram.sendMaxChars`
16
- in `~/.pi/agent/settings.json`, default 4096 = Telegram's per-message limit);
17
- there is no tweet-length default. Over the cap, the crafting model distills
18
- first and `rich: true` splits-to-fit instead. Returns the delivery
19
- result (message_id or error). Outbound sends the raw trimmed
20
- text verbatim - the `[tg-end]` marker is an INBOUND parse boundary only and
21
- never appears on outbound messages.
22
- - **Turn-complete auto-notify (opt-in)**: with
23
- `BRAID_TG_NOTIFY_ENABLED=1`, when a turn ends with a completed plain-text
24
- answer (no trailing tool call), a second LLM call (key-ring-backed via
25
- `ctx.modelRegistry`, never the bot token) distills the answer into an owner
26
- update capped at `braid.telegram.notifyMaxChars` (default 1200) and sends it
27
- through the same outbound seam. Rate-limited (default 4/min,
28
- `BRAID_TG_NOTIFY_MAX_PER_MIN`); model override via `BRAID_TG_NOTIFY_MODEL`.
29
- Default OFF - no unsolicited messages.
30
- - **Live-update tracked message (default-on)**: on every escalated
31
- inbound owner message the bot immediately sends one "⚙️ Working…" message,
32
- edits it in place (Telegram's edit affordance pins it at its position) as work
33
- progresses, then on a completed turn edits it to "✅ Done" and sends a SEPARATE
34
- beautifully formatted full report via rich Markdown + split-to-fit
35
- (`sendMessageChunks`). Progress edits are rate-limited (default 4/min);
36
- `finish()` is never dropped. Default ON - set
37
- `BRAID_TG_LIVE_UPDATE_ENABLED=0` to disable.
38
- - **Rich / split-to-fit outbound**: `telegram_send` gained optional
39
- `rich: true` and `parse_mode: "HTML"|"Markdown"`. `rich` bypasses the send
40
- cap and the craft hook, delivering the text verbatim split on
41
- paragraph→line→word boundaries with a `(i/N)` marker; bodies that ship as
42
- HTML are split tag-aware (no cut inside a tag/entity; a chunk closes the tags
43
- it opens, the next chunk reopens them). A Markdown balance guard
44
- (`isBalancedMarkdown`) drops `parse_mode` to plain text (never an API error)
45
- when Telegram would reject unbalanced emphasis/link delimiters, and the
46
- MarkdownV2→HTML conversion is validated against Telegram's HTML parser
47
- (`checkTelegramHtml`): a conversion that would cross delimiter pairs, emit an
48
- unbalanced/broken author tag or cross the cap is refused, and the body ships
49
- as authored. Default path (no `rich`) is plain text with the
50
- settings-driven cap.
51
- - **Decision buttons (tap-to-answer)**: `telegram_send` gained optional
52
- `options` - 1-2 rows of up to 4 `{ label, value }` buttons attached to the
53
- message as an inline keyboard - and `decisionToken`, their correlation id
54
- (generated when omitted, echoed in the tool result). A tap is acknowledged
55
- with a toast and reaches the agent as a normal inbound message
56
- `[decision] <token> → <label> (<value>)` (through the same coalescing
57
- window and steer handoff as a text message). The owner can always answer
58
- in words;
59
- malformed rows refuse the send (nothing delivered); `pause`/`resume`/`status`
60
- control taps keep their own handler.
61
- - **Inbound (agentic pull, default)**: `telegram_inbox` tool - the agent calls
62
- it mid-turn to fetch pending messages from whitelisted chats via `getUpdates`
63
- (offset confirm-on-read, persisted across restarts). Results come back as
64
- braid-whisper envelopes (context, NOT synthetic user turns) with sender
65
- provenance + a per-message `fromOwner` flag; only owner messages may be
66
- escalated to a turn.
67
- - **Inbound (background poller, opt-in only)**: the legacy long-poll injector
68
- is OFF by default. Explicitly enable via `BRAID_TG_POLL_ENABLED=1` at load,
69
- `/telegram enable`, or the `telegram_poller` tool (`action:"enable"`). At
70
- most ONE poller per process (singleton). Owner messages are delivered as
71
- `[braid-whisper - telegram] ... [braid-whisper-end]` envelopes.
72
-
73
- Zero npm runtime dependencies: the client is built on Node 22's global fetch.
74
- No live credentials, no real network calls in the test suite (recorded-fixture
75
- fake fetch).
5
+ Talk to your pi coding agent from Telegram: it sends you answers, reads your replies, and lets you
6
+ approve a decision with a tap. Text and voice both directions, one bot, no extra service.
76
7
 
77
8
  ## Install
78
9
 
@@ -80,143 +11,70 @@ fake fetch).
80
11
  pi install npm:pi-braid-telegram
81
12
  ```
82
13
 
83
- Or register the workspace in `~/.pi/agent/settings.json`:
84
-
85
- ```json
86
- {
87
- "packages": ["file:~/pi-braid/packages/telegram"]
88
- }
89
- ```
90
-
91
- ## What this does not do
92
-
93
- - It does not poll or push by default. The background poller is OFF, turn-complete auto-notify is
94
- opt-in, and the tracked in-progress message fires only on an escalated inbound owner message.
95
- - It does not accept strangers. Only whitelisted chats/users are read, and only owner messages may
96
- be escalated to a turn.
97
- - It does not bundle a Telegram client library - the Bot API calls use Node 22's global fetch.
98
-
99
- ## Activation preconditions
100
-
101
- - `BRAID_TG_BOT_TOKEN` set - this is what enables the channel.
102
- - A bot token from @BotFather; optionally `BRAID_TG_CHAT_ID` / `BRAID_TG_ALLOWED_USERS` for the
103
- allow-list.
104
-
105
- ## Settings cadence
106
-
107
- Settings live in `~/.pi/agent/settings.json`. `braid.telegram.pauseStateFile`
108
- is captured as the callback write target when the extension loads. `getPauseState()`
109
- resolves its read path per call, so restart after changing the setting to keep
110
- reads and writes aligned. `braid.telegram.tts` is loaded into the voice hook at
111
- extension load; restart after changing its source, rate, or voices.
112
- The send and notification caps (`braid.telegram.sendMaxChars` and
113
- `braid.telegram.notifyMaxChars`) are re-read per operation and change without
114
- a restart.
115
-
116
- ## Environment variables
117
-
118
- | Var | Purpose | Required |
119
- | ---------------------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------- |
120
- | `BRAID_TG_BOT_TOKEN` | Telegram bot token from @BotFather | **enables the channel** (if-has-token guard) |
121
- | `BRAID_TG_CHAT_ID` | Owner chat/user id for outbound + allow-list | optional (bootstrap fallback) |
122
- | `BRAID_TG_ALLOWED_USERS` | Extra allow-list ids/@usernames (comma-separated) | optional |
123
- | `BRAID_TG_STATE_FILE` | Offset/state file path | optional, default `~/.pi/agent/braid/telegram-state.json` |
124
- | `BRAID_TG_POLL_INTERVAL_MS` | Poll cadence (background poller) | optional, default 1500 |
125
- | `BRAID_TG_POLL_ENABLED` | Explicit opt-in: auto-start the background poller at load (`1`) | optional; default OFF (`TELEGRAM_POLL_ENABLED` alias) |
126
- | `BRAID_TG_POLL_DISABLED` | Legacy opt-out flag (superseded by default-off; still honored) | optional |
127
- | `BRAID_TG_COALESCE_WINDOW_MS` | Coalescing window for inbound owner bursts (ms; `0` = next tick) | optional, default 2000 |
128
- | `BRAID_TG_VERBOSE` | Route debug/info to the notify sink (still never console.\*) | optional |
129
- | `BRAID_TG_NOTIFY_ENABLED` | Opt-in: turn-complete auto-notify, default OFF | optional |
130
- | `BRAID_TG_NOTIFY_MODEL` | Crafting model override (`provider/model-id`); default = session model | optional |
131
- | `BRAID_TG_NOTIFY_MAX_PER_MIN` | Auto-notify rate cap (sliding window), default 4 | optional |
132
- | `BRAID_TG_LIVE_UPDATE_ENABLED` | Live-update tracked message, default ON (`0` disables) | optional |
133
- | `BRAID_TG_LIVE_UPDATE_MAX_PER_MIN` | Live-update progress-edit rate cap (sliding window), default 4 | optional |
134
- | `BRAID_TG_LIVE_UPDATE_STATE_FILE` | Tracked-message state file path | optional, default `~/.pi/agent/braid/telegram-live-update.json` |
135
-
136
- All `BRAID_TG_*` names have `TELEGRAM_*` owner-side aliases; `BRAID_TG_*` wins
137
- when both are set. No token → the extension factory returns immediately; no
138
- tools, no command, no poller, nothing crashes (debug log only).
139
-
140
- ## Tools & command
141
-
142
- | Surface | Purpose |
143
- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
144
- | `telegram_send` | Outbound text/voice to the owner (raw trimmed text, no end marker); optional `rich: true` for verbatim split-to-fit delivery, `parse_mode: "HTML" or "Markdown"`, `options` for decision buttons (1-2 rows of up to 4 `{ label, value }` buttons; a tap returns `[decision] <token> → <label> (<value>)`), `decisionToken` correlation id |
145
- | `telegram_inbox` | Agentic pull - fetch pending messages, confirm-on-read, `fromOwner` flag |
146
- | `telegram_poller` | Enable/disable the singleton background poller (agent tool) |
147
- | `/telegram enable` | Start the singleton background poller |
148
- | `/telegram disable` | Stop the singleton background poller |
149
- | `/telegram send <text>` | Send a message from the shell (raw trimmed text, no marker) |
150
- | `/telegram status` | Show channel + poller state |
151
-
152
- ## Components
153
-
154
- | Path | Purpose |
155
- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
156
- | `src/index.ts` | Extension factory: if-has-token guard, registers `telegram_send`/`telegram_inbox`/`telegram_poller`, `/telegram` command, singleton poller (OFF by default), TUI-safe notify sink, turn-complete auto-notify (`turn_end` listener, opt-in), live-update tracked message (`start` on inbound / `finish` on `turn_end`, default-on), LLM-crafted + rich/split-to-fit outbound |
157
- | `src/lib/telegram-client.ts` | Low-level `api.telegram.org/bot<token>/<method>` client (sendMessage, editMessageText, sendVoiceNote, sendChatAction, getUpdates, getMe, testToken) with injectable fetch; `parse_mode` on text sends/edits |
158
- | `src/lib/inbound-poller.ts` | Long-poll loop: allow-list + bootstrap filtering, group/non-text rejection, confirm-on-read offset persistence, injection retry buffer |
159
- | `src/lib/telegram-inbox.ts` | `fetchInbox` agentic-pull core: fetch → filter → return with `fromOwner` → confirm offset; braid-whisper envelope formatting |
160
- | `src/lib/tool-logic.ts` | `telegram_send` validation, settings-driven cap enforcement (craft hook replaces dumb truncate; `braid.telegram.sendMaxChars` default 4096), rich/split-to-fit + parse_mode + Markdown-balance guard, text/voice delivery orchestration |
161
- | `src/lib/tts.ts` | Outbound voice synthesis: `braid.telegram.tts` source/rate/voice reader (default edge-tts, rate +20%, RU/EN/HE voices by script), edge-tts → ffmpeg ogg/opus with retry, gated macOS `say` fallback, `source: "none"` → voice refusal; injectable spawn seam |
162
- | `src/lib/format.ts` | `splitLongText` (paragraph→line→word boundaries, `(i/N)` markers), `splitHtmlText` (tag-aware chunks: tags close/reopen across cuts, entities stay whole; an over-cap tag refuses the body instead of being trimmed), `sendMessageChunks` (split-to-fit 4096, parseMode-propagation, replyMarkup on the last chunk), `isBalancedMarkdown` (pre-send guard), `convertMarkdownV2ToHtml` (refuses conversions Telegram would reject), `resolveDeliveryFormat` (mode decision point) |
163
- | `src/lib/html-check.ts` | `checkTelegramHtml`: strict local mirror of Telegram's HTML parser (tag set, attribute quoting, end-tag attributes, unquoted-value delimiters, span/tg-emoji attribute rules, LIFO nesting), calibrated against the live API; gates every conversion and every HTML wire chunk |
164
- | `src/lib/decision-buttons.ts` | Decision-button protocol: `options` rows → `dec:<token>:<value>` inline keyboard (64-byte callback_data cap enforced), tap parse + label recovery, the answered row is dropped from the message while open rows stay (a multi-question keyboard survives a tap), `[decision] <token> → <label> (<value>)` delivery payload |
165
- | `src/lib/telegram-settings.ts` | `braid.telegram` caps reader (`sendMaxChars` 4096, `notifyMaxChars` 1200) from `~/.pi/agent/settings.json`: per-call, safe defaults on missing/invalid input |
166
- | `src/lib/notify/craft.ts` | Turn-complete notify: pure detection (`shouldNotifyTurnEnd`), final-text extraction, distilling prompt (cap injected from settings), guard-fallback at the same cap; `buildRichSummaryPrompts` (live-update rich-report prompt) |
167
- | `src/lib/notify/rate-limit.ts` | Sliding-window rate limiter (max N per minute, deterministic timestamps) |
168
- | `src/lib/notify/model.ts` | Key-ring-backed crafting model call (completeSimple via `ctx.modelRegistry`, never the bot token) + text-craft hooks for `telegram_send`/`/telegram send` and rich summaries |
169
- | `src/lib/notify/live-update.ts` | Live-update tracker: `start` (send + persist tracked message, idempotent restart re-pin) / `update` (edit in place) / `finish` (edit → Done, then separate rich summary) / `isActive` / `getState` + state-file persistence |
170
- | `src/lib/notify/turn-notify.ts` | `turn_end` handler orchestration: detect → rate-limit → craft → deliver (injectable for tests) |
171
- | `test/*.test.mjs` | Unit tests against recorded fixtures (fake fetch / stubbed client), no network; `test/corpus-runner.mjs` replays the committed adversarial corpus (wire validity, fidelity changes, cap contracts) |
172
-
173
- ## Tests
174
-
175
- ```bash
176
- npm test # emits src -> dist (gitignored), runs all test files
177
- npm test -w pi-braid-telegram # via the monorepo workspace
178
- npx tsc --noEmit # typecheck (guardrail build)
179
- ```
180
-
181
- Coverage: client method extraction & error mapping, param validation, cap
182
- enforcement (settings-driven default + explicit limit), allow-list filtering,
183
- bootstrap, offset confirm-on-read
184
- persistence across restarts and fetch calls, retry-on-injection-failure,
185
- group/non-text rejection, if-has-token guard, inbound/outbound envelope
186
- formats (inbound carries the `[tg-end]` end marker; outbound carries NONE),
187
- default-off poller, poll-enabled opt-in, singleton
188
- poller, `/telegram` command verbs, telegram settings caps (defaults,
189
- overrides, invalid-input degradation, per-call re-read), voice TTS
190
- (`braid.telegram.tts` defaults / `source: "none"` refusal / invalid-input
191
- fallback, script→voice, edge-tts retry, gated say fallback, handoff into the
192
- send path), turn-complete
193
- auto-notify (detection,
194
- rate limit, guard fallback, cap + token-budget injection, key-ring model
195
- resolver, no marker on outbound),
196
- live-update tracked message (start/update/finish idempotency, restart re-pin,
197
- rate limit, finish-not-rate-limited, default-on + `=0` opt-out, trailing-tool gating,
198
- state-file persistence), rich/split-to-fit (paragraph→line→word boundaries,
199
- never mid-word, `(i/N)` markers, 4096 cap sequence, honored parse_mode,
200
- Markdown-balance guard, craft bypass when `rich`),
201
- decision buttons (row/token validation, malformed-row refusal, 64-byte
202
- callback_data cap, generated-token echo, dec: parse/label/format, tap handler
203
- ack + delivery payload, multi-question keyboards keep the open rows after a
204
- tap, voice-path refusal, keyboard on the last rich chunk),
205
- callback routing through the real poller (dec: tap delivered as a whisper,
206
- pause tap persists state, unknown data answered without a crash),
207
- format corpus (`test/corpus.test.mjs` + `corpus-runner.mjs`: 76 hostile bodies ×
208
- 3 requested modes, recorded live parse verdicts vs the local checker, the 21-cell
209
- resolution matrix, cap-crossing bodies; `test/live-html-probe.mjs` re-verifies
210
- the checker against the live API, opt-in and never run by `npm test`).
211
-
212
- ## Live E2E (postponed)
213
-
214
- Configure the env vars above, add `packages/telegram` to the pi `packages`
215
- list (like `packages/providers`), then: `testToken` → `telegram_send` a text →
216
- `telegram_inbox` to pull replies (or explicitly `BRAID_TG_POLL_ENABLED=1` /
217
- `/telegram enable` for the background injector). `voice: true` synthesizes
218
- through `braid.telegram.tts` (default: latest edge-tts via uvx, rate +20%,
219
- voices picked by script) → ffmpeg ogg/opus → `sendVoice`; `source: "none"`
220
- disables synthesis, and `voice: true` then returns a clear "no TTS source is
221
- configured" error instead of silently sending text. macOS `say` is the
222
- explicit-config emergency fallback (`source: "say"` or `"edge-tts+say"`).
14
+ Set `BRAID_TG_BOT_TOKEN` from @BotFather, and optionally `BRAID_TG_CHAT_ID` to pin the owner chat.
15
+ Without a token the extension loads, does nothing, and says so in the log.
16
+
17
+ ## What you get
18
+
19
+ | Surface | What it gives you |
20
+ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
21
+ | `telegram_send` | Text or synthesized voice to the owner; long messages split to fit; optional inline decision buttons whose tap comes back as an inbound message |
22
+ | `telegram_inbox` | Pull pending messages mid-turn, with sender provenance and an owner flag |
23
+ | `telegram_poller` | Optional background long-poll delivery; one poller per process |
24
+ | Live update | On an owner message: one "working" message edited in place, then a formatted report |
25
+ | Inbound media | Owner photos, documents and voice notes are downloaded to the media directory; a voice note is transcribed when a transcription key is configured |
26
+ | Turn-complete notify | Opt-in: a distilled owner update when a turn ends with a completed answer |
27
+ | Decision buttons | 1 or 2 rows of up to 4 buttons on a message; a tap returns to the agent as an inbound message, and the owner can always answer in words |
28
+
29
+ ## Configuration
30
+
31
+ ### Environment
32
+
33
+ | Variable | Purpose | Default |
34
+ | ---------------------------------- | ----------------------------------------------------------- | ----------------- |
35
+ | `BRAID_TG_BOT_TOKEN` | Bot token from @BotFather; its presence enables the channel | required to run |
36
+ | `BRAID_TG_CHAT_ID` | Owner chat id for outbound and the allow-list | unset |
37
+ | `BRAID_TG_ALLOWED_USERS` | Extra allow-listed ids or usernames, comma-separated | unset |
38
+ | `BRAID_TG_POLL_ENABLED` | Opt-in: start the background poller at load | off |
39
+ | `BRAID_TG_POLL_INTERVAL_MS` | Poll cadence | `1500` |
40
+ | `BRAID_TG_COALESCE_WINDOW_MS` | Window that gathers an owner burst into one message | `2000` |
41
+ | `BRAID_TG_NOTIFY_ENABLED` | Opt-in: turn-complete notification | off |
42
+ | `BRAID_TG_NOTIFY_MODEL` | Crafting model override, as provider and model id | the session model |
43
+ | `BRAID_TG_NOTIFY_MAX_PER_MIN` | Notification rate cap | `4` |
44
+ | `BRAID_TG_LIVE_UPDATE_ENABLED` | The tracked "working" message | on; `0` disables |
45
+ | `BRAID_TG_LIVE_UPDATE_MAX_PER_MIN` | Progress edit rate cap | `4` |
46
+ | `BRAID_TG_VERBOSE` | Route debug and info lines to the notify sink | off |
47
+
48
+ Two families beyond the table: the `BRAID_TG_STT_*` variables configure speech to text (an API key,
49
+ base URL, model and language, plus a key pool), and `BRAID_TG_STATE_FILE` relocates the poll offset.
50
+ Every `BRAID_TG_*` name has a `TELEGRAM_*` alias; the prefixed name wins when both are set.
51
+
52
+ ### Settings
53
+
54
+ `braid.telegram.*` keys in `~/.pi/agent/settings.json`:
55
+
56
+ | Key | Default | Effect |
57
+ | ------------------------------- | -------- | ---------------------------------------------------------- |
58
+ | `braid.telegram.sendMaxChars` | `4096` | Cap for plain `telegram_send` text; re-read per send |
59
+ | `braid.telegram.notifyMaxChars` | `1200` | Cap for the turn-complete update; re-read per notification |
60
+ | `braid.telegram.tts` | edge-tts | Voice source, rate and voices; read at extension load |
61
+ | `braid.telegram.pauseStateFile` | unset | Where the pause control keeps its state; read at load |
62
+
63
+ ## Limits
64
+
65
+ - Only whitelisted chats are read, and only owner messages can become a turn.
66
+ - The poller is off by default and only one runs per process.
67
+ - Voice replies need a TTS source. `source: "none"` refuses the send rather than silently sending
68
+ text.
69
+ - Transcription needs a key. Without one a voice note is still delivered, as the downloaded file,
70
+ and the message says so.
71
+
72
+ ## Documentation
73
+
74
+ - [Live update](docs/live-update.md): the tracked message, its states and its rate limits.
75
+ - [Turn-complete notify](docs/turn-complete-notify.md): detection, crafting, and the cap.
76
+ - [Pause control](docs/pause-control.md): how a paused session queues and resumes.
77
+
78
+ ## License
79
+
80
+ [MIT](LICENSE)
package/build-info.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "pi-braid-telegram",
3
- "version": "0.1.6",
4
- "sha": "dc847759a4c99339571e7583ae848d8ec99e694c",
5
- "shaShort": "dc84775",
6
- "branch": "main",
3
+ "version": "0.1.7",
4
+ "sha": "55abdd57dac34879f6b39b357e31283ad6c3e974",
5
+ "shaShort": "55abdd57",
6
+ "branch": "detached",
7
7
  "dirty": false,
8
- "packedAt": "2026-10-23T21:27:14.009Z"
8
+ "packedAt": "2026-11-03T21:27:05.199Z"
9
9
  }
@@ -48,8 +48,8 @@ registry model. The call is key-ring-backed: the API key comes from
48
48
  `ctx.modelRegistry.getApiKeyForProvider(provider)`, which
49
49
  pi-braid-providers wires to the key-ring (`ring-lifecycle.ts` auth.resolve →
50
50
  `getActiveKey`) - never the bot token.
51
- Note: core's `/utility-model` role key (`/max-power-model` is a deprecated
52
- alias of it) lives in core's global-state (unreachable from the standalone
51
+ Note: core's `/utility-model` role key lives in core's global-state
52
+ (unreachable from the standalone
53
53
  telegram package without a cross-package import). The env override is the
54
54
  telegram-native equivalent.
55
55
  Owner call: if honoring the /utility-model role key is required, that needs the
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-braid-telegram",
3
- "version": "0.1.6",
4
- "description": "Bidirectional Telegram channel for pi-braid: telegram_send tool (outbound) + inbound long-poll injector (backward channel)",
3
+ "version": "0.1.7",
4
+ "description": "Talk to your pi coding agent from Telegram: send text or voice, get the answer back, and tap a button to decide.",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "src/",
@@ -15,13 +15,12 @@
15
15
  },
16
16
  "keywords": [
17
17
  "pi-package",
18
- "pi",
18
+ "braid",
19
19
  "pi-coding-agent",
20
- "bot",
21
- "extension",
22
20
  "telegram",
23
- "channel",
24
- "messaging"
21
+ "telegram-bot",
22
+ "remote-control",
23
+ "voice"
25
24
  ],
26
25
  "pi": {
27
26
  "extensions": [
@@ -43,8 +42,8 @@
43
42
  "typebox": "1.1.38"
44
43
  },
45
44
  "peerDependencies": {
46
- "@earendil-works/pi-ai": "^1.2.0",
47
- "@earendil-works/pi-coding-agent": "^1.2.0",
45
+ "@earendil-works/pi-ai": "^1.5.0",
46
+ "@earendil-works/pi-coding-agent": "^1.5.0",
48
47
  "typebox": "^1.1.38"
49
48
  },
50
49
  "author": "kifirkin",
@@ -59,6 +58,6 @@
59
58
  },
60
59
  "homepage": "https://github.com/kifirkin/pi-braid/tree/main/packages/telegram",
61
60
  "engines": {
62
- "node": ">=22.19.0"
61
+ "node": ">=24.0.0"
63
62
  }
64
63
  }