pi-braid-telegram 0.1.4 → 0.1.5

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
@@ -4,6 +4,12 @@
4
4
 
5
5
  Bidirectional Telegram channel for pi-braid.
6
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
+
7
13
  - **Outbound**: `telegram_send` tool - the agent sends text messages to the
8
14
  owner (or voice notes once a TTS source is configured). Messages are LONG by
9
15
  default: plain text sends verbatim up to the cap (`braid.telegram.sendMaxChars`
@@ -96,6 +102,17 @@ Or register the workspace in `~/.pi/agent/settings.json`:
96
102
  - A bot token from @BotFather; optionally `BRAID_TG_CHAT_ID` / `BRAID_TG_ALLOWED_USERS` for the
97
103
  allow-list.
98
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
+
99
116
  ## Environment variables
100
117
 
101
118
  | Var | Purpose | Required |
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "pi-braid-telegram",
3
+ "version": "0.1.5",
4
+ "sha": "752d2e6e9b45037a8ebcc17f3d6f90c905b2c71c",
5
+ "shaShort": "752d2e6",
6
+ "branch": "detached",
7
+ "dirty": false,
8
+ "packedAt": "2026-10-19T11:29:41.109Z"
9
+ }
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "pi-braid-telegram",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Bidirectional Telegram channel for pi-braid: telegram_send tool (outbound) + inbound long-poll injector (backward channel)",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "src/",
8
8
  "docs/",
9
9
  "README.md",
10
- "LICENSE"
10
+ "LICENSE",
11
+ "build-info.json"
11
12
  ],
12
13
  "exports": {
13
14
  ".": "./src/index.ts"
@@ -34,16 +35,17 @@
34
35
  "test": "node test/run-tests.mjs",
35
36
  "check:doc-index": "node ../../packages/core/scripts/check-doc-index.mjs",
36
37
  "publish:local": "node ../../packages/core/scripts/publish-local.mjs telegram",
37
- "prepack": "npm run build"
38
+ "prepack": "npm run build && node ../../packages/core/scripts/pack-provenance.mjs write",
39
+ "postpack": "node ../../packages/core/scripts/pack-provenance.mjs remove"
38
40
  },
39
41
  "devDependencies": {
40
42
  "typescript": "6.0.2",
41
43
  "typebox": "1.1.38"
42
44
  },
43
45
  "peerDependencies": {
44
- "@earendil-works/pi-ai": "*",
45
- "@earendil-works/pi-coding-agent": "*",
46
- "typebox": "*"
46
+ "@earendil-works/pi-ai": "^1.2.0",
47
+ "@earendil-works/pi-coding-agent": "^1.2.0",
48
+ "typebox": "^1.1.38"
47
49
  },
48
50
  "author": "kifirkin",
49
51
  "license": "MIT",
package/src/lib/format.ts CHANGED
@@ -27,7 +27,11 @@ import type {
27
27
  TelegramSendResult,
28
28
  ParseMode,
29
29
  } from "./telegram-client.js";
30
- import { checkTelegramHtml, parseTelegramTagAt } from "./html-check.js";
30
+ import {
31
+ TELEGRAM_HTML_TAGS,
32
+ checkTelegramHtml,
33
+ parseTelegramTagAt,
34
+ } from "./html-check.js";
31
35
 
32
36
  /** Telegram hard cap for a single text message (https://core.telegram.org/bots/api#sendmessage). */
33
37
  export const TELEGRAM_MAX_TEXT_LENGTH = 4096;
@@ -145,17 +149,26 @@ export function isBalancedMarkdown(text: string): boolean {
145
149
  // attribute value is part of the tag, so `<a href="a>b">` is one token and is
146
150
  // removed whole rather than truncated at the first `>`.
147
151
 
148
- /** True when the text contains raw HTML tags — a signal it was authored as HTML. */
152
+ /** True when the text contains a tag Telegram's HTML parser accepts.
153
+ *
154
+ * Tag-shaped is not enough: auto-selecting HTML for a body carrying `<n>` or
155
+ * `<b/>` makes Telegram reject the whole message ("Unsupported start tag"),
156
+ * while as a plain body the same characters reach the reader literally. Only
157
+ * a token whose name is in Telegram's tag set and whose syntax the parser
158
+ * accepts is a signal the body was authored as HTML.
159
+ */
149
160
  export function hasHtmlTags(text: string): boolean {
150
161
  return findTagToken(text) !== null;
151
162
  }
152
163
 
153
- /** First tag-shaped token in `text`, or null. */
164
+ /** First tag-shaped token Telegram would accept, or null. */
154
165
  function findTagToken(text: string): { start: number; end: number } | null {
155
166
  let i = text.indexOf("<");
156
167
  while (i !== -1) {
157
168
  const tag = parseTelegramTagAt(text, i);
158
- if (tag) return { start: i, end: tag.end };
169
+ if (tag && tag.error === undefined && TELEGRAM_HTML_TAGS.has(tag.name)) {
170
+ return { start: i, end: tag.end };
171
+ }
159
172
  i = text.indexOf("<", i + 1);
160
173
  }
161
174
  return null;