@tritard/waterbrother 0.16.32 → 0.16.33
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/README.md +2 -0
- package/package.json +1 -1
- package/src/cli.js +15 -1
- package/src/gateway.js +25 -0
package/README.md
CHANGED
|
@@ -283,6 +283,8 @@ Current Telegram behavior:
|
|
|
283
283
|
- Telegram now supports remote workspace control with `/cwd`, `/use <path>`, `/desktop`, and `/new-project <name>`
|
|
284
284
|
- shared projects now support `/room`, `/members`, `/invites`, `/tasks`, `/mode`, `/claim`, `/release`, `/invite`, `/accept-invite`, `/approve-invite`, `/reject-invite`, `/remove-member`, `/room-runtime`, and `/task ...` from Telegram
|
|
285
285
|
- `/room` now includes pending invite count plus task ownership summaries
|
|
286
|
+
- local `/status` now includes `sharedRoom` with pending invites, task ownership summary, and recent task activity
|
|
287
|
+
- Telegram now posts a Roundtable ownership notice when shared task ownership changes via assign/claim/move
|
|
286
288
|
- shared Telegram execution only runs when the shared room is in `execute` mode
|
|
287
289
|
- room administration is owner-only, and only owners/editors can hold the operator lock
|
|
288
290
|
- `/room` status now shows the active executor surface plus provider/model/runtime identity
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -2652,10 +2652,23 @@ function buildRoomStatusPayload(project, runtime = null, currentSession = null)
|
|
|
2652
2652
|
const assignee = String(task?.assignedTo || "").trim() || "unassigned";
|
|
2653
2653
|
taskSummary.byAssignee[assignee] = (taskSummary.byAssignee[assignee] || 0) + 1;
|
|
2654
2654
|
}
|
|
2655
|
+
const recentActivity = tasks
|
|
2656
|
+
.flatMap((task) => (Array.isArray(task.history) ? task.history.map((entry) => ({
|
|
2657
|
+
taskId: task.id,
|
|
2658
|
+
taskText: task.text,
|
|
2659
|
+
type: entry.type,
|
|
2660
|
+
text: entry.text,
|
|
2661
|
+
actorId: entry.actorId || "",
|
|
2662
|
+
actorName: entry.actorName || "",
|
|
2663
|
+
createdAt: entry.createdAt || ""
|
|
2664
|
+
})) : []))
|
|
2665
|
+
.sort((a, b) => String(b.createdAt).localeCompare(String(a.createdAt)))
|
|
2666
|
+
.slice(0, 5);
|
|
2655
2667
|
return {
|
|
2656
2668
|
...project,
|
|
2657
2669
|
pendingInviteCount: Array.isArray(project.pendingInvites) ? project.pendingInvites.length : 0,
|
|
2658
2670
|
taskSummary,
|
|
2671
|
+
recentActivity,
|
|
2659
2672
|
executor: {
|
|
2660
2673
|
surface: "local-tui",
|
|
2661
2674
|
roomRuntimeProfile: project.runtimeProfile || "",
|
|
@@ -7557,7 +7570,8 @@ Be concrete about surfaces — name actual pages/flows. Choose the best stack fo
|
|
|
7557
7570
|
sessionApprovals: approvals,
|
|
7558
7571
|
sessionApprovalsSummary: formatSessionApprovalsSummary(approvals),
|
|
7559
7572
|
messageCount: agent.getSessionMessages().length,
|
|
7560
|
-
mcp: mcpStatus
|
|
7573
|
+
mcp: mcpStatus,
|
|
7574
|
+
sharedRoom: await loadSharedProject(context.cwd).then((project) => buildRoomStatusPayload(project, context.runtime, currentSession)).catch(() => ({ enabled: false }))
|
|
7561
7575
|
},
|
|
7562
7576
|
null,
|
|
7563
7577
|
2
|
package/src/gateway.js
CHANGED
|
@@ -411,6 +411,23 @@ function formatTelegramTaskHistoryMarkup(result) {
|
|
|
411
411
|
return lines.join("\n");
|
|
412
412
|
}
|
|
413
413
|
|
|
414
|
+
function buildTaskOwnershipNotice(task, { action = "updated", previousAssignee = "", previousState = "" } = {}) {
|
|
415
|
+
if (!task) return "";
|
|
416
|
+
const bits = [
|
|
417
|
+
"<b>Roundtable update</b>",
|
|
418
|
+
`<code>${escapeTelegramHtml(task.id || "")}</code> ${escapeTelegramHtml(task.text || "")}`
|
|
419
|
+
];
|
|
420
|
+
if (action === "assign") {
|
|
421
|
+
bits.push(`owner: <code>${escapeTelegramHtml(previousAssignee || "unassigned")}</code> → <code>${escapeTelegramHtml(task.assignedTo || "unassigned")}</code>`);
|
|
422
|
+
} else if (action === "claim") {
|
|
423
|
+
bits.push(`claimed by <code>${escapeTelegramHtml(task.assignedTo || "unassigned")}</code>`);
|
|
424
|
+
} else if (action === "move") {
|
|
425
|
+
bits.push(`state: <code>${escapeTelegramHtml(previousState || "open")}</code> → <code>${escapeTelegramHtml(task.state || "open")}</code>`);
|
|
426
|
+
if (task.assignedTo) bits.push(`owner: <code>${escapeTelegramHtml(task.assignedTo)}</code>`);
|
|
427
|
+
}
|
|
428
|
+
return bits.join("\n");
|
|
429
|
+
}
|
|
430
|
+
|
|
414
431
|
function classifyTelegramGroupIntent(text = "") {
|
|
415
432
|
const normalized = String(text || "").trim();
|
|
416
433
|
const lower = normalized.toLowerCase();
|
|
@@ -1395,8 +1412,11 @@ class TelegramGateway {
|
|
|
1395
1412
|
return;
|
|
1396
1413
|
}
|
|
1397
1414
|
try {
|
|
1415
|
+
const before = (project?.tasks || []).find((task) => task.id === taskId) || null;
|
|
1398
1416
|
const result = await moveSharedTask(session.cwd || this.cwd, taskId, state, { actorId: userId });
|
|
1399
1417
|
await this.sendMessage(message.chat.id, `Moved shared task <code>${escapeTelegramHtml(result.task.id)}</code> to <code>${escapeTelegramHtml(result.task.state)}</code>`, message.message_id);
|
|
1418
|
+
const notice = buildTaskOwnershipNotice(result.task, { action: "move", previousAssignee: before?.assignedTo || "", previousState: before?.state || "" });
|
|
1419
|
+
if (notice) await this.sendMessage(message.chat.id, notice, null, { parseMode: "HTML" });
|
|
1400
1420
|
} catch (error) {
|
|
1401
1421
|
await this.sendMessage(message.chat.id, escapeTelegramHtml(error instanceof Error ? error.message : String(error)), message.message_id);
|
|
1402
1422
|
}
|
|
@@ -1415,8 +1435,11 @@ class TelegramGateway {
|
|
|
1415
1435
|
return;
|
|
1416
1436
|
}
|
|
1417
1437
|
try {
|
|
1438
|
+
const before = (project?.tasks || []).find((task) => task.id === taskId) || null;
|
|
1418
1439
|
const result = await assignSharedTask(session.cwd || this.cwd, taskId, memberId, { actorId: userId });
|
|
1419
1440
|
await this.sendMessage(message.chat.id, `Assigned shared task <code>${escapeTelegramHtml(result.task.id)}</code> to <code>${escapeTelegramHtml(memberId)}</code>`, message.message_id);
|
|
1441
|
+
const notice = buildTaskOwnershipNotice(result.task, { action: "assign", previousAssignee: before?.assignedTo || "" });
|
|
1442
|
+
if (notice) await this.sendMessage(message.chat.id, notice, null, { parseMode: "HTML" });
|
|
1420
1443
|
} catch (error) {
|
|
1421
1444
|
await this.sendMessage(message.chat.id, escapeTelegramHtml(error instanceof Error ? error.message : String(error)), message.message_id);
|
|
1422
1445
|
}
|
|
@@ -1482,6 +1505,8 @@ class TelegramGateway {
|
|
|
1482
1505
|
try {
|
|
1483
1506
|
const result = await claimSharedTask(session.cwd || this.cwd, taskId, { actorId: userId });
|
|
1484
1507
|
await this.sendMessage(message.chat.id, `Claimed shared task <code>${escapeTelegramHtml(result.task.id)}</code>`, message.message_id);
|
|
1508
|
+
const notice = buildTaskOwnershipNotice(result.task, { action: "claim" });
|
|
1509
|
+
if (notice) await this.sendMessage(message.chat.id, notice, null, { parseMode: "HTML" });
|
|
1485
1510
|
} catch (error) {
|
|
1486
1511
|
await this.sendMessage(message.chat.id, escapeTelegramHtml(error instanceof Error ? error.message : String(error)), message.message_id);
|
|
1487
1512
|
}
|