@tritard/waterbrother 0.16.74 → 0.16.75

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 +98 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tritard/waterbrother",
3
- "version": "0.16.74",
3
+ "version": "0.16.75",
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
@@ -419,6 +419,28 @@ function chooseExecutorAgent(project, fallbackExecutor = {}) {
419
419
  return null;
420
420
  }
421
421
 
422
+ function getLatestBlockingReviewPolicy(project) {
423
+ const events = Array.isArray(project?.recentEvents) ? [...project.recentEvents] : [];
424
+ const ordered = events
425
+ .filter((event) => event?.createdAt)
426
+ .sort((a, b) => String(b.createdAt || "").localeCompare(String(a.createdAt || "")));
427
+ const resolvedAgents = new Set();
428
+ for (const event of ordered) {
429
+ const type = String(event?.type || "").trim();
430
+ const meta = event?.meta && typeof event.meta === "object" ? event.meta : {};
431
+ const agentId = String(meta.agentId || "").trim();
432
+ if (!agentId) continue;
433
+ if (type === "review-policy-cleared" || type === "review-policy-override") {
434
+ resolvedAgents.add(agentId);
435
+ continue;
436
+ }
437
+ if (type === "review-policy" && String(meta.policy || "").trim() === "blocking" && !resolvedAgents.has(agentId)) {
438
+ return event;
439
+ }
440
+ }
441
+ return null;
442
+ }
443
+
422
444
  function memberRoleWeight(role = "") {
423
445
  const normalized = String(role || "").trim().toLowerCase();
424
446
  if (normalized === "owner") return 3;
@@ -1778,6 +1800,56 @@ class TelegramGateway {
1778
1800
  ].join("\n")
1779
1801
  };
1780
1802
  }
1803
+ if (continuation.kind === "blocking-review-override") {
1804
+ const reply = this.stripBotMention(String(message?.text || "").trim()).toLowerCase();
1805
+ const actorId = String(message?.from?.id || "").trim();
1806
+ const actorName = peer?.username || [message?.from?.first_name, message?.from?.last_name].filter(Boolean).join(" ").trim() || actorId;
1807
+ const session = await loadSession(sessionId);
1808
+ if (/\boverride\b/.test(reply)) {
1809
+ await addSharedRoomNote(session.cwd || this.cwd, `${continuation.context?.ownerName || "Assigned"} blocking review overridden for now`, {
1810
+ actorId,
1811
+ actorName,
1812
+ type: "review-policy-override",
1813
+ meta: {
1814
+ agentId: String(continuation.context?.agentId || "").trim()
1815
+ }
1816
+ });
1817
+ return {
1818
+ markup: [
1819
+ "<b>Blocking review overridden</b>",
1820
+ `reviewer: <code>${escapeTelegramHtml(continuation.context?.ownerName || "unknown")}</code>`,
1821
+ "Execution can proceed for now."
1822
+ ].join("\n")
1823
+ };
1824
+ }
1825
+ if (/\breviewed\b/.test(reply) || /\bdone\b/.test(reply) || /\bcomplete\b/.test(reply)) {
1826
+ await addSharedRoomNote(session.cwd || this.cwd, `${continuation.context?.ownerName || "Assigned"} blocking review marked complete`, {
1827
+ actorId,
1828
+ actorName,
1829
+ type: "review-policy-cleared",
1830
+ meta: {
1831
+ agentId: String(continuation.context?.agentId || "").trim()
1832
+ }
1833
+ });
1834
+ return {
1835
+ markup: [
1836
+ "<b>Blocking review cleared</b>",
1837
+ `reviewer: <code>${escapeTelegramHtml(continuation.context?.ownerName || "unknown")}</code>`,
1838
+ "Execution can proceed."
1839
+ ].join("\n")
1840
+ };
1841
+ }
1842
+ return {
1843
+ markup: "Reply with <code>override</code> to proceed anyway, or <code>reviewed</code> after the blocking review is complete.",
1844
+ remember: {
1845
+ text: String(continuation.lastPrompt || "").trim() || "Reply with override or reviewed.",
1846
+ kind: continuation.kind,
1847
+ source: continuation.source,
1848
+ context: continuation.context || {},
1849
+ force: true
1850
+ }
1851
+ };
1852
+ }
1781
1853
  return null;
1782
1854
  }
1783
1855
 
@@ -3467,6 +3539,32 @@ Ask them to run <code>/whoami</code> and then <code>/accept-invite ${escapeTeleg
3467
3539
  await this.sendMessage(message.chat.id, escapeTelegramHtml(gateReason), message.message_id, { parseMode: "HTML" });
3468
3540
  return;
3469
3541
  }
3542
+ const blockingReview = getLatestBlockingReviewPolicy(operatorGate.project);
3543
+ if (blockingReview) {
3544
+ const meta = blockingReview.meta && typeof blockingReview.meta === "object" ? blockingReview.meta : {};
3545
+ const reviewerName = String(meta.ownerName || meta.agentId || "assigned reviewer").trim();
3546
+ const followUp = `Blocking review is assigned to ${reviewerName}. Reply with override to proceed anyway, or reviewed when the review is done.`;
3547
+ await this.sendMarkup(
3548
+ message.chat.id,
3549
+ [
3550
+ "<b>Blocking review in effect</b>",
3551
+ `reviewer: <code>${escapeTelegramHtml(reviewerName)}</code>`,
3552
+ "Execution is paused until the blocking review is cleared or overridden.",
3553
+ followUp
3554
+ ].join("\n"),
3555
+ message.message_id
3556
+ );
3557
+ await this.rememberContinuationWithOptions(message, followUp, {
3558
+ kind: "blocking-review-override",
3559
+ source: "review-policy-gate",
3560
+ context: {
3561
+ agentId: String(meta.agentId || "").trim(),
3562
+ ownerName: reviewerName
3563
+ },
3564
+ force: true
3565
+ });
3566
+ return;
3567
+ }
3470
3568
  previewMessage = await this.sendProgressMessage(message.chat.id, message.message_id);
3471
3569
  const content = (await this.runPromptViaBridge(message, sessionId, promptText, { explicitExecution: shouldExecutePrompt }))
3472
3570
  ?? (await this.runPromptFallback(sessionId, promptText));