@dreb/telegram 2.34.2 → 2.34.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"buddy.d.ts","sourceRoot":"","sources":["../../src/handlers/buddy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAuC,MAAM,0BAA0B,CAAC;AAChG,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAElC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAM1C,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAmBhD,CAAC;AAUF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAgC1D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAErF;AAMD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC5C,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,GAClB,eAAe,CAwCjB","sourcesContent":["/**\n * Telegram buddy handler — creates and configures a BuddyController\n * with Telegram-specific rendering callbacks and formatting.\n */\n\nimport type { BuddyCallbacks, BuddyState } from \"@dreb/coding-agent/buddy\";\nimport { BuddyController, BuddyManager, STAT_NAMES, type Stat } from \"@dreb/coding-agent/buddy\";\nimport type { Api } from \"grammy\";\nimport { ensureBridgeWithSession } from \"../bridge-lifecycle.js\";\nimport type { Config } from \"../config.js\";\nimport type { UserState } from \"../types.js\";\nimport type { SendFn } from \"./events.js\";\n\n// ---------------------------------------------------------------------------\n// Species emoji mapping\n// ---------------------------------------------------------------------------\n\nexport const SPECIES_EMOJI: Record<string, string> = {\n\tDuck: \"đŸĻ†\",\n\tGoose: \"đŸĒŋ\",\n\tBlob: \"đŸŸĸ\",\n\tCat: \"🐱\",\n\tDragon: \"🐉\",\n\tOctopus: \"🐙\",\n\tOwl: \"đŸĻ‰\",\n\tPenguin: \"🐧\",\n\tTurtle: \"đŸĸ\",\n\tSnail: \"🐌\",\n\tGhost: \"đŸ‘ģ\",\n\tAxolotl: \"đŸĢŽ\",\n\tCapybara: \"đŸĻĢ\",\n\tCactus: \"đŸŒĩ\",\n\tRobot: \"🤖\",\n\tRabbit: \"🐰\",\n\tMushroom: \"🍄\",\n\tChonk: \"🐹\",\n};\n\nfunction speciesEmoji(species: string): string {\n\treturn SPECIES_EMOJI[species] ?? \"đŸŖ\";\n}\n\n// ---------------------------------------------------------------------------\n// Formatting helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Format a stats panel as a Telegram code block.\n * Shows stat bars using █ and ░ characters.\n */\nexport function formatBuddyStats(state: BuddyState): string {\n\tconst emoji = speciesEmoji(state.species);\n\tconst shiny = state.shiny ? \" ✨ SHINY!\" : \"\";\n\tconst maxBar = 10;\n\tconst personality = state.personality.replace(/\\n/g, \" \");\n\tconst backstory = state.backstory.replace(/\\n/g, \" \");\n\tconst hatched = state.hatchedAt ? new Date(state.hatchedAt).toLocaleDateString() : \"unknown\";\n\n\tconst statLines = STAT_NAMES.map((s: string) => {\n\t\tconst value = state.stats[s as Stat];\n\t\tconst filled = Math.round((value / 100) * maxBar);\n\t\tconst bar = \"█\".repeat(filled) + \"░\".repeat(maxBar - filled);\n\t\treturn `│ ${s.padEnd(12)} ${bar} ${value}`;\n\t});\n\n\treturn [\n\t\t`\\`\\`\\``,\n\t\t`╭─ ${emoji} ${state.name} ${shiny} ──────────────────╮`,\n\t\t`│ Species: ${state.species}`,\n\t\t`│ Rarity: ${state.rarity}`,\n\t\t`│ Eyes: ${state.eyeStyle} Hat: ${state.hat || \"none\"}`,\n\t\t`│ Hatched: ${hatched}`,\n\t\t`│ Re-rolls: ${state.rerollCount}`,\n\t\t`│`,\n\t\t`│ Stats:`,\n\t\t...statLines,\n\t\t`│`,\n\t\t`│ Personality: ${personality}`,\n\t\t`│ Backstory: ${backstory}`,\n\t\t`╰──────────────────────────────────╯`,\n\t\t`\\`\\`\\``,\n\t].join(\"\\n\");\n}\n\n/**\n * Format a buddy speech/reaction message.\n */\nexport function formatBuddySpeech(name: string, species: string, text: string): string {\n\treturn `${speciesEmoji(species)} ${name}: \"${text}\"`;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a BuddyController wired up with Telegram-specific callbacks.\n *\n * @param send — outbox send function (enqueueSend) for reliable delivery\n * @param api — grammy Api instance for chat actions and reactions\n * @param chatId — Telegram chat ID for this user\n * @param config — bot config (for bridge resolution in hatch/reroll)\n * @param userState — per-user state (for bridge resolution in hatch/reroll)\n */\nexport function createTelegramBuddyController(\n\tsend: SendFn,\n\tapi: Api,\n\tchatId: number,\n\tconfig: Config,\n\tuserState: UserState,\n): BuddyController {\n\tconst manager = new BuddyManager();\n\n\tconst callbacks: BuddyCallbacks = {\n\t\tonSpeech(text: string): void {\n\t\t\tconst name = manager.getName() ?? \"Buddy\";\n\t\t\tconst state = manager.getState();\n\t\t\tconst species = state?.species ?? \"\";\n\t\t\tsend(formatBuddySpeech(name, species, text));\n\t\t},\n\t\tonThinkingStart(): void {\n\t\t\t// Fire-and-forget typing indicator\n\t\t\tapi.sendChatAction(chatId, \"typing\").catch(() => {});\n\t\t},\n\t\tonThinkingEnd(): void {\n\t\t\t// No-op — can't cancel a chat action in Telegram\n\t\t},\n\t\tasync onHatch(_mgr): Promise<BuddyState> {\n\t\t\tconst bridge = await ensureBridgeWithSession(config, userState);\n\t\t\treturn bridge.buddyHatch();\n\t\t},\n\t\tasync onReroll(_mgr): Promise<BuddyState> {\n\t\t\tconst bridge = await ensureBridgeWithSession(config, userState);\n\t\t\treturn bridge.buddyReroll();\n\t\t},\n\t};\n\n\tconst controller = new BuddyController(manager, callbacks, {\n\t\tidleTimeoutMs: 30_000,\n\t\treactionCooldownMs: 60_000,\n\t\tcontextMaxEntries: 20,\n\t\tactivityGateMs: 7_200_000, // 2 hours\n\t\treactionsPerHour: 3,\n\t});\n\n\t// Auto-load buddy from shared buddy.json (same file TUI uses).\n\t// If a buddy exists and is visible, it'll be active immediately.\n\tcontroller.start();\n\n\treturn controller;\n}\n"]}
1
+ {"version":3,"file":"buddy.d.ts","sourceRoot":"","sources":["../../src/handlers/buddy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAuC,MAAM,0BAA0B,CAAC;AAChG,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAElC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAM1C,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAmBhD,CAAC;AAUF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAgC1D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAErF;AAMD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC5C,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,GAClB,eAAe,CA8CjB","sourcesContent":["/**\n * Telegram buddy handler — creates and configures a BuddyController\n * with Telegram-specific rendering callbacks and formatting.\n */\n\nimport type { BuddyCallbacks, BuddyState } from \"@dreb/coding-agent/buddy\";\nimport { BuddyController, BuddyManager, STAT_NAMES, type Stat } from \"@dreb/coding-agent/buddy\";\nimport type { Api } from \"grammy\";\nimport { ensureBridgeWithSession } from \"../bridge-lifecycle.js\";\nimport type { Config } from \"../config.js\";\nimport type { UserState } from \"../types.js\";\nimport type { SendFn } from \"./events.js\";\n\n// ---------------------------------------------------------------------------\n// Species emoji mapping\n// ---------------------------------------------------------------------------\n\nexport const SPECIES_EMOJI: Record<string, string> = {\n\tDuck: \"đŸĻ†\",\n\tGoose: \"đŸĒŋ\",\n\tBlob: \"đŸŸĸ\",\n\tCat: \"🐱\",\n\tDragon: \"🐉\",\n\tOctopus: \"🐙\",\n\tOwl: \"đŸĻ‰\",\n\tPenguin: \"🐧\",\n\tTurtle: \"đŸĸ\",\n\tSnail: \"🐌\",\n\tGhost: \"đŸ‘ģ\",\n\tAxolotl: \"đŸĢŽ\",\n\tCapybara: \"đŸĻĢ\",\n\tCactus: \"đŸŒĩ\",\n\tRobot: \"🤖\",\n\tRabbit: \"🐰\",\n\tMushroom: \"🍄\",\n\tChonk: \"🐹\",\n};\n\nfunction speciesEmoji(species: string): string {\n\treturn SPECIES_EMOJI[species] ?? \"đŸŖ\";\n}\n\n// ---------------------------------------------------------------------------\n// Formatting helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Format a stats panel as a Telegram code block.\n * Shows stat bars using █ and ░ characters.\n */\nexport function formatBuddyStats(state: BuddyState): string {\n\tconst emoji = speciesEmoji(state.species);\n\tconst shiny = state.shiny ? \" ✨ SHINY!\" : \"\";\n\tconst maxBar = 10;\n\tconst personality = state.personality.replace(/\\n/g, \" \");\n\tconst backstory = state.backstory.replace(/\\n/g, \" \");\n\tconst hatched = state.hatchedAt ? new Date(state.hatchedAt).toLocaleDateString() : \"unknown\";\n\n\tconst statLines = STAT_NAMES.map((s: string) => {\n\t\tconst value = state.stats[s as Stat];\n\t\tconst filled = Math.round((value / 100) * maxBar);\n\t\tconst bar = \"█\".repeat(filled) + \"░\".repeat(maxBar - filled);\n\t\treturn `│ ${s.padEnd(12)} ${bar} ${value}`;\n\t});\n\n\treturn [\n\t\t`\\`\\`\\``,\n\t\t`╭─ ${emoji} ${state.name} ${shiny} ──────────────────╮`,\n\t\t`│ Species: ${state.species}`,\n\t\t`│ Rarity: ${state.rarity}`,\n\t\t`│ Eyes: ${state.eyeStyle} Hat: ${state.hat || \"none\"}`,\n\t\t`│ Hatched: ${hatched}`,\n\t\t`│ Re-rolls: ${state.rerollCount}`,\n\t\t`│`,\n\t\t`│ Stats:`,\n\t\t...statLines,\n\t\t`│`,\n\t\t`│ Personality: ${personality}`,\n\t\t`│ Backstory: ${backstory}`,\n\t\t`╰──────────────────────────────────╯`,\n\t\t`\\`\\`\\``,\n\t].join(\"\\n\");\n}\n\n/**\n * Format a buddy speech/reaction message.\n */\nexport function formatBuddySpeech(name: string, species: string, text: string): string {\n\treturn `${speciesEmoji(species)} ${name}: \"${text}\"`;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a BuddyController wired up with Telegram-specific callbacks.\n *\n * @param send — outbox send function (enqueueSend) for reliable delivery\n * @param api — grammy Api instance for chat actions and reactions\n * @param chatId — Telegram chat ID for this user\n * @param config — bot config (for bridge resolution in hatch/reroll)\n * @param userState — per-user state (for bridge resolution in hatch/reroll)\n */\nexport function createTelegramBuddyController(\n\tsend: SendFn,\n\tapi: Api,\n\tchatId: number,\n\tconfig: Config,\n\tuserState: UserState,\n): BuddyController {\n\tconst manager = new BuddyManager();\n\n\tconst callbacks: BuddyCallbacks = {\n\t\tonSpeech(text: string): void {\n\t\t\tconst name = manager.getName() ?? \"Buddy\";\n\t\t\tconst state = manager.getState();\n\t\t\tconst species = state?.species ?? \"\";\n\t\t\tsend(formatBuddySpeech(name, species, text));\n\t\t},\n\t\tonThinkingStart(): void {\n\t\t\t// Fire-and-forget typing indicator\n\t\t\tapi.sendChatAction(chatId, \"typing\").catch(() => {});\n\t\t},\n\t\tonThinkingEnd(): void {\n\t\t\t// No-op — can't cancel a chat action in Telegram\n\t\t},\n\t\tasync onHatch(_mgr): Promise<BuddyState> {\n\t\t\tconst bridge = await ensureBridgeWithSession(config, userState);\n\t\t\treturn bridge.buddyHatch();\n\t\t},\n\t\tasync onReroll(_mgr): Promise<BuddyState> {\n\t\t\tconst bridge = await ensureBridgeWithSession(config, userState);\n\t\t\treturn bridge.buddyReroll();\n\t\t},\n\t\tonVisibilityChange(_visible: boolean): void {\n\t\t\t// Telegram has no persistent buddy widget — reaction suppression and\n\t\t\t// re-enable already flow from the controller's `enabled` flag, which\n\t\t\t// syncHiddenState() updates from the shared buddy.json. Nothing to\n\t\t\t// mount/unmount here, so this is intentionally a no-op.\n\t\t},\n\t};\n\n\tconst controller = new BuddyController(manager, callbacks, {\n\t\tidleTimeoutMs: 30_000,\n\t\treactionCooldownMs: 60_000,\n\t\tcontextMaxEntries: 20,\n\t\tactivityGateMs: 7_200_000, // 2 hours\n\t\treactionsPerHour: 3,\n\t});\n\n\t// Auto-load buddy from shared buddy.json (same file TUI uses).\n\t// If a buddy exists and is visible, it'll be active immediately.\n\tcontroller.start();\n\n\treturn controller;\n}\n"]}
@@ -110,6 +110,12 @@ export function createTelegramBuddyController(send, api, chatId, config, userSta
110
110
  const bridge = await ensureBridgeWithSession(config, userState);
111
111
  return bridge.buddyReroll();
112
112
  },
113
+ onVisibilityChange(_visible) {
114
+ // Telegram has no persistent buddy widget — reaction suppression and
115
+ // re-enable already flow from the controller's `enabled` flag, which
116
+ // syncHiddenState() updates from the shared buddy.json. Nothing to
117
+ // mount/unmount here, so this is intentionally a no-op.
118
+ },
113
119
  };
114
120
  const controller = new BuddyController(manager, callbacks, {
115
121
  idleTimeoutMs: 30_000,
@@ -1 +1 @@
1
- {"version":3,"file":"buddy.js","sourceRoot":"","sources":["../../src/handlers/buddy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Telegram buddy handler — creates and configures a BuddyController\n * with Telegram-specific rendering callbacks and formatting.\n */\n\nimport type { BuddyCallbacks, BuddyState } from \"@dreb/coding-agent/buddy\";\nimport { BuddyController, BuddyManager, STAT_NAMES, type Stat } from \"@dreb/coding-agent/buddy\";\nimport type { Api } from \"grammy\";\nimport { ensureBridgeWithSession } from \"../bridge-lifecycle.js\";\nimport type { Config } from \"../config.js\";\nimport type { UserState } from \"../types.js\";\nimport type { SendFn } from \"./events.js\";\n\n// ---------------------------------------------------------------------------\n// Species emoji mapping\n// ---------------------------------------------------------------------------\n\nexport const SPECIES_EMOJI: Record<string, string> = {\n\tDuck: \"đŸĻ†\",\n\tGoose: \"đŸĒŋ\",\n\tBlob: \"đŸŸĸ\",\n\tCat: \"🐱\",\n\tDragon: \"🐉\",\n\tOctopus: \"🐙\",\n\tOwl: \"đŸĻ‰\",\n\tPenguin: \"🐧\",\n\tTurtle: \"đŸĸ\",\n\tSnail: \"🐌\",\n\tGhost: \"đŸ‘ģ\",\n\tAxolotl: \"đŸĢŽ\",\n\tCapybara: \"đŸĻĢ\",\n\tCactus: \"đŸŒĩ\",\n\tRobot: \"🤖\",\n\tRabbit: \"🐰\",\n\tMushroom: \"🍄\",\n\tChonk: \"🐹\",\n};\n\nfunction speciesEmoji(species: string): string {\n\treturn SPECIES_EMOJI[species] ?? \"đŸŖ\";\n}\n\n// ---------------------------------------------------------------------------\n// Formatting helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Format a stats panel as a Telegram code block.\n * Shows stat bars using █ and ░ characters.\n */\nexport function formatBuddyStats(state: BuddyState): string {\n\tconst emoji = speciesEmoji(state.species);\n\tconst shiny = state.shiny ? \" ✨ SHINY!\" : \"\";\n\tconst maxBar = 10;\n\tconst personality = state.personality.replace(/\\n/g, \" \");\n\tconst backstory = state.backstory.replace(/\\n/g, \" \");\n\tconst hatched = state.hatchedAt ? new Date(state.hatchedAt).toLocaleDateString() : \"unknown\";\n\n\tconst statLines = STAT_NAMES.map((s: string) => {\n\t\tconst value = state.stats[s as Stat];\n\t\tconst filled = Math.round((value / 100) * maxBar);\n\t\tconst bar = \"█\".repeat(filled) + \"░\".repeat(maxBar - filled);\n\t\treturn `│ ${s.padEnd(12)} ${bar} ${value}`;\n\t});\n\n\treturn [\n\t\t`\\`\\`\\``,\n\t\t`╭─ ${emoji} ${state.name} ${shiny} ──────────────────╮`,\n\t\t`│ Species: ${state.species}`,\n\t\t`│ Rarity: ${state.rarity}`,\n\t\t`│ Eyes: ${state.eyeStyle} Hat: ${state.hat || \"none\"}`,\n\t\t`│ Hatched: ${hatched}`,\n\t\t`│ Re-rolls: ${state.rerollCount}`,\n\t\t`│`,\n\t\t`│ Stats:`,\n\t\t...statLines,\n\t\t`│`,\n\t\t`│ Personality: ${personality}`,\n\t\t`│ Backstory: ${backstory}`,\n\t\t`╰──────────────────────────────────╯`,\n\t\t`\\`\\`\\``,\n\t].join(\"\\n\");\n}\n\n/**\n * Format a buddy speech/reaction message.\n */\nexport function formatBuddySpeech(name: string, species: string, text: string): string {\n\treturn `${speciesEmoji(species)} ${name}: \"${text}\"`;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a BuddyController wired up with Telegram-specific callbacks.\n *\n * @param send — outbox send function (enqueueSend) for reliable delivery\n * @param api — grammy Api instance for chat actions and reactions\n * @param chatId — Telegram chat ID for this user\n * @param config — bot config (for bridge resolution in hatch/reroll)\n * @param userState — per-user state (for bridge resolution in hatch/reroll)\n */\nexport function createTelegramBuddyController(\n\tsend: SendFn,\n\tapi: Api,\n\tchatId: number,\n\tconfig: Config,\n\tuserState: UserState,\n): BuddyController {\n\tconst manager = new BuddyManager();\n\n\tconst callbacks: BuddyCallbacks = {\n\t\tonSpeech(text: string): void {\n\t\t\tconst name = manager.getName() ?? \"Buddy\";\n\t\t\tconst state = manager.getState();\n\t\t\tconst species = state?.species ?? \"\";\n\t\t\tsend(formatBuddySpeech(name, species, text));\n\t\t},\n\t\tonThinkingStart(): void {\n\t\t\t// Fire-and-forget typing indicator\n\t\t\tapi.sendChatAction(chatId, \"typing\").catch(() => {});\n\t\t},\n\t\tonThinkingEnd(): void {\n\t\t\t// No-op — can't cancel a chat action in Telegram\n\t\t},\n\t\tasync onHatch(_mgr): Promise<BuddyState> {\n\t\t\tconst bridge = await ensureBridgeWithSession(config, userState);\n\t\t\treturn bridge.buddyHatch();\n\t\t},\n\t\tasync onReroll(_mgr): Promise<BuddyState> {\n\t\t\tconst bridge = await ensureBridgeWithSession(config, userState);\n\t\t\treturn bridge.buddyReroll();\n\t\t},\n\t};\n\n\tconst controller = new BuddyController(manager, callbacks, {\n\t\tidleTimeoutMs: 30_000,\n\t\treactionCooldownMs: 60_000,\n\t\tcontextMaxEntries: 20,\n\t\tactivityGateMs: 7_200_000, // 2 hours\n\t\treactionsPerHour: 3,\n\t});\n\n\t// Auto-load buddy from shared buddy.json (same file TUI uses).\n\t// If a buddy exists and is visible, it'll be active immediately.\n\tcontroller.start();\n\n\treturn controller;\n}\n"]}
1
+ {"version":3,"file":"buddy.js","sourceRoot":"","sources":["../../src/handlers/buddy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Telegram buddy handler — creates and configures a BuddyController\n * with Telegram-specific rendering callbacks and formatting.\n */\n\nimport type { BuddyCallbacks, BuddyState } from \"@dreb/coding-agent/buddy\";\nimport { BuddyController, BuddyManager, STAT_NAMES, type Stat } from \"@dreb/coding-agent/buddy\";\nimport type { Api } from \"grammy\";\nimport { ensureBridgeWithSession } from \"../bridge-lifecycle.js\";\nimport type { Config } from \"../config.js\";\nimport type { UserState } from \"../types.js\";\nimport type { SendFn } from \"./events.js\";\n\n// ---------------------------------------------------------------------------\n// Species emoji mapping\n// ---------------------------------------------------------------------------\n\nexport const SPECIES_EMOJI: Record<string, string> = {\n\tDuck: \"đŸĻ†\",\n\tGoose: \"đŸĒŋ\",\n\tBlob: \"đŸŸĸ\",\n\tCat: \"🐱\",\n\tDragon: \"🐉\",\n\tOctopus: \"🐙\",\n\tOwl: \"đŸĻ‰\",\n\tPenguin: \"🐧\",\n\tTurtle: \"đŸĸ\",\n\tSnail: \"🐌\",\n\tGhost: \"đŸ‘ģ\",\n\tAxolotl: \"đŸĢŽ\",\n\tCapybara: \"đŸĻĢ\",\n\tCactus: \"đŸŒĩ\",\n\tRobot: \"🤖\",\n\tRabbit: \"🐰\",\n\tMushroom: \"🍄\",\n\tChonk: \"🐹\",\n};\n\nfunction speciesEmoji(species: string): string {\n\treturn SPECIES_EMOJI[species] ?? \"đŸŖ\";\n}\n\n// ---------------------------------------------------------------------------\n// Formatting helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Format a stats panel as a Telegram code block.\n * Shows stat bars using █ and ░ characters.\n */\nexport function formatBuddyStats(state: BuddyState): string {\n\tconst emoji = speciesEmoji(state.species);\n\tconst shiny = state.shiny ? \" ✨ SHINY!\" : \"\";\n\tconst maxBar = 10;\n\tconst personality = state.personality.replace(/\\n/g, \" \");\n\tconst backstory = state.backstory.replace(/\\n/g, \" \");\n\tconst hatched = state.hatchedAt ? new Date(state.hatchedAt).toLocaleDateString() : \"unknown\";\n\n\tconst statLines = STAT_NAMES.map((s: string) => {\n\t\tconst value = state.stats[s as Stat];\n\t\tconst filled = Math.round((value / 100) * maxBar);\n\t\tconst bar = \"█\".repeat(filled) + \"░\".repeat(maxBar - filled);\n\t\treturn `│ ${s.padEnd(12)} ${bar} ${value}`;\n\t});\n\n\treturn [\n\t\t`\\`\\`\\``,\n\t\t`╭─ ${emoji} ${state.name} ${shiny} ──────────────────╮`,\n\t\t`│ Species: ${state.species}`,\n\t\t`│ Rarity: ${state.rarity}`,\n\t\t`│ Eyes: ${state.eyeStyle} Hat: ${state.hat || \"none\"}`,\n\t\t`│ Hatched: ${hatched}`,\n\t\t`│ Re-rolls: ${state.rerollCount}`,\n\t\t`│`,\n\t\t`│ Stats:`,\n\t\t...statLines,\n\t\t`│`,\n\t\t`│ Personality: ${personality}`,\n\t\t`│ Backstory: ${backstory}`,\n\t\t`╰──────────────────────────────────╯`,\n\t\t`\\`\\`\\``,\n\t].join(\"\\n\");\n}\n\n/**\n * Format a buddy speech/reaction message.\n */\nexport function formatBuddySpeech(name: string, species: string, text: string): string {\n\treturn `${speciesEmoji(species)} ${name}: \"${text}\"`;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a BuddyController wired up with Telegram-specific callbacks.\n *\n * @param send — outbox send function (enqueueSend) for reliable delivery\n * @param api — grammy Api instance for chat actions and reactions\n * @param chatId — Telegram chat ID for this user\n * @param config — bot config (for bridge resolution in hatch/reroll)\n * @param userState — per-user state (for bridge resolution in hatch/reroll)\n */\nexport function createTelegramBuddyController(\n\tsend: SendFn,\n\tapi: Api,\n\tchatId: number,\n\tconfig: Config,\n\tuserState: UserState,\n): BuddyController {\n\tconst manager = new BuddyManager();\n\n\tconst callbacks: BuddyCallbacks = {\n\t\tonSpeech(text: string): void {\n\t\t\tconst name = manager.getName() ?? \"Buddy\";\n\t\t\tconst state = manager.getState();\n\t\t\tconst species = state?.species ?? \"\";\n\t\t\tsend(formatBuddySpeech(name, species, text));\n\t\t},\n\t\tonThinkingStart(): void {\n\t\t\t// Fire-and-forget typing indicator\n\t\t\tapi.sendChatAction(chatId, \"typing\").catch(() => {});\n\t\t},\n\t\tonThinkingEnd(): void {\n\t\t\t// No-op — can't cancel a chat action in Telegram\n\t\t},\n\t\tasync onHatch(_mgr): Promise<BuddyState> {\n\t\t\tconst bridge = await ensureBridgeWithSession(config, userState);\n\t\t\treturn bridge.buddyHatch();\n\t\t},\n\t\tasync onReroll(_mgr): Promise<BuddyState> {\n\t\t\tconst bridge = await ensureBridgeWithSession(config, userState);\n\t\t\treturn bridge.buddyReroll();\n\t\t},\n\t\tonVisibilityChange(_visible: boolean): void {\n\t\t\t// Telegram has no persistent buddy widget — reaction suppression and\n\t\t\t// re-enable already flow from the controller's `enabled` flag, which\n\t\t\t// syncHiddenState() updates from the shared buddy.json. Nothing to\n\t\t\t// mount/unmount here, so this is intentionally a no-op.\n\t\t},\n\t};\n\n\tconst controller = new BuddyController(manager, callbacks, {\n\t\tidleTimeoutMs: 30_000,\n\t\treactionCooldownMs: 60_000,\n\t\tcontextMaxEntries: 20,\n\t\tactivityGateMs: 7_200_000, // 2 hours\n\t\treactionsPerHour: 3,\n\t});\n\n\t// Auto-load buddy from shared buddy.json (same file TUI uses).\n\t// If a buddy exists and is visible, it'll be active immediately.\n\tcontroller.start();\n\n\treturn controller;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreb/telegram",
3
- "version": "2.34.2",
3
+ "version": "2.34.3",
4
4
  "description": "Telegram bot frontend for dreb coding agent",
5
5
  "license": "MIT",
6
6
  "type": "module",