@paretools/docker 0.12.0 → 0.13.0
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/dist/lib/formatters.d.ts +10 -31
- package/dist/lib/formatters.d.ts.map +1 -1
- package/dist/lib/formatters.js +118 -107
- package/dist/lib/formatters.js.map +1 -1
- package/dist/lib/parsers.d.ts +2 -2
- package/dist/lib/parsers.d.ts.map +1 -1
- package/dist/lib/parsers.js +9 -68
- package/dist/lib/parsers.js.map +1 -1
- package/dist/schemas/index.d.ts +8 -39
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +8 -41
- package/dist/schemas/index.js.map +1 -1
- package/dist/tools/compose-build.d.ts.map +1 -1
- package/dist/tools/compose-build.js +2 -1
- package/dist/tools/compose-build.js.map +1 -1
- package/dist/tools/compose-down.js +1 -1
- package/dist/tools/compose-down.js.map +1 -1
- package/dist/tools/compose-up.js +1 -1
- package/dist/tools/compose-up.js.map +1 -1
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +98 -34
- package/dist/tools/index.js.map +1 -1
- package/package.json +4 -4
package/dist/lib/formatters.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/** Formats structured Docker container data into a human-readable listing with state and ports. */
|
|
2
2
|
export function formatPs(data) {
|
|
3
|
-
const
|
|
3
|
+
const total = data.containers.length;
|
|
4
|
+
const running = data.containers.filter((c) => c.state === "running").length;
|
|
5
|
+
const stopped = total - running;
|
|
6
|
+
const lines = [`${total} containers (${running} running, ${stopped} stopped)`];
|
|
4
7
|
for (const c of data.containers) {
|
|
5
8
|
const portsArr = c.ports ?? [];
|
|
6
9
|
const ports = portsArr.length
|
|
@@ -16,20 +19,24 @@ export function formatPs(data) {
|
|
|
16
19
|
/** Formats structured Docker build results into a human-readable success/failure summary.
|
|
17
20
|
* #97: Includes structured error details with line numbers. */
|
|
18
21
|
export function formatBuild(data) {
|
|
22
|
+
const cacheByStep = data.cacheByStep ?? [];
|
|
23
|
+
const cacheHits = cacheByStep.filter((s) => s.cached).length;
|
|
24
|
+
const cacheMisses = cacheByStep.filter((s) => !s.cached).length;
|
|
25
|
+
const steps = cacheByStep.length;
|
|
19
26
|
if (data.success) {
|
|
20
|
-
const parts = [
|
|
27
|
+
const parts = ["Build succeeded"];
|
|
21
28
|
if (data.imageId)
|
|
22
29
|
parts[0] += ` → ${data.imageId}`;
|
|
23
|
-
if (
|
|
24
|
-
parts.push(`${
|
|
25
|
-
if (
|
|
26
|
-
parts.push(`cache hits=${
|
|
30
|
+
if (steps > 0)
|
|
31
|
+
parts.push(`${steps} steps`);
|
|
32
|
+
if (cacheByStep.length > 0) {
|
|
33
|
+
parts.push(`cache hits=${cacheHits}, misses=${cacheMisses}`);
|
|
27
34
|
}
|
|
28
35
|
return parts.join(", ");
|
|
29
36
|
}
|
|
30
|
-
const lines = [
|
|
31
|
-
if (
|
|
32
|
-
lines.push(` cache hits=${
|
|
37
|
+
const lines = ["Build failed"];
|
|
38
|
+
if (cacheByStep.length > 0) {
|
|
39
|
+
lines.push(` cache hits=${cacheHits}, misses=${cacheMisses}`);
|
|
33
40
|
}
|
|
34
41
|
for (const err of data.errors ?? []) {
|
|
35
42
|
if (typeof err === "string") {
|
|
@@ -48,12 +55,11 @@ export function formatBuild(data) {
|
|
|
48
55
|
}
|
|
49
56
|
return lines.join("\n");
|
|
50
57
|
}
|
|
51
|
-
/** Formats structured Docker logs data into a human-readable output with
|
|
58
|
+
/** Formats structured Docker logs data into a human-readable output with line count.
|
|
52
59
|
* #113: Notes when separate stdout/stderr streams are available. */
|
|
53
60
|
export function formatLogs(data) {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
: `${data.container} (${data.total} lines)`;
|
|
61
|
+
const total = (data.lines ?? []).length;
|
|
62
|
+
const header = data.isTruncated ? `${total} lines (truncated)` : `${total} lines`;
|
|
57
63
|
const streamInfo = data.stdoutLines || data.stderrLines
|
|
58
64
|
? ` [stdout=${(data.stdoutLines ?? []).length}, stderr=${(data.stderrLines ?? []).length}]`
|
|
59
65
|
: "";
|
|
@@ -65,9 +71,10 @@ export function formatLogs(data) {
|
|
|
65
71
|
/** Formats structured Docker image data into a human-readable listing with repository, tag, and size.
|
|
66
72
|
* #110: Shows ISO creation timestamp when available. */
|
|
67
73
|
export function formatImages(data) {
|
|
68
|
-
|
|
74
|
+
const total = data.images.length;
|
|
75
|
+
if (total === 0)
|
|
69
76
|
return "No images found.";
|
|
70
|
-
const lines = [`${
|
|
77
|
+
const lines = [`${total} images:`];
|
|
71
78
|
for (const img of data.images) {
|
|
72
79
|
const tag = img.tag && img.tag !== "<none>" ? `:${img.tag}` : "";
|
|
73
80
|
const digest = img.digest ? ` [${img.digest.slice(0, 19)}...]` : "";
|
|
@@ -85,7 +92,7 @@ export function formatImages(data) {
|
|
|
85
92
|
export function formatRun(data) {
|
|
86
93
|
const name = data.name ? ` (${data.name})` : "";
|
|
87
94
|
const mode = data.detached ? "detached" : "attached";
|
|
88
|
-
const lines = [`Container ${data.containerId}${name} started
|
|
95
|
+
const lines = [`Container ${data.containerId}${name} started [${mode}]`];
|
|
89
96
|
if (data.exitCode != null && data.exitCode !== 0) {
|
|
90
97
|
lines.push(` Exit code: ${data.exitCode}`);
|
|
91
98
|
if (data.errorCategory)
|
|
@@ -104,14 +111,14 @@ export function formatRun(data) {
|
|
|
104
111
|
/** Formats structured Docker exec output into a human-readable summary.
|
|
105
112
|
* #108: Shows truncation indicator. */
|
|
106
113
|
export function formatExec(data) {
|
|
114
|
+
const success = data.exitCode === 0;
|
|
107
115
|
const status = data.timedOut
|
|
108
116
|
? "timed out"
|
|
109
|
-
:
|
|
117
|
+
: success
|
|
110
118
|
? "succeeded"
|
|
111
119
|
: `failed (exit code ${data.exitCode})`;
|
|
112
|
-
const dur = data.duration != null ? ` in ${data.duration}s` : "";
|
|
113
120
|
const trunc = data.isTruncated ? " [truncated]" : "";
|
|
114
|
-
const lines = [`Exec ${status}${
|
|
121
|
+
const lines = [`Exec ${status}${trunc}`];
|
|
115
122
|
if (data.stdout)
|
|
116
123
|
lines.push(data.stdout);
|
|
117
124
|
if (data.stderr)
|
|
@@ -127,11 +134,10 @@ export function formatExec(data) {
|
|
|
127
134
|
export function formatComposeUp(data) {
|
|
128
135
|
if (!data.success)
|
|
129
136
|
return "Compose up failed";
|
|
130
|
-
|
|
137
|
+
const started = (data.services ?? []).length;
|
|
138
|
+
if (started === 0)
|
|
131
139
|
return "Compose up succeeded (no new services started)";
|
|
132
|
-
const lines = [
|
|
133
|
-
`Compose up: ${data.started} services started (${(data.services ?? []).join(", ")})`,
|
|
134
|
-
];
|
|
140
|
+
const lines = [`Compose up: ${started} services started (${(data.services ?? []).join(", ")})`];
|
|
135
141
|
if (data.serviceStates && data.serviceStates.length > 0) {
|
|
136
142
|
for (const ss of data.serviceStates) {
|
|
137
143
|
lines.push(` ${ss.name}: ${ss.action}`);
|
|
@@ -149,7 +155,9 @@ export function formatComposeUp(data) {
|
|
|
149
155
|
export function formatComposeDown(data) {
|
|
150
156
|
if (!data.success)
|
|
151
157
|
return "Compose down failed";
|
|
152
|
-
const
|
|
158
|
+
const removedContainers = (data.containers ?? []).filter((c) => c.action === "Removed").length;
|
|
159
|
+
const removed = removedContainers + (data.volumesRemoved ?? 0) + (data.networksRemoved ?? 0);
|
|
160
|
+
const parts = [`Compose down: ${data.stopped} stopped, ${removed} removed`];
|
|
153
161
|
if (data.volumesRemoved)
|
|
154
162
|
parts[0] += `, ${data.volumesRemoved} volumes removed`;
|
|
155
163
|
if (data.networksRemoved)
|
|
@@ -167,13 +175,13 @@ export function formatPull(data) {
|
|
|
167
175
|
if (!data.success) {
|
|
168
176
|
const errType = data.errorType ? ` (${data.errorType})` : "";
|
|
169
177
|
const msg = data.errorMessage ? `: ${data.errorMessage}` : "";
|
|
170
|
-
return `Pull failed
|
|
178
|
+
return `Pull failed${errType}${msg}`;
|
|
171
179
|
}
|
|
172
180
|
const digest = data.digest ? ` (${data.digest.slice(0, 19)}...)` : "";
|
|
173
181
|
const size = data.size ? ` [${data.size}]` : "";
|
|
174
182
|
if (data.status === "up-to-date")
|
|
175
|
-
return
|
|
176
|
-
return `Pulled
|
|
183
|
+
return `Image is up to date${digest}`;
|
|
184
|
+
return `Pulled${digest}${size}`;
|
|
177
185
|
}
|
|
178
186
|
export function compactPsMap(data) {
|
|
179
187
|
return {
|
|
@@ -183,13 +191,12 @@ export function compactPsMap(data) {
|
|
|
183
191
|
image: c.image,
|
|
184
192
|
status: c.status,
|
|
185
193
|
})),
|
|
186
|
-
total: data.total,
|
|
187
|
-
running: data.running,
|
|
188
|
-
stopped: data.stopped,
|
|
189
194
|
};
|
|
190
195
|
}
|
|
191
196
|
export function formatPsCompact(data) {
|
|
192
|
-
const
|
|
197
|
+
const total = data.containers.length;
|
|
198
|
+
const running = data.containers.filter((c) => c.status.toLowerCase().startsWith("up")).length;
|
|
199
|
+
const lines = [`${total} containers (${running} running)`];
|
|
193
200
|
for (const c of data.containers) {
|
|
194
201
|
lines.push(` ${c.id.slice(0, 12)} ${c.name} (${c.image}) ${c.status}`);
|
|
195
202
|
}
|
|
@@ -203,13 +210,13 @@ export function compactImagesMap(data) {
|
|
|
203
210
|
tag: img.tag,
|
|
204
211
|
size: img.size,
|
|
205
212
|
})),
|
|
206
|
-
total: data.total,
|
|
207
213
|
};
|
|
208
214
|
}
|
|
209
215
|
export function formatImagesCompact(data) {
|
|
210
|
-
|
|
216
|
+
const total = data.images.length;
|
|
217
|
+
if (total === 0)
|
|
211
218
|
return "No images found.";
|
|
212
|
-
const lines = [`${
|
|
219
|
+
const lines = [`${total} images:`];
|
|
213
220
|
for (const img of data.images) {
|
|
214
221
|
const tag = img.tag && img.tag !== "<none>" ? `:${img.tag}` : "";
|
|
215
222
|
lines.push(` ${img.repository}${tag} (${img.size})`);
|
|
@@ -220,48 +227,35 @@ export function compactBuildMap(data) {
|
|
|
220
227
|
return {
|
|
221
228
|
success: data.success,
|
|
222
229
|
...(data.imageId ? { imageId: data.imageId } : {}),
|
|
223
|
-
duration: data.duration,
|
|
224
|
-
errorCount: (data.errors ?? []).length,
|
|
225
|
-
...(data.cacheHits != null ? { cacheHits: data.cacheHits } : {}),
|
|
226
|
-
...(data.cacheMisses != null ? { cacheMisses: data.cacheMisses } : {}),
|
|
227
230
|
};
|
|
228
231
|
}
|
|
229
232
|
export function formatBuildCompact(data) {
|
|
230
233
|
if (data.success) {
|
|
231
234
|
const id = data.imageId ? ` → ${data.imageId}` : "";
|
|
232
|
-
|
|
233
|
-
? ` [cache h=${data.cacheHits ?? 0} m=${data.cacheMisses ?? 0}]`
|
|
234
|
-
: "";
|
|
235
|
-
return `Build succeeded in ${data.duration}s${id}${cache}`;
|
|
235
|
+
return `Build succeeded${id}`;
|
|
236
236
|
}
|
|
237
|
-
|
|
238
|
-
? `, cache h=${data.cacheHits ?? 0} m=${data.cacheMisses ?? 0}`
|
|
239
|
-
: "";
|
|
240
|
-
return `Build failed (${data.duration}s, ${data.errorCount} errors${cache})`;
|
|
237
|
+
return "Build failed";
|
|
241
238
|
}
|
|
242
239
|
export function compactLogsMap(data) {
|
|
243
240
|
const HEAD_SIZE = 5;
|
|
244
241
|
const TAIL_SIZE = 5;
|
|
245
242
|
const lines = data.lines ?? [];
|
|
243
|
+
const total = lines.length;
|
|
246
244
|
return {
|
|
247
|
-
container: data.container,
|
|
248
|
-
total: data.total,
|
|
249
245
|
head: lines.slice(0, HEAD_SIZE),
|
|
250
|
-
tail:
|
|
246
|
+
tail: total > HEAD_SIZE + TAIL_SIZE ? lines.slice(-TAIL_SIZE) : [],
|
|
251
247
|
};
|
|
252
248
|
}
|
|
253
249
|
export function formatLogsCompact(data) {
|
|
254
|
-
const parts = [`${data.
|
|
250
|
+
const parts = [`${data.head.length + data.tail.length} lines`];
|
|
255
251
|
if (data.head.length)
|
|
256
252
|
parts.push(data.head.join("\n"));
|
|
257
253
|
if (data.tail.length)
|
|
258
|
-
parts.push(
|
|
254
|
+
parts.push(" ... lines omitted ...", data.tail.join("\n"));
|
|
259
255
|
return parts.join("\n");
|
|
260
256
|
}
|
|
261
257
|
export function compactPullMap(data) {
|
|
262
258
|
return {
|
|
263
|
-
image: data.image,
|
|
264
|
-
tag: data.tag,
|
|
265
259
|
...(data.digest ? { digest: data.digest } : {}),
|
|
266
260
|
status: data.status,
|
|
267
261
|
success: data.success,
|
|
@@ -271,29 +265,26 @@ export function compactPullMap(data) {
|
|
|
271
265
|
export function formatPullCompact(data) {
|
|
272
266
|
if (!data.success) {
|
|
273
267
|
const err = data.errorType ? ` (${data.errorType})` : "";
|
|
274
|
-
return `Pull failed
|
|
268
|
+
return `Pull failed${err}`;
|
|
275
269
|
}
|
|
276
270
|
const digest = data.digest ? ` (${data.digest.slice(0, 19)}...)` : "";
|
|
277
271
|
if (data.status === "up-to-date")
|
|
278
|
-
return
|
|
279
|
-
return `Pulled
|
|
272
|
+
return `Image is up to date${digest}`;
|
|
273
|
+
return `Pulled${digest}`;
|
|
280
274
|
}
|
|
281
275
|
export function compactRunMap(data) {
|
|
282
276
|
return {
|
|
283
277
|
containerId: data.containerId,
|
|
284
|
-
image: data.image,
|
|
285
278
|
detached: data.detached,
|
|
286
279
|
};
|
|
287
280
|
}
|
|
288
281
|
export function formatRunCompact(data) {
|
|
289
282
|
const mode = data.detached ? "detached" : "attached";
|
|
290
|
-
return `Container ${data.containerId}
|
|
283
|
+
return `Container ${data.containerId} [${mode}]`;
|
|
291
284
|
}
|
|
292
285
|
export function compactExecMap(data) {
|
|
293
286
|
return {
|
|
294
287
|
exitCode: data.exitCode,
|
|
295
|
-
success: data.success,
|
|
296
|
-
...(data.duration != null ? { duration: data.duration } : {}),
|
|
297
288
|
...(data.timedOut ? { timedOut: true } : {}),
|
|
298
289
|
...(data.isTruncated ? { isTruncated: true } : {}),
|
|
299
290
|
...(data.stdout ? { stdoutPreview: data.stdout.slice(0, 200) } : {}),
|
|
@@ -301,14 +292,14 @@ export function compactExecMap(data) {
|
|
|
301
292
|
};
|
|
302
293
|
}
|
|
303
294
|
export function formatExecCompact(data) {
|
|
304
|
-
const
|
|
295
|
+
const success = data.exitCode === 0;
|
|
305
296
|
const status = data.timedOut
|
|
306
297
|
? "timed out"
|
|
307
|
-
:
|
|
298
|
+
: success
|
|
308
299
|
? "succeeded"
|
|
309
300
|
: `failed (exit code ${data.exitCode})`;
|
|
310
301
|
const trunc = data.isTruncated ? " [truncated]" : "";
|
|
311
|
-
const lines = [`Exec ${status}${
|
|
302
|
+
const lines = [`Exec ${status}${trunc}`];
|
|
312
303
|
if (data.stdoutPreview)
|
|
313
304
|
lines.push(data.stdoutPreview);
|
|
314
305
|
if (data.stderrPreview)
|
|
@@ -318,7 +309,7 @@ export function formatExecCompact(data) {
|
|
|
318
309
|
export function compactComposeUpMap(data) {
|
|
319
310
|
return {
|
|
320
311
|
success: data.success,
|
|
321
|
-
|
|
312
|
+
...(data.services ? { services: data.services } : {}),
|
|
322
313
|
...(data.networksCreated != null ? { networksCreated: data.networksCreated } : {}),
|
|
323
314
|
...(data.volumesCreated != null ? { volumesCreated: data.volumesCreated } : {}),
|
|
324
315
|
};
|
|
@@ -326,22 +317,22 @@ export function compactComposeUpMap(data) {
|
|
|
326
317
|
export function formatComposeUpCompact(data) {
|
|
327
318
|
if (!data.success)
|
|
328
319
|
return "Compose up failed";
|
|
320
|
+
const started = (data.services ?? []).length;
|
|
329
321
|
const infra = data.networksCreated != null || data.volumesCreated != null
|
|
330
322
|
? ` (networks=${data.networksCreated ?? 0}, volumes=${data.volumesCreated ?? 0})`
|
|
331
323
|
: "";
|
|
332
|
-
return `Compose up: ${
|
|
324
|
+
return `Compose up: ${started} services started${infra}`;
|
|
333
325
|
}
|
|
334
326
|
export function compactComposeDownMap(data) {
|
|
335
327
|
return {
|
|
336
328
|
success: data.success,
|
|
337
329
|
stopped: data.stopped,
|
|
338
|
-
removed: data.removed,
|
|
339
330
|
};
|
|
340
331
|
}
|
|
341
332
|
export function formatComposeDownCompact(data) {
|
|
342
333
|
if (!data.success)
|
|
343
334
|
return "Compose down failed";
|
|
344
|
-
return `Compose down: ${data.stopped} stopped
|
|
335
|
+
return `Compose down: ${data.stopped} stopped`;
|
|
345
336
|
}
|
|
346
337
|
// ── Inspect ──────────────────────────────────────────────────────────
|
|
347
338
|
/** Formats structured Docker inspect data into a human-readable summary.
|
|
@@ -508,9 +499,10 @@ export function formatInspectCompact(data) {
|
|
|
508
499
|
* #115: Shows labels when present.
|
|
509
500
|
* #116: Shows boolean flags. */
|
|
510
501
|
export function formatNetworkLs(data) {
|
|
511
|
-
|
|
502
|
+
const total = data.networks.length;
|
|
503
|
+
if (total === 0)
|
|
512
504
|
return "No networks found.";
|
|
513
|
-
const lines = [`${
|
|
505
|
+
const lines = [`${total} networks:`];
|
|
514
506
|
for (const n of data.networks) {
|
|
515
507
|
const created = n.createdAt ? ` (${n.createdAt})` : "";
|
|
516
508
|
const flags = [];
|
|
@@ -533,13 +525,13 @@ export function compactNetworkLsMap(data) {
|
|
|
533
525
|
name: n.name,
|
|
534
526
|
driver: n.driver,
|
|
535
527
|
})),
|
|
536
|
-
total: data.total,
|
|
537
528
|
};
|
|
538
529
|
}
|
|
539
530
|
export function formatNetworkLsCompact(data) {
|
|
540
|
-
|
|
531
|
+
const total = data.networks.length;
|
|
532
|
+
if (total === 0)
|
|
541
533
|
return "No networks found.";
|
|
542
|
-
const lines = [`${
|
|
534
|
+
const lines = [`${total} networks:`];
|
|
543
535
|
for (const n of data.networks) {
|
|
544
536
|
const id = n.id ? ` [${n.id}]` : "";
|
|
545
537
|
lines.push(` ${n.name} (${n.driver})${id}`);
|
|
@@ -550,9 +542,10 @@ export function formatNetworkLsCompact(data) {
|
|
|
550
542
|
/** Formats structured Docker volume list into a human-readable listing.
|
|
551
543
|
* #125: Shows labels when present. */
|
|
552
544
|
export function formatVolumeLs(data) {
|
|
553
|
-
|
|
545
|
+
const total = data.volumes.length;
|
|
546
|
+
if (total === 0)
|
|
554
547
|
return "No volumes found.";
|
|
555
|
-
const lines = [`${
|
|
548
|
+
const lines = [`${total} volumes:`];
|
|
556
549
|
for (const v of data.volumes) {
|
|
557
550
|
const created = v.createdAt ? ` (${v.createdAt})` : "";
|
|
558
551
|
const status = v.status ? ` status=${v.status}` : "";
|
|
@@ -568,13 +561,13 @@ export function compactVolumeLsMap(data) {
|
|
|
568
561
|
driver: v.driver,
|
|
569
562
|
...(v.mountpoint ? { mountpoint: v.mountpoint } : {}),
|
|
570
563
|
})),
|
|
571
|
-
total: data.total,
|
|
572
564
|
};
|
|
573
565
|
}
|
|
574
566
|
export function formatVolumeLsCompact(data) {
|
|
575
|
-
|
|
567
|
+
const total = data.volumes.length;
|
|
568
|
+
if (total === 0)
|
|
576
569
|
return "No volumes found.";
|
|
577
|
-
const lines = [`${
|
|
570
|
+
const lines = [`${total} volumes:`];
|
|
578
571
|
for (const v of data.volumes) {
|
|
579
572
|
const mp = v.mountpoint ? ` @ ${v.mountpoint}` : "";
|
|
580
573
|
lines.push(` ${v.name} (${v.driver})${mp}`);
|
|
@@ -585,15 +578,18 @@ export function formatVolumeLsCompact(data) {
|
|
|
585
578
|
/** Formats structured Docker Compose build output into a human-readable summary.
|
|
586
579
|
* #99: Shows per-service duration. */
|
|
587
580
|
export function formatComposeBuild(data) {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
581
|
+
const services = data.services ?? [];
|
|
582
|
+
const built = services.filter((s) => s.success).length;
|
|
583
|
+
const failed = services.filter((s) => !s.success).length;
|
|
584
|
+
if (!data.success && built === 0) {
|
|
585
|
+
const lines = ["Compose build failed"];
|
|
586
|
+
for (const s of services) {
|
|
591
587
|
if (s.error)
|
|
592
588
|
lines.push(` ${s.service}: ${s.error}`);
|
|
593
589
|
}
|
|
594
590
|
return lines.join("\n");
|
|
595
591
|
}
|
|
596
|
-
const lines = [`Compose build: ${
|
|
592
|
+
const lines = [`Compose build: ${built} built, ${failed} failed`];
|
|
597
593
|
for (const s of data.services ?? []) {
|
|
598
594
|
const status = s.success ? "built" : "failed";
|
|
599
595
|
const error = s.error ? ` — ${s.error}` : "";
|
|
@@ -608,9 +604,10 @@ export function formatComposeBuild(data) {
|
|
|
608
604
|
/** Formats structured Docker stats data into a human-readable listing with CPU, memory, and I/O.
|
|
609
605
|
* #123/#124: Shows numeric memory and I/O values. */
|
|
610
606
|
export function formatStats(data) {
|
|
611
|
-
|
|
607
|
+
const total = data.containers.length;
|
|
608
|
+
if (total === 0)
|
|
612
609
|
return "No container stats available.";
|
|
613
|
-
const lines = [`${
|
|
610
|
+
const lines = [`${total} containers:`];
|
|
614
611
|
for (const c of data.containers) {
|
|
615
612
|
const state = c.state ? ` [${c.state}]` : "";
|
|
616
613
|
lines.push(` ${c.name}${state} (${c.id}) CPU: ${c.cpuPercent.toFixed(2)}% Mem: ${c.memoryUsage}/${c.memoryLimit} (${c.memoryPercent.toFixed(2)}%) Net: ${c.netIO} Block: ${c.blockIO} PIDs: ${c.pids}`);
|
|
@@ -620,16 +617,24 @@ export function formatStats(data) {
|
|
|
620
617
|
export function compactComposeBuildMap(data) {
|
|
621
618
|
return {
|
|
622
619
|
success: data.success,
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
620
|
+
...(data.services
|
|
621
|
+
? {
|
|
622
|
+
services: data.services.map((s) => ({
|
|
623
|
+
service: s.service,
|
|
624
|
+
success: s.success,
|
|
625
|
+
})),
|
|
626
|
+
}
|
|
627
|
+
: {}),
|
|
626
628
|
};
|
|
627
629
|
}
|
|
628
630
|
export function formatComposeBuildCompact(data) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
+
const services = data.services ?? [];
|
|
632
|
+
const built = services.filter((s) => s.success).length;
|
|
633
|
+
const failed = services.filter((s) => !s.success).length;
|
|
634
|
+
if (!data.success && built === 0) {
|
|
635
|
+
return "Compose build failed";
|
|
631
636
|
}
|
|
632
|
-
return `Compose build: ${
|
|
637
|
+
return `Compose build: ${built} built, ${failed} failed`;
|
|
633
638
|
}
|
|
634
639
|
export function compactStatsMap(data) {
|
|
635
640
|
return {
|
|
@@ -642,13 +647,13 @@ export function compactStatsMap(data) {
|
|
|
642
647
|
memoryPercent: c.memoryPercent,
|
|
643
648
|
pids: c.pids,
|
|
644
649
|
})),
|
|
645
|
-
total: data.total,
|
|
646
650
|
};
|
|
647
651
|
}
|
|
648
652
|
export function formatStatsCompact(data) {
|
|
649
|
-
|
|
653
|
+
const total = data.containers.length;
|
|
654
|
+
if (total === 0)
|
|
650
655
|
return "No container stats available.";
|
|
651
|
-
const lines = [`${
|
|
656
|
+
const lines = [`${total} containers:`];
|
|
652
657
|
for (const c of data.containers) {
|
|
653
658
|
const mem = c.memoryUsage ? ` ${c.memoryUsage}` : "";
|
|
654
659
|
const state = c.state ? ` [${c.state}]` : "";
|
|
@@ -661,12 +666,13 @@ export function formatStatsCompact(data) {
|
|
|
661
666
|
* #105: Shows health status.
|
|
662
667
|
* #106: Shows running/stopped counts. */
|
|
663
668
|
export function formatComposePs(data) {
|
|
664
|
-
|
|
669
|
+
const total = data.services.length;
|
|
670
|
+
if (total === 0)
|
|
665
671
|
return "No compose services found.";
|
|
666
|
-
const
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
const lines = [`${
|
|
672
|
+
const running = data.services.filter((s) => s.state === "running").length;
|
|
673
|
+
const stopped = data.services.filter((s) => s.state === "exited" || s.state === "dead" || s.state === "removing").length;
|
|
674
|
+
const countInfo = ` (${running} running, ${stopped} stopped)`;
|
|
675
|
+
const lines = [`${total} services${countInfo}:`];
|
|
670
676
|
for (const s of data.services) {
|
|
671
677
|
const portsArr = s.ports ?? [];
|
|
672
678
|
const ports = portsArr.length
|
|
@@ -686,13 +692,13 @@ export function compactComposePsMap(data) {
|
|
|
686
692
|
state: s.state,
|
|
687
693
|
...(s.exitCode != null ? { exitCode: s.exitCode } : {}),
|
|
688
694
|
})),
|
|
689
|
-
total: data.total,
|
|
690
695
|
};
|
|
691
696
|
}
|
|
692
697
|
export function formatComposePsCompact(data) {
|
|
693
|
-
|
|
698
|
+
const total = data.services.length;
|
|
699
|
+
if (total === 0)
|
|
694
700
|
return "No compose services found.";
|
|
695
|
-
const lines = [`${
|
|
701
|
+
const lines = [`${total} services:`];
|
|
696
702
|
for (const s of data.services) {
|
|
697
703
|
const exit = s.exitCode != null ? ` exit=${s.exitCode}` : "";
|
|
698
704
|
lines.push(` ${s.state.padEnd(10)} ${s.name} (${s.service})${exit}`);
|
|
@@ -703,9 +709,13 @@ export function formatComposePsCompact(data) {
|
|
|
703
709
|
/** Formats structured Docker Compose logs into a human-readable output grouped by service.
|
|
704
710
|
* #104: Shows log level when available. */
|
|
705
711
|
export function formatComposeLogs(data) {
|
|
712
|
+
const entries = data.entries ?? [];
|
|
713
|
+
const total = entries.length;
|
|
714
|
+
const serviceSet = new Set(entries.map((e) => e.service));
|
|
715
|
+
const serviceCount = serviceSet.size;
|
|
706
716
|
const header = data.isTruncated
|
|
707
|
-
? `Compose logs: ${
|
|
708
|
-
: `Compose logs: ${
|
|
717
|
+
? `Compose logs: ${serviceCount} services, ${total} entries (truncated)`
|
|
718
|
+
: `Compose logs: ${serviceCount} services, ${total} entries`;
|
|
709
719
|
const lines = [header];
|
|
710
720
|
for (const entry of data.entries ?? []) {
|
|
711
721
|
const ts = entry.timestamp ? `${entry.timestamp} ` : "";
|
|
@@ -718,15 +728,14 @@ export function compactComposeLogsMap(data) {
|
|
|
718
728
|
const HEAD_SIZE = 5;
|
|
719
729
|
const TAIL_SIZE = 5;
|
|
720
730
|
const entries = data.entries ?? [];
|
|
731
|
+
const total = entries.length;
|
|
721
732
|
return {
|
|
722
|
-
services: data.services,
|
|
723
|
-
total: data.total,
|
|
724
733
|
head: entries.slice(0, HEAD_SIZE).map((e) => ({
|
|
725
734
|
service: e.service,
|
|
726
735
|
message: e.message,
|
|
727
736
|
...(e.timestamp ? { timestamp: e.timestamp } : {}),
|
|
728
737
|
})),
|
|
729
|
-
tail:
|
|
738
|
+
tail: total > HEAD_SIZE + TAIL_SIZE
|
|
730
739
|
? entries.slice(-TAIL_SIZE).map((e) => ({
|
|
731
740
|
service: e.service,
|
|
732
741
|
message: e.message,
|
|
@@ -736,13 +745,15 @@ export function compactComposeLogsMap(data) {
|
|
|
736
745
|
};
|
|
737
746
|
}
|
|
738
747
|
export function formatComposeLogsCompact(data) {
|
|
739
|
-
const
|
|
748
|
+
const total = data.head.length + data.tail.length;
|
|
749
|
+
const serviceSet = new Set([...data.head, ...data.tail].map((e) => e.service));
|
|
750
|
+
const parts = [`Compose logs: ${serviceSet.size} services, ${total} entries`];
|
|
740
751
|
for (const e of data.head) {
|
|
741
752
|
const ts = e.timestamp ? `${e.timestamp} ` : "";
|
|
742
753
|
parts.push(` ${e.service} | ${ts}${e.message}`);
|
|
743
754
|
}
|
|
744
755
|
if (data.tail.length) {
|
|
745
|
-
parts.push(
|
|
756
|
+
parts.push(" ... entries omitted ...");
|
|
746
757
|
for (const e of data.tail) {
|
|
747
758
|
const ts = e.timestamp ? `${e.timestamp} ` : "";
|
|
748
759
|
parts.push(` ${e.service} | ${ts}${e.message}`);
|