onveloz 0.0.0-beta.22 → 0.0.0-beta.23
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/deploy-tui-U7fsZN6x.mjs +1028 -0
- package/dist/index.mjs +11 -265
- package/dist/login-DEQ5zMzL.mjs +3 -0
- package/package.json +4 -1
- package/dist/login-jxR-lGEN.mjs +0 -3
|
@@ -0,0 +1,1028 @@
|
|
|
1
|
+
import { a as statusLabels, i as TERMINAL_STATUSES, l as info, n as isHiddenMessage, o as getClient, r as parseBuildLine, t as cleanDisplayLine, u as success } from "./index.mjs";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { Box, Static, Text, render, useApp } from "ink";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
//#region ../../packages/api/src/lib/build-steps.ts
|
|
8
|
+
const TIMESTAMP_RE = /^\[(\d{4}-\d{2}-\d{2}T[\d:.]+Z)\]\s*/;
|
|
9
|
+
const STEP_PREFIX_RE = /^#(\d+)\s+(.*)/;
|
|
10
|
+
const TIMING_PREFIX_RE = /^(\d+\.\d+)\s*(.*)/;
|
|
11
|
+
const DONE_RE = /^DONE\s+([\d.]+s?)$/;
|
|
12
|
+
const STAGE_RE = /^\[([\w-]+)\s+(\d+)\/\d+\]/;
|
|
13
|
+
function parseStageInfo(title) {
|
|
14
|
+
const match = title.match(STAGE_RE);
|
|
15
|
+
if (!match) return null;
|
|
16
|
+
return {
|
|
17
|
+
stage: match[1].toLowerCase(),
|
|
18
|
+
substep: parseInt(match[2], 10)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Derive stage order from first occurrence in the step list (preserves Dockerfile order). */
|
|
22
|
+
function buildStageOrder(steps) {
|
|
23
|
+
const order = /* @__PURE__ */ new Map();
|
|
24
|
+
for (const step of steps) {
|
|
25
|
+
const info$1 = parseStageInfo(step.title);
|
|
26
|
+
if (info$1 && !order.has(info$1.stage)) order.set(info$1.stage, order.size);
|
|
27
|
+
}
|
|
28
|
+
return order;
|
|
29
|
+
}
|
|
30
|
+
const RUNTIME_LINE_PATTERNS = [
|
|
31
|
+
/^[\u26A0\u{1F680}]/u,
|
|
32
|
+
/^\{.*"(?:level|msg|pid)"/,
|
|
33
|
+
/^Error:\s/,
|
|
34
|
+
/^\s+at\s+/,
|
|
35
|
+
/^errorno:/i,
|
|
36
|
+
/^code:\s+'/,
|
|
37
|
+
/^syscall:\s+'/,
|
|
38
|
+
/Server (?:running|started)/i
|
|
39
|
+
];
|
|
40
|
+
function isRuntimeLine(content) {
|
|
41
|
+
return RUNTIME_LINE_PATTERNS.some((p) => p.test(content.trim()));
|
|
42
|
+
}
|
|
43
|
+
function parseBuildSteps(rawText) {
|
|
44
|
+
const rawLines = rawText.split("\n");
|
|
45
|
+
let currentPhase = 0;
|
|
46
|
+
let maxStepInPhase = 0;
|
|
47
|
+
const phaseStepMap = /* @__PURE__ */ new Map();
|
|
48
|
+
const allSteps = [];
|
|
49
|
+
let currentGeneralStep = null;
|
|
50
|
+
for (const raw of rawLines) {
|
|
51
|
+
const trimmed = raw.trim();
|
|
52
|
+
if (!trimmed) continue;
|
|
53
|
+
const tsMatch = trimmed.match(TIMESTAMP_RE);
|
|
54
|
+
const timestamp = tsMatch?.[1] ?? null;
|
|
55
|
+
const line = tsMatch ? trimmed.slice(tsMatch[0].length) : trimmed;
|
|
56
|
+
if (!line.trim()) continue;
|
|
57
|
+
const stepMatch = line.match(STEP_PREFIX_RE);
|
|
58
|
+
if (!stepMatch) {
|
|
59
|
+
if (!currentGeneralStep) {
|
|
60
|
+
currentGeneralStep = {
|
|
61
|
+
stepNumber: null,
|
|
62
|
+
title: "Configuração",
|
|
63
|
+
duration: null,
|
|
64
|
+
status: "done",
|
|
65
|
+
lines: [],
|
|
66
|
+
phase: currentPhase,
|
|
67
|
+
startedAt: timestamp
|
|
68
|
+
};
|
|
69
|
+
allSteps.push(currentGeneralStep);
|
|
70
|
+
}
|
|
71
|
+
currentGeneralStep.lines.push({
|
|
72
|
+
content: line,
|
|
73
|
+
elapsed: null,
|
|
74
|
+
timestamp
|
|
75
|
+
});
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
currentGeneralStep = null;
|
|
79
|
+
const stepNum = parseInt(stepMatch[1], 10);
|
|
80
|
+
let content = stepMatch[2];
|
|
81
|
+
if (content.trim() === "...") continue;
|
|
82
|
+
const existingKey = `${currentPhase}-${stepNum}`;
|
|
83
|
+
const existing = phaseStepMap.get(existingKey);
|
|
84
|
+
if (existing && (existing.status === "done" || existing.status === "cached") && stepNum < maxStepInPhase) {
|
|
85
|
+
currentPhase++;
|
|
86
|
+
maxStepInPhase = 0;
|
|
87
|
+
}
|
|
88
|
+
if (stepNum > maxStepInPhase) maxStepInPhase = stepNum;
|
|
89
|
+
const key = `${currentPhase}-${stepNum}`;
|
|
90
|
+
let step = phaseStepMap.get(key);
|
|
91
|
+
if (!step) {
|
|
92
|
+
step = {
|
|
93
|
+
stepNumber: stepNum,
|
|
94
|
+
title: "",
|
|
95
|
+
duration: null,
|
|
96
|
+
status: "running",
|
|
97
|
+
lines: [],
|
|
98
|
+
phase: currentPhase,
|
|
99
|
+
startedAt: timestamp
|
|
100
|
+
};
|
|
101
|
+
phaseStepMap.set(key, step);
|
|
102
|
+
allSteps.push(step);
|
|
103
|
+
}
|
|
104
|
+
const doneMatch = content.match(DONE_RE);
|
|
105
|
+
if (doneMatch) {
|
|
106
|
+
step.duration = doneMatch[1];
|
|
107
|
+
step.status = "done";
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (content.trim() === "CACHED") {
|
|
111
|
+
step.status = "cached";
|
|
112
|
+
step.duration = "cached";
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
let elapsed = null;
|
|
116
|
+
const timingMatch = content.match(TIMING_PREFIX_RE);
|
|
117
|
+
if (timingMatch) {
|
|
118
|
+
elapsed = parseFloat(timingMatch[1]);
|
|
119
|
+
content = timingMatch[2];
|
|
120
|
+
}
|
|
121
|
+
if (!content.trim()) continue;
|
|
122
|
+
if (!step.title) step.title = content.trim();
|
|
123
|
+
if (step.lines.length > 0 || content.trim() !== step.title) step.lines.push({
|
|
124
|
+
content: content.trim(),
|
|
125
|
+
elapsed,
|
|
126
|
+
timestamp
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const numberedWithIndex = [];
|
|
130
|
+
const structure = [];
|
|
131
|
+
for (let i = 0; i < allSteps.length; i++) {
|
|
132
|
+
const step = allSteps[i];
|
|
133
|
+
if (step.stepNumber === null) structure.push({
|
|
134
|
+
type: "general",
|
|
135
|
+
origIdx: i
|
|
136
|
+
});
|
|
137
|
+
else if (step.title.trim() !== "") {
|
|
138
|
+
structure.push({
|
|
139
|
+
type: "numbered",
|
|
140
|
+
origIdx: i
|
|
141
|
+
});
|
|
142
|
+
numberedWithIndex.push({
|
|
143
|
+
step,
|
|
144
|
+
origIdx: i
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const stageOrder = buildStageOrder(numberedWithIndex.map((n) => n.step));
|
|
149
|
+
numberedWithIndex.sort((a, b) => {
|
|
150
|
+
if (a.step.phase !== b.step.phase) return a.step.phase - b.step.phase;
|
|
151
|
+
if (a.step.startedAt && b.step.startedAt) {
|
|
152
|
+
const tsDiff = new Date(a.step.startedAt).getTime() - new Date(b.step.startedAt).getTime();
|
|
153
|
+
if (tsDiff !== 0) return tsDiff;
|
|
154
|
+
}
|
|
155
|
+
const aInfo = parseStageInfo(a.step.title);
|
|
156
|
+
const bInfo = parseStageInfo(b.step.title);
|
|
157
|
+
const aOrder = aInfo ? stageOrder.get(aInfo.stage) ?? 99 : 99;
|
|
158
|
+
const bOrder = bInfo ? stageOrder.get(bInfo.stage) ?? 99 : 99;
|
|
159
|
+
if (aOrder !== bOrder) return aOrder - bOrder;
|
|
160
|
+
return (aInfo?.substep ?? a.step.stepNumber ?? 0) - (bInfo?.substep ?? b.step.stepNumber ?? 0);
|
|
161
|
+
});
|
|
162
|
+
const result = [];
|
|
163
|
+
let nIdx = 0;
|
|
164
|
+
let generalCount = 0;
|
|
165
|
+
const totalGenerals = structure.filter((s) => s.type === "general").length;
|
|
166
|
+
for (const entry of structure) {
|
|
167
|
+
if (entry.type === "numbered") {
|
|
168
|
+
result.push(numberedWithIndex[nIdx].step);
|
|
169
|
+
nIdx++;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
generalCount++;
|
|
173
|
+
const generalStep = allSteps[entry.origIdx];
|
|
174
|
+
if (generalCount === totalGenerals && totalGenerals > 1) {
|
|
175
|
+
const deployLines = [];
|
|
176
|
+
const healthLines = [];
|
|
177
|
+
let hitRuntime = false;
|
|
178
|
+
for (const line of generalStep.lines) {
|
|
179
|
+
if (!hitRuntime && isRuntimeLine(line.content)) hitRuntime = true;
|
|
180
|
+
if (hitRuntime) healthLines.push(line);
|
|
181
|
+
else deployLines.push(line);
|
|
182
|
+
}
|
|
183
|
+
if (deployLines.length > 0) result.push({
|
|
184
|
+
stepNumber: null,
|
|
185
|
+
title: "Finalização",
|
|
186
|
+
duration: null,
|
|
187
|
+
status: "done",
|
|
188
|
+
lines: deployLines,
|
|
189
|
+
phase: generalStep.phase,
|
|
190
|
+
startedAt: deployLines[0]?.timestamp ?? generalStep.startedAt
|
|
191
|
+
});
|
|
192
|
+
if (healthLines.length > 0) result.push({
|
|
193
|
+
stepNumber: null,
|
|
194
|
+
title: "Verificação de saúde",
|
|
195
|
+
duration: null,
|
|
196
|
+
status: "done",
|
|
197
|
+
lines: healthLines,
|
|
198
|
+
phase: generalStep.phase,
|
|
199
|
+
startedAt: healthLines[0]?.timestamp ?? null
|
|
200
|
+
});
|
|
201
|
+
} else result.push(generalStep);
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
//#endregion
|
|
207
|
+
//#region src/components/deploy-tui.tsx
|
|
208
|
+
const BRAND_COLOR = "#FF4D00";
|
|
209
|
+
const BAR_WIDTH = 20;
|
|
210
|
+
const SPINNER_FRAMES = [
|
|
211
|
+
"⠋",
|
|
212
|
+
"⠙",
|
|
213
|
+
"⠹",
|
|
214
|
+
"⠸",
|
|
215
|
+
"⠼",
|
|
216
|
+
"⠴",
|
|
217
|
+
"⠦",
|
|
218
|
+
"⠧",
|
|
219
|
+
"⠇",
|
|
220
|
+
"⠏"
|
|
221
|
+
];
|
|
222
|
+
const MAX_OUTPUT_LINES = 5;
|
|
223
|
+
/** Regex to extract stage info from BuildStep titles like `[stage-0 3/11] COPY ...` */
|
|
224
|
+
const STAGE_TITLE_RE = /^\[([\w-]+)\s+(\d+)\/(\d+)\]\s+(.+)$/;
|
|
225
|
+
function buildStepsToStages(steps) {
|
|
226
|
+
const stages = /* @__PURE__ */ new Map();
|
|
227
|
+
const platformMessages = [];
|
|
228
|
+
const stepDetails = /* @__PURE__ */ new Map();
|
|
229
|
+
const displayOrder = [];
|
|
230
|
+
const seenStages = /* @__PURE__ */ new Set();
|
|
231
|
+
for (const step of steps) {
|
|
232
|
+
if (step.stepNumber === null) {
|
|
233
|
+
for (const line of step.lines) {
|
|
234
|
+
const cleaned = cleanDisplayLine(line.content);
|
|
235
|
+
if (cleaned) platformMessages.push(cleaned);
|
|
236
|
+
}
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const match = step.title.match(STAGE_TITLE_RE);
|
|
240
|
+
if (!match) {
|
|
241
|
+
if (step.title && !/^\[(?:depot|internal)\]/i.test(step.title)) displayOrder.push({
|
|
242
|
+
kind: "extra",
|
|
243
|
+
step
|
|
244
|
+
});
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
const stageName = match[1];
|
|
248
|
+
const substep = parseInt(match[2], 10);
|
|
249
|
+
const total = parseInt(match[3], 10);
|
|
250
|
+
const command = match[4];
|
|
251
|
+
let stage = stages.get(stageName);
|
|
252
|
+
if (!stage) {
|
|
253
|
+
stage = {
|
|
254
|
+
name: stageName,
|
|
255
|
+
total,
|
|
256
|
+
steps: /* @__PURE__ */ new Map(),
|
|
257
|
+
stepNumMap: /* @__PURE__ */ new Map(),
|
|
258
|
+
cachedStepNums: /* @__PURE__ */ new Set(),
|
|
259
|
+
doneStepNums: /* @__PURE__ */ new Set()
|
|
260
|
+
};
|
|
261
|
+
stages.set(stageName, stage);
|
|
262
|
+
}
|
|
263
|
+
if (!seenStages.has(stageName)) {
|
|
264
|
+
seenStages.add(stageName);
|
|
265
|
+
displayOrder.push({
|
|
266
|
+
kind: "stage",
|
|
267
|
+
name: stageName
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
stage.steps.set(substep, command);
|
|
271
|
+
stage.stepNumMap.set(step.stepNumber, substep);
|
|
272
|
+
stage.total = Math.max(stage.total, total);
|
|
273
|
+
if (step.status === "cached") stage.cachedStepNums.add(step.stepNumber);
|
|
274
|
+
else if (step.status === "done") stage.doneStepNums.add(step.stepNumber);
|
|
275
|
+
stepDetails.set(`${stageName}-${substep}`, {
|
|
276
|
+
duration: step.duration !== "cached" ? step.duration : null,
|
|
277
|
+
status: step.status,
|
|
278
|
+
lastLines: step.lines.slice(-MAX_OUTPUT_LINES).map((l) => l.content),
|
|
279
|
+
lineCount: step.lines.length
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
stages,
|
|
284
|
+
platformMessages,
|
|
285
|
+
displayOrder,
|
|
286
|
+
stepDetails
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function AnimatedSpinner({ color = "cyan" }) {
|
|
290
|
+
const [frame, setFrame] = useState(0);
|
|
291
|
+
useEffect(() => {
|
|
292
|
+
const timer = setInterval(() => {
|
|
293
|
+
setFrame((f) => (f + 1) % SPINNER_FRAMES.length);
|
|
294
|
+
}, 80);
|
|
295
|
+
return () => clearInterval(timer);
|
|
296
|
+
}, []);
|
|
297
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
298
|
+
color,
|
|
299
|
+
children: SPINNER_FRAMES[frame]
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
function ProgressBar({ filled, total, allCached, allDone }) {
|
|
303
|
+
const ratio = total > 0 ? filled / total : 0;
|
|
304
|
+
const filledChars = Math.round(ratio * BAR_WIDTH);
|
|
305
|
+
const emptyChars = BAR_WIDTH - filledChars;
|
|
306
|
+
const counter = `${filled}/${total}`;
|
|
307
|
+
if (allCached) return /* @__PURE__ */ jsxs(Text, {
|
|
308
|
+
color: BRAND_COLOR,
|
|
309
|
+
children: [
|
|
310
|
+
"━".repeat(BAR_WIDTH),
|
|
311
|
+
" ",
|
|
312
|
+
counter,
|
|
313
|
+
" ✓ veloz cache"
|
|
314
|
+
]
|
|
315
|
+
});
|
|
316
|
+
if (allDone) return /* @__PURE__ */ jsxs(Text, {
|
|
317
|
+
color: "green",
|
|
318
|
+
children: [
|
|
319
|
+
"━".repeat(BAR_WIDTH),
|
|
320
|
+
" ",
|
|
321
|
+
counter,
|
|
322
|
+
" ✓"
|
|
323
|
+
]
|
|
324
|
+
});
|
|
325
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
326
|
+
/* @__PURE__ */ jsx(Text, {
|
|
327
|
+
color: "cyan",
|
|
328
|
+
children: "━".repeat(filledChars)
|
|
329
|
+
}),
|
|
330
|
+
/* @__PURE__ */ jsx(Text, {
|
|
331
|
+
dimColor: true,
|
|
332
|
+
children: "─".repeat(emptyChars)
|
|
333
|
+
}),
|
|
334
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
335
|
+
dimColor: true,
|
|
336
|
+
children: [" ", counter]
|
|
337
|
+
})
|
|
338
|
+
] });
|
|
339
|
+
}
|
|
340
|
+
function getStageStats(stage) {
|
|
341
|
+
let finishedCount = 0;
|
|
342
|
+
let cachedCount = 0;
|
|
343
|
+
for (const bkNum of stage.stepNumMap.keys()) if (stage.cachedStepNums.has(bkNum)) {
|
|
344
|
+
finishedCount++;
|
|
345
|
+
cachedCount++;
|
|
346
|
+
} else if (stage.doneStepNums.has(bkNum)) finishedCount++;
|
|
347
|
+
const allFinished = stage.total > 0 && finishedCount >= stage.total;
|
|
348
|
+
return {
|
|
349
|
+
finishedCount,
|
|
350
|
+
cachedCount,
|
|
351
|
+
allFinished,
|
|
352
|
+
allCached: allFinished && cachedCount >= stage.total,
|
|
353
|
+
allDone: allFinished && cachedCount < stage.total
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function getStepStatus(stepNum, stage) {
|
|
357
|
+
for (const [bkNum, dockerStep] of stage.stepNumMap.entries()) if (dockerStep === stepNum) {
|
|
358
|
+
if (stage.cachedStepNums.has(bkNum)) return "cached";
|
|
359
|
+
if (stage.doneStepNums.has(bkNum)) return "done";
|
|
360
|
+
return "running";
|
|
361
|
+
}
|
|
362
|
+
return "pending";
|
|
363
|
+
}
|
|
364
|
+
function StepStatusIcon({ status, spinnerFrame }) {
|
|
365
|
+
switch (status) {
|
|
366
|
+
case "cached": return /* @__PURE__ */ jsx(Text, {
|
|
367
|
+
color: BRAND_COLOR,
|
|
368
|
+
children: "✓"
|
|
369
|
+
});
|
|
370
|
+
case "done": return /* @__PURE__ */ jsx(Text, {
|
|
371
|
+
color: "green",
|
|
372
|
+
children: "✓"
|
|
373
|
+
});
|
|
374
|
+
case "running": return /* @__PURE__ */ jsx(Text, {
|
|
375
|
+
color: "cyan",
|
|
376
|
+
children: SPINNER_FRAMES[spinnerFrame]
|
|
377
|
+
});
|
|
378
|
+
case "pending": return /* @__PURE__ */ jsx(Text, {
|
|
379
|
+
dimColor: true,
|
|
380
|
+
children: "·"
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
function friendlyExtraTitle(title) {
|
|
385
|
+
if (/^exporting to image/i.test(title)) return "Código compilado, distribuindo no sistema da Veloz";
|
|
386
|
+
if (/^exporting to client/i.test(title)) return "Exportando resultado";
|
|
387
|
+
return title;
|
|
388
|
+
}
|
|
389
|
+
function BuildDashboard({ serviceName, stages, displayOrder, committedCount, platformMessages, stepDetails, spinnerText }) {
|
|
390
|
+
const [spinnerFrame, setSpinnerFrame] = useState(0);
|
|
391
|
+
useEffect(() => {
|
|
392
|
+
const timer = setInterval(() => {
|
|
393
|
+
setSpinnerFrame((f) => (f + 1) % SPINNER_FRAMES.length);
|
|
394
|
+
}, 80);
|
|
395
|
+
return () => clearInterval(timer);
|
|
396
|
+
}, []);
|
|
397
|
+
const visibleItems = displayOrder.slice(committedCount);
|
|
398
|
+
const showHeader = committedCount === 0;
|
|
399
|
+
const stageNames = displayOrder.filter((d) => d.kind === "stage").map((d) => d.name);
|
|
400
|
+
const maxNameLen = Math.max(...stageNames.map((n) => n.length), 4);
|
|
401
|
+
const allStagesComplete = stageNames.length > 0 && stageNames.every((name) => {
|
|
402
|
+
const stage = stages.get(name);
|
|
403
|
+
return stage ? getStageStats(stage).allFinished : false;
|
|
404
|
+
});
|
|
405
|
+
const hasRunningExtra = displayOrder.some((d) => d.kind === "extra" && d.step.status === "running");
|
|
406
|
+
const allComplete = displayOrder.length > 0 && displayOrder.every((item) => {
|
|
407
|
+
if (item.kind === "stage") {
|
|
408
|
+
const stage = stages.get(item.name);
|
|
409
|
+
return stage ? getStageStats(stage).allFinished : false;
|
|
410
|
+
}
|
|
411
|
+
return item.step.status === "done" || item.step.status === "cached";
|
|
412
|
+
});
|
|
413
|
+
let bottomSpinner = spinnerText;
|
|
414
|
+
if (allComplete) bottomSpinner = "Finalizando build...";
|
|
415
|
+
else if (allStagesComplete && hasRunningExtra) bottomSpinner = "Distribuindo...";
|
|
416
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
417
|
+
flexDirection: "column",
|
|
418
|
+
paddingLeft: 2,
|
|
419
|
+
children: [
|
|
420
|
+
showHeader && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
421
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
422
|
+
bold: true,
|
|
423
|
+
color: "cyan",
|
|
424
|
+
children: ["BUILD ", serviceName ? /* @__PURE__ */ jsxs(Text, {
|
|
425
|
+
dimColor: true,
|
|
426
|
+
children: [
|
|
427
|
+
"(",
|
|
428
|
+
serviceName,
|
|
429
|
+
")"
|
|
430
|
+
]
|
|
431
|
+
}) : null]
|
|
432
|
+
}),
|
|
433
|
+
platformMessages.map((msg, i) => /* @__PURE__ */ jsxs(Text, { children: [" ", msg] }, `pm-${i}`)),
|
|
434
|
+
displayOrder.length > 0 && /* @__PURE__ */ jsx(Text, { children: "" })
|
|
435
|
+
] }),
|
|
436
|
+
visibleItems.map((item, idx) => {
|
|
437
|
+
if (item.kind === "stage") {
|
|
438
|
+
const stage = stages.get(item.name);
|
|
439
|
+
const stats = getStageStats(stage);
|
|
440
|
+
const sortedSteps = [...stage.steps.entries()].sort((a, b) => a[0] - b[0]);
|
|
441
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
442
|
+
flexDirection: "column",
|
|
443
|
+
children: [
|
|
444
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
445
|
+
/* @__PURE__ */ jsx(Text, {
|
|
446
|
+
bold: true,
|
|
447
|
+
children: item.name.padEnd(maxNameLen)
|
|
448
|
+
}),
|
|
449
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
450
|
+
/* @__PURE__ */ jsx(ProgressBar, {
|
|
451
|
+
filled: stats.finishedCount,
|
|
452
|
+
total: stage.total,
|
|
453
|
+
allCached: stats.allCached,
|
|
454
|
+
allDone: stats.allDone
|
|
455
|
+
})
|
|
456
|
+
] }),
|
|
457
|
+
sortedSteps.map(([stepNum, command]) => {
|
|
458
|
+
const status$1 = getStepStatus(stepNum, stage);
|
|
459
|
+
const detail = stepDetails.get(`${item.name}-${stepNum}`);
|
|
460
|
+
const isDone$1 = status$1 === "done" || status$1 === "cached";
|
|
461
|
+
const isRunning$1 = status$1 === "running";
|
|
462
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
463
|
+
flexDirection: "column",
|
|
464
|
+
children: [/* @__PURE__ */ jsxs(Box, { children: [
|
|
465
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
466
|
+
/* @__PURE__ */ jsx(StepStatusIcon, {
|
|
467
|
+
status: status$1,
|
|
468
|
+
spinnerFrame
|
|
469
|
+
}),
|
|
470
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
471
|
+
dimColor: isDone$1,
|
|
472
|
+
children: [
|
|
473
|
+
" ",
|
|
474
|
+
command,
|
|
475
|
+
status$1 === "cached" ? /* @__PURE__ */ jsx(Text, {
|
|
476
|
+
color: BRAND_COLOR,
|
|
477
|
+
children: " (veloz cache)"
|
|
478
|
+
}) : isDone$1 && detail?.duration ? /* @__PURE__ */ jsxs(Text, {
|
|
479
|
+
dimColor: true,
|
|
480
|
+
children: [" ", detail.duration]
|
|
481
|
+
}) : null
|
|
482
|
+
]
|
|
483
|
+
})
|
|
484
|
+
] }), isRunning$1 && detail && detail.lastLines.length > 0 && /* @__PURE__ */ jsx(Box, {
|
|
485
|
+
flexDirection: "column",
|
|
486
|
+
children: detail.lastLines.map((line, li) => /* @__PURE__ */ jsxs(Text, {
|
|
487
|
+
dimColor: true,
|
|
488
|
+
children: [" ", line]
|
|
489
|
+
}, li))
|
|
490
|
+
})]
|
|
491
|
+
}, stepNum);
|
|
492
|
+
}),
|
|
493
|
+
idx < visibleItems.length - 1 && /* @__PURE__ */ jsx(Text, { children: "" })
|
|
494
|
+
]
|
|
495
|
+
}, item.name);
|
|
496
|
+
}
|
|
497
|
+
const step = item.step;
|
|
498
|
+
const isDone = step.status === "done" || step.status === "cached";
|
|
499
|
+
const isRunning = step.status === "running";
|
|
500
|
+
const status = step.status === "error" ? "running" : step.status;
|
|
501
|
+
const title = friendlyExtraTitle(step.title);
|
|
502
|
+
const lastLines = step.lines.slice(-MAX_OUTPUT_LINES).map((l) => l.content);
|
|
503
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
504
|
+
flexDirection: "column",
|
|
505
|
+
children: [/* @__PURE__ */ jsxs(Box, { children: [
|
|
506
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
507
|
+
/* @__PURE__ */ jsx(StepStatusIcon, {
|
|
508
|
+
status,
|
|
509
|
+
spinnerFrame
|
|
510
|
+
}),
|
|
511
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
512
|
+
dimColor: isDone,
|
|
513
|
+
children: [
|
|
514
|
+
" ",
|
|
515
|
+
title,
|
|
516
|
+
isDone && step.duration && step.duration !== "cached" ? /* @__PURE__ */ jsxs(Text, {
|
|
517
|
+
dimColor: true,
|
|
518
|
+
children: [" ", step.duration]
|
|
519
|
+
}) : null
|
|
520
|
+
]
|
|
521
|
+
})
|
|
522
|
+
] }), isRunning && lastLines.length > 0 && /* @__PURE__ */ jsx(Box, {
|
|
523
|
+
flexDirection: "column",
|
|
524
|
+
children: lastLines.map((line, li) => /* @__PURE__ */ jsxs(Text, {
|
|
525
|
+
dimColor: true,
|
|
526
|
+
children: [" ", line]
|
|
527
|
+
}, li))
|
|
528
|
+
})]
|
|
529
|
+
}, `extra-${idx}`);
|
|
530
|
+
}),
|
|
531
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
532
|
+
marginTop: 1,
|
|
533
|
+
children: [/* @__PURE__ */ jsx(AnimatedSpinner, {}), /* @__PURE__ */ jsxs(Text, { children: [" ", bottomSpinner] })]
|
|
534
|
+
})
|
|
535
|
+
]
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
function DeployTUIApp({ stream, serviceName, resultRef }) {
|
|
539
|
+
const { exit } = useApp();
|
|
540
|
+
const [, forceUpdate] = useState(0);
|
|
541
|
+
const [staticLines, setStaticLines] = useState([]);
|
|
542
|
+
const [shouldExit, setShouldExit] = useState(false);
|
|
543
|
+
const stateRef = useRef({
|
|
544
|
+
stages: /* @__PURE__ */ new Map(),
|
|
545
|
+
displayOrder: [],
|
|
546
|
+
platformMessages: [],
|
|
547
|
+
stepDetails: /* @__PURE__ */ new Map(),
|
|
548
|
+
phase: "waiting",
|
|
549
|
+
finalStatus: "",
|
|
550
|
+
committedCount: 0,
|
|
551
|
+
headerCommitted: false
|
|
552
|
+
});
|
|
553
|
+
useEffect(() => {
|
|
554
|
+
if (shouldExit) exit();
|
|
555
|
+
}, [shouldExit, exit]);
|
|
556
|
+
useEffect(() => {
|
|
557
|
+
const state$1 = stateRef.current;
|
|
558
|
+
const allLogs = [];
|
|
559
|
+
let accumulatedBuildLogs = "";
|
|
560
|
+
let runtimeLogId = 0;
|
|
561
|
+
function applyBuildParse() {
|
|
562
|
+
const result = buildStepsToStages(parseBuildSteps(accumulatedBuildLogs));
|
|
563
|
+
state$1.stages = result.stages;
|
|
564
|
+
state$1.displayOrder = result.displayOrder;
|
|
565
|
+
state$1.platformMessages = result.platformMessages;
|
|
566
|
+
state$1.stepDetails = result.stepDetails;
|
|
567
|
+
}
|
|
568
|
+
/** Check if a display item is fully complete */
|
|
569
|
+
function isItemComplete(item) {
|
|
570
|
+
if (item.kind === "stage") {
|
|
571
|
+
const stage = state$1.stages.get(item.name);
|
|
572
|
+
return stage ? getStageStats(stage).allFinished : false;
|
|
573
|
+
}
|
|
574
|
+
return item.step.status === "done" || item.step.status === "cached";
|
|
575
|
+
}
|
|
576
|
+
/** Progressively commit completed leading items to Static for scrolling */
|
|
577
|
+
function commitCompleted() {
|
|
578
|
+
const newItems = [];
|
|
579
|
+
if (!state$1.headerCommitted && state$1.displayOrder.length > 0) {
|
|
580
|
+
state$1.headerCommitted = true;
|
|
581
|
+
newItems.push({
|
|
582
|
+
id: "build-header",
|
|
583
|
+
node: /* @__PURE__ */ jsxs(Text, {
|
|
584
|
+
bold: true,
|
|
585
|
+
color: "cyan",
|
|
586
|
+
children: [" BUILD ", serviceName ? /* @__PURE__ */ jsxs(Text, {
|
|
587
|
+
dimColor: true,
|
|
588
|
+
children: [
|
|
589
|
+
"(",
|
|
590
|
+
serviceName,
|
|
591
|
+
")"
|
|
592
|
+
]
|
|
593
|
+
}) : null]
|
|
594
|
+
})
|
|
595
|
+
});
|
|
596
|
+
for (const [i, msg] of state$1.platformMessages.entries()) newItems.push({
|
|
597
|
+
id: `platform-${i}`,
|
|
598
|
+
node: /* @__PURE__ */ jsxs(Text, { children: [" ", msg] })
|
|
599
|
+
});
|
|
600
|
+
newItems.push({
|
|
601
|
+
id: "header-gap",
|
|
602
|
+
node: /* @__PURE__ */ jsx(Text, { children: "" })
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
const stageNames = state$1.displayOrder.filter((d) => d.kind === "stage").map((d) => d.name);
|
|
606
|
+
const maxNameLen = Math.max(...stageNames.map((n) => n.length), 4);
|
|
607
|
+
for (let i = state$1.committedCount; i < state$1.displayOrder.length; i++) {
|
|
608
|
+
const item = state$1.displayOrder[i];
|
|
609
|
+
if (!isItemComplete(item)) break;
|
|
610
|
+
if (item.kind === "stage") {
|
|
611
|
+
const stage = state$1.stages.get(item.name);
|
|
612
|
+
const stats = getStageStats(stage);
|
|
613
|
+
const counter = `${stats.finishedCount}/${stage.total}`;
|
|
614
|
+
const barNode = stats.allCached ? /* @__PURE__ */ jsxs(Text, {
|
|
615
|
+
color: BRAND_COLOR,
|
|
616
|
+
children: [
|
|
617
|
+
"━".repeat(BAR_WIDTH),
|
|
618
|
+
" ",
|
|
619
|
+
counter,
|
|
620
|
+
" ✓ veloz cache"
|
|
621
|
+
]
|
|
622
|
+
}) : /* @__PURE__ */ jsxs(Text, {
|
|
623
|
+
color: "green",
|
|
624
|
+
children: [
|
|
625
|
+
"━".repeat(BAR_WIDTH),
|
|
626
|
+
" ",
|
|
627
|
+
counter,
|
|
628
|
+
" ✓"
|
|
629
|
+
]
|
|
630
|
+
});
|
|
631
|
+
newItems.push({
|
|
632
|
+
id: `stage-${item.name}`,
|
|
633
|
+
node: /* @__PURE__ */ jsxs(Box, { children: [
|
|
634
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
635
|
+
bold: true,
|
|
636
|
+
children: [" ", item.name.padEnd(maxNameLen)]
|
|
637
|
+
}),
|
|
638
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
639
|
+
barNode
|
|
640
|
+
] })
|
|
641
|
+
});
|
|
642
|
+
const sortedSteps = [...stage.steps.entries()].sort((a, b) => a[0] - b[0]);
|
|
643
|
+
for (const [stepNum, command] of sortedSteps) {
|
|
644
|
+
const stepStatus = getStepStatus(stepNum, stage);
|
|
645
|
+
const detail = state$1.stepDetails.get(`${item.name}-${stepNum}`);
|
|
646
|
+
const icon = stepStatus === "cached" ? /* @__PURE__ */ jsx(Text, {
|
|
647
|
+
color: BRAND_COLOR,
|
|
648
|
+
children: "✓"
|
|
649
|
+
}) : /* @__PURE__ */ jsx(Text, {
|
|
650
|
+
color: "green",
|
|
651
|
+
children: "✓"
|
|
652
|
+
});
|
|
653
|
+
const suffix = stepStatus === "cached" ? /* @__PURE__ */ jsx(Text, {
|
|
654
|
+
color: BRAND_COLOR,
|
|
655
|
+
children: " (veloz cache)"
|
|
656
|
+
}) : detail?.duration ? /* @__PURE__ */ jsxs(Text, {
|
|
657
|
+
dimColor: true,
|
|
658
|
+
children: [" ", detail.duration]
|
|
659
|
+
}) : null;
|
|
660
|
+
newItems.push({
|
|
661
|
+
id: `step-${item.name}-${stepNum}`,
|
|
662
|
+
node: /* @__PURE__ */ jsxs(Text, { children: [
|
|
663
|
+
" ",
|
|
664
|
+
icon,
|
|
665
|
+
" ",
|
|
666
|
+
/* @__PURE__ */ jsx(Text, {
|
|
667
|
+
dimColor: true,
|
|
668
|
+
children: command
|
|
669
|
+
}),
|
|
670
|
+
suffix
|
|
671
|
+
] })
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
} else {
|
|
675
|
+
const step = item.step;
|
|
676
|
+
const title = friendlyExtraTitle(step.title);
|
|
677
|
+
const duration = step.duration && step.duration !== "cached" ? ` ${step.duration}` : "";
|
|
678
|
+
newItems.push({
|
|
679
|
+
id: `extra-${i}`,
|
|
680
|
+
node: /* @__PURE__ */ jsxs(Text, { children: [
|
|
681
|
+
" ",
|
|
682
|
+
/* @__PURE__ */ jsx(Text, {
|
|
683
|
+
color: "green",
|
|
684
|
+
children: "✓"
|
|
685
|
+
}),
|
|
686
|
+
" ",
|
|
687
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
688
|
+
dimColor: true,
|
|
689
|
+
children: [title, duration]
|
|
690
|
+
})
|
|
691
|
+
] })
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
newItems.push({
|
|
695
|
+
id: `gap-${i}`,
|
|
696
|
+
node: /* @__PURE__ */ jsx(Text, { children: "" })
|
|
697
|
+
});
|
|
698
|
+
state$1.committedCount = i + 1;
|
|
699
|
+
}
|
|
700
|
+
if (newItems.length > 0) setStaticLines((prev) => [...prev, ...newItems]);
|
|
701
|
+
}
|
|
702
|
+
/** Force-commit all remaining items (even if not complete) — used at phase transitions */
|
|
703
|
+
function commitAllRemaining() {
|
|
704
|
+
const newItems = [];
|
|
705
|
+
const stageNames = state$1.displayOrder.filter((d) => d.kind === "stage").map((d) => d.name);
|
|
706
|
+
const maxNameLen = Math.max(...stageNames.map((n) => n.length), 4);
|
|
707
|
+
for (let i = state$1.committedCount; i < state$1.displayOrder.length; i++) {
|
|
708
|
+
const item = state$1.displayOrder[i];
|
|
709
|
+
if (item.kind === "stage") {
|
|
710
|
+
const stage = state$1.stages.get(item.name);
|
|
711
|
+
const stats = getStageStats(stage);
|
|
712
|
+
const counter = `${stats.finishedCount}/${stage.total}`;
|
|
713
|
+
const barNode = stats.allCached ? /* @__PURE__ */ jsxs(Text, {
|
|
714
|
+
color: BRAND_COLOR,
|
|
715
|
+
children: [
|
|
716
|
+
"━".repeat(BAR_WIDTH),
|
|
717
|
+
" ",
|
|
718
|
+
counter,
|
|
719
|
+
" ✓ veloz cache"
|
|
720
|
+
]
|
|
721
|
+
}) : stats.allDone ? /* @__PURE__ */ jsxs(Text, {
|
|
722
|
+
color: "green",
|
|
723
|
+
children: [
|
|
724
|
+
"━".repeat(BAR_WIDTH),
|
|
725
|
+
" ",
|
|
726
|
+
counter,
|
|
727
|
+
" ✓"
|
|
728
|
+
]
|
|
729
|
+
}) : /* @__PURE__ */ jsxs(Text, { children: [
|
|
730
|
+
/* @__PURE__ */ jsx(Text, {
|
|
731
|
+
color: "cyan",
|
|
732
|
+
children: "━".repeat(Math.round(stats.finishedCount / Math.max(stage.total, 1) * BAR_WIDTH))
|
|
733
|
+
}),
|
|
734
|
+
/* @__PURE__ */ jsx(Text, {
|
|
735
|
+
dimColor: true,
|
|
736
|
+
children: "─".repeat(BAR_WIDTH - Math.round(stats.finishedCount / Math.max(stage.total, 1) * BAR_WIDTH))
|
|
737
|
+
}),
|
|
738
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
739
|
+
dimColor: true,
|
|
740
|
+
children: [" ", counter]
|
|
741
|
+
})
|
|
742
|
+
] });
|
|
743
|
+
newItems.push({
|
|
744
|
+
id: `stage-${item.name}`,
|
|
745
|
+
node: /* @__PURE__ */ jsxs(Box, { children: [
|
|
746
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
747
|
+
bold: true,
|
|
748
|
+
children: [" ", item.name.padEnd(maxNameLen)]
|
|
749
|
+
}),
|
|
750
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
751
|
+
barNode
|
|
752
|
+
] })
|
|
753
|
+
});
|
|
754
|
+
const sortedSteps = [...stage.steps.entries()].sort((a, b) => a[0] - b[0]);
|
|
755
|
+
for (const [stepNum, command] of sortedSteps) {
|
|
756
|
+
const stepStatus = getStepStatus(stepNum, stage);
|
|
757
|
+
const detail = state$1.stepDetails.get(`${item.name}-${stepNum}`);
|
|
758
|
+
const icon = stepStatus === "cached" ? /* @__PURE__ */ jsx(Text, {
|
|
759
|
+
color: BRAND_COLOR,
|
|
760
|
+
children: "✓"
|
|
761
|
+
}) : stepStatus === "done" || stepStatus === "cached" ? /* @__PURE__ */ jsx(Text, {
|
|
762
|
+
color: "green",
|
|
763
|
+
children: "✓"
|
|
764
|
+
}) : /* @__PURE__ */ jsx(Text, {
|
|
765
|
+
dimColor: true,
|
|
766
|
+
children: "·"
|
|
767
|
+
});
|
|
768
|
+
const suffix = stepStatus === "cached" ? /* @__PURE__ */ jsx(Text, {
|
|
769
|
+
color: BRAND_COLOR,
|
|
770
|
+
children: " (veloz cache)"
|
|
771
|
+
}) : detail?.duration ? /* @__PURE__ */ jsxs(Text, {
|
|
772
|
+
dimColor: true,
|
|
773
|
+
children: [" ", detail.duration]
|
|
774
|
+
}) : null;
|
|
775
|
+
newItems.push({
|
|
776
|
+
id: `step-${item.name}-${stepNum}`,
|
|
777
|
+
node: /* @__PURE__ */ jsxs(Text, { children: [
|
|
778
|
+
" ",
|
|
779
|
+
icon,
|
|
780
|
+
" ",
|
|
781
|
+
/* @__PURE__ */ jsx(Text, {
|
|
782
|
+
dimColor: true,
|
|
783
|
+
children: command
|
|
784
|
+
}),
|
|
785
|
+
suffix
|
|
786
|
+
] })
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
} else {
|
|
790
|
+
const step = item.step;
|
|
791
|
+
const isDone = step.status === "done" || step.status === "cached";
|
|
792
|
+
const title = friendlyExtraTitle(step.title);
|
|
793
|
+
const duration = isDone && step.duration && step.duration !== "cached" ? ` ${step.duration}` : "";
|
|
794
|
+
const icon = isDone ? /* @__PURE__ */ jsx(Text, {
|
|
795
|
+
color: "green",
|
|
796
|
+
children: "✓"
|
|
797
|
+
}) : /* @__PURE__ */ jsx(Text, {
|
|
798
|
+
dimColor: true,
|
|
799
|
+
children: "·"
|
|
800
|
+
});
|
|
801
|
+
newItems.push({
|
|
802
|
+
id: `extra-${i}`,
|
|
803
|
+
node: /* @__PURE__ */ jsxs(Text, { children: [
|
|
804
|
+
" ",
|
|
805
|
+
icon,
|
|
806
|
+
" ",
|
|
807
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
808
|
+
dimColor: true,
|
|
809
|
+
children: [title, duration]
|
|
810
|
+
})
|
|
811
|
+
] })
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
newItems.push({
|
|
815
|
+
id: `gap-${i}`,
|
|
816
|
+
node: /* @__PURE__ */ jsx(Text, { children: "" })
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
state$1.committedCount = state$1.displayOrder.length;
|
|
820
|
+
return newItems;
|
|
821
|
+
}
|
|
822
|
+
const consume = async () => {
|
|
823
|
+
try {
|
|
824
|
+
for await (const event of stream) if (event.type === "status") {
|
|
825
|
+
state$1.finalStatus = event.content;
|
|
826
|
+
switch (event.content) {
|
|
827
|
+
case "BUILDING":
|
|
828
|
+
state$1.phase = "building";
|
|
829
|
+
forceUpdate((n) => n + 1);
|
|
830
|
+
break;
|
|
831
|
+
case "DEPLOYING":
|
|
832
|
+
if (accumulatedBuildLogs) applyBuildParse();
|
|
833
|
+
for (const stage of state$1.stages.values()) if (stage.steps.size > 0 && stage.steps.size < stage.total) stage.total = stage.steps.size;
|
|
834
|
+
commitCompleted();
|
|
835
|
+
if (state$1.committedCount < state$1.displayOrder.length) {
|
|
836
|
+
const remaining = commitAllRemaining();
|
|
837
|
+
if (remaining.length > 0) setStaticLines((prev) => [...prev, ...remaining]);
|
|
838
|
+
}
|
|
839
|
+
state$1.phase = "deploying";
|
|
840
|
+
forceUpdate((n) => n + 1);
|
|
841
|
+
break;
|
|
842
|
+
case "LIVE":
|
|
843
|
+
setStaticLines((prev) => [...prev, {
|
|
844
|
+
id: "live-status",
|
|
845
|
+
node: /* @__PURE__ */ jsxs(Text, {
|
|
846
|
+
color: "green",
|
|
847
|
+
children: [" ", "✓ Publicado"]
|
|
848
|
+
})
|
|
849
|
+
}]);
|
|
850
|
+
state$1.phase = "live";
|
|
851
|
+
forceUpdate((n) => n + 1);
|
|
852
|
+
break;
|
|
853
|
+
default: if (TERMINAL_STATUSES.has(event.content)) {
|
|
854
|
+
if (accumulatedBuildLogs) applyBuildParse();
|
|
855
|
+
if (state$1.phase === "building" || state$1.phase === "waiting") {
|
|
856
|
+
commitCompleted();
|
|
857
|
+
if (state$1.committedCount < state$1.displayOrder.length) {
|
|
858
|
+
const remaining = commitAllRemaining();
|
|
859
|
+
if (remaining.length > 0) setStaticLines((prev) => [...prev, ...remaining]);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
state$1.phase = "failed";
|
|
863
|
+
forceUpdate((n) => n + 1);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
} else if (event.type === "log") {
|
|
867
|
+
const lines = event.content.split("\n");
|
|
868
|
+
allLogs.push(...lines);
|
|
869
|
+
if (state$1.phase === "deploying" || state$1.phase === "live") {
|
|
870
|
+
for (const line of lines) {
|
|
871
|
+
const trimmed = line.trim();
|
|
872
|
+
if (!trimmed) continue;
|
|
873
|
+
const parsed = parseBuildLine(trimmed);
|
|
874
|
+
let text = null;
|
|
875
|
+
if (parsed.kind === "platform") text = parsed.message;
|
|
876
|
+
else if (parsed.kind === "other" && parsed.text) text = parsed.text;
|
|
877
|
+
else if (parsed.kind === "output") text = parsed.text;
|
|
878
|
+
if (text && !isHiddenMessage(text)) {
|
|
879
|
+
const logId = runtimeLogId++;
|
|
880
|
+
const newItems = [];
|
|
881
|
+
if (logId === 0) newItems.push({
|
|
882
|
+
id: "runtime-header",
|
|
883
|
+
node: /* @__PURE__ */ jsx(Text, {
|
|
884
|
+
bold: true,
|
|
885
|
+
color: "cyan",
|
|
886
|
+
children: "\n RUNTIME"
|
|
887
|
+
})
|
|
888
|
+
});
|
|
889
|
+
newItems.push({
|
|
890
|
+
id: `log-${logId}`,
|
|
891
|
+
node: /* @__PURE__ */ jsxs(Text, { children: [" ", text] })
|
|
892
|
+
});
|
|
893
|
+
setStaticLines((prev) => [...prev, ...newItems]);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
continue;
|
|
897
|
+
}
|
|
898
|
+
if (state$1.phase === "waiting") state$1.phase = "building";
|
|
899
|
+
if (accumulatedBuildLogs && !accumulatedBuildLogs.endsWith("\n")) accumulatedBuildLogs += "\n";
|
|
900
|
+
accumulatedBuildLogs += event.content;
|
|
901
|
+
applyBuildParse();
|
|
902
|
+
commitCompleted();
|
|
903
|
+
forceUpdate((n) => n + 1);
|
|
904
|
+
}
|
|
905
|
+
} catch {}
|
|
906
|
+
resultRef.current = {
|
|
907
|
+
status: state$1.finalStatus,
|
|
908
|
+
logs: allLogs.filter((l) => l.trim())
|
|
909
|
+
};
|
|
910
|
+
setShouldExit(true);
|
|
911
|
+
};
|
|
912
|
+
consume();
|
|
913
|
+
}, [
|
|
914
|
+
stream,
|
|
915
|
+
serviceName,
|
|
916
|
+
resultRef,
|
|
917
|
+
exit,
|
|
918
|
+
setShouldExit
|
|
919
|
+
]);
|
|
920
|
+
const state = stateRef.current;
|
|
921
|
+
const showBuild = state.phase === "waiting" || state.phase === "building";
|
|
922
|
+
const showDeploySpinner = state.phase === "deploying";
|
|
923
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
924
|
+
flexDirection: "column",
|
|
925
|
+
children: [
|
|
926
|
+
/* @__PURE__ */ jsx(Static, {
|
|
927
|
+
items: staticLines,
|
|
928
|
+
children: (line) => /* @__PURE__ */ jsx(Box, { children: line.node }, line.id)
|
|
929
|
+
}),
|
|
930
|
+
showBuild && /* @__PURE__ */ jsx(BuildDashboard, {
|
|
931
|
+
serviceName,
|
|
932
|
+
stages: state.stages,
|
|
933
|
+
displayOrder: state.displayOrder,
|
|
934
|
+
committedCount: state.committedCount,
|
|
935
|
+
platformMessages: state.platformMessages,
|
|
936
|
+
stepDetails: state.stepDetails,
|
|
937
|
+
spinnerText: state.phase === "waiting" ? "Aguardando início do build..." : "Compilando..."
|
|
938
|
+
}),
|
|
939
|
+
showDeploySpinner && /* @__PURE__ */ jsxs(Box, {
|
|
940
|
+
paddingLeft: 2,
|
|
941
|
+
children: [/* @__PURE__ */ jsx(AnimatedSpinner, {}), /* @__PURE__ */ jsx(Text, { children: " Publicando..." })]
|
|
942
|
+
})
|
|
943
|
+
]
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
async function fetchDeployUrls(client, serviceId) {
|
|
947
|
+
try {
|
|
948
|
+
return (await client.domains.list({ serviceId })).map((d) => `https://${d.domain}`);
|
|
949
|
+
} catch {
|
|
950
|
+
return [];
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
function getFailureHints(status) {
|
|
954
|
+
switch (status) {
|
|
955
|
+
case "BUILD_FAILED": return [
|
|
956
|
+
"Verifique os logs de build acima para erros de compilação",
|
|
957
|
+
"Teste o build localmente: rode o comando de build do seu projeto",
|
|
958
|
+
"Use 'veloz config show' para verificar as configurações"
|
|
959
|
+
];
|
|
960
|
+
case "DEPLOY_FAILED": return [
|
|
961
|
+
"O build passou mas o serviço falhou ao iniciar",
|
|
962
|
+
"Verifique se a porta configurada está correta: 'veloz config show'",
|
|
963
|
+
"Veja os logs de runtime: 'veloz logs -f'"
|
|
964
|
+
];
|
|
965
|
+
case "CANCELLED": return ["Deploy cancelado. Execute 'veloz deploy' para tentar novamente."];
|
|
966
|
+
default: return ["Execute 'veloz logs -f' para mais detalhes."];
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
async function renderDeployTUI(deploymentId, serviceId, serviceName) {
|
|
970
|
+
const client = await getClient();
|
|
971
|
+
const stream = await client.logs.streamBuildLogs({ deploymentId });
|
|
972
|
+
const resultRef = { current: {
|
|
973
|
+
status: "",
|
|
974
|
+
logs: []
|
|
975
|
+
} };
|
|
976
|
+
const instance = render(/* @__PURE__ */ jsx(DeployTUIApp, {
|
|
977
|
+
stream,
|
|
978
|
+
serviceName,
|
|
979
|
+
resultRef
|
|
980
|
+
}), {
|
|
981
|
+
exitOnCtrlC: false,
|
|
982
|
+
patchConsole: false
|
|
983
|
+
});
|
|
984
|
+
try {
|
|
985
|
+
await instance.waitUntilExit();
|
|
986
|
+
} catch {
|
|
987
|
+
instance.unmount();
|
|
988
|
+
}
|
|
989
|
+
if (!resultRef.current.status) try {
|
|
990
|
+
const d = await client.deployments.get({ deploymentId });
|
|
991
|
+
resultRef.current.status = d.status;
|
|
992
|
+
try {
|
|
993
|
+
const logs = await client.logs.getBuildLogs({ deploymentId });
|
|
994
|
+
if (logs.buildLogs) resultRef.current.logs.push(...logs.buildLogs.split("\n"));
|
|
995
|
+
} catch {}
|
|
996
|
+
} catch {}
|
|
997
|
+
const urls = resultRef.current.status === "LIVE" ? await fetchDeployUrls(client, serviceId) : [];
|
|
998
|
+
const finalStatus = resultRef.current.status;
|
|
999
|
+
if (finalStatus === "LIVE") {
|
|
1000
|
+
success(serviceName ? `Deploy de ${chalk.bold(serviceName)} concluído! Serviço ativo.` : "Deploy concluído! Serviço ativo.");
|
|
1001
|
+
for (const url of urls) info(chalk.bold(url));
|
|
1002
|
+
} else if (TERMINAL_STATUSES.has(finalStatus)) {
|
|
1003
|
+
const label = statusLabels[finalStatus] ?? finalStatus;
|
|
1004
|
+
const hints = getFailureHints(finalStatus);
|
|
1005
|
+
const allLogs = resultRef.current.logs;
|
|
1006
|
+
if (allLogs.length > 0) {
|
|
1007
|
+
process.stderr.write("\n");
|
|
1008
|
+
process.stderr.write(chalk.red(` ${"─".repeat(50)}`) + "\n");
|
|
1009
|
+
process.stderr.write(chalk.red.bold(" Logs de build:") + "\n");
|
|
1010
|
+
process.stderr.write(chalk.red(` ${"─".repeat(50)}`) + "\n");
|
|
1011
|
+
for (const line of allLogs) if (line.trim()) process.stderr.write(chalk.dim(` ${line}`) + "\n");
|
|
1012
|
+
process.stderr.write(chalk.red(` ${"─".repeat(50)}`) + "\n");
|
|
1013
|
+
}
|
|
1014
|
+
const errorMsg = serviceName ? `Deploy de ${chalk.bold(serviceName)} finalizou: ${label}` : `Deploy finalizou: ${label}`;
|
|
1015
|
+
process.stderr.write(chalk.red(`\n✗ ${errorMsg}`) + "\n");
|
|
1016
|
+
for (const hint of hints) process.stderr.write(chalk.yellow(` → ${hint}`) + "\n");
|
|
1017
|
+
process.exit(1);
|
|
1018
|
+
}
|
|
1019
|
+
return {
|
|
1020
|
+
status: finalStatus,
|
|
1021
|
+
logs: resultRef.current.logs.filter((l) => l.trim()),
|
|
1022
|
+
urls,
|
|
1023
|
+
serviceName
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
//#endregion
|
|
1028
|
+
export { renderDeployTUI };
|
package/dist/index.mjs
CHANGED
|
@@ -943,7 +943,7 @@ const requireAuth = middleware(async (_c, next) => {
|
|
|
943
943
|
console.error("Não autorizado. Defina VELOZ_API_KEY ou execute `veloz login`.");
|
|
944
944
|
process.exit(1);
|
|
945
945
|
}
|
|
946
|
-
const { performLogin: performLogin$1 } = await import("./login-
|
|
946
|
+
const { performLogin: performLogin$1 } = await import("./login-DEQ5zMzL.mjs");
|
|
947
947
|
await performLogin$1();
|
|
948
948
|
}
|
|
949
949
|
await next();
|
|
@@ -4299,236 +4299,19 @@ function parseBuildLine(raw) {
|
|
|
4299
4299
|
text: trimmed
|
|
4300
4300
|
};
|
|
4301
4301
|
}
|
|
4302
|
-
const BAR_WIDTH = 20;
|
|
4303
|
-
const BRAND = chalk.rgb(255, 77, 0);
|
|
4304
|
-
function renderProgressBar(filled, total, allCached, allDone) {
|
|
4305
|
-
const ratio = total > 0 ? filled / total : 0;
|
|
4306
|
-
const filledChars = Math.round(ratio * BAR_WIDTH);
|
|
4307
|
-
const emptyChars = BAR_WIDTH - filledChars;
|
|
4308
|
-
const counter = `${filled}/${total}`;
|
|
4309
|
-
if (allCached) return `${BRAND("━".repeat(BAR_WIDTH))} ${BRAND(`${counter} ◆ cached`)}`;
|
|
4310
|
-
if (allDone) return `${chalk.green("━".repeat(BAR_WIDTH))} ${chalk.green(`${counter} ✓`)}`;
|
|
4311
|
-
return chalk.cyan("━".repeat(filledChars)) + chalk.dim("─".repeat(emptyChars)) + ` ${chalk.dim(counter)}`;
|
|
4312
|
-
}
|
|
4313
|
-
const SPINNER_FRAMES = [
|
|
4314
|
-
"⠋",
|
|
4315
|
-
"⠙",
|
|
4316
|
-
"⠹",
|
|
4317
|
-
"⠸",
|
|
4318
|
-
"⠼",
|
|
4319
|
-
"⠴",
|
|
4320
|
-
"⠦",
|
|
4321
|
-
"⠧",
|
|
4322
|
-
"⠇",
|
|
4323
|
-
"⠏"
|
|
4324
|
-
];
|
|
4325
|
-
/**
|
|
4326
|
-
* Dashboard-style renderer for compact TTY mode.
|
|
4327
|
-
* Redraws the entire build progress block on each update.
|
|
4328
|
-
* Includes an integrated spinner that animates via setInterval.
|
|
4329
|
-
*/
|
|
4330
|
-
var BuildProgressRenderer = class {
|
|
4331
|
-
stages = /* @__PURE__ */ new Map();
|
|
4332
|
-
stageOrder = [];
|
|
4333
|
-
platformMessages = [];
|
|
4334
|
-
renderLineCount = 0;
|
|
4335
|
-
phase = "waiting";
|
|
4336
|
-
runtimeHeaderPrinted = false;
|
|
4337
|
-
serviceName;
|
|
4338
|
-
spinnerFrame = 0;
|
|
4339
|
-
spinnerInterval = null;
|
|
4340
|
-
spinnerText = "Aguardando início do build...";
|
|
4341
|
-
/** External ora spinner reference — used to pause/resume during runtime log output */
|
|
4342
|
-
externalSpinner = null;
|
|
4343
|
-
/** Pending render scheduled via setTimeout for batching rapid updates */
|
|
4344
|
-
pendingRender = null;
|
|
4345
|
-
constructor(serviceName) {
|
|
4346
|
-
this.serviceName = serviceName;
|
|
4347
|
-
this.startSpinner();
|
|
4348
|
-
}
|
|
4349
|
-
setExternalSpinner(spinner$1) {
|
|
4350
|
-
this.externalSpinner = spinner$1;
|
|
4351
|
-
}
|
|
4352
|
-
startSpinner() {
|
|
4353
|
-
if (this.spinnerInterval) return;
|
|
4354
|
-
this.spinnerInterval = setInterval(() => {
|
|
4355
|
-
this.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length;
|
|
4356
|
-
this.render();
|
|
4357
|
-
}, 120);
|
|
4358
|
-
}
|
|
4359
|
-
stopSpinner() {
|
|
4360
|
-
if (this.spinnerInterval) {
|
|
4361
|
-
clearInterval(this.spinnerInterval);
|
|
4362
|
-
this.spinnerInterval = null;
|
|
4363
|
-
}
|
|
4364
|
-
if (this.pendingRender) {
|
|
4365
|
-
clearTimeout(this.pendingRender);
|
|
4366
|
-
this.pendingRender = null;
|
|
4367
|
-
}
|
|
4368
|
-
}
|
|
4369
|
-
setBuilding() {
|
|
4370
|
-
this.phase = "building";
|
|
4371
|
-
this.spinnerText = "Compilando...";
|
|
4372
|
-
}
|
|
4373
|
-
switchToRuntime() {
|
|
4374
|
-
if (this.phase === "runtime") return;
|
|
4375
|
-
for (const stage of this.stages.values()) if (stage.steps.size > 0 && stage.steps.size < stage.total) stage.total = stage.steps.size;
|
|
4376
|
-
this.stopSpinner();
|
|
4377
|
-
this.render();
|
|
4378
|
-
this.renderLineCount = 0;
|
|
4379
|
-
this.phase = "runtime";
|
|
4380
|
-
}
|
|
4381
|
-
processLine(raw) {
|
|
4382
|
-
const trimmed = raw.trim();
|
|
4383
|
-
if (!trimmed) return;
|
|
4384
|
-
if (this.phase === "runtime") {
|
|
4385
|
-
this.printRuntimeLine(trimmed);
|
|
4386
|
-
return;
|
|
4387
|
-
}
|
|
4388
|
-
if (this.phase === "waiting") {
|
|
4389
|
-
this.phase = "building";
|
|
4390
|
-
this.spinnerText = "Compilando...";
|
|
4391
|
-
}
|
|
4392
|
-
const parsed = parseBuildLine(trimmed);
|
|
4393
|
-
switch (parsed.kind) {
|
|
4394
|
-
case "step": {
|
|
4395
|
-
let stage = this.stages.get(parsed.stage);
|
|
4396
|
-
if (!stage) {
|
|
4397
|
-
stage = {
|
|
4398
|
-
name: parsed.stage,
|
|
4399
|
-
total: parsed.total,
|
|
4400
|
-
steps: /* @__PURE__ */ new Map(),
|
|
4401
|
-
stepNumMap: /* @__PURE__ */ new Map(),
|
|
4402
|
-
cachedStepNums: /* @__PURE__ */ new Set(),
|
|
4403
|
-
doneStepNums: /* @__PURE__ */ new Set()
|
|
4404
|
-
};
|
|
4405
|
-
this.stages.set(parsed.stage, stage);
|
|
4406
|
-
this.stageOrder.push(parsed.stage);
|
|
4407
|
-
}
|
|
4408
|
-
stage.steps.set(parsed.step, parsed.command);
|
|
4409
|
-
stage.stepNumMap.set(parsed.stepNum, parsed.step);
|
|
4410
|
-
stage.total = Math.max(stage.total, parsed.total);
|
|
4411
|
-
break;
|
|
4412
|
-
}
|
|
4413
|
-
case "cached":
|
|
4414
|
-
for (const stage of this.stages.values()) if (stage.stepNumMap.has(parsed.stepNum)) {
|
|
4415
|
-
stage.cachedStepNums.add(parsed.stepNum);
|
|
4416
|
-
break;
|
|
4417
|
-
}
|
|
4418
|
-
break;
|
|
4419
|
-
case "done":
|
|
4420
|
-
for (const stage of this.stages.values()) if (stage.stepNumMap.has(parsed.stepNum)) {
|
|
4421
|
-
stage.doneStepNums.add(parsed.stepNum);
|
|
4422
|
-
break;
|
|
4423
|
-
}
|
|
4424
|
-
break;
|
|
4425
|
-
case "platform": {
|
|
4426
|
-
const cleaned = cleanDisplayLine(parsed.message);
|
|
4427
|
-
if (cleaned) this.platformMessages.push(cleaned);
|
|
4428
|
-
break;
|
|
4429
|
-
}
|
|
4430
|
-
case "output":
|
|
4431
|
-
case "other": break;
|
|
4432
|
-
}
|
|
4433
|
-
this.scheduleRender();
|
|
4434
|
-
}
|
|
4435
|
-
printRuntimeLine(line) {
|
|
4436
|
-
const parsed = parseBuildLine(line);
|
|
4437
|
-
let text = null;
|
|
4438
|
-
if (parsed.kind === "platform") text = parsed.message;
|
|
4439
|
-
else if (parsed.kind === "other" && parsed.text) text = parsed.text;
|
|
4440
|
-
else if (parsed.kind === "output") text = parsed.text;
|
|
4441
|
-
if (!text) return;
|
|
4442
|
-
if (isHiddenMessage(text)) return;
|
|
4443
|
-
if (this.externalSpinner) this.externalSpinner.clear();
|
|
4444
|
-
if (!this.runtimeHeaderPrinted) {
|
|
4445
|
-
this.runtimeHeaderPrinted = true;
|
|
4446
|
-
console.log(chalk.cyan.bold(`\n RUNTIME`));
|
|
4447
|
-
}
|
|
4448
|
-
console.log(` ${text}`);
|
|
4449
|
-
if (this.externalSpinner) this.externalSpinner.render();
|
|
4450
|
-
}
|
|
4451
|
-
isStageComplete(stage) {
|
|
4452
|
-
return stage.steps.size >= stage.total;
|
|
4453
|
-
}
|
|
4454
|
-
/**
|
|
4455
|
-
* Schedule a render on the next tick — batches rapid processLine() calls
|
|
4456
|
-
* so we don't re-render for every single log line in a burst.
|
|
4457
|
-
*/
|
|
4458
|
-
scheduleRender() {
|
|
4459
|
-
if (this.pendingRender) return;
|
|
4460
|
-
this.pendingRender = setTimeout(() => {
|
|
4461
|
-
this.pendingRender = null;
|
|
4462
|
-
this.render();
|
|
4463
|
-
}, 0);
|
|
4464
|
-
}
|
|
4465
|
-
render() {
|
|
4466
|
-
const buf = [];
|
|
4467
|
-
if (this.renderLineCount > 0) buf.push(`\x1b[${this.renderLineCount}A\x1b[J`);
|
|
4468
|
-
let lines = 0;
|
|
4469
|
-
const label = this.serviceName ? `BUILD ${chalk.dim(`(${this.serviceName})`)}` : "BUILD";
|
|
4470
|
-
buf.push(`${chalk.cyan.bold(` ${label}`)}\n`);
|
|
4471
|
-
lines++;
|
|
4472
|
-
for (const msg of this.platformMessages) {
|
|
4473
|
-
buf.push(` ${msg}\n`);
|
|
4474
|
-
lines++;
|
|
4475
|
-
}
|
|
4476
|
-
if (this.stageOrder.length > 0) {
|
|
4477
|
-
buf.push("\n");
|
|
4478
|
-
lines++;
|
|
4479
|
-
}
|
|
4480
|
-
const maxNameLen = Math.max(...this.stageOrder.map((n) => n.length), 4);
|
|
4481
|
-
for (let i = 0; i < this.stageOrder.length; i++) {
|
|
4482
|
-
const stageName = this.stageOrder[i];
|
|
4483
|
-
const stage = this.stages.get(stageName);
|
|
4484
|
-
const complete = this.isStageComplete(stage);
|
|
4485
|
-
const allCached = complete && stage.cachedStepNums.size === stage.steps.size;
|
|
4486
|
-
const allDone = complete && !allCached;
|
|
4487
|
-
const bar = renderProgressBar(stage.steps.size, stage.total, allCached, allDone);
|
|
4488
|
-
const paddedName = chalk.bold(stageName.padEnd(maxNameLen));
|
|
4489
|
-
buf.push(` ${paddedName} ${bar}\n`);
|
|
4490
|
-
lines++;
|
|
4491
|
-
const sortedSteps = [...stage.steps.entries()].sort((a, b) => a[0] - b[0]);
|
|
4492
|
-
const spinnerChar = SPINNER_FRAMES[this.spinnerFrame];
|
|
4493
|
-
for (const [stepNum, command] of sortedSteps) {
|
|
4494
|
-
let stepStatus = "";
|
|
4495
|
-
for (const [bkNum, dockerStep] of stage.stepNumMap.entries()) if (dockerStep === stepNum) {
|
|
4496
|
-
if (stage.cachedStepNums.has(bkNum)) stepStatus = ` ${BRAND("◆")}`;
|
|
4497
|
-
else if (stage.doneStepNums.has(bkNum)) stepStatus = ` ${chalk.green("✓")}`;
|
|
4498
|
-
else stepStatus = ` ${chalk.cyan(spinnerChar)}`;
|
|
4499
|
-
break;
|
|
4500
|
-
}
|
|
4501
|
-
buf.push(` ${command}${stepStatus}\n`);
|
|
4502
|
-
lines++;
|
|
4503
|
-
}
|
|
4504
|
-
if (i < this.stageOrder.length - 1) {
|
|
4505
|
-
buf.push("\n");
|
|
4506
|
-
lines++;
|
|
4507
|
-
}
|
|
4508
|
-
}
|
|
4509
|
-
if (this.spinnerInterval) {
|
|
4510
|
-
if (!(this.stageOrder.length > 0 && this.stageOrder.every((name) => this.isStageComplete(this.stages.get(name))))) {
|
|
4511
|
-
const frame = SPINNER_FRAMES[this.spinnerFrame];
|
|
4512
|
-
buf.push(`\n ${chalk.cyan(frame)} ${this.spinnerText}\n`);
|
|
4513
|
-
lines += 2;
|
|
4514
|
-
}
|
|
4515
|
-
}
|
|
4516
|
-
process.stdout.write(buf.join(""));
|
|
4517
|
-
this.renderLineCount = lines;
|
|
4518
|
-
}
|
|
4519
|
-
};
|
|
4520
4302
|
async function streamDeploymentLogs(deploymentId, serviceId, serviceName) {
|
|
4521
4303
|
const client = await getClient();
|
|
4522
4304
|
const isVerbose = process.env.VELOZ_VERBOSE === "true";
|
|
4523
4305
|
const mcp = isMcpMode();
|
|
4524
4306
|
const isTTY = !mcp && process.stdout.isTTY;
|
|
4525
4307
|
const isGHA = !mcp && process.env.GITHUB_ACTIONS === "true";
|
|
4308
|
+
if (isTTY && !isVerbose) {
|
|
4309
|
+
const { renderDeployTUI } = await import("./deploy-tui-U7fsZN6x.mjs");
|
|
4310
|
+
return renderDeployTUI(deploymentId, serviceId, serviceName);
|
|
4311
|
+
}
|
|
4526
4312
|
const allLogLines = [];
|
|
4527
|
-
let buildSpinner = null;
|
|
4528
|
-
let renderer = null;
|
|
4529
4313
|
if (mcp) log(serviceName ? `[deploy] Build: ${serviceName}` : "[deploy] Build iniciando...");
|
|
4530
4314
|
else if (isGHA) startGroup(serviceName ? `Build: ${serviceName}` : "Build");
|
|
4531
|
-
else if (isTTY && !isVerbose) renderer = new BuildProgressRenderer(serviceName);
|
|
4532
4315
|
else if (isTTY) {
|
|
4533
4316
|
const header = serviceName ? `Build: ${chalk.bold(serviceName)}` : "Build";
|
|
4534
4317
|
console.log(chalk.cyan(`\n${header}`));
|
|
@@ -4544,29 +4327,7 @@ async function streamDeploymentLogs(deploymentId, serviceId, serviceName) {
|
|
|
4544
4327
|
const label = statusLabels[event.content] ?? event.content;
|
|
4545
4328
|
finalStatus = event.content;
|
|
4546
4329
|
if (mcp) log(`[deploy] Status: ${label}`);
|
|
4547
|
-
else
|
|
4548
|
-
if (event.content === "BUILDING") renderer.setBuilding();
|
|
4549
|
-
else if (event.content === "DEPLOYING") {
|
|
4550
|
-
renderer.switchToRuntime();
|
|
4551
|
-
buildSpinner = ora({
|
|
4552
|
-
text: "Publicando...",
|
|
4553
|
-
color: "cyan"
|
|
4554
|
-
}).start();
|
|
4555
|
-
renderer.setExternalSpinner(buildSpinner);
|
|
4556
|
-
} else if (event.content === "LIVE") {
|
|
4557
|
-
if (buildSpinner) {
|
|
4558
|
-
renderer.setExternalSpinner(null);
|
|
4559
|
-
buildSpinner.succeed("Publicado");
|
|
4560
|
-
buildSpinner = null;
|
|
4561
|
-
}
|
|
4562
|
-
} else if (TERMINAL_STATUSES.has(event.content) && event.content !== "LIVE") {
|
|
4563
|
-
if (buildSpinner) {
|
|
4564
|
-
renderer.setExternalSpinner(null);
|
|
4565
|
-
buildSpinner.fail(label);
|
|
4566
|
-
buildSpinner = null;
|
|
4567
|
-
}
|
|
4568
|
-
}
|
|
4569
|
-
} else {
|
|
4330
|
+
else {
|
|
4570
4331
|
const icon = statusIcons[event.content] ?? chalk.yellow("●");
|
|
4571
4332
|
process.stdout.write(`\n${icon} ${chalk.bold(label)}\n`);
|
|
4572
4333
|
}
|
|
@@ -4575,15 +4336,9 @@ async function streamDeploymentLogs(deploymentId, serviceId, serviceName) {
|
|
|
4575
4336
|
allLogLines.push(...lines);
|
|
4576
4337
|
if (mcp) {
|
|
4577
4338
|
for (const line of lines) if (line.trim()) log(`[build] ${line.trim()}`);
|
|
4578
|
-
} else
|
|
4579
|
-
else for (const line of lines) if (line.trim()) process.stdout.write(` ${line}\n`);
|
|
4339
|
+
} else for (const line of lines) if (line.trim()) process.stdout.write(` ${line}\n`);
|
|
4580
4340
|
}
|
|
4581
4341
|
} catch {
|
|
4582
|
-
if (renderer) renderer.stopSpinner();
|
|
4583
|
-
if (buildSpinner) {
|
|
4584
|
-
buildSpinner.stop();
|
|
4585
|
-
buildSpinner = null;
|
|
4586
|
-
}
|
|
4587
4342
|
try {
|
|
4588
4343
|
finalStatus = (await client.deployments.get({ deploymentId })).status;
|
|
4589
4344
|
try {
|
|
@@ -4593,20 +4348,11 @@ async function streamDeploymentLogs(deploymentId, serviceId, serviceName) {
|
|
|
4593
4348
|
} catch {}
|
|
4594
4349
|
}
|
|
4595
4350
|
if (isGHA) endGroup();
|
|
4596
|
-
if (renderer) renderer.stopSpinner();
|
|
4597
4351
|
const urls = finalStatus === "LIVE" ? await fetchDeployUrls$1(client, serviceId) : [];
|
|
4598
4352
|
if (finalStatus === "LIVE") {
|
|
4599
|
-
if (buildSpinner) {
|
|
4600
|
-
buildSpinner.stop();
|
|
4601
|
-
buildSpinner = null;
|
|
4602
|
-
}
|
|
4603
4353
|
success(serviceName ? `Deploy de ${mcp ? serviceName : chalk.bold(serviceName)} concluído! Serviço ativo.` : "Deploy concluído! Serviço ativo.");
|
|
4604
4354
|
if (urls.length > 0) for (const url of urls) info(mcp ? url : `${chalk.bold(url)}`);
|
|
4605
4355
|
} else if (TERMINAL_STATUSES.has(finalStatus)) {
|
|
4606
|
-
if (buildSpinner) {
|
|
4607
|
-
buildSpinner.stop();
|
|
4608
|
-
buildSpinner = null;
|
|
4609
|
-
}
|
|
4610
4356
|
const label = statusLabels[finalStatus] ?? finalStatus;
|
|
4611
4357
|
const hints = getFailureHints$1(finalStatus);
|
|
4612
4358
|
if (mcp) {
|
|
@@ -4675,7 +4421,7 @@ const LOGO_LINES = [
|
|
|
4675
4421
|
];
|
|
4676
4422
|
const BRAND_COLOR = "#FF4D00";
|
|
4677
4423
|
function getVersion() {
|
|
4678
|
-
return "0.0.0-beta.
|
|
4424
|
+
return "0.0.0-beta.23";
|
|
4679
4425
|
}
|
|
4680
4426
|
function printBanner(subtitle) {
|
|
4681
4427
|
const version = getVersion();
|
|
@@ -5701,7 +5447,7 @@ async function autoUpdate() {
|
|
|
5701
5447
|
if (process.env.VELOZ_MCP === "true") return;
|
|
5702
5448
|
const pm = detectPackageManager();
|
|
5703
5449
|
if (!pm) return;
|
|
5704
|
-
const currentVersion = "0.0.0-beta.
|
|
5450
|
+
const currentVersion = "0.0.0-beta.23";
|
|
5705
5451
|
const latestVersion = await fetchLatestVersion();
|
|
5706
5452
|
if (!latestVersion || latestVersion === currentVersion) return;
|
|
5707
5453
|
const installCmd = getInstallCommand(pm, latestVersion);
|
|
@@ -7256,7 +7002,7 @@ async function pruneRemovedEntries(config, existingConfig, services, databases)
|
|
|
7256
7002
|
//#region src/index.ts
|
|
7257
7003
|
if (process.argv.includes("--mcp")) process.env.VELOZ_MCP = "true";
|
|
7258
7004
|
const cli = Cli.create("veloz", {
|
|
7259
|
-
version: "0.0.0-beta.
|
|
7005
|
+
version: "0.0.0-beta.23",
|
|
7260
7006
|
description: "CLI da plataforma Veloz — deploy rápido para o Brasil",
|
|
7261
7007
|
env: z.object({ VELOZ_ENV: z.string().optional().describe("Ambiente alvo (ex: preview, staging)") })
|
|
7262
7008
|
});
|
|
@@ -7332,4 +7078,4 @@ registerPull(cli);
|
|
|
7332
7078
|
cli.serve();
|
|
7333
7079
|
|
|
7334
7080
|
//#endregion
|
|
7335
|
-
export { registerLogin as n, performLogin as t };
|
|
7081
|
+
export { statusLabels as a, registerLogin as c, TERMINAL_STATUSES as i, info as l, isHiddenMessage as n, getClient as o, parseBuildLine as r, performLogin as s, cleanDisplayLine as t, success as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "onveloz",
|
|
3
|
-
"version": "0.0.0-beta.
|
|
3
|
+
"version": "0.0.0-beta.23",
|
|
4
4
|
"description": "CLI da plataforma Veloz — deploy rápido para o Brasil",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"brasil",
|
|
@@ -33,13 +33,16 @@
|
|
|
33
33
|
"form-data": "^4.0.0",
|
|
34
34
|
"ignore": "^5.3.0",
|
|
35
35
|
"incur": "^0.3.3",
|
|
36
|
+
"ink": "^6.8.0",
|
|
36
37
|
"ora": "^8.2.0",
|
|
38
|
+
"react": "^19.2.4",
|
|
37
39
|
"tar": "^6.2.0",
|
|
38
40
|
"ws": "^8.20.0",
|
|
39
41
|
"zod": "^4.1.13"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
42
44
|
"@types/node": "^22.13.14",
|
|
45
|
+
"@types/react": "^19.2.14",
|
|
43
46
|
"@types/tar": "^6.1.11",
|
|
44
47
|
"@types/ws": "^8.18.1",
|
|
45
48
|
"@veloz/api": "workspace:*",
|
package/dist/login-jxR-lGEN.mjs
DELETED