@tritard/waterbrother 0.16.108 → 0.16.110
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/package.json +1 -1
- package/src/gateway.js +155 -2
package/package.json
CHANGED
package/src/gateway.js
CHANGED
|
@@ -646,6 +646,36 @@ function getLatestReviewResult(project) {
|
|
|
646
646
|
return ordered.find((event) => String(event?.type || "").trim() === "review-result") || null;
|
|
647
647
|
}
|
|
648
648
|
|
|
649
|
+
function getBlockingVerificationResult(project) {
|
|
650
|
+
if (String(project?.verificationMode || "manual").trim() !== "blocking") {
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
653
|
+
const latestResult = getLatestVerificationResult(project);
|
|
654
|
+
const latestId = String(latestResult?.id || "").trim();
|
|
655
|
+
const latestOutcome = String(latestResult?.outcome || "").trim().toLowerCase();
|
|
656
|
+
if (!latestId || !latestOutcome || latestOutcome === "passed") {
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
const events = Array.isArray(project?.recentEvents) ? [...project.recentEvents] : [];
|
|
660
|
+
const ordered = events
|
|
661
|
+
.filter((event) => event?.createdAt)
|
|
662
|
+
.sort((a, b) => String(b.createdAt || "").localeCompare(String(a.createdAt || "")));
|
|
663
|
+
for (const event of ordered) {
|
|
664
|
+
const type = String(event?.type || "").trim();
|
|
665
|
+
const meta = event?.meta && typeof event.meta === "object" ? event.meta : {};
|
|
666
|
+
if (String(meta.verificationResultId || "").trim() !== latestId) {
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
if (type === "verification-override") {
|
|
670
|
+
return null;
|
|
671
|
+
}
|
|
672
|
+
if (type === "verification-result") {
|
|
673
|
+
return latestResult;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return latestResult;
|
|
677
|
+
}
|
|
678
|
+
|
|
649
679
|
function memberRoleWeight(role = "") {
|
|
650
680
|
const normalized = String(role || "").trim().toLowerCase();
|
|
651
681
|
if (normalized === "owner") return 3;
|
|
@@ -862,7 +892,9 @@ function parseTelegramAgentIntent(text = "") {
|
|
|
862
892
|
/^(?:have|make|set)\s+(.+?)['’]s\s+(?:bot|terminal)\s+(?:be|as|to)?\s*(?:the\s+)?(executor|reviewer|verifier|standby)\s*$/i,
|
|
863
893
|
/^(?:have|make|set)\s+(.+?)\s+(?:bot|terminal)\s+(?:be|as|to)?\s*(?:the\s+)?(executor|reviewer|verifier|standby)\s*$/i,
|
|
864
894
|
/^(.+?)['’]s\s+(?:bot|terminal)\s+should\s+(?:be\s+)?(?:the\s+)?(executor|reviewer|verifier|standby)\s*$/i,
|
|
865
|
-
/^(.+?)\s+(?:bot|terminal)\s+should\s+(?:be\s+)?(?:the\s+)?(executor|reviewer|verifier|standby)\s*$/i
|
|
895
|
+
/^(.+?)\s+(?:bot|terminal)\s+should\s+(?:be\s+)?(?:the\s+)?(executor|reviewer|verifier|standby)\s*$/i,
|
|
896
|
+
/^(?:have|make|set)\s+(.+?)\s+(?:be|as|to)?\s*(?:the\s+)?(executor|reviewer|verifier|standby)\s*$/i,
|
|
897
|
+
/^(.+?)\s+should\s+(?:be\s+)?(?:the\s+)?(executor|reviewer|verifier|standby)\s*$/i
|
|
866
898
|
];
|
|
867
899
|
for (const pattern of patterns) {
|
|
868
900
|
const match = value.match(pattern);
|
|
@@ -914,6 +946,12 @@ function parseTelegramStateIntent(text = "") {
|
|
|
914
946
|
if (/^(?:run|start|do)\s+verification\b/.test(lower) || /^(?:verify)\b/.test(lower) || /\bshow latest verification result\b/.test(lower) || /\bdid verification pass\b/.test(lower)) {
|
|
915
947
|
return { action: /\bshow latest verification result\b/.test(lower) || /\bdid verification pass\b/.test(lower) ? "verification-status" : "run-verification" };
|
|
916
948
|
}
|
|
949
|
+
if (/\boverride verification\b/.test(lower)) {
|
|
950
|
+
return { action: "verification-override" };
|
|
951
|
+
}
|
|
952
|
+
if (/\bre-?run verification\b/.test(lower) || /\brun verification again\b/.test(lower) || /\bverify again\b/.test(lower)) {
|
|
953
|
+
return { action: "verification-rerun" };
|
|
954
|
+
}
|
|
917
955
|
if (/\bverification mode\b/.test(lower)) {
|
|
918
956
|
const modeMatch = lower.match(/\b(off|manual|auto|blocking)\b/);
|
|
919
957
|
return modeMatch?.[1] ? { action: "verification-mode-set", mode: modeMatch[1] } : { action: "verification-mode-status" };
|
|
@@ -2433,6 +2471,29 @@ class TelegramGateway {
|
|
|
2433
2471
|
}
|
|
2434
2472
|
};
|
|
2435
2473
|
}
|
|
2474
|
+
if (continuation.kind === "blocking-verification-override") {
|
|
2475
|
+
const reply = this.stripBotMention(String(message?.text || "").trim()).toLowerCase();
|
|
2476
|
+
if (/\boverride verification\b/.test(reply) || /\boverride\b/.test(reply)) {
|
|
2477
|
+
return {
|
|
2478
|
+
markup: await this.handleStateIntent(message, sessionId, { action: "verification-override" })
|
|
2479
|
+
};
|
|
2480
|
+
}
|
|
2481
|
+
if (/\bre-?run verification\b/.test(reply) || /\brerun\b/.test(reply) || /\bverify again\b/.test(reply)) {
|
|
2482
|
+
return {
|
|
2483
|
+
markup: await this.handleStateIntent(message, sessionId, { action: "verification-rerun" })
|
|
2484
|
+
};
|
|
2485
|
+
}
|
|
2486
|
+
return {
|
|
2487
|
+
markup: "Reply with <code>rerun verification</code> or <code>override verification</code>.",
|
|
2488
|
+
remember: {
|
|
2489
|
+
text: String(continuation.lastPrompt || "").trim() || "Reply with rerun verification or override verification.",
|
|
2490
|
+
kind: continuation.kind,
|
|
2491
|
+
source: continuation.source,
|
|
2492
|
+
context: continuation.context || {},
|
|
2493
|
+
force: true
|
|
2494
|
+
}
|
|
2495
|
+
};
|
|
2496
|
+
}
|
|
2436
2497
|
return null;
|
|
2437
2498
|
}
|
|
2438
2499
|
|
|
@@ -2530,6 +2591,37 @@ class TelegramGateway {
|
|
|
2530
2591
|
return formatVerificationResultMarkup(result, verifier);
|
|
2531
2592
|
}
|
|
2532
2593
|
|
|
2594
|
+
if (intent.action === "verification-override") {
|
|
2595
|
+
if (!project?.enabled) {
|
|
2596
|
+
return "This project is not shared.";
|
|
2597
|
+
}
|
|
2598
|
+
const blockingVerification = getBlockingVerificationResult(project);
|
|
2599
|
+
if (!blockingVerification) {
|
|
2600
|
+
return "<b>Verification override</b>\nNo blocking verification is active.";
|
|
2601
|
+
}
|
|
2602
|
+
await addSharedRoomNote(cwd, "Blocking verification overridden for now", {
|
|
2603
|
+
actorId,
|
|
2604
|
+
actorName,
|
|
2605
|
+
type: "verification-override",
|
|
2606
|
+
meta: {
|
|
2607
|
+
verificationResultId: String(blockingVerification.id || "").trim(),
|
|
2608
|
+
outcome: String(blockingVerification.outcome || "").trim()
|
|
2609
|
+
}
|
|
2610
|
+
});
|
|
2611
|
+
return [
|
|
2612
|
+
"<b>Verification overridden</b>",
|
|
2613
|
+
`latest outcome: <code>${escapeTelegramHtml(String(blockingVerification.outcome || "failed"))}</code>`,
|
|
2614
|
+
"Execution can proceed for now."
|
|
2615
|
+
].join("\n");
|
|
2616
|
+
}
|
|
2617
|
+
|
|
2618
|
+
if (intent.action === "verification-rerun") {
|
|
2619
|
+
if (!project?.enabled) {
|
|
2620
|
+
return "This project is not shared.";
|
|
2621
|
+
}
|
|
2622
|
+
return this.handleStateIntent(message, sessionId, { action: "run-verification" });
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2533
2625
|
if (intent.action === "run-verification") {
|
|
2534
2626
|
if (!project?.enabled) {
|
|
2535
2627
|
return "This project is not shared.";
|
|
@@ -3544,7 +3636,10 @@ class TelegramGateway {
|
|
|
3544
3636
|
const sourcePrefix = sourceHost
|
|
3545
3637
|
? `<b>Handled by</b>\n<code>${escapeTelegramHtml(formatBridgeHostLabel(sourceHost) || sourceHost.sessionId || "live terminal")}</code>\n\n`
|
|
3546
3638
|
: "";
|
|
3547
|
-
const
|
|
3639
|
+
const contentChunks = renderTelegramChunks(String(content || ""));
|
|
3640
|
+
const chunks = contentChunks.length
|
|
3641
|
+
? [sourcePrefix ? `${sourcePrefix}${contentChunks[0]}` : contentChunks[0], ...contentChunks.slice(1)]
|
|
3642
|
+
: (sourcePrefix ? [sourcePrefix.trim()] : []);
|
|
3548
3643
|
if (!chunks.length) {
|
|
3549
3644
|
if (previewMessage?.message_id) {
|
|
3550
3645
|
await this.editMessage(chatId, previewMessage.message_id, "(no content)");
|
|
@@ -4618,6 +4713,31 @@ Ask them to run <code>/whoami</code> and then <code>/accept-invite ${escapeTeleg
|
|
|
4618
4713
|
});
|
|
4619
4714
|
return;
|
|
4620
4715
|
}
|
|
4716
|
+
const blockingVerification = getBlockingVerificationResult(operatorGate.project);
|
|
4717
|
+
if (blockingVerification) {
|
|
4718
|
+
const followUp = "Reply with rerun verification to try again, or override verification to proceed anyway.";
|
|
4719
|
+
await this.sendMarkup(
|
|
4720
|
+
message.chat.id,
|
|
4721
|
+
[
|
|
4722
|
+
"<b>Blocking verification in effect</b>",
|
|
4723
|
+
`latest outcome: <code>${escapeTelegramHtml(String(blockingVerification.outcome || "failed"))}</code>`,
|
|
4724
|
+
blockingVerification.summary ? `summary: <code>${escapeTelegramHtml(String(blockingVerification.summary || ""))}</code>` : "",
|
|
4725
|
+
"Execution is paused until verification passes or the room overrides it.",
|
|
4726
|
+
followUp
|
|
4727
|
+
].filter(Boolean).join("\n"),
|
|
4728
|
+
message.message_id
|
|
4729
|
+
);
|
|
4730
|
+
await this.rememberContinuationWithOptions(message, followUp, {
|
|
4731
|
+
kind: "blocking-verification-override",
|
|
4732
|
+
source: "verification-policy-gate",
|
|
4733
|
+
context: {
|
|
4734
|
+
verificationResultId: String(blockingVerification.id || "").trim(),
|
|
4735
|
+
outcome: String(blockingVerification.outcome || "").trim()
|
|
4736
|
+
},
|
|
4737
|
+
force: true
|
|
4738
|
+
});
|
|
4739
|
+
return;
|
|
4740
|
+
}
|
|
4621
4741
|
const liveHosts = await this.getLiveBridgeHosts({ cwd: operatorGate.session?.cwd || this.cwd });
|
|
4622
4742
|
const host = await this.getLiveBridgeHost();
|
|
4623
4743
|
const activeExecutor = {
|
|
@@ -4684,6 +4804,39 @@ Ask them to run <code>/whoami</code> and then <code>/accept-invite ${escapeTeleg
|
|
|
4684
4804
|
sourceHost: typeof result === "string" ? null : (result?.sourceHost || null)
|
|
4685
4805
|
});
|
|
4686
4806
|
await this.rememberContinuation(message, finalContent);
|
|
4807
|
+
if (["auto", "blocking"].includes(String(operatorGate.project?.verificationMode || "manual").trim())) {
|
|
4808
|
+
const verificationMarkup = await this.handleStateIntent(message, sessionId, { action: "run-verification" });
|
|
4809
|
+
if (verificationMarkup) {
|
|
4810
|
+
await this.sendMarkup(message.chat.id, verificationMarkup, message.message_id);
|
|
4811
|
+
}
|
|
4812
|
+
if (String(operatorGate.project?.verificationMode || "manual").trim() === "blocking") {
|
|
4813
|
+
const nextProject = await loadSharedProject(operatorGate.session?.cwd || this.cwd);
|
|
4814
|
+
const nextBlockingVerification = getBlockingVerificationResult(nextProject);
|
|
4815
|
+
if (nextBlockingVerification) {
|
|
4816
|
+
const followUp = "Reply with rerun verification to try again, or override verification to proceed anyway.";
|
|
4817
|
+
await this.sendMarkup(
|
|
4818
|
+
message.chat.id,
|
|
4819
|
+
[
|
|
4820
|
+
"<b>Blocking verification in effect</b>",
|
|
4821
|
+
`latest outcome: <code>${escapeTelegramHtml(String(nextBlockingVerification.outcome || "failed"))}</code>`,
|
|
4822
|
+
nextBlockingVerification.summary ? `summary: <code>${escapeTelegramHtml(String(nextBlockingVerification.summary || ""))}</code>` : "",
|
|
4823
|
+
"Further execution is paused until verification passes or the room overrides it.",
|
|
4824
|
+
followUp
|
|
4825
|
+
].filter(Boolean).join("\n"),
|
|
4826
|
+
message.message_id
|
|
4827
|
+
);
|
|
4828
|
+
await this.rememberContinuationWithOptions(message, followUp, {
|
|
4829
|
+
kind: "blocking-verification-override",
|
|
4830
|
+
source: "verification-policy-gate",
|
|
4831
|
+
context: {
|
|
4832
|
+
verificationResultId: String(nextBlockingVerification.id || "").trim(),
|
|
4833
|
+
outcome: String(nextBlockingVerification.outcome || "").trim()
|
|
4834
|
+
},
|
|
4835
|
+
force: true
|
|
4836
|
+
});
|
|
4837
|
+
}
|
|
4838
|
+
}
|
|
4839
|
+
}
|
|
4687
4840
|
} catch (error) {
|
|
4688
4841
|
await this.deliverPromptFailure(message.chat.id, message.message_id, previewMessage, error);
|
|
4689
4842
|
} finally {
|