@intflow/sentinelctl 0.3.0 → 0.3.2
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/client.mjs +2 -2
- package/src/commands.mjs +7 -5
package/package.json
CHANGED
package/src/client.mjs
CHANGED
|
@@ -11,7 +11,7 @@ export class ApiError extends Error {
|
|
|
11
11
|
|
|
12
12
|
const userAgent = 'sentinelctl';
|
|
13
13
|
|
|
14
|
-
export function createClient({ server, token = null, fetch: fetchImplementation = globalThis.fetch, timeoutMs = 60_000, maxRetries =
|
|
14
|
+
export function createClient({ server, token = null, fetch: fetchImplementation = globalThis.fetch, timeoutMs = 60_000, maxRetries = 5, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) }) {
|
|
15
15
|
async function request(method, path, { query, body, auth = true, allowStatuses = [] } = {}) {
|
|
16
16
|
const url = new URL(path, server);
|
|
17
17
|
for (const [key, value] of Object.entries(query ?? {})) {
|
|
@@ -45,7 +45,7 @@ export function createClient({ server, token = null, fetch: fetchImplementation
|
|
|
45
45
|
}
|
|
46
46
|
const retryAfterSeconds = Number(response.headers.get('retry-after')) || null;
|
|
47
47
|
if (response.status === 429 && method === 'GET' && attempt < maxRetries) {
|
|
48
|
-
await sleep(Math.min(retryAfterSeconds ?? 1,
|
|
48
|
+
await sleep(Math.min(Math.max(retryAfterSeconds ?? 1, 2 ** attempt), 15) * 1_000);
|
|
49
49
|
continue;
|
|
50
50
|
}
|
|
51
51
|
if (response.ok || allowStatuses.includes(response.status)) return { status: response.status, body: payload };
|
package/src/commands.mjs
CHANGED
|
@@ -237,11 +237,12 @@ async function devicesShow(context, { options, positionals }) {
|
|
|
237
237
|
const agentId = requireAgentId(positionals);
|
|
238
238
|
const body = await context.client.get(`/api/devices/${encodeURIComponent(agentId)}`, { range: options.range, refresh: options.refresh ? 1 : undefined });
|
|
239
239
|
const device = body.device;
|
|
240
|
+
const current = body.current ?? {};
|
|
240
241
|
emit(context, body, () => renderKeyValues([
|
|
241
242
|
['Agent ID', device.agentId], ['Name', device.displayName], ['Host', device.host],
|
|
242
243
|
['Status', device.observedStatus ?? device.status], ['Last seen', ageText(device.ageSeconds)],
|
|
243
|
-
['CPU', percentText(device.cpu)], ['Memory', percentText(device.memory)], ['Disk', percentText(device.disk)],
|
|
244
|
-
['Load', device.load], ['Temperature', device.temperature], ['Role', device.metadata?.role ?? device.role],
|
|
244
|
+
['CPU', percentText(current.cpu ?? device.cpu)], ['Memory', percentText(current.memory ?? device.memory)], ['Disk', percentText(current.disk ?? device.disk)],
|
|
245
|
+
['Load', current.load ?? device.load], ['Temperature', current.temperature ?? device.temperature], ['Role', device.metadata?.role ?? device.role],
|
|
245
246
|
['Maintainer', device.metadata?.maintainer], ['Lifecycle', device.metadata?.lifecycle], ['Notes', device.metadata?.description],
|
|
246
247
|
['Data', body.stale ? `stale (${body.staleReason ?? ''})` : 'fresh'],
|
|
247
248
|
]));
|
|
@@ -273,12 +274,13 @@ async function devicesOverview(context, { options, positionals }) {
|
|
|
273
274
|
normalRatio: Number.isFinite(history.normalRatio) ? Math.round(history.normalRatio * 1000) / 10 : null,
|
|
274
275
|
}];
|
|
275
276
|
}));
|
|
276
|
-
const describe = (item) => `${item.state ?? '-'} · ${item.outages ?? '-'} outages, ${item.missingMinutes ?? '-'} min missing (longest ${item.longestOutageMinutes ?? '-'} min), normal ${item.normalRatio ?? '-'}%`;
|
|
277
|
+
const describe = (item) => `${item.state ?? '-'} · ${item.outages ?? '-'} ${item.outages === 1 ? 'outage' : 'outages'}, ${item.missingMinutes ?? '-'} min missing (longest ${item.longestOutageMinutes ?? '-'} min), normal ${item.normalRatio ?? '-'}%`;
|
|
277
278
|
emit(context, { summary, ...body }, () => renderKeyValues([
|
|
278
279
|
['Agent ID', body.agentId], ['Name', body.device?.displayName], ['Window', options.range],
|
|
279
280
|
['Metrics', describe(summary.metrics)], ['Logs', describe(summary.logs)],
|
|
280
281
|
['Attention', (body.attentionReasons ?? []).join(', ') || 'none'],
|
|
281
|
-
['
|
|
282
|
+
['Hypervisor', body.related?.parent ? `${body.related.parent.displayName} (${body.related.parent.agentId})` : body.related?.expectedParent ?? null],
|
|
283
|
+
['VMs', (body.related?.children ?? []).map((child) => child.displayName ?? child.agentId).join(', ') || null],
|
|
282
284
|
]));
|
|
283
285
|
}
|
|
284
286
|
|
|
@@ -674,7 +676,7 @@ const commands = [
|
|
|
674
676
|
args: [{ name: 'agent-id' }],
|
|
675
677
|
options: { range: { alias: 'r', type: 'string', default: '24h', placeholder: 'window', description: 'History window, e.g. 24h or 7d.' } },
|
|
676
678
|
examples: ['sentinelctl devices overview <agent-id> -r 7d -o json'],
|
|
677
|
-
output: '{summary{metrics, logs}: {state, outages, delays, missingMinutes, longestOutageMinutes, normalRatio}, agentId, device, products, attentionReasons[], history, related[]}.',
|
|
679
|
+
output: '{summary{metrics, logs}: {state, outages, delays, missingMinutes, longestOutageMinutes, normalRatio}, agentId, device, products, attentionReasons[], history, related{parent, children[], expectedParent}}.',
|
|
678
680
|
},
|
|
679
681
|
{
|
|
680
682
|
group: 'metadata', name: 'get', run: metadataGet, role: 'viewer', mutates: false,
|