@tritard/waterbrother 0.16.100 → 0.16.101
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/cli.js +98 -1
- package/src/gateway-state.js +2 -0
- package/src/gateway.js +30 -1
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -3154,7 +3154,7 @@ async function dequeueTelegramBridgeRequest({ cwd }) {
|
|
|
3154
3154
|
return next;
|
|
3155
3155
|
}
|
|
3156
3156
|
|
|
3157
|
-
async function deliverTelegramBridgeReply(request, { sessionId, content = "", error = "" }) {
|
|
3157
|
+
async function deliverTelegramBridgeReply(request, { sessionId, content = "", error = "", meta = {} }) {
|
|
3158
3158
|
const bridge = await loadGatewayBridge(TELEGRAM_BRIDGE_SERVICE);
|
|
3159
3159
|
const replies = Array.isArray(bridge.deliveredReplies) ? bridge.deliveredReplies : [];
|
|
3160
3160
|
replies.push({
|
|
@@ -3163,6 +3163,7 @@ async function deliverTelegramBridgeReply(request, { sessionId, content = "", er
|
|
|
3163
3163
|
sessionId: String(sessionId || "").trim(),
|
|
3164
3164
|
content: String(content || "").trim(),
|
|
3165
3165
|
error: String(error || "").trim(),
|
|
3166
|
+
meta: meta && typeof meta === "object" ? { ...meta } : {},
|
|
3166
3167
|
completedAt: new Date().toISOString(),
|
|
3167
3168
|
source: "tui"
|
|
3168
3169
|
});
|
|
@@ -3187,6 +3188,92 @@ function formatTelegramRemoteActor(request = {}) {
|
|
|
3187
3188
|
return username || userId || "telegram";
|
|
3188
3189
|
}
|
|
3189
3190
|
|
|
3191
|
+
async function planTelegramVerificationCommands(cwd) {
|
|
3192
|
+
const packageJsonPath = path.join(cwd, "package.json");
|
|
3193
|
+
let scripts = {};
|
|
3194
|
+
try {
|
|
3195
|
+
const raw = await fs.readFile(packageJsonPath, "utf8");
|
|
3196
|
+
const parsed = JSON.parse(raw);
|
|
3197
|
+
scripts = parsed?.scripts && typeof parsed.scripts === "object" ? parsed.scripts : {};
|
|
3198
|
+
} catch {}
|
|
3199
|
+
const commands = [];
|
|
3200
|
+
if (scripts.check) commands.push(["npm", ["run", "check"], "npm run check"]);
|
|
3201
|
+
if (scripts.test) commands.push(["npm", ["test"], "npm test"]);
|
|
3202
|
+
if (scripts.build) commands.push(["npm", ["run", "build"], "npm run build"]);
|
|
3203
|
+
if (!commands.length) {
|
|
3204
|
+
throw new Error("No verification commands are available here. Expected package.json scripts like check, test, or build.");
|
|
3205
|
+
}
|
|
3206
|
+
return commands;
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
function formatTelegramVerificationSummary(result = {}) {
|
|
3210
|
+
const lines = [
|
|
3211
|
+
"Verification result",
|
|
3212
|
+
`outcome: ${String(result.outcome || "failed").trim() || "failed"}`
|
|
3213
|
+
];
|
|
3214
|
+
if (Array.isArray(result.commands) && result.commands.length) {
|
|
3215
|
+
lines.push("commands:");
|
|
3216
|
+
for (const command of result.commands) {
|
|
3217
|
+
lines.push(`• ${String(command || "").trim()}`);
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
if (result.summary) {
|
|
3221
|
+
lines.push("Summary");
|
|
3222
|
+
lines.push(String(result.summary || "").trim());
|
|
3223
|
+
}
|
|
3224
|
+
if (Array.isArray(result.logs) && result.logs.length) {
|
|
3225
|
+
lines.push("Top errors");
|
|
3226
|
+
for (const line of result.logs.slice(0, 6)) {
|
|
3227
|
+
lines.push(`• ${String(line || "").trim()}`);
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
return lines.filter(Boolean).join("\n");
|
|
3231
|
+
}
|
|
3232
|
+
|
|
3233
|
+
async function runTelegramLocalVerification(cwd) {
|
|
3234
|
+
const planned = await planTelegramVerificationCommands(cwd);
|
|
3235
|
+
const commands = [];
|
|
3236
|
+
const startedAt = new Date().toISOString();
|
|
3237
|
+
const logs = [];
|
|
3238
|
+
let passedCount = 0;
|
|
3239
|
+
for (const [bin, args, label] of planned) {
|
|
3240
|
+
commands.push(label);
|
|
3241
|
+
try {
|
|
3242
|
+
await execFileAsync(bin, args, {
|
|
3243
|
+
cwd,
|
|
3244
|
+
env: { ...process.env },
|
|
3245
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
3246
|
+
timeout: 10 * 60 * 1000
|
|
3247
|
+
});
|
|
3248
|
+
passedCount += 1;
|
|
3249
|
+
} catch (error) {
|
|
3250
|
+
const combined = `${String(error?.stderr || "")}\n${String(error?.stdout || "")}`.trim();
|
|
3251
|
+
const extracted = combined
|
|
3252
|
+
.split("\n")
|
|
3253
|
+
.map((line) => String(line || "").trim())
|
|
3254
|
+
.filter(Boolean)
|
|
3255
|
+
.slice(0, 6);
|
|
3256
|
+
logs.push(...extracted);
|
|
3257
|
+
return {
|
|
3258
|
+
outcome: error?.killed || error?.signal === "SIGTERM" ? "timeout" : (passedCount > 0 ? "partial" : "failed"),
|
|
3259
|
+
summary: `${label} failed${passedCount > 0 ? ` after ${passedCount} passing check${passedCount === 1 ? "" : "s"}` : ""}.`,
|
|
3260
|
+
commands,
|
|
3261
|
+
startedAt,
|
|
3262
|
+
completedAt: new Date().toISOString(),
|
|
3263
|
+
logs
|
|
3264
|
+
};
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
return {
|
|
3268
|
+
outcome: "passed",
|
|
3269
|
+
summary: `${commands.length} verification command${commands.length === 1 ? "" : "s"} passed.`,
|
|
3270
|
+
commands,
|
|
3271
|
+
startedAt,
|
|
3272
|
+
completedAt: new Date().toISOString(),
|
|
3273
|
+
logs
|
|
3274
|
+
};
|
|
3275
|
+
}
|
|
3276
|
+
|
|
3190
3277
|
async function chooseFromInteractiveMenu({ title, options, defaultIndex = 0 }) {
|
|
3191
3278
|
if (!process.stdin.isTTY || !process.stdout.isTTY || options.length === 0) {
|
|
3192
3279
|
return options[Math.max(0, Math.min(defaultIndex, options.length - 1))] || null;
|
|
@@ -7714,6 +7801,16 @@ Be concrete about surfaces — name actual pages/flows. Choose the best stack fo
|
|
|
7714
7801
|
}
|
|
7715
7802
|
console.log(cyan(`telegram request from ${remoteActor}`));
|
|
7716
7803
|
console.log(`${cyan("telegram>")} ${sanitizeTerminalText(remoteRequest.text || "")}`);
|
|
7804
|
+
if (String(remoteRequest.requestKind || "").trim() === "verification") {
|
|
7805
|
+
const verificationResult = await runTelegramLocalVerification(context.cwd);
|
|
7806
|
+
await deliverTelegramBridgeReply(remoteRequest, {
|
|
7807
|
+
sessionId: remoteSessionId,
|
|
7808
|
+
content: formatTelegramVerificationSummary(verificationResult),
|
|
7809
|
+
meta: { verificationResult }
|
|
7810
|
+
});
|
|
7811
|
+
console.log(green(`telegram verification sent -> ${remoteActor}`));
|
|
7812
|
+
continue;
|
|
7813
|
+
}
|
|
7717
7814
|
const remoteManifest = await buildSelfAwarenessManifest({
|
|
7718
7815
|
cwd: context.cwd,
|
|
7719
7816
|
runtime: context.runtime,
|
package/src/gateway-state.js
CHANGED
|
@@ -53,6 +53,7 @@ function normalizeBridgeRequest(parsed = {}) {
|
|
|
53
53
|
displayName: String(parsed?.displayName || "").trim(),
|
|
54
54
|
sessionId: String(parsed?.sessionId || "").trim(),
|
|
55
55
|
text: String(parsed?.text || "").trim(),
|
|
56
|
+
requestKind: String(parsed?.requestKind || "prompt").trim() || "prompt",
|
|
56
57
|
explicitExecution: parsed?.explicitExecution === true,
|
|
57
58
|
targetPid: Number.isFinite(Number(parsed?.targetPid)) ? Math.floor(Number(parsed.targetPid)) : 0,
|
|
58
59
|
targetSessionId: String(parsed?.targetSessionId || "").trim(),
|
|
@@ -72,6 +73,7 @@ function normalizeBridgeReply(parsed = {}) {
|
|
|
72
73
|
sessionId: String(parsed?.sessionId || "").trim(),
|
|
73
74
|
content: String(parsed?.content || "").trim(),
|
|
74
75
|
error: String(parsed?.error || "").trim(),
|
|
76
|
+
meta: parsed?.meta && typeof parsed.meta === "object" ? { ...parsed.meta } : {},
|
|
75
77
|
completedAt: String(parsed?.completedAt || "").trim(),
|
|
76
78
|
source: String(parsed?.source || "tui").trim() || "tui"
|
|
77
79
|
};
|
package/src/gateway.js
CHANGED
|
@@ -2448,6 +2448,34 @@ class TelegramGateway {
|
|
|
2448
2448
|
if (!project?.enabled) {
|
|
2449
2449
|
return "This project is not shared.";
|
|
2450
2450
|
}
|
|
2451
|
+
const liveHosts = await this.getLiveBridgeHosts({ cwd });
|
|
2452
|
+
const verifierHost = verifier ? findLiveHostForAgent(liveHosts, verifier) : null;
|
|
2453
|
+
if (verifier && verifierHost?.pid) {
|
|
2454
|
+
const bridgeResult = await this.runPromptViaBridge(message, sessionId, "run verification", {
|
|
2455
|
+
explicitExecution: true,
|
|
2456
|
+
requestKind: "verification",
|
|
2457
|
+
targetHost: verifierHost,
|
|
2458
|
+
includeSource: true
|
|
2459
|
+
});
|
|
2460
|
+
const routedResult = bridgeResult?.replyMeta?.verificationResult && typeof bridgeResult.replyMeta.verificationResult === "object"
|
|
2461
|
+
? bridgeResult.replyMeta.verificationResult
|
|
2462
|
+
: null;
|
|
2463
|
+
const handledBy = formatBridgeHostLabel(bridgeResult?.sourceHost || verifierHost) || verifierHost.sessionId || "live terminal";
|
|
2464
|
+
if (routedResult) {
|
|
2465
|
+
const nextProject = await addVerificationResult(cwd, routedResult, { actorId, actorName });
|
|
2466
|
+
const latest = getLatestVerificationResult(nextProject) || routedResult;
|
|
2467
|
+
return [
|
|
2468
|
+
`<b>Handled by</b> <code>${escapeTelegramHtml(handledBy)}</code>`,
|
|
2469
|
+
"",
|
|
2470
|
+
formatVerificationResultMarkup(latest, verifier)
|
|
2471
|
+
].join("\n");
|
|
2472
|
+
}
|
|
2473
|
+
return [
|
|
2474
|
+
`<b>Handled by</b> <code>${escapeTelegramHtml(handledBy)}</code>`,
|
|
2475
|
+
"",
|
|
2476
|
+
String(bridgeResult?.content || "").trim() || "<b>Verification result</b>\n(no content)"
|
|
2477
|
+
].join("\n");
|
|
2478
|
+
}
|
|
2451
2479
|
const result = await this.runLocalVerification(cwd, verifier);
|
|
2452
2480
|
const nextProject = await addVerificationResult(cwd, result, { actorId, actorName });
|
|
2453
2481
|
const latest = getLatestVerificationResult(nextProject) || result;
|
|
@@ -3213,6 +3241,7 @@ class TelegramGateway {
|
|
|
3213
3241
|
displayName: this.describeTelegramUser(message?.from || {}).displayName,
|
|
3214
3242
|
sessionId: String(sessionId || "").trim(),
|
|
3215
3243
|
text: String(promptText || "").trim(),
|
|
3244
|
+
requestKind: String(options.requestKind || "prompt").trim() || "prompt",
|
|
3216
3245
|
explicitExecution: options.explicitExecution === true,
|
|
3217
3246
|
targetPid: Number(host?.pid || 0),
|
|
3218
3247
|
targetSessionId: String(host?.sessionId || "").trim(),
|
|
@@ -3243,7 +3272,7 @@ class TelegramGateway {
|
|
|
3243
3272
|
}
|
|
3244
3273
|
const content = String(reply.content || "").trim() || "(no content)";
|
|
3245
3274
|
return options.includeSource
|
|
3246
|
-
? { content, sourceHost: host }
|
|
3275
|
+
? { content, sourceHost: host, replyMeta: reply.meta && typeof reply.meta === "object" ? { ...reply.meta } : {} }
|
|
3247
3276
|
: content;
|
|
3248
3277
|
}
|
|
3249
3278
|
|