@tritard/waterbrother 0.16.64 → 0.16.65
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/shared-project.js +115 -1
package/package.json
CHANGED
package/src/shared-project.js
CHANGED
|
@@ -7,6 +7,8 @@ const SHARED_FILE = path.join(".waterbrother", "shared.json");
|
|
|
7
7
|
const ROUNDTABLE_FILE = "ROUNDTABLE.md";
|
|
8
8
|
const TASK_STATES = ["open", "active", "blocked", "done"];
|
|
9
9
|
const RECENT_EVENT_LIMIT = 24;
|
|
10
|
+
const PARTICIPANT_ROLES = ["owner", "editor", "observer"];
|
|
11
|
+
const AGENT_ROLES = ["executor", "reviewer", "standby", "coordinator"];
|
|
10
12
|
|
|
11
13
|
function makeId(prefix = "id") {
|
|
12
14
|
return `${prefix}_${crypto.randomBytes(3).toString("hex")}`;
|
|
@@ -16,11 +18,117 @@ function normalizeMember(member = {}) {
|
|
|
16
18
|
return {
|
|
17
19
|
id: String(member.id || "").trim(),
|
|
18
20
|
name: String(member.name || "").trim(),
|
|
19
|
-
role:
|
|
21
|
+
role: PARTICIPANT_ROLES.includes(String(member.role || "").trim()) ? String(member.role).trim() : "editor",
|
|
20
22
|
paired: member.paired !== false
|
|
21
23
|
};
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
function inferParticipantChannels(memberId = "", participant = {}) {
|
|
27
|
+
const channels = participant?.channels && typeof participant.channels === "object" ? { ...participant.channels } : {};
|
|
28
|
+
const normalizedId = String(memberId || "").trim();
|
|
29
|
+
if (!normalizedId) return channels;
|
|
30
|
+
if (/^\d+$/.test(normalizedId)) {
|
|
31
|
+
channels.telegram = channels.telegram && typeof channels.telegram === "object"
|
|
32
|
+
? { ...channels.telegram, userId: normalizedId }
|
|
33
|
+
: { userId: normalizedId };
|
|
34
|
+
} else if (normalizedId.startsWith("local:")) {
|
|
35
|
+
const localName = normalizedId.slice("local:".length).trim();
|
|
36
|
+
channels.local = channels.local && typeof channels.local === "object"
|
|
37
|
+
? { ...channels.local, userId: normalizedId, username: channels.local.username || localName }
|
|
38
|
+
: { userId: normalizedId, username: localName };
|
|
39
|
+
}
|
|
40
|
+
return channels;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function normalizeParticipant(participant = {}) {
|
|
44
|
+
return {
|
|
45
|
+
id: String(participant.id || participant.memberId || "").trim(),
|
|
46
|
+
memberId: String(participant.memberId || participant.id || "").trim(),
|
|
47
|
+
kind: "human",
|
|
48
|
+
displayName: String(participant.displayName || participant.name || "").trim(),
|
|
49
|
+
role: PARTICIPANT_ROLES.includes(String(participant.role || "").trim()) ? String(participant.role).trim() : "editor",
|
|
50
|
+
trusted: participant.trusted !== false,
|
|
51
|
+
channels: participant.channels && typeof participant.channels === "object" ? { ...participant.channels } : {},
|
|
52
|
+
joinedAt: String(participant.joinedAt || new Date().toISOString()).trim()
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function normalizeAgent(agent = {}) {
|
|
57
|
+
return {
|
|
58
|
+
id: String(agent.id || "").trim(),
|
|
59
|
+
ownerId: String(agent.ownerId || "").trim(),
|
|
60
|
+
label: String(agent.label || agent.name || "").trim(),
|
|
61
|
+
surface: String(agent.surface || "").trim(),
|
|
62
|
+
role: AGENT_ROLES.includes(String(agent.role || "").trim()) ? String(agent.role).trim() : "standby",
|
|
63
|
+
provider: String(agent.provider || "").trim(),
|
|
64
|
+
model: String(agent.model || "").trim(),
|
|
65
|
+
runtimeProfile: String(agent.runtimeProfile || "").trim(),
|
|
66
|
+
sessionId: String(agent.sessionId || "").trim(),
|
|
67
|
+
updatedAt: String(agent.updatedAt || new Date().toISOString()).trim()
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function buildProjectParticipants(project = {}) {
|
|
72
|
+
const members = Array.isArray(project.members) ? project.members.map(normalizeMember).filter((item) => item.id) : [];
|
|
73
|
+
const memberIds = new Set(members.map((member) => member.id));
|
|
74
|
+
const existing = new Map(
|
|
75
|
+
(Array.isArray(project.participants) ? project.participants : [])
|
|
76
|
+
.map((participant) => normalizeParticipant(participant))
|
|
77
|
+
.filter((participant) => participant.id)
|
|
78
|
+
.map((participant) => [participant.id, participant])
|
|
79
|
+
);
|
|
80
|
+
const next = members.map((member) => {
|
|
81
|
+
const prior = existing.get(member.id) || {};
|
|
82
|
+
return normalizeParticipant({
|
|
83
|
+
...prior,
|
|
84
|
+
id: member.id,
|
|
85
|
+
memberId: member.id,
|
|
86
|
+
displayName: prior.displayName || member.name || member.id,
|
|
87
|
+
role: member.role,
|
|
88
|
+
trusted: prior.trusted !== false && member.paired !== false,
|
|
89
|
+
channels: inferParticipantChannels(member.id, prior),
|
|
90
|
+
joinedAt: prior.joinedAt || project.createdAt || new Date().toISOString()
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
for (const participant of existing.values()) {
|
|
94
|
+
if (!participant.id) continue;
|
|
95
|
+
if (participant.memberId && !memberIds.has(participant.memberId)) continue;
|
|
96
|
+
if (next.some((item) => item.id === participant.id)) continue;
|
|
97
|
+
next.push(normalizeParticipant(participant));
|
|
98
|
+
}
|
|
99
|
+
return next;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function buildProjectAgents(project = {}) {
|
|
103
|
+
const existing = new Map(
|
|
104
|
+
(Array.isArray(project.agents) ? project.agents : [])
|
|
105
|
+
.map((agent) => normalizeAgent(agent))
|
|
106
|
+
.filter((agent) => agent.id)
|
|
107
|
+
.map((agent) => [agent.id, agent])
|
|
108
|
+
);
|
|
109
|
+
const next = [];
|
|
110
|
+
const activeOperatorId = String(project.activeOperator?.id || "").trim();
|
|
111
|
+
if (activeOperatorId) {
|
|
112
|
+
const inferredId = `agent:operator:${activeOperatorId}`;
|
|
113
|
+
const prior = existing.get(inferredId) || {};
|
|
114
|
+
next.push(normalizeAgent({
|
|
115
|
+
...prior,
|
|
116
|
+
id: inferredId,
|
|
117
|
+
ownerId: activeOperatorId,
|
|
118
|
+
label: prior.label || `${project.activeOperator?.name || activeOperatorId} terminal`,
|
|
119
|
+
surface: prior.surface || (activeOperatorId.startsWith("local:") ? "local-tui" : String(project.room?.provider || "remote").trim() || "remote"),
|
|
120
|
+
role: "executor",
|
|
121
|
+
updatedAt: new Date().toISOString()
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
for (const agent of existing.values()) {
|
|
125
|
+
if (!agent.id) continue;
|
|
126
|
+
if (next.some((item) => item.id === agent.id)) continue;
|
|
127
|
+
next.push(normalizeAgent(agent));
|
|
128
|
+
}
|
|
129
|
+
return next;
|
|
130
|
+
}
|
|
131
|
+
|
|
24
132
|
function memberRoleWeight(role = "") {
|
|
25
133
|
const normalized = String(role || "").trim().toLowerCase();
|
|
26
134
|
if (normalized === "owner") return 3;
|
|
@@ -54,6 +162,8 @@ function normalizeSharedProject(project = {}, cwd = process.cwd()) {
|
|
|
54
162
|
claimedAt: String(project.activeOperator.claimedAt || "").trim()
|
|
55
163
|
}
|
|
56
164
|
: null;
|
|
165
|
+
const participants = buildProjectParticipants({ ...project, members });
|
|
166
|
+
const agents = buildProjectAgents({ ...project, members, activeOperator });
|
|
57
167
|
|
|
58
168
|
return {
|
|
59
169
|
version: 1,
|
|
@@ -72,6 +182,8 @@ function normalizeSharedProject(project = {}, cwd = process.cwd()) {
|
|
|
72
182
|
: "chat",
|
|
73
183
|
runtimeProfile: String(project.runtimeProfile || "").trim(),
|
|
74
184
|
members,
|
|
185
|
+
participants,
|
|
186
|
+
agents,
|
|
75
187
|
tasks,
|
|
76
188
|
pendingInvites,
|
|
77
189
|
recentEvents,
|
|
@@ -899,6 +1011,8 @@ export function formatSharedProjectStatus(project) {
|
|
|
899
1011
|
approvalPolicy: project.approvalPolicy,
|
|
900
1012
|
activeOperator: project.activeOperator,
|
|
901
1013
|
members: project.members,
|
|
1014
|
+
participants: project.participants,
|
|
1015
|
+
agents: project.agents,
|
|
902
1016
|
pendingInvites: project.pendingInvites,
|
|
903
1017
|
tasks: project.tasks,
|
|
904
1018
|
recentEvents: project.recentEvents
|