@tritard/waterbrother 0.16.84 → 0.16.85

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 +104 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tritard/waterbrother",
3
- "version": "0.16.84",
3
+ "version": "0.16.85",
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
@@ -540,6 +540,14 @@ function getLatestBlockingReviewPolicy(project) {
540
540
  return null;
541
541
  }
542
542
 
543
+ function getLatestReviewResult(project) {
544
+ const events = Array.isArray(project?.recentEvents) ? [...project.recentEvents] : [];
545
+ const ordered = events
546
+ .filter((event) => event?.createdAt)
547
+ .sort((a, b) => String(b.createdAt || "").localeCompare(String(a.createdAt || "")));
548
+ return ordered.find((event) => String(event?.type || "").trim() === "review-result") || null;
549
+ }
550
+
543
551
  function memberRoleWeight(role = "") {
544
552
  const normalized = String(role || "").trim().toLowerCase();
545
553
  if (normalized === "owner") return 3;
@@ -817,6 +825,16 @@ function parseTelegramStateIntent(text = "") {
817
825
  return { action: "member-status", target: memberMatch[1].trim() };
818
826
  }
819
827
 
828
+ if (/\baccept reviewer concerns\b/.test(lower) || /\baccept the reviewer'?s concerns\b/.test(lower)) {
829
+ return { action: "accept-reviewer-concerns" };
830
+ }
831
+ if (/\boverride reviewer\b/.test(lower) || /\boverride the reviewer\b/.test(lower)) {
832
+ return { action: "override-reviewer" };
833
+ }
834
+ if (/\bswitch executor to reviewer\b/.test(lower) || /\bmake reviewer the executor\b/.test(lower) || /\buse reviewer as executor\b/.test(lower)) {
835
+ return { action: "switch-executor-to-reviewer" };
836
+ }
837
+
820
838
  return null;
821
839
  }
822
840
 
@@ -2138,6 +2156,8 @@ class TelegramGateway {
2138
2156
  const { session, project } = await this.bindSharedRoomForMessage(message, sessionId);
2139
2157
  const cwd = session.cwd || this.cwd;
2140
2158
  const known = this.listKnownChatPeople(message);
2159
+ const actorId = String(message?.from?.id || "").trim();
2160
+ const actorName = this.describeTelegramUser(message?.from || {}).displayName || actorId;
2141
2161
  const host = await this.getLiveBridgeHost();
2142
2162
  const executor = {
2143
2163
  surface: host?.surface || (host ? "live-tui" : "telegram-fallback"),
@@ -2147,6 +2167,90 @@ class TelegramGateway {
2147
2167
  hostSessionId: host?.sessionId || ""
2148
2168
  };
2149
2169
 
2170
+ if (intent.action === "accept-reviewer-concerns") {
2171
+ if (!project?.enabled) {
2172
+ return "This project is not shared.";
2173
+ }
2174
+ const result = getLatestReviewResult(project);
2175
+ if (!result) {
2176
+ return "<b>Reviewer concerns</b>\nNo reviewer result is on record yet.";
2177
+ }
2178
+ const meta = result.meta && typeof result.meta === "object" ? result.meta : {};
2179
+ if (String(meta.outcome || "").trim() !== "concerns") {
2180
+ return "<b>Reviewer concerns</b>\nThe latest reviewer result is not concerns.";
2181
+ }
2182
+ await addSharedRoomNote(cwd, "Reviewer concerns accepted; revise before continuing", {
2183
+ actorId,
2184
+ actorName,
2185
+ type: "review-concerns-accepted",
2186
+ meta: {
2187
+ agentId: String(meta.agentId || "").trim()
2188
+ }
2189
+ });
2190
+ await addSharedRoomNote(cwd, "Blocking review cleared after reviewer concerns were accepted", {
2191
+ actorId,
2192
+ actorName,
2193
+ type: "review-policy-cleared",
2194
+ meta: {
2195
+ agentId: String(meta.agentId || "").trim()
2196
+ }
2197
+ });
2198
+ return [
2199
+ "<b>Reviewer concerns accepted</b>",
2200
+ "The room accepted the reviewer concerns.",
2201
+ "Blocking review has been cleared so the team can revise and continue."
2202
+ ].join("\n");
2203
+ }
2204
+
2205
+ if (intent.action === "override-reviewer") {
2206
+ if (!project?.enabled) {
2207
+ return "This project is not shared.";
2208
+ }
2209
+ const result = getLatestReviewResult(project);
2210
+ const meta = result?.meta && typeof result.meta === "object" ? result.meta : {};
2211
+ await addSharedRoomNote(cwd, "Reviewer outcome overridden by the room", {
2212
+ actorId,
2213
+ actorName,
2214
+ type: "review-policy-override",
2215
+ meta: {
2216
+ agentId: String(meta.agentId || "").trim()
2217
+ }
2218
+ });
2219
+ return [
2220
+ "<b>Reviewer overridden</b>",
2221
+ "The room overrode the reviewer outcome.",
2222
+ "Execution may proceed."
2223
+ ].join("\n");
2224
+ }
2225
+
2226
+ if (intent.action === "switch-executor-to-reviewer") {
2227
+ if (!project?.enabled) {
2228
+ return "This project is not shared.";
2229
+ }
2230
+ const reviewer = chooseReviewerAgent(project);
2231
+ if (!reviewer) {
2232
+ return "<b>Executor switch</b>\nNo reviewer is assigned.";
2233
+ }
2234
+ const currentExecutor = chooseExecutorAgent(project, executor);
2235
+ if (currentExecutor?.id && currentExecutor.id !== reviewer.id) {
2236
+ await upsertSharedAgent(cwd, { ...currentExecutor, role: "standby" }, { actorId, actorName });
2237
+ }
2238
+ await upsertSharedAgent(cwd, { ...reviewer, role: "executor" }, { actorId, actorName });
2239
+ await addSharedRoomNote(cwd, `${reviewer.ownerName || reviewer.label || reviewer.ownerId || "Reviewer"} is now the executor`, {
2240
+ actorId,
2241
+ actorName,
2242
+ type: "executor-handoff-reassigned",
2243
+ meta: {
2244
+ currentAgentId: String(reviewer.id || "").trim()
2245
+ }
2246
+ });
2247
+ return [
2248
+ "<b>Executor switched</b>",
2249
+ `executor: <code>${escapeTelegramHtml(reviewer.ownerName || reviewer.label || reviewer.ownerId || reviewer.id || "reviewer")}</code>`,
2250
+ "The reviewer is now the selected executor."
2251
+ ].join("\n");
2252
+ }
2253
+
2150
2254
  if (intent.action === "project-status") {
2151
2255
  return formatTelegramSummaryMarkup({
2152
2256
  cwd,