@tritard/waterbrother 0.16.93 → 0.16.95

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/gateway.js +47 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tritard/waterbrother",
3
- "version": "0.16.93",
3
+ "version": "0.16.95",
4
4
  "description": "Waterbrother: bring-your-own-model coding CLI with local tools, sessions, operator modes, and approval controls",
5
5
  "type": "module",
6
6
  "bin": {
package/src/gateway.js CHANGED
@@ -342,8 +342,10 @@ function buildTelegramRoomGuidanceMarkup({ project = null, member = null, execut
342
342
 
343
343
  function buildTelegramAgentAnnouncementMarkup(event = {}) {
344
344
  const meta = event?.meta && typeof event.meta === "object" ? event.meta : {};
345
- const ownerName = String(meta.ownerName || "").trim() || String(meta.ownerId || "").trim() || "unknown";
346
- const label = String(meta.label || meta.agentId || "").trim() || "terminal";
345
+ const rawOwnerName = String(meta.ownerName || "").trim() || String(meta.ownerId || "").trim();
346
+ const rawLabel = String(meta.label || meta.agentId || "").trim();
347
+ const ownerName = rawOwnerName && !/^unknown$/i.test(rawOwnerName) ? rawOwnerName : "this room";
348
+ const label = rawLabel && !/\bundefined\b/i.test(rawLabel) ? rawLabel : (ownerName !== "this room" ? `${ownerName} terminal` : "live terminal");
347
349
  const runtime = meta.provider && meta.model ? `${meta.provider}/${meta.model}` : "";
348
350
  const title = meta.isNew ? "Roundtable terminal joined" : "Roundtable terminal updated";
349
351
  const role = String(meta.role || "standby").trim() || "standby";
@@ -361,7 +363,7 @@ function buildTelegramAgentAnnouncementMarkup(event = {}) {
361
363
  runtime ? `runtime: <code>${escapeTelegramHtml(runtime)}</code>` : "",
362
364
  meta.runtimeProfile ? `runtime profile: <code>${escapeTelegramHtml(String(meta.runtimeProfile || ""))}</code>` : "",
363
365
  roleGuidance,
364
- "Examples: <code>which terminals are live?</code>, <code>have Austin's bot be reviewer</code>, <code>have Phillip's bot take execution</code>"
366
+ "Examples: <code>which terminals are live?</code>, <code>make this terminal the reviewer</code>, <code>make this terminal the executor</code>"
365
367
  ].filter(Boolean).join("\n");
366
368
  }
367
369
 
@@ -786,6 +788,9 @@ function parseTelegramStateIntent(text = "") {
786
788
  const lower = value.toLowerCase();
787
789
  if (!value) return null;
788
790
 
791
+ if (/^(?:hi|hello|hey|yo|sup|suh|wazzup|whazzup|what'?s up|whats up|how are you)\b.*$/i.test(value)) {
792
+ return { action: "bot-greeting" };
793
+ }
789
794
  if (/^(?:are you|you(?:'re| are)?|wb|waterbrother)\s+(?:online|running|alive|there)\??$/.test(lower)
790
795
  || /^(?:you online|you running|you there)\??$/.test(lower)
791
796
  || /^(?:are you online|are you running|are you there)\??$/.test(lower)) {
@@ -1609,13 +1614,38 @@ class TelegramGateway {
1609
1614
  if (String(project?.room?.chatId || "").trim() !== String(message?.chat?.id || "").trim()) return;
1610
1615
  const events = Array.isArray(project.recentEvents) ? project.recentEvents : [];
1611
1616
  const announced = new Set(Array.isArray(this.state.announcedEvents) ? this.state.announcedEvents : []);
1617
+ const agents = listProjectAgents(project);
1618
+ const freshThresholdMs = 2 * 60 * 1000;
1619
+ const now = Date.now();
1612
1620
  const pending = events
1613
1621
  .filter((event) => String(event?.type || "").trim() === "agent-upsert")
1614
1622
  .filter((event) => event?.id && !announced.has(String(event.id)))
1623
+ .filter((event) => {
1624
+ const createdAtMs = Date.parse(String(event?.createdAt || "").trim());
1625
+ return Number.isFinite(createdAtMs) ? now - createdAtMs <= freshThresholdMs : true;
1626
+ })
1615
1627
  .slice(-3);
1616
1628
  if (!pending.length) return;
1617
1629
  for (const event of pending) {
1618
- await this.sendMarkup(message.chat.id, buildTelegramAgentAnnouncementMarkup(event), message.message_id);
1630
+ const meta = event?.meta && typeof event.meta === "object" ? { ...event.meta } : {};
1631
+ const agent = agents.find((item) => String(item?.id || "").trim() === String(meta.agentId || "").trim()) || null;
1632
+ const enrichedEvent = agent
1633
+ ? {
1634
+ ...event,
1635
+ meta: {
1636
+ ...meta,
1637
+ ownerId: String(meta.ownerId || agent.ownerId || "").trim(),
1638
+ ownerName: String(meta.ownerName || agent.ownerName || "").trim(),
1639
+ label: String(meta.label || agent.label || "").trim(),
1640
+ role: String(meta.role || agent.role || "").trim(),
1641
+ surface: String(meta.surface || agent.surface || "").trim(),
1642
+ provider: String(meta.provider || agent.provider || "").trim(),
1643
+ model: String(meta.model || agent.model || "").trim(),
1644
+ runtimeProfile: String(meta.runtimeProfile || agent.runtimeProfile || "").trim()
1645
+ }
1646
+ }
1647
+ : event;
1648
+ await this.sendMarkup(message.chat.id, buildTelegramAgentAnnouncementMarkup(enrichedEvent), message.message_id);
1619
1649
  announced.add(String(event.id));
1620
1650
  }
1621
1651
  this.state.announcedEvents = [...announced].slice(-100);
@@ -2208,6 +2238,18 @@ class TelegramGateway {
2208
2238
  return lines.join("\n");
2209
2239
  }
2210
2240
 
2241
+ if (intent.action === "bot-greeting") {
2242
+ return [
2243
+ "<b>Waterbrother</b>",
2244
+ "I’m here.",
2245
+ `room mode: <code>${escapeTelegramHtml(project?.enabled ? (project.roomMode || "chat") : "off")}</code>`,
2246
+ project?.activeOperator?.id
2247
+ ? `active operator: <code>${escapeTelegramHtml(project.activeOperator.name || project.activeOperator.id)}</code>`
2248
+ : "active operator: <code>none</code>",
2249
+ "Ask a question, discuss a plan, or give me a task when you want me to act."
2250
+ ].join("\n");
2251
+ }
2252
+
2211
2253
  if (intent.action === "accept-reviewer-concerns") {
2212
2254
  if (!project?.enabled) {
2213
2255
  return "This project is not shared.";
@@ -3940,6 +3982,7 @@ Ask them to run <code>/whoami</code> and then <code>/accept-invite ${escapeTeleg
3940
3982
  return;
3941
3983
  }
3942
3984
  }
3985
+ const stateIntent = parseTelegramStateIntent(promptText);
3943
3986
  const groupIntent = this.isGroupChat(message)
3944
3987
  ? (isExplicitRun
3945
3988
  ? { kind: "execution", reason: "explicit /run" }
@@ -3949,7 +3992,6 @@ Ask them to run <code>/whoami</code> and then <code>/accept-invite ${escapeTeleg
3949
3992
  : { kind: "execution", reason: "private chat" };
3950
3993
  const shouldExecutePrompt = !this.isGroupChat(message) || groupIntent.kind === "execution";
3951
3994
  const sharedBinding = await this.bindSharedRoomForMessage(message, sessionId);
3952
- const stateIntent = !shouldExecutePrompt ? parseTelegramStateIntent(promptText) : null;
3953
3995
  if (stateIntent) {
3954
3996
  try {
3955
3997
  const markup = await this.handleStateIntent(message, sessionId, stateIntent);