@tritard/waterbrother 0.16.51 → 0.16.53
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 +135 -22
package/package.json
CHANGED
package/src/gateway.js
CHANGED
|
@@ -270,19 +270,28 @@ function formatGatewaySessionStatus({ sessionId, userId, username, cwd, runtimeP
|
|
|
270
270
|
return bits.join("\n");
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
-
function
|
|
273
|
+
function formatTelegramSummaryMarkup({ cwd, project, chatId = "", title = "", executor = {} }) {
|
|
274
|
+
const roomLabel = project?.room?.chatId
|
|
275
|
+
? `${project.room.provider || "telegram"} ${project.room.chatId}${project.room.title ? ` (${project.room.title})` : ""}`
|
|
276
|
+
: "not linked";
|
|
277
|
+
const activeOperator = project?.activeOperator?.id
|
|
278
|
+
? `${project.activeOperator.name || project.activeOperator.id} (${project.activeOperator.id})`
|
|
279
|
+
: "none";
|
|
274
280
|
const lines = [
|
|
275
|
-
"<b>
|
|
281
|
+
"<b>Project summary</b>",
|
|
282
|
+
`project: <code>${escapeTelegramHtml(project?.projectName || path.basename(cwd || "") || "-")}</code>`,
|
|
276
283
|
`cwd: <code>${escapeTelegramHtml(cwd || "-")}</code>`,
|
|
277
|
-
`name: <code>${escapeTelegramHtml(project?.projectName || path.basename(cwd || "") || "-")}</code>`,
|
|
278
284
|
`shared: <code>${project?.enabled ? "yes" : "no"}</code>`
|
|
279
285
|
];
|
|
280
286
|
if (project?.enabled) {
|
|
281
287
|
lines.push(`room mode: <code>${escapeTelegramHtml(project.roomMode || "chat")}</code>`);
|
|
282
|
-
lines.push(
|
|
283
|
-
|
|
284
|
-
);
|
|
288
|
+
lines.push(`bound chat: <code>${escapeTelegramHtml(roomLabel)}</code>`);
|
|
289
|
+
lines.push(`active operator: <code>${escapeTelegramHtml(activeOperator)}</code>`);
|
|
285
290
|
lines.push(`members: <code>${escapeTelegramHtml(String((project.members || []).length))}</code>`);
|
|
291
|
+
if (executor?.surface) lines.push(`executor: <code>${escapeTelegramHtml(executor.surface)}</code>`);
|
|
292
|
+
if (executor?.provider && executor?.model) {
|
|
293
|
+
lines.push(`runtime: <code>${escapeTelegramHtml(`${executor.provider}/${executor.model}`)}</code>`);
|
|
294
|
+
}
|
|
286
295
|
}
|
|
287
296
|
if (!project?.enabled) {
|
|
288
297
|
lines.push("Use <code>/project share</code> to turn on Roundtable for this project in this chat.");
|
|
@@ -292,6 +301,10 @@ function formatTelegramProjectMarkup({ cwd, project, chatId = "", title = "" })
|
|
|
292
301
|
return lines.join("\n");
|
|
293
302
|
}
|
|
294
303
|
|
|
304
|
+
function formatTelegramProjectMarkup({ cwd, project, chatId = "", title = "" }) {
|
|
305
|
+
return formatTelegramSummaryMarkup({ cwd, project, chatId, title });
|
|
306
|
+
}
|
|
307
|
+
|
|
295
308
|
function normalizeTelegramProjectIntentText(text = "") {
|
|
296
309
|
return String(text || "").trim().replace(/\s+/g, " ");
|
|
297
310
|
}
|
|
@@ -519,6 +532,31 @@ function formatTelegramRoomMarkup(project, options = {}) {
|
|
|
519
532
|
].join("\n");
|
|
520
533
|
}
|
|
521
534
|
|
|
535
|
+
function formatOwnerActionMarkup({
|
|
536
|
+
title = "Roundtable update",
|
|
537
|
+
projectName = "",
|
|
538
|
+
cwd = "",
|
|
539
|
+
paired = null,
|
|
540
|
+
member = null,
|
|
541
|
+
role = "",
|
|
542
|
+
targetName = "",
|
|
543
|
+
targetId = "",
|
|
544
|
+
note = ""
|
|
545
|
+
} = {}) {
|
|
546
|
+
const lines = [
|
|
547
|
+
`<b>${escapeTelegramHtml(title)}</b>`,
|
|
548
|
+
targetName || targetId ? `person: <code>${escapeTelegramHtml(targetName || targetId)}</code>` : "",
|
|
549
|
+
targetId ? `user id: <code>${escapeTelegramHtml(targetId)}</code>` : "",
|
|
550
|
+
paired === null ? "" : `paired: <code>${paired ? "yes" : "no"}</code>`,
|
|
551
|
+
member === null ? "" : `project member: <code>${member ? "yes" : "no"}</code>`,
|
|
552
|
+
role ? `role: <code>${escapeTelegramHtml(role)}</code>` : "",
|
|
553
|
+
projectName ? `project: <code>${escapeTelegramHtml(projectName)}</code>` : "",
|
|
554
|
+
cwd ? `cwd: <code>${escapeTelegramHtml(cwd)}</code>` : "",
|
|
555
|
+
note ? escapeTelegramHtml(note) : ""
|
|
556
|
+
].filter(Boolean);
|
|
557
|
+
return lines.join("\n");
|
|
558
|
+
}
|
|
559
|
+
|
|
522
560
|
function formatTelegramMembersMarkup(project) {
|
|
523
561
|
if (!project?.enabled) {
|
|
524
562
|
return "This project is not shared.";
|
|
@@ -1005,6 +1043,15 @@ class TelegramGateway {
|
|
|
1005
1043
|
if (!value) {
|
|
1006
1044
|
throw new Error("member target is required");
|
|
1007
1045
|
}
|
|
1046
|
+
const replied = this.describeTelegramUser(message?.reply_to_message?.from || {});
|
|
1047
|
+
const normalizedPronoun = value.toLowerCase().replace(/[?.!]+$/g, "").trim();
|
|
1048
|
+
if (["him", "her", "them", "this person", "this user", "that person", "that user"].includes(normalizedPronoun)) {
|
|
1049
|
+
if (replied.userId) {
|
|
1050
|
+
const knownReply = this.listKnownChatPeople(message).find((person) => person.userId === replied.userId) || replied;
|
|
1051
|
+
return { userId: replied.userId, displayName: knownReply.displayName || replied.displayName || replied.userId };
|
|
1052
|
+
}
|
|
1053
|
+
throw new Error("Reply to the person's message first, or use /people to choose them by name or id.");
|
|
1054
|
+
}
|
|
1008
1055
|
if (/^\d+$/.test(value) || value.startsWith("@")) {
|
|
1009
1056
|
const match = this.resolveInviteTarget(message, value);
|
|
1010
1057
|
return { userId: match.userId, displayName: match.displayName };
|
|
@@ -1016,6 +1063,17 @@ class TelegramGateway {
|
|
|
1016
1063
|
if (exact) {
|
|
1017
1064
|
return { userId: exact.userId, displayName: exact.displayName || exact.userId };
|
|
1018
1065
|
}
|
|
1066
|
+
const byFirstName = known.filter((person) => {
|
|
1067
|
+
const display = String(person.displayName || "").trim().toLowerCase();
|
|
1068
|
+
const first = display.split(/\s+/).filter(Boolean)[0] || "";
|
|
1069
|
+
return first === normalized;
|
|
1070
|
+
});
|
|
1071
|
+
if (byFirstName.length === 1) {
|
|
1072
|
+
return { userId: byFirstName[0].userId, displayName: byFirstName[0].displayName || byFirstName[0].userId };
|
|
1073
|
+
}
|
|
1074
|
+
if (byFirstName.length > 1) {
|
|
1075
|
+
throw new Error(`Multiple Telegram users matched first name ${value}. Use /people and choose by id or full name.`);
|
|
1076
|
+
}
|
|
1019
1077
|
const partial = known.filter((person) => {
|
|
1020
1078
|
const display = String(person.displayName || "").trim().toLowerCase();
|
|
1021
1079
|
const handle = String(person.usernameHandle || "").trim().toLowerCase();
|
|
@@ -1050,7 +1108,16 @@ class TelegramGateway {
|
|
|
1050
1108
|
return {
|
|
1051
1109
|
kind: "member",
|
|
1052
1110
|
project: nextProject,
|
|
1053
|
-
markup:
|
|
1111
|
+
markup: formatOwnerActionMarkup({
|
|
1112
|
+
title: "Roundtable member updated",
|
|
1113
|
+
projectName: nextProject.projectName || path.basename(session.cwd || this.cwd),
|
|
1114
|
+
cwd: session.cwd || this.cwd,
|
|
1115
|
+
paired: true,
|
|
1116
|
+
member: true,
|
|
1117
|
+
role: intent.role,
|
|
1118
|
+
targetName: target.displayName || target.userId,
|
|
1119
|
+
targetId: target.userId
|
|
1120
|
+
})
|
|
1054
1121
|
};
|
|
1055
1122
|
}
|
|
1056
1123
|
const known = this.listKnownChatPeople(message);
|
|
@@ -1068,7 +1135,16 @@ class TelegramGateway {
|
|
|
1068
1135
|
return {
|
|
1069
1136
|
kind: "member",
|
|
1070
1137
|
project: nextProject,
|
|
1071
|
-
markup:
|
|
1138
|
+
markup: formatOwnerActionMarkup({
|
|
1139
|
+
title: pairedNow ? "Paired and added to Roundtable" : "Added to Roundtable",
|
|
1140
|
+
projectName: nextProject.projectName || path.basename(session.cwd || this.cwd),
|
|
1141
|
+
cwd: session.cwd || this.cwd,
|
|
1142
|
+
paired: true,
|
|
1143
|
+
member: true,
|
|
1144
|
+
role: intent.role,
|
|
1145
|
+
targetName: target.displayName || target.userId,
|
|
1146
|
+
targetId: target.userId
|
|
1147
|
+
})
|
|
1072
1148
|
};
|
|
1073
1149
|
}
|
|
1074
1150
|
|
|
@@ -1078,7 +1154,7 @@ class TelegramGateway {
|
|
|
1078
1154
|
const known = this.listKnownChatPeople(message);
|
|
1079
1155
|
|
|
1080
1156
|
if (intent.action === "project-status") {
|
|
1081
|
-
return
|
|
1157
|
+
return formatTelegramSummaryMarkup({
|
|
1082
1158
|
cwd,
|
|
1083
1159
|
project,
|
|
1084
1160
|
chatId: String(message.chat.id),
|
|
@@ -1454,7 +1530,15 @@ class TelegramGateway {
|
|
|
1454
1530
|
runtimeProfile: project?.runtimeProfile || this.channel.defaultRuntimeProfile || this.gateway.defaultRuntimeProfile || "",
|
|
1455
1531
|
hostSessionId: host?.sessionId || ""
|
|
1456
1532
|
};
|
|
1457
|
-
return project?.enabled
|
|
1533
|
+
return project?.enabled
|
|
1534
|
+
? `${formatTelegramSummaryMarkup({
|
|
1535
|
+
cwd: project.cwd || this.cwd,
|
|
1536
|
+
project,
|
|
1537
|
+
chatId: String(message.chat.id),
|
|
1538
|
+
title: String(message.chat.title || "").trim(),
|
|
1539
|
+
executor
|
|
1540
|
+
})}\n\n${formatTelegramRoomMarkup(project, { executor })}`
|
|
1541
|
+
: "<b>Shared room</b>\nThis project is not shared.";
|
|
1458
1542
|
}
|
|
1459
1543
|
|
|
1460
1544
|
async ensureSharedOperator(message, sessionId) {
|
|
@@ -1776,9 +1860,18 @@ class TelegramGateway {
|
|
|
1776
1860
|
}
|
|
1777
1861
|
try {
|
|
1778
1862
|
const result = await this.pairKnownTelegramUser(message, rawTarget);
|
|
1863
|
+
const pairSession = await loadSession(sessionId);
|
|
1779
1864
|
await this.sendMarkup(
|
|
1780
1865
|
message.chat.id,
|
|
1781
|
-
|
|
1866
|
+
formatOwnerActionMarkup({
|
|
1867
|
+
title: "Telegram user paired",
|
|
1868
|
+
projectName: path.basename(pairSession.cwd || this.cwd),
|
|
1869
|
+
cwd: pairSession.cwd || this.cwd,
|
|
1870
|
+
paired: true,
|
|
1871
|
+
targetName: result.displayName,
|
|
1872
|
+
targetId: result.userId,
|
|
1873
|
+
note: `via ${result.configPath}`
|
|
1874
|
+
}),
|
|
1782
1875
|
message.message_id
|
|
1783
1876
|
);
|
|
1784
1877
|
} catch (error) {
|
|
@@ -1789,13 +1882,19 @@ class TelegramGateway {
|
|
|
1789
1882
|
|
|
1790
1883
|
if (text === "/project") {
|
|
1791
1884
|
const { session, project } = await this.bindSharedRoomForMessage(message, sessionId);
|
|
1885
|
+
const host = await this.getLiveBridgeHost();
|
|
1792
1886
|
await this.sendMarkup(
|
|
1793
1887
|
message.chat.id,
|
|
1794
|
-
|
|
1888
|
+
formatTelegramSummaryMarkup({
|
|
1795
1889
|
cwd: session.cwd || this.cwd,
|
|
1796
1890
|
project,
|
|
1797
1891
|
chatId: String(message.chat.id),
|
|
1798
|
-
title: String(message.chat.title || "").trim()
|
|
1892
|
+
title: String(message.chat.title || "").trim(),
|
|
1893
|
+
executor: {
|
|
1894
|
+
surface: host ? "live-tui" : "telegram-fallback",
|
|
1895
|
+
provider: this.runtime.provider,
|
|
1896
|
+
model: this.runtime.model
|
|
1897
|
+
}
|
|
1799
1898
|
}),
|
|
1800
1899
|
message.message_id
|
|
1801
1900
|
);
|
|
@@ -1807,7 +1906,7 @@ class TelegramGateway {
|
|
|
1807
1906
|
const { session, project } = await this.ensureProjectSharedForChat(message, sessionId);
|
|
1808
1907
|
await this.sendMarkup(
|
|
1809
1908
|
message.chat.id,
|
|
1810
|
-
`${
|
|
1909
|
+
`${formatTelegramSummaryMarkup({
|
|
1811
1910
|
cwd: session.cwd || this.cwd,
|
|
1812
1911
|
project,
|
|
1813
1912
|
chatId: String(message.chat.id),
|
|
@@ -1831,7 +1930,7 @@ class TelegramGateway {
|
|
|
1831
1930
|
const result = await this.switchPeerProject(message, rawPath);
|
|
1832
1931
|
await this.sendMarkup(
|
|
1833
1932
|
message.chat.id,
|
|
1834
|
-
`${
|
|
1933
|
+
`${formatTelegramSummaryMarkup({
|
|
1835
1934
|
cwd: result.cwd,
|
|
1836
1935
|
project: result.project,
|
|
1837
1936
|
chatId: String(message.chat.id),
|
|
@@ -1855,7 +1954,7 @@ class TelegramGateway {
|
|
|
1855
1954
|
const result = await this.switchPeerProject(message, projectName, { create: true });
|
|
1856
1955
|
await this.sendMarkup(
|
|
1857
1956
|
message.chat.id,
|
|
1858
|
-
`${
|
|
1957
|
+
`${formatTelegramSummaryMarkup({
|
|
1859
1958
|
cwd: result.cwd,
|
|
1860
1959
|
project: result.project,
|
|
1861
1960
|
chatId: String(message.chat.id),
|
|
@@ -2425,7 +2524,15 @@ Ask them to run <code>/whoami</code> and then <code>/accept-invite ${escapeTeleg
|
|
|
2425
2524
|
const result = await this.pairKnownTelegramUser(message, pairingIntent.target);
|
|
2426
2525
|
await this.sendMarkup(
|
|
2427
2526
|
message.chat.id,
|
|
2428
|
-
|
|
2527
|
+
formatOwnerActionMarkup({
|
|
2528
|
+
title: "Telegram user paired",
|
|
2529
|
+
projectName: sharedBinding.project?.projectName || path.basename(sharedBinding.session.cwd || this.cwd),
|
|
2530
|
+
cwd: sharedBinding.session.cwd || this.cwd,
|
|
2531
|
+
paired: true,
|
|
2532
|
+
targetName: result.displayName,
|
|
2533
|
+
targetId: result.userId,
|
|
2534
|
+
note: `via ${result.configPath}`
|
|
2535
|
+
}),
|
|
2429
2536
|
message.message_id
|
|
2430
2537
|
);
|
|
2431
2538
|
} catch (error) {
|
|
@@ -2445,13 +2552,19 @@ Ask them to run <code>/whoami</code> and then <code>/accept-invite ${escapeTeleg
|
|
|
2445
2552
|
}
|
|
2446
2553
|
const projectIntent = parseTelegramProjectIntent(promptText);
|
|
2447
2554
|
if (projectIntent?.action === "show-project") {
|
|
2555
|
+
const host = await this.getLiveBridgeHost();
|
|
2448
2556
|
await this.sendMarkup(
|
|
2449
2557
|
message.chat.id,
|
|
2450
|
-
|
|
2558
|
+
formatTelegramSummaryMarkup({
|
|
2451
2559
|
cwd: sharedBinding.session.cwd || this.cwd,
|
|
2452
2560
|
project: sharedBinding.project,
|
|
2453
2561
|
chatId: String(message.chat.id),
|
|
2454
|
-
title: String(message.chat.title || "").trim()
|
|
2562
|
+
title: String(message.chat.title || "").trim(),
|
|
2563
|
+
executor: {
|
|
2564
|
+
surface: host ? "live-tui" : "telegram-fallback",
|
|
2565
|
+
provider: this.runtime.provider,
|
|
2566
|
+
model: this.runtime.model
|
|
2567
|
+
}
|
|
2455
2568
|
}),
|
|
2456
2569
|
message.message_id
|
|
2457
2570
|
);
|
|
@@ -2462,7 +2575,7 @@ Ask them to run <code>/whoami</code> and then <code>/accept-invite ${escapeTeleg
|
|
|
2462
2575
|
const { session, project } = await this.ensureProjectSharedForChat(message, sessionId);
|
|
2463
2576
|
await this.sendMarkup(
|
|
2464
2577
|
message.chat.id,
|
|
2465
|
-
`${
|
|
2578
|
+
`${formatTelegramSummaryMarkup({
|
|
2466
2579
|
cwd: session.cwd || this.cwd,
|
|
2467
2580
|
project,
|
|
2468
2581
|
chatId: String(message.chat.id),
|
|
@@ -2480,7 +2593,7 @@ Ask them to run <code>/whoami</code> and then <code>/accept-invite ${escapeTeleg
|
|
|
2480
2593
|
const result = await this.switchPeerProject(message, projectIntent.target);
|
|
2481
2594
|
await this.sendMarkup(
|
|
2482
2595
|
message.chat.id,
|
|
2483
|
-
`${
|
|
2596
|
+
`${formatTelegramSummaryMarkup({
|
|
2484
2597
|
cwd: result.cwd,
|
|
2485
2598
|
project: result.project,
|
|
2486
2599
|
chatId: String(message.chat.id),
|
|
@@ -2498,7 +2611,7 @@ Ask them to run <code>/whoami</code> and then <code>/accept-invite ${escapeTeleg
|
|
|
2498
2611
|
const result = await this.switchPeerProject(message, projectIntent.name, { create: true, share: projectIntent.share });
|
|
2499
2612
|
await this.sendMarkup(
|
|
2500
2613
|
message.chat.id,
|
|
2501
|
-
`${
|
|
2614
|
+
`${formatTelegramSummaryMarkup({
|
|
2502
2615
|
cwd: result.cwd,
|
|
2503
2616
|
project: result.project,
|
|
2504
2617
|
chatId: String(message.chat.id),
|