shadok-ai 0.16.20 → 0.16.22

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
@@ -341,12 +341,21 @@ Enter to skip; you can add it later from the web UI).
341
341
  The Telegram panel (header icon) carries a folded *How to set it up, step by step*
342
342
  guide, open until a token is saved and a group is bound.
343
343
 
344
+ **Pairing.** The bot answers nobody until it is paired from the cockpit. In the
345
+ Telegram panel (admin only), click **Pair Telegram**: it shows an 8-digit code,
346
+ valid 10 minutes, single-use, cancelled after 5 wrong tries. Send `/setup <code>`
347
+ in the group to make it the board, or in a private chat with the bot to make its
348
+ DMs yours — or use the panel's one-click links, which pass the code for you.
349
+ Whoever enters the code becomes the owner of the bot's DMs. A group bound before
350
+ pairing existed stays bound; to move to another group, unbind it in the panel
351
+ and pair again.
352
+
344
353
  Add your bot to a group with **Topics** enabled, make it an admin with *Manage
345
354
  topics* (and *Delete messages* so `/secret` can scrub values), then in the group:
346
355
 
347
356
  | Command | |
348
357
  |---|---|
349
- | `/setup` | bind this group as the board (one group per instance) |
358
+ | `/setup <code>` | bind this group as the board (one group per instance), with the code from the panel's **Pair Telegram** |
350
359
  | `/spawn [profile] <name>` | new isolated agent in its own topic (also a web tab) |
351
360
  | `/stop` (alias `/esc`) | interrupt the current turn — does **not** end the session |
352
361
  | `/new` · `/end` | reset · kill the session |
package/dist/server.js CHANGED
@@ -39,6 +39,7 @@ import { getUsage } from "./usage.js";
39
39
  import { loadChannels, loadGroups, saveGroups, upsertChannel, removeChannel, mergeClientChannels, channelWriteAllowed, profilePatch, loadTgGroup, saveTgGroup, isHomeChannel, homeAdoptionTarget, resolveSessionTarget, resolveResumeId, resumeTarget, } from "./channels.js";
40
40
  import { deliverWithRetry } from "./reload.js";
41
41
  import { startTelegram, renameTelegramTopic, closeTelegramTopic, probeToken, isStalePreface, announceLoggedOut, resetLoggedOutNotice, attachmentPrompt, pasteFileName, MEDIA_DIR, } from "./telegram.js";
42
+ import { cancelPairingCode, issuePairingCode, pairingStatus } from "./tg-pairing.js";
42
43
  import { migrateTgBindings } from "./channels.js";
43
44
  import { instanceKey } from "./paths.js";
44
45
  import { peerFileFor, loadPeers, savePeers, peerFromToken, signPeerToken, newPeer, withSalts, redeemVerdict, redeemPeer, normPeerName, removePeer, ownedByPeer, peersOutFileFor, agentInvitePrompt, peerScope, } from "./peers.js";
@@ -2728,6 +2729,37 @@ app.put("/telegram", async (req, res) => {
2728
2729
  }
2729
2730
  res.json(await telegramState());
2730
2731
  });
2732
+ // Pairing code for the bot (`src/tg-pairing.ts`): binding the board group or
2733
+ // owning the DMs needs a code only this admin-only panel shows. POST issues a
2734
+ // fresh one (revoking any previous code) and is the ONE response that carries
2735
+ // it; GET reports whether one is live, never the code itself. Browser-only
2736
+ // writes, like the rest of the Telegram config: an agent must not be able to
2737
+ // mint a code and pair a Telegram account of its choosing.
2738
+ app.get("/telegram/pairing", (req, res) => {
2739
+ if (!accountAdmin(req, res, false, "pair the Telegram bot"))
2740
+ return;
2741
+ res.json(pairingStatus());
2742
+ });
2743
+ app.post("/telegram/pairing", async (req, res) => {
2744
+ if (!accountAdmin(req, res, true, "pair the Telegram bot"))
2745
+ return;
2746
+ const p = issuePairingCode();
2747
+ const username = (await telegramState()).username;
2748
+ const bot = username ? String(username).replace(/^@/, "") : null;
2749
+ res.json({
2750
+ code: p.code,
2751
+ expiresAt: p.expiresAt,
2752
+ // Deep links: Telegram delivers `/start <code>` by itself, so one tap pairs.
2753
+ groupLink: bot ? `https://t.me/${bot}?startgroup=${p.code}` : null,
2754
+ dmLink: bot ? `https://t.me/${bot}?start=${p.code}` : null,
2755
+ });
2756
+ });
2757
+ app.delete("/telegram/pairing", (req, res) => {
2758
+ if (!accountAdmin(req, res, true, "pair the Telegram bot"))
2759
+ return;
2760
+ cancelPairingCode();
2761
+ res.json(pairingStatus());
2762
+ });
2731
2763
  const server = http.createServer(app);
2732
2764
  const wss = new WebSocketServer({
2733
2765
  server,