@agent-relay/dashboard-server 2.0.69 → 2.0.70
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/dist/server.js +27 -7
- package/dist/server.js.map +1 -1
- package/out/404.html +1 -1
- package/out/about.html +1 -1
- package/out/about.txt +1 -1
- package/out/app/onboarding.html +1 -1
- package/out/app/onboarding.txt +1 -1
- package/out/app.html +1 -1
- package/out/app.txt +1 -1
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +1 -1
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
- package/out/blog/let-them-cook-multi-agent-orchestration.html +1 -1
- package/out/blog/let-them-cook-multi-agent-orchestration.txt +1 -1
- package/out/blog.html +1 -1
- package/out/blog.txt +1 -1
- package/out/careers.html +1 -1
- package/out/careers.txt +1 -1
- package/out/changelog.html +1 -1
- package/out/changelog.txt +1 -1
- package/out/cloud/link.html +1 -1
- package/out/cloud/link.txt +1 -1
- package/out/complete-profile.html +1 -1
- package/out/complete-profile.txt +1 -1
- package/out/connect-repos.html +1 -1
- package/out/connect-repos.txt +1 -1
- package/out/contact.html +1 -1
- package/out/contact.txt +1 -1
- package/out/docs.html +1 -1
- package/out/docs.txt +1 -1
- package/out/history.html +1 -1
- package/out/history.txt +1 -1
- package/out/index.html +1 -1
- package/out/index.txt +1 -1
- package/out/login.html +1 -1
- package/out/login.txt +1 -1
- package/out/metrics.html +1 -1
- package/out/metrics.txt +1 -1
- package/out/pricing.html +1 -1
- package/out/pricing.txt +1 -1
- package/out/privacy.html +1 -1
- package/out/privacy.txt +1 -1
- package/out/providers/setup/claude.html +1 -1
- package/out/providers/setup/claude.txt +1 -1
- package/out/providers/setup/codex.html +1 -1
- package/out/providers/setup/codex.txt +1 -1
- package/out/providers/setup/cursor.html +1 -1
- package/out/providers/setup/cursor.txt +1 -1
- package/out/providers.html +1 -1
- package/out/providers.txt +1 -1
- package/out/security.html +1 -1
- package/out/security.txt +1 -1
- package/out/signup.html +1 -1
- package/out/signup.txt +1 -1
- package/out/terms.html +1 -1
- package/out/terms.txt +1 -1
- package/package.json +1 -1
- /package/out/_next/static/{ksklx6dOwf9cjVY6ez8ZH → -BPTMieIVPN3UZGwSczoP}/_buildManifest.js +0 -0
- /package/out/_next/static/{ksklx6dOwf9cjVY6ez8ZH → -BPTMieIVPN3UZGwSczoP}/_ssgManifest.js +0 -0
package/dist/server.js
CHANGED
|
@@ -1756,15 +1756,17 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
1756
1756
|
existing.avatarUrl = user.avatarUrl;
|
|
1757
1757
|
}
|
|
1758
1758
|
else {
|
|
1759
|
-
|
|
1759
|
+
// Use stable timestamps from the user/file data, not new Date(),
|
|
1760
|
+
// so getAllData() produces deterministic output for dedup comparison
|
|
1761
|
+
const stableTimestamp = user.lastSeen || user.connectedAt || new Date(remoteData.updatedAt).toISOString();
|
|
1760
1762
|
agentsMap.set(user.name, {
|
|
1761
1763
|
name: user.name,
|
|
1762
1764
|
role: 'User',
|
|
1763
1765
|
cli: 'dashboard',
|
|
1764
1766
|
messageCount: 0,
|
|
1765
1767
|
status: 'online',
|
|
1766
|
-
lastSeen:
|
|
1767
|
-
lastActive:
|
|
1768
|
+
lastSeen: stableTimestamp,
|
|
1769
|
+
lastActive: stableTimestamp,
|
|
1768
1770
|
needsAttention: false,
|
|
1769
1771
|
avatarUrl: user.avatarUrl,
|
|
1770
1772
|
});
|
|
@@ -1954,18 +1956,21 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
1954
1956
|
return true;
|
|
1955
1957
|
});
|
|
1956
1958
|
// Separate AI agents from human users
|
|
1959
|
+
// Sort by name for deterministic JSON serialization (enables dedup comparison)
|
|
1957
1960
|
const filteredAgents = validEntries
|
|
1958
1961
|
.filter(agent => agent.cli !== 'dashboard')
|
|
1959
1962
|
.map(agent => ({
|
|
1960
1963
|
...agent,
|
|
1961
1964
|
isHuman: false,
|
|
1962
|
-
}))
|
|
1965
|
+
}))
|
|
1966
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
1963
1967
|
const humanUsers = validEntries
|
|
1964
1968
|
.filter(agent => agent.cli === 'dashboard')
|
|
1965
1969
|
.map(agent => ({
|
|
1966
1970
|
...agent,
|
|
1967
1971
|
isHuman: true,
|
|
1968
|
-
}))
|
|
1972
|
+
}))
|
|
1973
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
1969
1974
|
return {
|
|
1970
1975
|
agents: filteredAgents,
|
|
1971
1976
|
users: humanUsers,
|
|
@@ -1978,6 +1983,7 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
1978
1983
|
// Track clients that are still initializing (haven't received first data yet)
|
|
1979
1984
|
// This prevents race conditions where broadcastData sends before initial data is sent
|
|
1980
1985
|
const initializingClients = new WeakSet();
|
|
1986
|
+
let lastBroadcastPayload = '';
|
|
1981
1987
|
const broadcastData = async () => {
|
|
1982
1988
|
try {
|
|
1983
1989
|
const data = await getAllData();
|
|
@@ -1987,6 +1993,11 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
1987
1993
|
console.warn('[dashboard] Skipping broadcast - empty payload');
|
|
1988
1994
|
return;
|
|
1989
1995
|
}
|
|
1996
|
+
// Skip broadcast if data hasn't changed since last send
|
|
1997
|
+
if (rawPayload === lastBroadcastPayload) {
|
|
1998
|
+
return;
|
|
1999
|
+
}
|
|
2000
|
+
lastBroadcastPayload = rawPayload;
|
|
1990
2001
|
// Push into buffer and wrap with sequence ID for replay support
|
|
1991
2002
|
const seq = mainMessageBuffer.push('data', rawPayload);
|
|
1992
2003
|
const payload = JSON.stringify({ seq, ...data });
|
|
@@ -2066,6 +2077,7 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
2066
2077
|
}
|
|
2067
2078
|
return { projects: [], messages: [], connected: false };
|
|
2068
2079
|
};
|
|
2080
|
+
let lastBridgeBroadcastPayload = '';
|
|
2069
2081
|
const broadcastBridgeData = async () => {
|
|
2070
2082
|
try {
|
|
2071
2083
|
const data = await getBridgeData();
|
|
@@ -2075,6 +2087,11 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
2075
2087
|
console.warn('[dashboard] Skipping bridge broadcast - empty payload');
|
|
2076
2088
|
return;
|
|
2077
2089
|
}
|
|
2090
|
+
// Skip broadcast if data hasn't changed since last send
|
|
2091
|
+
if (payload === lastBridgeBroadcastPayload) {
|
|
2092
|
+
return;
|
|
2093
|
+
}
|
|
2094
|
+
lastBridgeBroadcastPayload = payload;
|
|
2078
2095
|
wssBridge.clients.forEach(client => {
|
|
2079
2096
|
if (client.readyState === WebSocket.OPEN) {
|
|
2080
2097
|
try {
|
|
@@ -5816,12 +5833,15 @@ Start by greeting the project leads and asking for status updates.`;
|
|
|
5816
5833
|
}
|
|
5817
5834
|
return {};
|
|
5818
5835
|
}
|
|
5819
|
-
// Watch for changes
|
|
5836
|
+
// Watch for changes - poll as a safety net for DB-backed storage mode.
|
|
5837
|
+
// Real-time updates are already handled by explicit broadcastData() calls
|
|
5838
|
+
// at every data mutation point (message send, spawn, release, cwd update, etc.).
|
|
5839
|
+
// This interval only catches external/indirect changes (presence, DB edits).
|
|
5820
5840
|
if (storage) {
|
|
5821
5841
|
setInterval(() => {
|
|
5822
5842
|
broadcastData().catch((err) => console.error('Broadcast failed', err));
|
|
5823
5843
|
broadcastBridgeData().catch((err) => console.error('Bridge broadcast failed', err));
|
|
5824
|
-
},
|
|
5844
|
+
}, 5000);
|
|
5825
5845
|
}
|
|
5826
5846
|
else {
|
|
5827
5847
|
let fsWait = null;
|