agent-relay-server 0.4.14 → 0.4.16
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 +1 -1
- package/package.json +1 -1
- package/public/dashboard.js +68 -5
- package/public/index.html +7 -1
package/README.md
CHANGED
|
@@ -111,7 +111,7 @@ The plugin or sidecar registers the agent and injects messaging context:
|
|
|
111
111
|
|
|
112
112
|
```
|
|
113
113
|
Agent Relay active. Your agent ID: macmini2-cli-myproject-a1b2c3
|
|
114
|
-
Relay URL: http://localhost:4850 | Server: 0.4.
|
|
114
|
+
Relay URL: http://localhost:4850 | Server: 0.4.16 | Plugin: 0.4.16
|
|
115
115
|
Approval mode: open
|
|
116
116
|
```
|
|
117
117
|
|
package/package.json
CHANGED
package/public/dashboard.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const DEFAULT_COMPOSE = { from: "", to: "", body: "", channel: "", subject: "", claimable: false };
|
|
4
4
|
const CLOSED_TASK_STATUSES = new Set(["done", "failed", "canceled"]);
|
|
5
5
|
const STATUS_SORT_ORDER = { online: 0, idle: 1, busy: 2, offline: 3 };
|
|
6
|
+
const LIVE_REFRESH_MS = 5_000;
|
|
6
7
|
|
|
7
8
|
function loadPref(key, fallback) {
|
|
8
9
|
try {
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
tasks: [],
|
|
33
34
|
taskEvents: [],
|
|
34
35
|
stats: {},
|
|
36
|
+
now: Date.now(),
|
|
35
37
|
authToken: loadPref("authToken", ""),
|
|
36
38
|
|
|
37
39
|
selectedAgent: "",
|
|
@@ -57,12 +59,19 @@
|
|
|
57
59
|
|
|
58
60
|
chartInstances: {},
|
|
59
61
|
_es: null,
|
|
60
|
-
|
|
62
|
+
_clockTimer: null,
|
|
63
|
+
_refreshTimer: null,
|
|
64
|
+
_refreshInFlight: false,
|
|
61
65
|
};
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
function watchPersistedPrefs(vm) {
|
|
65
69
|
vm.$watch("showOffline", (value) => vm.save("showOffline", value));
|
|
70
|
+
vm.$watch("autoRefresh", (value) => {
|
|
71
|
+
vm.save("autoRefresh", value);
|
|
72
|
+
if (value) vm.startAutoRefresh();
|
|
73
|
+
else vm.stopAutoRefresh();
|
|
74
|
+
});
|
|
66
75
|
vm.$watch("agentSort", (value) => vm.save("agentSort", value));
|
|
67
76
|
vm.$watch("agentSortDir", (value) => vm.save("agentSortDir", value));
|
|
68
77
|
vm.$watch("agentStatusFilter", (value) => vm.save("agentStatusFilter", value));
|
|
@@ -95,12 +104,31 @@
|
|
|
95
104
|
else vm.tasks.unshift(task);
|
|
96
105
|
}
|
|
97
106
|
|
|
107
|
+
function syncAgentStats(vm) {
|
|
108
|
+
vm.stats.agents = vm.agents.length;
|
|
109
|
+
vm.stats.online = vm.agents.filter((agent) => agent.status !== "offline").length;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function syncMessageStats(vm, msg) {
|
|
113
|
+
vm.stats.messages = (vm.stats.messages ?? 0) + 1;
|
|
114
|
+
const createdAt = new Date(msg.createdAt || Date.now()).getTime();
|
|
115
|
+
if (Number.isFinite(createdAt) && Date.now() - createdAt <= 86_400_000) {
|
|
116
|
+
vm.stats.messagesLast24h = (vm.stats.messagesLast24h ?? 0) + 1;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function refreshChartsIfVisible(vm) {
|
|
121
|
+
if (vm.view !== "analytics") return;
|
|
122
|
+
vm.$nextTick(() => vm.renderCharts());
|
|
123
|
+
}
|
|
124
|
+
|
|
98
125
|
function createLifecycleMethods() {
|
|
99
126
|
return {
|
|
100
127
|
async init() {
|
|
101
128
|
await this.refresh();
|
|
102
129
|
this.connectSSE();
|
|
103
|
-
this.
|
|
130
|
+
this.startClock();
|
|
131
|
+
this.startAutoRefresh();
|
|
104
132
|
watchPersistedPrefs(this);
|
|
105
133
|
},
|
|
106
134
|
|
|
@@ -113,6 +141,25 @@
|
|
|
113
141
|
if (view === "messages") this.fetchMessages();
|
|
114
142
|
if (view === "tasks") this.fetchTasks();
|
|
115
143
|
},
|
|
144
|
+
|
|
145
|
+
startClock() {
|
|
146
|
+
if (this._clockTimer) return;
|
|
147
|
+
this._clockTimer = setInterval(() => {
|
|
148
|
+
this.now = Date.now();
|
|
149
|
+
}, 1_000);
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
startAutoRefresh() {
|
|
153
|
+
this.stopAutoRefresh();
|
|
154
|
+
if (!this.autoRefresh) return;
|
|
155
|
+
this._refreshTimer = setInterval(() => this.refreshLiveData(), LIVE_REFRESH_MS);
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
stopAutoRefresh() {
|
|
159
|
+
if (!this._refreshTimer) return;
|
|
160
|
+
clearInterval(this._refreshTimer);
|
|
161
|
+
this._refreshTimer = null;
|
|
162
|
+
},
|
|
116
163
|
};
|
|
117
164
|
}
|
|
118
165
|
|
|
@@ -156,17 +203,22 @@
|
|
|
156
203
|
|
|
157
204
|
vm.messages.push(msg);
|
|
158
205
|
if (vm.messages.length > 200) vm.messages.shift();
|
|
159
|
-
|
|
206
|
+
syncMessageStats(vm, msg);
|
|
207
|
+
refreshChartsIfVisible(vm);
|
|
160
208
|
}
|
|
161
209
|
|
|
162
210
|
function handleAgentStatus(vm, agent) {
|
|
163
211
|
upsertById(vm.agents, agent);
|
|
164
212
|
vm.agentsById[agent.id] = agent;
|
|
213
|
+
syncAgentStats(vm);
|
|
214
|
+
refreshChartsIfVisible(vm);
|
|
165
215
|
}
|
|
166
216
|
|
|
167
217
|
function handleAgentRemoved(vm, data) {
|
|
168
218
|
vm.agents = vm.agents.filter((agent) => agent.id !== data.id);
|
|
169
219
|
delete vm.agentsById[data.id];
|
|
220
|
+
syncAgentStats(vm);
|
|
221
|
+
refreshChartsIfVisible(vm);
|
|
170
222
|
}
|
|
171
223
|
|
|
172
224
|
function handleMessageClaimed(vm, data) {
|
|
@@ -216,6 +268,17 @@
|
|
|
216
268
|
await Promise.all([this.fetchStats(), this.fetchAgents(), this.fetchMessages(), this.fetchTasks()]);
|
|
217
269
|
},
|
|
218
270
|
|
|
271
|
+
async refreshLiveData() {
|
|
272
|
+
if (this._refreshInFlight || this.authNeeded) return;
|
|
273
|
+
this._refreshInFlight = true;
|
|
274
|
+
try {
|
|
275
|
+
await this.refresh();
|
|
276
|
+
refreshChartsIfVisible(this);
|
|
277
|
+
} finally {
|
|
278
|
+
this._refreshInFlight = false;
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
|
|
219
282
|
async fetchStats() {
|
|
220
283
|
try {
|
|
221
284
|
this.stats = await this.api("GET", "/stats");
|
|
@@ -392,7 +455,7 @@
|
|
|
392
455
|
const lastSeenMs = new Date(agent.lastSeen).getTime();
|
|
393
456
|
if (!Number.isFinite(lastSeenMs)) return "Trying to reconnect...";
|
|
394
457
|
|
|
395
|
-
const ageSec = Math.max(0, (Date.now() - lastSeenMs) / 1000);
|
|
458
|
+
const ageSec = Math.max(0, ((this.now || Date.now()) - lastSeenMs) / 1000);
|
|
396
459
|
return ageSec <= 45 ? "Starting up..." : "Trying to reconnect...";
|
|
397
460
|
}
|
|
398
461
|
|
|
@@ -401,7 +464,7 @@
|
|
|
401
464
|
const ts = new Date(iso).getTime();
|
|
402
465
|
if (!Number.isFinite(ts)) return "";
|
|
403
466
|
|
|
404
|
-
const diff = Math.max(0, (Date.now() - ts) / 1000);
|
|
467
|
+
const diff = Math.max(0, ((this.now || Date.now()) - ts) / 1000);
|
|
405
468
|
if (diff < 60) return Math.floor(diff) + "s ago";
|
|
406
469
|
if (diff < 3600) return Math.floor(diff / 60) + "m ago";
|
|
407
470
|
if (diff < 86400) return Math.floor(diff / 3600) + "h ago";
|
package/public/index.html
CHANGED
|
@@ -109,6 +109,12 @@
|
|
|
109
109
|
<input type="checkbox" class="form-check-input" x-model="showOffline">
|
|
110
110
|
<span class="form-check-label small">Show offline</span>
|
|
111
111
|
</label>
|
|
112
|
+
</div>
|
|
113
|
+
<div class="d-flex align-items-center gap-2 mb-2">
|
|
114
|
+
<label class="form-check form-switch mb-0">
|
|
115
|
+
<input type="checkbox" class="form-check-input" x-model="autoRefresh">
|
|
116
|
+
<span class="form-check-label small">Auto refresh</span>
|
|
117
|
+
</label>
|
|
112
118
|
</div>
|
|
113
119
|
<div class="text-muted small" x-show="stats.version" x-text="'v' + stats.version"></div>
|
|
114
120
|
</div>
|
|
@@ -389,7 +395,7 @@
|
|
|
389
395
|
<div class="ms-auto d-flex gap-2 align-items-center flex-wrap">
|
|
390
396
|
<select class="form-select form-select-sm" style="width: auto; min-width: 160px" x-model="selectedAgent" @change="fetchMessages()">
|
|
391
397
|
<option value="">All agents</option>
|
|
392
|
-
<template x-for="a in
|
|
398
|
+
<template x-for="a in composeAgents" :key="a.id">
|
|
393
399
|
<option :value="a.id" x-text="displayName(a) + ' [' + a.id.slice(-6) + ']'"></option>
|
|
394
400
|
</template>
|
|
395
401
|
</select>
|