agent-tank 0.9.4 → 0.9.5
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 +19 -2
- package/bin/agent-tank.js +15 -0
- package/package.json +1 -1
- package/src/agents/base.js +1 -1
- package/src/agents/gemini.js +20 -18
- package/src/auto-refresh-manager.js +4 -5
- package/src/index.js +116 -13
- package/src/server.js +1 -0
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ By default it starts on:
|
|
|
75
75
|
http://127.0.0.1:3456
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
If Docker is
|
|
78
|
+
If Docker is available, Agent Tank asks Docker for the active bridge gateway addresses and binds them by default so containers on the same host can reach it without exposing it on the public interface. If Docker is unavailable, it falls back to local bridge interface detection.
|
|
79
79
|
|
|
80
80
|
Use this if you want localhost only:
|
|
81
81
|
|
|
@@ -97,6 +97,9 @@ agent-tank --once --json
|
|
|
97
97
|
|
|
98
98
|
# Show the installed Agent Tank version
|
|
99
99
|
agent-tank --version
|
|
100
|
+
|
|
101
|
+
# Require at least 60 seconds between refreshes for the same agent
|
|
102
|
+
agent-tank --refresh-cooldown 60
|
|
100
103
|
```
|
|
101
104
|
|
|
102
105
|
## What You Get
|
|
@@ -165,6 +168,16 @@ agent-tank --no-docker
|
|
|
165
168
|
agent-tank --auto-refresh-mode none
|
|
166
169
|
```
|
|
167
170
|
|
|
171
|
+
### Slow Down Agent Refreshes
|
|
172
|
+
|
|
173
|
+
By default, Agent Tank will not refresh the same agent more than once every 30 seconds, even if the refresh is triggered manually or by detected CLI activity. This reduces unnecessary polling and helps avoid CLI-side rate limiting.
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
agent-tank --refresh-cooldown 60
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Set it to `0` to disable the cooldown entirely.
|
|
180
|
+
|
|
168
181
|
## Command Line Options
|
|
169
182
|
|
|
170
183
|
```text
|
|
@@ -186,6 +199,7 @@ Options:
|
|
|
186
199
|
--auto-refresh Enable/disable background auto-refresh (default: true)
|
|
187
200
|
--auto-refresh-mode <mode> Refresh mode: none, interval, activity (default: activity)
|
|
188
201
|
--auto-refresh-interval <seconds> Auto-refresh interval in seconds (default: 60)
|
|
202
|
+
--refresh-cooldown <seconds> Minimum time between refreshes per agent (default: 30, 0 = disabled)
|
|
189
203
|
--activity-debounce <ms> Activity debounce interval in milliseconds (default: 5000)
|
|
190
204
|
--keepalive Enable/disable session keepalive (default: true)
|
|
191
205
|
--keepalive-interval <seconds> Session keepalive interval in seconds (default: 300)
|
|
@@ -213,6 +227,7 @@ Environment variables override CLI flags and config file values.
|
|
|
213
227
|
| `AGENT_TANK_AUTO_REFRESH` | Enable/disable auto-refresh |
|
|
214
228
|
| `AGENT_TANK_AUTO_REFRESH_MODE` | `none`, `interval`, or `activity` |
|
|
215
229
|
| `AGENT_TANK_AUTO_REFRESH_INTERVAL` | Auto-refresh interval in seconds |
|
|
230
|
+
| `AGENT_TANK_REFRESH_COOLDOWN` | Minimum time between refreshes per agent in seconds |
|
|
216
231
|
| `AGENT_TANK_ACTIVITY_DEBOUNCE` | Activity debounce interval in milliseconds |
|
|
217
232
|
| `AGENT_TANK_KEEPALIVE` | Enable/disable keepalive |
|
|
218
233
|
| `AGENT_TANK_KEEPALIVE_INTERVAL` | Keepalive interval in seconds |
|
|
@@ -228,10 +243,12 @@ Environment variables override CLI flags and config file values.
|
|
|
228
243
|
"port": 8080,
|
|
229
244
|
"dockerAccess": true,
|
|
230
245
|
"claudeApi": false,
|
|
246
|
+
"refreshCooldown": 30,
|
|
231
247
|
"autoRefresh": {
|
|
232
248
|
"mode": "activity",
|
|
233
249
|
"interval": 60,
|
|
234
|
-
"activityDebounce": 5000
|
|
250
|
+
"activityDebounce": 5000,
|
|
251
|
+
"refreshCooldown": 30
|
|
235
252
|
},
|
|
236
253
|
"keepalive": {
|
|
237
254
|
"enabled": true,
|
package/bin/agent-tank.js
CHANGED
|
@@ -25,6 +25,7 @@ const options = {
|
|
|
25
25
|
'auto-refresh': { type: 'boolean', default: true },
|
|
26
26
|
'auto-refresh-interval': { type: 'string', default: '60' },
|
|
27
27
|
'auto-refresh-mode': { type: 'string', default: 'activity' },
|
|
28
|
+
'refresh-cooldown': { type: 'string', default: '30' },
|
|
28
29
|
'activity-debounce': { type: 'string', default: '5000' },
|
|
29
30
|
'history-retention-days': { type: 'string', default: '14' },
|
|
30
31
|
'keepalive': { type: 'boolean', default: true },
|
|
@@ -66,6 +67,7 @@ Options:
|
|
|
66
67
|
--auto-refresh Enable/disable background auto-refresh (default: true)
|
|
67
68
|
--auto-refresh-mode <mode> Refresh mode: none, interval, activity (default: activity)
|
|
68
69
|
--auto-refresh-interval <seconds> Auto-refresh interval in seconds (default: 60, 0 = disabled)
|
|
70
|
+
--refresh-cooldown <seconds> Minimum time between refreshes per agent (default: 30, 0 = disabled)
|
|
69
71
|
--activity-debounce <ms> Activity debounce interval in milliseconds (default: 5000)
|
|
70
72
|
--keepalive Enable/disable session keepalive (default: true)
|
|
71
73
|
--keepalive-interval <seconds> Session keepalive interval in seconds (default: 300, 0 = disabled)
|
|
@@ -91,6 +93,7 @@ Environment variables:
|
|
|
91
93
|
AGENT_TANK_AUTO_REFRESH Enable/disable background auto-refresh ("1" or "true" / "0" or "false")
|
|
92
94
|
AGENT_TANK_AUTO_REFRESH_MODE Refresh mode: none, interval, activity
|
|
93
95
|
AGENT_TANK_AUTO_REFRESH_INTERVAL Auto-refresh interval in seconds
|
|
96
|
+
AGENT_TANK_REFRESH_COOLDOWN Minimum time between refreshes per agent in seconds
|
|
94
97
|
AGENT_TANK_ACTIVITY_DEBOUNCE Activity debounce interval in milliseconds
|
|
95
98
|
AGENT_TANK_KEEPALIVE Enable/disable session keepalive ("1" or "true" / "0" or "false")
|
|
96
99
|
AGENT_TANK_KEEPALIVE_INTERVAL Session keepalive interval in seconds
|
|
@@ -109,6 +112,7 @@ Examples:
|
|
|
109
112
|
agent-tank --auto-refresh-mode activity # Use activity-based polling (default)
|
|
110
113
|
agent-tank --activity-debounce 10000 # Wait 10 seconds after activity before refresh
|
|
111
114
|
agent-tank --auto-refresh-interval 30 # Refresh every 30 seconds
|
|
115
|
+
agent-tank --refresh-cooldown 45 # Limit each agent to one refresh every 45 seconds
|
|
112
116
|
agent-tank --no-auto-refresh # Disable background auto-refresh
|
|
113
117
|
agent-tank --keepalive-interval 600 # Send keepalive every 10 minutes
|
|
114
118
|
agent-tank --no-keepalive # Disable session keepalive
|
|
@@ -210,6 +214,16 @@ async function main() {
|
|
|
210
214
|
autoRefreshMode = config.autoRefresh.mode;
|
|
211
215
|
}
|
|
212
216
|
|
|
217
|
+
const refreshCooldownEnv = process.env.AGENT_TANK_REFRESH_COOLDOWN;
|
|
218
|
+
let refreshCooldown = parseInt(values['refresh-cooldown'], 10);
|
|
219
|
+
if (refreshCooldownEnv !== undefined) {
|
|
220
|
+
refreshCooldown = parseInt(refreshCooldownEnv, 10);
|
|
221
|
+
} else if (config.refreshCooldown !== undefined) {
|
|
222
|
+
refreshCooldown = config.refreshCooldown;
|
|
223
|
+
} else if (config.autoRefresh?.refreshCooldown !== undefined) {
|
|
224
|
+
refreshCooldown = config.autoRefresh.refreshCooldown;
|
|
225
|
+
}
|
|
226
|
+
|
|
213
227
|
// Activity debounce configuration (env > CLI > config file)
|
|
214
228
|
const activityDebounceEnv = process.env.AGENT_TANK_ACTIVITY_DEBOUNCE;
|
|
215
229
|
let activityDebounce = parseInt(values['activity-debounce'], 10);
|
|
@@ -269,6 +283,7 @@ async function main() {
|
|
|
269
283
|
autoRefreshEnabled: onceMode ? false : autoRefreshEnabled, // Disable auto-refresh in one-shot mode
|
|
270
284
|
autoRefreshInterval,
|
|
271
285
|
autoRefreshMode: onceMode ? 'none' : autoRefreshMode, // Disable auto-refresh in one-shot mode
|
|
286
|
+
refreshCooldown,
|
|
272
287
|
activityDebounce,
|
|
273
288
|
keepaliveEnabled: onceMode ? false : keepaliveEnabled, // Disable keepalive in one-shot mode
|
|
274
289
|
keepaliveInterval,
|
package/package.json
CHANGED
package/src/agents/base.js
CHANGED
|
@@ -329,7 +329,7 @@ class BaseAgent {
|
|
|
329
329
|
|
|
330
330
|
// Process is already at prompt, send commands immediately
|
|
331
331
|
logger.agent(this.name, 'Sending commands to persistent process...');
|
|
332
|
-
this.sendCommands(this.shell,
|
|
332
|
+
this.sendCommands(this.shell, existingOutput);
|
|
333
333
|
});
|
|
334
334
|
}
|
|
335
335
|
|
package/src/agents/gemini.js
CHANGED
|
@@ -23,32 +23,36 @@ class GeminiAgent extends BaseAgent {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
_hasReadyPrompt(output) {
|
|
27
|
+
const clean = this.stripAnsi(output);
|
|
28
|
+
return clean.includes('Type your message')
|
|
29
|
+
|| clean.includes('gemini>')
|
|
30
|
+
|| /Ready\s*\(/.test(clean);
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
isReadyForCommands(output) {
|
|
27
34
|
// Don't consider ready if authentication is in progress
|
|
28
35
|
if (this._isAuthenticating(output)) {
|
|
29
36
|
return false;
|
|
30
37
|
}
|
|
31
|
-
|
|
32
|
-
// v0.35+: "Ready" in terminal title + visible prompt area (no "Type your message")
|
|
33
|
-
// Also check for terminal title sequence containing "Ready"
|
|
34
|
-
return output.includes('Type your message')
|
|
35
|
-
|| output.includes('gemini>')
|
|
36
|
-
|| /Ready\s*\(/.test(output);
|
|
38
|
+
return this._hasReadyPrompt(output);
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
_isAuthenticating(output) {
|
|
40
42
|
// Detect OAuth/authentication screens where Escape would cancel the flow
|
|
41
43
|
const clean = this.stripAnsi(output);
|
|
44
|
+
const hasAuthFlow = /waiting for authentication/i.test(clean)
|
|
45
|
+
|| /press esc.*to cancel/i.test(clean)
|
|
46
|
+
|| /authenticating\.\.\./i.test(clean);
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
if (clean.includes('Type your message') || clean.includes('? for shortcuts')) {
|
|
48
|
+
if (!hasAuthFlow) {
|
|
45
49
|
return false;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
// Newer Gemini builds can render footer hints like "? for shortcuts"
|
|
53
|
+
// before the actual input prompt is available. Treat auth as complete
|
|
54
|
+
// only when the real prompt has returned.
|
|
55
|
+
return !this._hasReadyPrompt(clean);
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
detectAuthenticationState(output) {
|
|
@@ -159,12 +163,10 @@ class GeminiAgent extends BaseAgent {
|
|
|
159
163
|
return;
|
|
160
164
|
}
|
|
161
165
|
logger.agent(this.name, 'Sending /stats command...');
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
setTimeout(() => shell.write('
|
|
165
|
-
setTimeout(() => shell.write('
|
|
166
|
-
setTimeout(() => shell.write('\x1b'), 1000);
|
|
167
|
-
setTimeout(() => shell.write('\r'), 1500);
|
|
166
|
+
// Newer Gemini builds use Esc for "rewind", which can derail the command flow.
|
|
167
|
+
// Submit /stats directly once the prompt is ready.
|
|
168
|
+
setTimeout(() => shell.write('/stats'), 200);
|
|
169
|
+
setTimeout(() => shell.write('\r'), 600);
|
|
168
170
|
}
|
|
169
171
|
|
|
170
172
|
// Calculate pace data for a model entry (Gemini uses 24h sessions)
|
|
@@ -230,12 +230,11 @@ class AutoRefreshManager {
|
|
|
230
230
|
console.log(`Backend auto-refresh [${globalAgents.join(', ')}]: every ${globalInterval}s (interval mode)`);
|
|
231
231
|
this.autoRefreshTimer = setInterval(async () => {
|
|
232
232
|
console.log(`[Auto-refresh] Refreshing ${globalAgents.join(', ')}...`);
|
|
233
|
-
const promises = globalAgents.map(name =>
|
|
234
|
-
|
|
235
|
-
return agent ? agent.refresh().catch(err =>
|
|
233
|
+
const promises = globalAgents.map(name =>
|
|
234
|
+
this.onRefreshAgent(name).catch(err =>
|
|
236
235
|
console.error(`Error refreshing ${name}:`, err.message)
|
|
237
|
-
)
|
|
238
|
-
|
|
236
|
+
)
|
|
237
|
+
);
|
|
239
238
|
await Promise.all(promises);
|
|
240
239
|
this.lastRefreshedAt = new Date().toISOString();
|
|
241
240
|
}, globalInterval * 1000);
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const path = require('node:path');
|
|
2
2
|
const os = require('node:os');
|
|
3
|
+
const { execFileSync } = require('node:child_process');
|
|
3
4
|
const { ClaudeAgent } = require('./agents/claude.js');
|
|
4
5
|
const { GeminiAgent } = require('./agents/gemini.js');
|
|
5
6
|
const { CodexAgent } = require('./agents/codex.js');
|
|
@@ -49,7 +50,9 @@ function isPrivateIpv4(address) {
|
|
|
49
50
|
/^172\.(1[6-9]|2\d|3[0-1])\./.test(address);
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
function
|
|
53
|
+
function detectDockerHostsFromInterfaces(networkInterfaces = os.networkInterfaces()) {
|
|
54
|
+
const hosts = [];
|
|
55
|
+
|
|
53
56
|
for (const [name, addresses] of Object.entries(networkInterfaces)) {
|
|
54
57
|
if (!DOCKER_INTERFACE_PATTERNS.some(pattern => pattern.test(name))) {
|
|
55
58
|
continue;
|
|
@@ -57,12 +60,55 @@ function detectDockerHost(networkInterfaces = os.networkInterfaces()) {
|
|
|
57
60
|
|
|
58
61
|
for (const info of addresses || []) {
|
|
59
62
|
if (info && info.family === 'IPv4' && !info.internal && isPrivateIpv4(info.address)) {
|
|
60
|
-
|
|
63
|
+
if (!hosts.includes(info.address)) {
|
|
64
|
+
hosts.push(info.address);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return hosts.length > 0 ? hosts : null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function detectDockerHosts({
|
|
74
|
+
exec = execFileSync,
|
|
75
|
+
networkInterfaces = os.networkInterfaces(),
|
|
76
|
+
} = {}) {
|
|
77
|
+
try {
|
|
78
|
+
const listOutput = exec('docker', ['network', 'ls', '--format', '{{json .}}'], {
|
|
79
|
+
encoding: 'utf8',
|
|
80
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
81
|
+
});
|
|
82
|
+
const networks = listOutput
|
|
83
|
+
.split('\n')
|
|
84
|
+
.map(line => line.trim())
|
|
85
|
+
.filter(Boolean)
|
|
86
|
+
.map(line => JSON.parse(line))
|
|
87
|
+
.filter(network => network && network.Driver === 'bridge');
|
|
88
|
+
|
|
89
|
+
const hosts = [];
|
|
90
|
+
for (const network of networks) {
|
|
91
|
+
const inspectOutput = exec('docker', ['network', 'inspect', network.ID, '--format', '{{json .IPAM.Config}}'], {
|
|
92
|
+
encoding: 'utf8',
|
|
93
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
94
|
+
}).trim();
|
|
95
|
+
|
|
96
|
+
const ipamConfigs = inspectOutput ? JSON.parse(inspectOutput) : [];
|
|
97
|
+
for (const config of ipamConfigs || []) {
|
|
98
|
+
if (config && config.Gateway && isPrivateIpv4(config.Gateway) && !hosts.includes(config.Gateway)) {
|
|
99
|
+
hosts.push(config.Gateway);
|
|
100
|
+
}
|
|
61
101
|
}
|
|
62
102
|
}
|
|
103
|
+
|
|
104
|
+
if (hosts.length > 0) {
|
|
105
|
+
return hosts;
|
|
106
|
+
}
|
|
107
|
+
} catch (_err) {
|
|
108
|
+
// Fall back to interface detection when Docker is unavailable.
|
|
63
109
|
}
|
|
64
110
|
|
|
65
|
-
return
|
|
111
|
+
return detectDockerHostsFromInterfaces(networkInterfaces);
|
|
66
112
|
}
|
|
67
113
|
|
|
68
114
|
class AgentTank {
|
|
@@ -83,6 +129,9 @@ class AgentTank {
|
|
|
83
129
|
this.publicStatus = {}; // Public API status from upstream providers
|
|
84
130
|
this.skipServer = options.skipServer || false; // Skip HTTP server in one-shot mode
|
|
85
131
|
this.lastRefreshedAt = null;
|
|
132
|
+
this.refreshCooldown = Math.max(0, options.refreshCooldown ?? 30);
|
|
133
|
+
this._agentRefreshStartedAt = new Map();
|
|
134
|
+
this._agentRefreshPromises = new Map();
|
|
86
135
|
this.stopping = false;
|
|
87
136
|
|
|
88
137
|
// Auto-refresh configuration (backend periodic refresh)
|
|
@@ -299,10 +348,10 @@ class AgentTank {
|
|
|
299
348
|
const [, publicStatusResult] = await Promise.all([
|
|
300
349
|
// Agent PTY refreshes
|
|
301
350
|
Promise.all(
|
|
302
|
-
Array.from(this.agents.
|
|
303
|
-
|
|
351
|
+
Array.from(this.agents.keys()).map(name =>
|
|
352
|
+
this._refreshAgentWithCooldown(name).catch(err => {
|
|
304
353
|
if (!this.stopping && err.message !== 'Agent stopping') {
|
|
305
|
-
logger.error(`Error refreshing ${
|
|
354
|
+
logger.error(`Error refreshing ${name}:`, err.message);
|
|
306
355
|
}
|
|
307
356
|
})
|
|
308
357
|
)
|
|
@@ -347,7 +396,7 @@ class AgentTank {
|
|
|
347
396
|
if (!agent) {
|
|
348
397
|
throw new Error(`Agent not found: ${name}`);
|
|
349
398
|
}
|
|
350
|
-
await
|
|
399
|
+
await this._refreshAgentWithCooldown(name);
|
|
351
400
|
|
|
352
401
|
// Record snapshot and attach pace evaluation for single agent refresh
|
|
353
402
|
if (agent.usage) {
|
|
@@ -356,6 +405,47 @@ class AgentTank {
|
|
|
356
405
|
}
|
|
357
406
|
}
|
|
358
407
|
|
|
408
|
+
_getRefreshCooldownRemainingMs(name, now = Date.now()) {
|
|
409
|
+
if (this.refreshCooldown <= 0) {
|
|
410
|
+
return 0;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const lastStartedAt = this._agentRefreshStartedAt.get(name);
|
|
414
|
+
if (!lastStartedAt) {
|
|
415
|
+
return 0;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return Math.max(0, (this.refreshCooldown * 1000) - (now - lastStartedAt));
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async _refreshAgentWithCooldown(name) {
|
|
422
|
+
const agent = this.agents.get(name);
|
|
423
|
+
if (!agent) {
|
|
424
|
+
throw new Error(`Agent not found: ${name}`);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const activeRefresh = this._agentRefreshPromises.get(name);
|
|
428
|
+
if (activeRefresh) {
|
|
429
|
+
logger.agent(name, 'Refresh already in progress, reusing existing refresh');
|
|
430
|
+
return activeRefresh;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const remainingMs = this._getRefreshCooldownRemainingMs(name);
|
|
434
|
+
if (remainingMs > 0) {
|
|
435
|
+
logger.agent(name, `Refresh cooldown active, skipping (${Math.ceil(remainingMs / 1000)}s remaining)`);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
this._agentRefreshStartedAt.set(name, Date.now());
|
|
440
|
+
const refreshPromise = agent.refresh().finally(() => {
|
|
441
|
+
if (this._agentRefreshPromises.get(name) === refreshPromise) {
|
|
442
|
+
this._agentRefreshPromises.delete(name);
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
this._agentRefreshPromises.set(name, refreshPromise);
|
|
446
|
+
return refreshPromise;
|
|
447
|
+
}
|
|
448
|
+
|
|
359
449
|
/** Get usage history statistics. @returns {Object} */
|
|
360
450
|
getHistoryStats() { return this.historyStore.getStats(); }
|
|
361
451
|
|
|
@@ -447,16 +537,22 @@ class AgentTank {
|
|
|
447
537
|
});
|
|
448
538
|
}
|
|
449
539
|
|
|
450
|
-
_resolveListenHosts(detectHost =
|
|
540
|
+
_resolveListenHosts(detectHost = detectDockerHosts) {
|
|
451
541
|
if (this.explicitHost) {
|
|
452
542
|
return [this.host];
|
|
453
543
|
}
|
|
454
544
|
|
|
455
545
|
const hosts = ['127.0.0.1'];
|
|
456
546
|
if (this.dockerAccess) {
|
|
457
|
-
const
|
|
458
|
-
if (
|
|
459
|
-
|
|
547
|
+
const dockerHosts = detectHost();
|
|
548
|
+
if (dockerHosts) {
|
|
549
|
+
// Handle both single IP (legacy) and array of IPs
|
|
550
|
+
const hostList = Array.isArray(dockerHosts) ? dockerHosts : [dockerHosts];
|
|
551
|
+
for (const h of hostList) {
|
|
552
|
+
if (h && h !== '127.0.0.1' && !hosts.includes(h)) {
|
|
553
|
+
hosts.push(h);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
460
556
|
}
|
|
461
557
|
}
|
|
462
558
|
|
|
@@ -500,8 +596,15 @@ class AgentTank {
|
|
|
500
596
|
|
|
501
597
|
/** Get the auto-refresh configuration. @returns {Object} */
|
|
502
598
|
getAutoRefreshConfig() {
|
|
503
|
-
return {
|
|
599
|
+
return {
|
|
600
|
+
mode: this.autoRefresh.mode,
|
|
601
|
+
enabled: this.autoRefresh.enabled,
|
|
602
|
+
interval: this.autoRefresh.interval,
|
|
603
|
+
activityDebounce: this.autoRefresh.activityDebounce,
|
|
604
|
+
refreshCooldown: this.refreshCooldown,
|
|
605
|
+
lastRefreshedAt: this.autoRefreshManager ? this.autoRefreshManager.getLastRefreshedAt() : null
|
|
606
|
+
};
|
|
504
607
|
}
|
|
505
608
|
}
|
|
506
609
|
|
|
507
|
-
module.exports = { AgentTank, AUTO_REFRESH_MODES,
|
|
610
|
+
module.exports = { AgentTank, AUTO_REFRESH_MODES, detectDockerHosts, detectDockerHostsFromInterfaces };
|
package/src/server.js
CHANGED
|
@@ -52,6 +52,7 @@ function createRequestHandler(tank) {
|
|
|
52
52
|
autoRefresh: {
|
|
53
53
|
enabled: tank.autoRefresh.enabled && tank.autoRefresh.interval > 0,
|
|
54
54
|
interval: tank.autoRefresh.interval, // in seconds
|
|
55
|
+
refreshCooldown: tank.refreshCooldown,
|
|
55
56
|
},
|
|
56
57
|
lastRefreshedAt: tank.lastRefreshedAt,
|
|
57
58
|
};
|