veryfront 0.0.83 → 0.0.86
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 +21 -60
- package/esm/deno.js +1 -1
- package/esm/src/cli/app/components/list-select.js +2 -2
- package/esm/src/cli/app/index.d.ts +1 -1
- package/esm/src/cli/app/index.d.ts.map +1 -1
- package/esm/src/cli/app/index.js +26 -33
- package/esm/src/cli/app/state.d.ts +3 -0
- package/esm/src/cli/app/state.d.ts.map +1 -1
- package/esm/src/cli/app/state.js +4 -0
- package/esm/src/cli/app/views/dashboard.d.ts.map +1 -1
- package/esm/src/cli/app/views/dashboard.js +46 -58
- package/esm/src/cli/app/views/startup.d.ts +39 -0
- package/esm/src/cli/app/views/startup.d.ts.map +1 -0
- package/esm/src/cli/app/views/startup.js +103 -0
- package/esm/src/cli/commands/dev.js +2 -2
- package/esm/src/cli/commands/new.js +1 -1
- package/esm/src/cli/ui/colors.d.ts +8 -0
- package/esm/src/cli/ui/colors.d.ts.map +1 -1
- package/esm/src/cli/ui/colors.js +34 -0
- package/esm/src/cli/ui/dot-matrix.d.ts +8 -0
- package/esm/src/cli/ui/dot-matrix.d.ts.map +1 -1
- package/esm/src/cli/ui/dot-matrix.js +67 -2
- package/esm/src/cli/ui/tui.js +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/loader.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/loader.js +28 -6
- package/esm/src/transforms/esm/http-cache.d.ts.map +1 -1
- package/esm/src/transforms/esm/http-cache.js +25 -17
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/src/cli/app/components/list-select.ts +2 -2
- package/src/src/cli/app/index.ts +34 -35
- package/src/src/cli/app/state.ts +7 -0
- package/src/src/cli/app/views/dashboard.ts +47 -61
- package/src/src/cli/app/views/startup.ts +132 -0
- package/src/src/cli/commands/dev.ts +2 -2
- package/src/src/cli/commands/new.ts +1 -1
- package/src/src/cli/ui/colors.ts +37 -0
- package/src/src/cli/ui/dot-matrix.ts +77 -1
- package/src/src/cli/ui/tui.ts +1 -1
- package/src/src/modules/react-loader/ssr-module-loader/loader.ts +43 -30
- package/src/src/transforms/esm/http-cache.ts +26 -17
|
@@ -157,8 +157,8 @@ export function devCommand(options) {
|
|
|
157
157
|
const serverUrl = `http://veryfront.me:${finalPort}`;
|
|
158
158
|
console.log();
|
|
159
159
|
console.log(banner({
|
|
160
|
-
title: "Veryfront",
|
|
161
|
-
subtitle: "is
|
|
160
|
+
title: "Veryfront Code",
|
|
161
|
+
subtitle: "is running",
|
|
162
162
|
info: {
|
|
163
163
|
url: serverUrl,
|
|
164
164
|
...(projectSlug ? { project: projectSlug } : {}),
|
|
@@ -102,7 +102,7 @@ export async function newCommand(name, options = {}, env = getRuntimeEnv()) {
|
|
|
102
102
|
exitProcess(1);
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
|
-
const tui = createTui({ title: "Veryfront", showLogs: true });
|
|
105
|
+
const tui = createTui({ title: "Veryfront Code", showLogs: true });
|
|
106
106
|
const restore = interceptConsole(tui);
|
|
107
107
|
const localUrl = `http://${name}.veryfront.me:${port}`;
|
|
108
108
|
const prodUrl = `https://${slug}.veryfront.com`;
|
|
@@ -20,4 +20,12 @@ export declare const successBold: (text: string) => string;
|
|
|
20
20
|
export declare const errorBold: (text: string) => string;
|
|
21
21
|
export { RESET as reset };
|
|
22
22
|
export declare function animatedMatrix(frame: number): string;
|
|
23
|
+
/**
|
|
24
|
+
* Apply shimmer effect to text - creates a wave of brightness moving across
|
|
25
|
+
* @param text The text to shimmer
|
|
26
|
+
* @param frame Current animation frame (increments over time)
|
|
27
|
+
* @param waveWidth Width of the bright wave (default: 3 characters)
|
|
28
|
+
* @returns Text with shimmer effect applied
|
|
29
|
+
*/
|
|
30
|
+
export declare function shimmer(text: string, frame: number, waveWidth?: number): string;
|
|
23
31
|
//# sourceMappingURL=colors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../../../../src/src/cli/ui/colors.ts"],"names":[],"mappings":"AACA,OAAO,EAAO,KAAK,EAAE,MAAM,WAAW,CAAC;AAEvC,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC;AAE7D,wBAAgB,aAAa,IAAI,UAAU,CA+B1C;AAED,wBAAgB,cAAc,IAAI,OAAO,CAExC;AASD,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAgED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGzD;AAMD,eAAO,MAAM,KAAK,SAJsC,MAAM,WAIxB,CAAC;AACvC,eAAO,MAAM,OAAO,SAJsC,MAAM,WAItB,CAAC;AAE3C,eAAO,MAAM,OAAO,SAPoC,MAAM,WAOvB,CAAC;AACxC,eAAO,MAAM,KAAK,SARsC,MAAM,WAQzB,CAAC;AACtC,eAAO,MAAM,OAAO,SAToC,MAAM,WASvB,CAAC;AACxC,eAAO,MAAM,KAAK,SAVsC,MAAM,WAUvB,CAAC;AAExC,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,WAA+B,CAAC;AACjE,eAAO,MAAM,GAAG,GAAI,MAAM,MAAM,WAA+B,CAAC;AAChE,eAAO,MAAM,MAAM,GAAI,MAAM,MAAM,WAA+B,CAAC;AACnE,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,WAA+B,CAAC;AAEtE,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,WAAsB,CAAC;AAC7D,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,WAAwB,CAAC;AACjE,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,WAAsB,CAAC;AAE7D,OAAO,EAAE,KAAK,IAAI,KAAK,EAAE,CAAC;AAS1B,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGpD"}
|
|
1
|
+
{"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../../../../src/src/cli/ui/colors.ts"],"names":[],"mappings":"AACA,OAAO,EAAO,KAAK,EAAE,MAAM,WAAW,CAAC;AAEvC,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC;AAE7D,wBAAgB,aAAa,IAAI,UAAU,CA+B1C;AAED,wBAAgB,cAAc,IAAI,OAAO,CAExC;AASD,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAgED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGzD;AAMD,eAAO,MAAM,KAAK,SAJsC,MAAM,WAIxB,CAAC;AACvC,eAAO,MAAM,OAAO,SAJsC,MAAM,WAItB,CAAC;AAE3C,eAAO,MAAM,OAAO,SAPoC,MAAM,WAOvB,CAAC;AACxC,eAAO,MAAM,KAAK,SARsC,MAAM,WAQzB,CAAC;AACtC,eAAO,MAAM,OAAO,SAToC,MAAM,WASvB,CAAC;AACxC,eAAO,MAAM,KAAK,SAVsC,MAAM,WAUvB,CAAC;AAExC,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,WAA+B,CAAC;AACjE,eAAO,MAAM,GAAG,GAAI,MAAM,MAAM,WAA+B,CAAC;AAChE,eAAO,MAAM,MAAM,GAAI,MAAM,MAAM,WAA+B,CAAC;AACnE,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,WAA+B,CAAC;AAEtE,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,WAAsB,CAAC;AAC7D,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,WAAwB,CAAC;AACjE,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,WAAsB,CAAC;AAE7D,OAAO,EAAE,KAAK,IAAI,KAAK,EAAE,CAAC;AAS1B,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,SAAI,GAAG,MAAM,CA4B1E"}
|
package/esm/src/cli/ui/colors.js
CHANGED
|
@@ -132,3 +132,37 @@ export function animatedMatrix(frame) {
|
|
|
132
132
|
const state = MATRIX_STATES[frame % MATRIX_STATES.length] ?? ["●", "○", "○"];
|
|
133
133
|
return state.map((dot) => (dot === "●" ? brand(dot) : muted(dot))).join("");
|
|
134
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Apply shimmer effect to text - creates a wave of brightness moving across
|
|
137
|
+
* @param text The text to shimmer
|
|
138
|
+
* @param frame Current animation frame (increments over time)
|
|
139
|
+
* @param waveWidth Width of the bright wave (default: 3 characters)
|
|
140
|
+
* @returns Text with shimmer effect applied
|
|
141
|
+
*/
|
|
142
|
+
export function shimmer(text, frame, waveWidth = 3) {
|
|
143
|
+
// Brand orange gradient: bright → normal → dim
|
|
144
|
+
const bright = (char) => applyColor(char, 255, 180, 140, false); // Brighter orange
|
|
145
|
+
const normal = (char) => applyColor(char, 252, 143, 93, false); // Brand orange
|
|
146
|
+
const dimmed = (char) => applyColor(char, 180, 100, 65, false); // Dimmer orange
|
|
147
|
+
const len = text.length;
|
|
148
|
+
const wavePos = frame % (len + waveWidth * 2);
|
|
149
|
+
let result = "";
|
|
150
|
+
for (let i = 0; i < len; i++) {
|
|
151
|
+
const char = text[i];
|
|
152
|
+
const distFromWave = i - (wavePos - waveWidth);
|
|
153
|
+
if (distFromWave >= 0 && distFromWave < waveWidth) {
|
|
154
|
+
// In the bright wave
|
|
155
|
+
const intensity = 1 - Math.abs(distFromWave - waveWidth / 2) / (waveWidth / 2);
|
|
156
|
+
if (intensity > 0.6) {
|
|
157
|
+
result += bright(char);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
result += normal(char);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
result += dimmed(char);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
@@ -48,6 +48,14 @@ export declare function getAgentFace(options?: DotMatrixOptions): string;
|
|
|
48
48
|
* Text lines appear to the right of the face, vertically centered
|
|
49
49
|
*/
|
|
50
50
|
export declare function getAgentFaceWithText(textLines: string[], options?: DotMatrixOptions): string;
|
|
51
|
+
/**
|
|
52
|
+
* Get the agent face with spinning blade animation
|
|
53
|
+
* Orange and purple dots rotate around the logo
|
|
54
|
+
* @param textLines Text to show next to the face
|
|
55
|
+
* @param frame Animation frame (0-15 for full rotation)
|
|
56
|
+
* @param options Dot matrix options
|
|
57
|
+
*/
|
|
58
|
+
export declare function getSpinningAgentFace(textLines: string[], frame: number, options?: DotMatrixOptions): string;
|
|
51
59
|
/**
|
|
52
60
|
* Animated dot matrix display with spinner support
|
|
53
61
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dot-matrix.d.ts","sourceRoot":"","sources":["../../../../src/src/cli/ui/dot-matrix.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,eAAO,MAAM,UAAU,EAAE,MAAM,EAAE,EAQhC,CAAC;AAIF,eAAO,MAAM,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAiB9C,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"dot-matrix.d.ts","sourceRoot":"","sources":["../../../../src/src/cli/ui/dot-matrix.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,eAAO,MAAM,UAAU,EAAE,MAAM,EAAE,EAQhC,CAAC;AAIF,eAAO,MAAM,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAiB9C,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAqHD;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAE3F;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,SAAI,GAAG,MAAM,EAAE,EAAE,CAWnF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,SAAI,GAAG,MAAM,EAAE,EAAE,EAAE,CAElE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAEnE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CAER;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EAAE,EACnB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CAER;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,UAAU,CAAuD;IACzE,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAe;gBAExB,OAAO,GAAE,gBAAqB;IAM1C;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM;IAI3C;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,aAAa;IAIrB;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EAAE,UAAU,SAAK,GAAG,IAAI;IAerE;;OAEG;IACH,oBAAoB,CAClB,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EAChC,UAAU,SAAK,GACd,IAAI;IAeP;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EAAE,UAAU,SAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B5F;;;OAGG;IACH,kBAAkB,CAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EAChC,UAAU,SAAK,GACd,OAAO,CAAC,IAAI,CAAC;IA2BhB;;OAEG;IACH,WAAW,IAAI,IAAI;IAMnB;;OAEG;IACH,IAAI,IAAI,IAAI;IAMZ;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI;CAGtC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAEjF;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
|
|
@@ -52,6 +52,13 @@ const COMPACT_OPTIONS = {
|
|
|
52
52
|
spacing: " ",
|
|
53
53
|
};
|
|
54
54
|
const RESET = "\x1b[0m";
|
|
55
|
+
// Colors for spinning animation - shades of orange
|
|
56
|
+
const SPIN_COLORS = {
|
|
57
|
+
bright: "\x1b[38;2;255;165;120m", // Bright orange (leading edge, toned down)
|
|
58
|
+
orange: "\x1b[38;2;252;143;93m", // Brand orange
|
|
59
|
+
mid: "\x1b[38;2;200;110;70m", // Mid orange (trailing)
|
|
60
|
+
dim: "\x1b[38;2;140;80;50m", // Dim orange/brown
|
|
61
|
+
};
|
|
55
62
|
function resolveOptions(options) {
|
|
56
63
|
if (options.compact)
|
|
57
64
|
return { ...DEFAULT_OPTIONS, ...COMPACT_OPTIONS, ...options };
|
|
@@ -65,8 +72,56 @@ function renderPattern(pattern, opts) {
|
|
|
65
72
|
return opts.prefix + dots.join(opts.spacing);
|
|
66
73
|
});
|
|
67
74
|
}
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Render the pattern with a spinning blade effect
|
|
77
|
+
* The blade sweeps across the lit dots, creating orange → purple gradient
|
|
78
|
+
*/
|
|
79
|
+
function renderSpinningPattern(pattern, frame, opts) {
|
|
80
|
+
const centerRow = 3;
|
|
81
|
+
const centerCol = 3;
|
|
82
|
+
const totalFrames = 16; // Full rotation in 16 frames
|
|
83
|
+
const bladeAngle = ((frame % totalFrames) / totalFrames) * Math.PI * 2;
|
|
84
|
+
return pattern.map((row, rowIdx) => {
|
|
85
|
+
const dots = row.map((dot, colIdx) => {
|
|
86
|
+
if (dot !== 1) {
|
|
87
|
+
return `${opts.offColor}${opts.offChar}${RESET}`;
|
|
88
|
+
}
|
|
89
|
+
// Calculate angle from center to this dot
|
|
90
|
+
const dy = rowIdx - centerRow;
|
|
91
|
+
const dx = colIdx - centerCol;
|
|
92
|
+
let dotAngle = Math.atan2(dy, dx);
|
|
93
|
+
if (dotAngle < 0)
|
|
94
|
+
dotAngle += Math.PI * 2;
|
|
95
|
+
// Calculate angular distance from the blade
|
|
96
|
+
let angleDiff = dotAngle - bladeAngle;
|
|
97
|
+
if (angleDiff < 0)
|
|
98
|
+
angleDiff += Math.PI * 2;
|
|
99
|
+
if (angleDiff > Math.PI)
|
|
100
|
+
angleDiff = Math.PI * 2 - angleDiff;
|
|
101
|
+
// Color based on angular distance from blade
|
|
102
|
+
const normalizedDiff = angleDiff / Math.PI; // 0 = at blade, 1 = opposite
|
|
103
|
+
let color;
|
|
104
|
+
if (normalizedDiff < 0.15) {
|
|
105
|
+
color = SPIN_COLORS.bright; // Leading edge - brightest orange
|
|
106
|
+
}
|
|
107
|
+
else if (normalizedDiff < 0.35) {
|
|
108
|
+
color = SPIN_COLORS.orange; // Near blade - brand orange
|
|
109
|
+
}
|
|
110
|
+
else if (normalizedDiff < 0.6) {
|
|
111
|
+
color = SPIN_COLORS.mid; // Trailing - mid orange
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
color = SPIN_COLORS.dim; // Far from blade - dim orange
|
|
115
|
+
}
|
|
116
|
+
return `${color}${opts.litChar}${RESET}`;
|
|
117
|
+
});
|
|
118
|
+
return opts.prefix + dots.join(opts.spacing);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function renderPatternWithText(pattern, textLines, opts, spinFrame) {
|
|
122
|
+
const faceLines = spinFrame !== undefined
|
|
123
|
+
? renderSpinningPattern(pattern, spinFrame, opts)
|
|
124
|
+
: renderPattern(pattern, opts);
|
|
70
125
|
const faceHeight = faceLines.length;
|
|
71
126
|
const startLine = Math.floor((faceHeight - textLines.length) / 2);
|
|
72
127
|
const result = faceLines.map((line, i) => {
|
|
@@ -120,6 +175,16 @@ export function getAgentFace(options = {}) {
|
|
|
120
175
|
export function getAgentFaceWithText(textLines, options = {}) {
|
|
121
176
|
return renderPatternWithText(AGENT_FACE, textLines, resolveOptions(options));
|
|
122
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Get the agent face with spinning blade animation
|
|
180
|
+
* Orange and purple dots rotate around the logo
|
|
181
|
+
* @param textLines Text to show next to the face
|
|
182
|
+
* @param frame Animation frame (0-15 for full rotation)
|
|
183
|
+
* @param options Dot matrix options
|
|
184
|
+
*/
|
|
185
|
+
export function getSpinningAgentFace(textLines, frame, options = {}) {
|
|
186
|
+
return renderPatternWithText(AGENT_FACE, textLines, resolveOptions(options), frame);
|
|
187
|
+
}
|
|
123
188
|
/**
|
|
124
189
|
* Animated dot matrix display with spinner support
|
|
125
190
|
*/
|
package/esm/src/cli/ui/tui.js
CHANGED
|
@@ -106,7 +106,7 @@ function stopSpinner() {
|
|
|
106
106
|
spinnerInterval = null;
|
|
107
107
|
}
|
|
108
108
|
export function createTui(cfg = {}) {
|
|
109
|
-
config = { title: "Veryfront", showLogs: true, ...cfg };
|
|
109
|
+
config = { title: "Veryfront Code", showLogs: true, ...cfg };
|
|
110
110
|
state = {
|
|
111
111
|
status: "Initializing...",
|
|
112
112
|
statusType: "loading",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/loader.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAsCpC,OAAO,KAAK,EAAoB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAgC3E;;;;;GAKG;AACH,qBAAa,eAAe;IAId,OAAO,CAAC,OAAO;IAH3B,OAAO,CAAC,EAAE,CAAsB;IAChC,OAAO,CAAC,mBAAmB,CAAuB;gBAE9B,OAAO,EAAE,sBAAsB;IAEnD;;OAEG;IACH,UAAU,CACR,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/loader.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAsCpC,OAAO,KAAK,EAAoB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAgC3E;;;;;GAKG;AACH,qBAAa,eAAe;IAId,OAAO,CAAC,OAAO;IAH3B,OAAO,CAAC,EAAE,CAAsB;IAChC,OAAO,CAAC,mBAAmB,CAAuB;gBAE9B,OAAO,EAAE,sBAAsB;IAEnD;;OAEG;IACH,UAAU,CACR,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAsGxD,OAAO,CAAC,mBAAmB;IAiC3B,OAAO,CAAC,wBAAwB;IAwBhC,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,yBAAyB;IAuBjC,OAAO,CAAC,kBAAkB;IAK1B;;OAEG;YACW,2BAA2B;IAkGzC,OAAO,CAAC,yBAAyB;YAiBnB,2BAA2B;IA6RzC;;;OAGG;YACW,mBAAmB;IA2CjC,OAAO,CAAC,yBAAyB;IAYjC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA4B3B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAuB3B,OAAO,CAAC,wBAAwB;IAehC,OAAO,CAAC,2BAA2B;IAiBnC,OAAO,CAAC,2BAA2B;IAWnC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4B3B;;OAEG;IACH,OAAO,CAAC,aAAa;YAIP,uBAAuB;IAyCrC;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAUhB;;;OAGG;YACW,gBAAgB;YAgBhB,WAAW;YAeX,YAAY;CAiC3B"}
|
|
@@ -97,18 +97,31 @@ export class SSRModuleLoader {
|
|
|
97
97
|
const bundleMatch = errorMsg.match(/veryfront-http-bundle\/http-([a-f0-9]+)\.mjs/);
|
|
98
98
|
if (bundleMatch) {
|
|
99
99
|
const hash = bundleMatch[1];
|
|
100
|
-
|
|
100
|
+
const cacheDir = getHttpBundleCacheDir();
|
|
101
|
+
logger.error("[SSR-MODULE-LOADER] Missing HTTP bundle after ensureHttpBundlesExist", {
|
|
101
102
|
file: filePath.slice(-40),
|
|
102
103
|
hash,
|
|
104
|
+
tempPath: cacheEntry.tempPath,
|
|
105
|
+
contentHash: cacheEntry.contentHash,
|
|
106
|
+
cacheDir,
|
|
107
|
+
expectedPath: `${cacheDir}/http-${hash}.mjs`,
|
|
103
108
|
});
|
|
104
109
|
const { recoverHttpBundleByHash } = await import("../../../transforms/esm/http-cache.js");
|
|
105
|
-
const cacheDir = getHttpBundleCacheDir();
|
|
106
110
|
const recovered = await recoverHttpBundleByHash(hash, cacheDir);
|
|
107
111
|
if (recovered) {
|
|
108
|
-
logger.info("[SSR-MODULE-LOADER] HTTP bundle recovered, retrying import", {
|
|
112
|
+
logger.info("[SSR-MODULE-LOADER] HTTP bundle recovered, retrying import", {
|
|
113
|
+
hash,
|
|
114
|
+
file: filePath.slice(-40),
|
|
115
|
+
});
|
|
109
116
|
mod = await import(`file://${cacheEntry.tempPath}?v=${cacheEntry.contentHash}&retry=1`);
|
|
110
117
|
}
|
|
111
118
|
else {
|
|
119
|
+
logger.error("[SSR-MODULE-LOADER] HTTP bundle recovery failed", {
|
|
120
|
+
hash,
|
|
121
|
+
file: filePath.slice(-40),
|
|
122
|
+
cacheDir,
|
|
123
|
+
hint: "Bundle may have expired from Redis (24h TTL) while transform was still cached",
|
|
124
|
+
});
|
|
112
125
|
throw importError;
|
|
113
126
|
}
|
|
114
127
|
}
|
|
@@ -313,9 +326,12 @@ export class SSRModuleLoader {
|
|
|
313
326
|
const cacheDir = getHttpBundleCacheDir();
|
|
314
327
|
const failed = await ensureHttpBundlesExist(bundlePaths, cacheDir);
|
|
315
328
|
if (failed.length > 0) {
|
|
316
|
-
logger.warn("[SSR-MODULE-LOADER]
|
|
329
|
+
logger.warn("[SSR-MODULE-LOADER] Unrecoverable HTTP bundles, re-transforming", {
|
|
317
330
|
file: filePath.slice(-40),
|
|
318
331
|
failed,
|
|
332
|
+
totalBundles: bundlePaths.length,
|
|
333
|
+
cacheDir,
|
|
334
|
+
source: "memory-cache",
|
|
319
335
|
});
|
|
320
336
|
globalModuleCache.delete(contentCacheKey);
|
|
321
337
|
globalModuleCache.delete(filePathCacheKey);
|
|
@@ -354,9 +370,12 @@ export class SSRModuleLoader {
|
|
|
354
370
|
const cacheDir = getHttpBundleCacheDir();
|
|
355
371
|
const failed = await ensureHttpBundlesExist(bundlePaths, cacheDir);
|
|
356
372
|
if (failed.length > 0) {
|
|
357
|
-
logger.warn("[SSR-MODULE-LOADER]
|
|
373
|
+
logger.warn("[SSR-MODULE-LOADER] Unrecoverable HTTP bundles, re-transforming", {
|
|
358
374
|
file: filePath.slice(-40),
|
|
359
375
|
failed,
|
|
376
|
+
totalBundles: bundlePaths.length,
|
|
377
|
+
cacheDir,
|
|
378
|
+
source: "redis-cache",
|
|
360
379
|
});
|
|
361
380
|
httpBundlesOk = false;
|
|
362
381
|
}
|
|
@@ -454,9 +473,12 @@ export class SSRModuleLoader {
|
|
|
454
473
|
const cacheDir = getHttpBundleCacheDir();
|
|
455
474
|
const failed = await ensureHttpBundlesExist(bundlePaths, cacheDir);
|
|
456
475
|
if (failed.length > 0) {
|
|
457
|
-
logger.warn("[SSR-MODULE-LOADER]
|
|
476
|
+
logger.warn("[SSR-MODULE-LOADER] Unrecoverable HTTP bundles", {
|
|
458
477
|
file: filePath.slice(-40),
|
|
459
478
|
failed,
|
|
479
|
+
totalBundles: bundlePaths.length,
|
|
480
|
+
cacheDir,
|
|
481
|
+
source: "fresh-transform",
|
|
460
482
|
});
|
|
461
483
|
}
|
|
462
484
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-cache.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/http-cache.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"http-cache.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/http-cache.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAgBzE,KAAK,YAAY,GAAG;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,eAAe,CAAC;IAC3B,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAqVF;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOvF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA8D9F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAClD,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,EAAE,CAAC,CAiInB"}
|
|
@@ -23,10 +23,13 @@ import { CacheBackends, createDistributedCacheAccessor } from "../../cache/backe
|
|
|
23
23
|
import { HTTP_MODULE_CACHE_MAX_ENTRIES, HTTP_MODULE_DISTRIBUTED_TTL_SEC, } from "../../utils/constants/cache.js";
|
|
24
24
|
/** Lazy-loaded distributed cache backend for cross-pod sharing */
|
|
25
25
|
const getDistributedCache = createDistributedCacheAccessor(() => CacheBackends.httpModule(), "HTTP-CACHE");
|
|
26
|
-
/** TTL for cached modules in distributed cache (uses centralized config) */
|
|
27
|
-
const DISTRIBUTED_CACHE_TTL_SECONDS = HTTP_MODULE_DISTRIBUTED_TTL_SEC;
|
|
28
26
|
const cachedPaths = new LRUCache({ maxEntries: HTTP_MODULE_CACHE_MAX_ENTRIES });
|
|
29
27
|
const processingStack = new Set();
|
|
28
|
+
/** Tracks last TTL refresh per hash. Refresh every 4h to keep 20h+ remaining (24h total). */
|
|
29
|
+
const lastDistributedRefresh = new LRUCache({
|
|
30
|
+
maxEntries: HTTP_MODULE_CACHE_MAX_ENTRIES,
|
|
31
|
+
});
|
|
32
|
+
const DISTRIBUTED_REFRESH_INTERVAL_MS = 4 * 60 * 60 * 1000;
|
|
30
33
|
function ensureAbsoluteDir(path) {
|
|
31
34
|
return isAbsolute(path) ? path : join(cwd(), path);
|
|
32
35
|
}
|
|
@@ -151,23 +154,28 @@ async function cacheHttpModule(url, options) {
|
|
|
151
154
|
const fs = createFileSystem();
|
|
152
155
|
if (await exists(cachePath)) {
|
|
153
156
|
cachedPaths.set(cacheKey, cachePath);
|
|
154
|
-
//
|
|
155
|
-
//
|
|
156
|
-
// Synchronous to guarantee data is stored before other pods need it
|
|
157
|
+
// Refresh distributed cache TTL so bundles outlive transforms that reference them.
|
|
158
|
+
// Without this, bundles expire (24h) while SSR transforms (6h) are still valid.
|
|
157
159
|
const distributed = await getDistributedCache();
|
|
158
160
|
if (distributed) {
|
|
159
161
|
const hash = simpleHash(normalizedUrl);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
162
|
+
const hashStr = String(hash);
|
|
163
|
+
const now = Date.now();
|
|
164
|
+
const lastRefresh = lastDistributedRefresh.get(hashStr);
|
|
165
|
+
const needsRefresh = !lastRefresh || (now - lastRefresh > DISTRIBUTED_REFRESH_INTERVAL_MS);
|
|
166
|
+
if (needsRefresh) {
|
|
167
|
+
try {
|
|
163
168
|
const code = await fs.readTextFile(cachePath);
|
|
164
|
-
await
|
|
165
|
-
|
|
169
|
+
await Promise.all([
|
|
170
|
+
distributed.set(`code:${hash}`, code, HTTP_MODULE_DISTRIBUTED_TTL_SEC),
|
|
171
|
+
distributed.set(`hash:${hash}`, normalizedUrl, HTTP_MODULE_DISTRIBUTED_TTL_SEC),
|
|
172
|
+
]);
|
|
173
|
+
lastDistributedRefresh.set(hashStr, now);
|
|
174
|
+
logger.debug("[HTTP-CACHE] Refreshed distributed cache TTL", { hash });
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
logger.debug("[HTTP-CACHE] Distributed cache refresh failed", { hash, error });
|
|
166
178
|
}
|
|
167
|
-
}
|
|
168
|
-
catch (error) {
|
|
169
|
-
// Log but don't fail - backfill is best-effort
|
|
170
|
-
logger.debug("[HTTP-CACHE] Backfill failed, continuing", { hash, error });
|
|
171
179
|
}
|
|
172
180
|
}
|
|
173
181
|
return cachePath;
|
|
@@ -232,9 +240,9 @@ async function cacheHttpModule(url, options) {
|
|
|
232
240
|
const hash = simpleHash(normalizedUrl);
|
|
233
241
|
try {
|
|
234
242
|
await Promise.all([
|
|
235
|
-
distributed.set(normalizedUrl, code,
|
|
236
|
-
distributed.set(`code:${hash}`, code,
|
|
237
|
-
distributed.set(`hash:${hash}`, normalizedUrl,
|
|
243
|
+
distributed.set(normalizedUrl, code, HTTP_MODULE_DISTRIBUTED_TTL_SEC),
|
|
244
|
+
distributed.set(`code:${hash}`, code, HTTP_MODULE_DISTRIBUTED_TTL_SEC),
|
|
245
|
+
distributed.set(`hash:${hash}`, normalizedUrl, HTTP_MODULE_DISTRIBUTED_TTL_SEC),
|
|
238
246
|
]);
|
|
239
247
|
}
|
|
240
248
|
catch (error) {
|
package/package.json
CHANGED
package/src/deno.js
CHANGED
|
@@ -196,8 +196,8 @@ export function renderList<T>(
|
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
if (start > 0) lines.unshift(` ${dim("
|
|
200
|
-
if (end < state.items.length) lines.push(` ${dim("
|
|
199
|
+
if (start > 0) lines.unshift(` ${dim("↑")} ${dim("more above")}`);
|
|
200
|
+
if (end < state.items.length) lines.push(` ${dim("↓")} ${dim("more below")}`);
|
|
201
201
|
|
|
202
202
|
return lines.join("\n");
|
|
203
203
|
}
|
package/src/src/cli/app/index.ts
CHANGED
|
@@ -19,9 +19,16 @@ import { join } from "../../platform/compat/path/index.js";
|
|
|
19
19
|
import { getRuntimeEnv } from "../../config/runtime-env.js";
|
|
20
20
|
import { getStdinReader, setRawMode } from "../../platform/compat/stdin.js";
|
|
21
21
|
import { cursor, screen, SPINNER_FRAMES } from "../ui/ansi.js";
|
|
22
|
-
import { brand, dim
|
|
22
|
+
import { brand, dim } from "../ui/colors.js";
|
|
23
|
+
import { getTerminalWidth } from "../ui/layout.js";
|
|
23
24
|
import { moveDown, moveUp, selectByNumber } from "./components/list-select.js";
|
|
24
25
|
import { renderDashboard, renderEmptyState } from "./views/dashboard.js";
|
|
26
|
+
import {
|
|
27
|
+
createStartupState,
|
|
28
|
+
incrementFrame,
|
|
29
|
+
renderStartup,
|
|
30
|
+
setStepActive,
|
|
31
|
+
} from "./views/startup.js";
|
|
25
32
|
import { openInBrowser, openInIDE, openInStudio, openMCPSettings } from "./actions.js";
|
|
26
33
|
import { initCommand } from "../commands/init/init-command.js";
|
|
27
34
|
import type { InitTemplate } from "../commands/init/types.js";
|
|
@@ -42,6 +49,7 @@ import {
|
|
|
42
49
|
setTemplates,
|
|
43
50
|
startInput,
|
|
44
51
|
type StateUpdater,
|
|
52
|
+
toggleHelp,
|
|
45
53
|
toggleLogsExpanded,
|
|
46
54
|
updateActiveList,
|
|
47
55
|
updateInputValue,
|
|
@@ -545,10 +553,13 @@ export function createApp(config: AppConfig): App {
|
|
|
545
553
|
|
|
546
554
|
const parts: string[] = [content];
|
|
547
555
|
|
|
556
|
+
// Divider width matches the box in dashboard
|
|
557
|
+
const dividerWidth = Math.min(getTerminalWidth() - 4, 80);
|
|
558
|
+
|
|
548
559
|
if (state.logs.length > 0) {
|
|
549
560
|
const logsHeader = state.logsExpanded ? "▼ Logs" : "▶ Logs";
|
|
550
561
|
parts.push("");
|
|
551
|
-
parts.push(
|
|
562
|
+
parts.push(dim("─".repeat(dividerWidth)));
|
|
552
563
|
parts.push(
|
|
553
564
|
` ${dim(logsHeader)} ${dim(`(${state.logs.length})`)} ${dim("l")} ${dim("toggle")} ${
|
|
554
565
|
state.logsExpanded ? `${dim("↑↓")} ${dim("scroll")}` : ""
|
|
@@ -563,14 +574,14 @@ export function createApp(config: AppConfig): App {
|
|
|
563
574
|
|
|
564
575
|
if (state.input.active) {
|
|
565
576
|
parts.push("");
|
|
566
|
-
parts.push(
|
|
577
|
+
parts.push(dim("─".repeat(dividerWidth)));
|
|
567
578
|
parts.push(renderInput(state.input));
|
|
568
579
|
}
|
|
569
580
|
|
|
570
581
|
if (!isInteractiveMode) return;
|
|
571
582
|
|
|
572
583
|
write(cursor.moveTo(1, 1) + screen.clearDown);
|
|
573
|
-
write(parts.join("\n"));
|
|
584
|
+
write("\n" + parts.join("\n"));
|
|
574
585
|
}
|
|
575
586
|
|
|
576
587
|
function update(updater: StateUpdater): void {
|
|
@@ -933,7 +944,7 @@ export function createApp(config: AppConfig): App {
|
|
|
933
944
|
}
|
|
934
945
|
|
|
935
946
|
if (key === "?") {
|
|
936
|
-
update(
|
|
947
|
+
update(toggleHelp());
|
|
937
948
|
return;
|
|
938
949
|
}
|
|
939
950
|
|
|
@@ -1422,47 +1433,35 @@ export function createApp(config: AppConfig): App {
|
|
|
1422
1433
|
}
|
|
1423
1434
|
|
|
1424
1435
|
/**
|
|
1425
|
-
* Show startup animation
|
|
1436
|
+
* Show startup animation with boxed view and shimmer effect
|
|
1426
1437
|
*/
|
|
1427
1438
|
export async function showStartup(steps: string[]): Promise<void> {
|
|
1428
1439
|
const write = (text: string): void => writeStdout(text);
|
|
1429
1440
|
|
|
1430
1441
|
write(screen.altOn + cursor.hide);
|
|
1431
1442
|
|
|
1432
|
-
|
|
1433
|
-
const step = steps[i]!;
|
|
1434
|
-
const completed = steps.slice(0, i).map((s) => ` ${success("✓")} ${dim(s)}`);
|
|
1435
|
-
const current = ` ${brand("●")} ${step}`;
|
|
1436
|
-
const pending = steps.slice(i + 1).map((s) => ` ${dim("○")} ${dim(s)}`);
|
|
1437
|
-
|
|
1438
|
-
const content = [
|
|
1439
|
-
"",
|
|
1440
|
-
` ${brand("Veryfront")} ${dim("starting...")}`,
|
|
1441
|
-
"",
|
|
1442
|
-
...completed,
|
|
1443
|
-
current,
|
|
1444
|
-
...pending,
|
|
1445
|
-
"",
|
|
1446
|
-
].join("\n");
|
|
1443
|
+
let startupState = createStartupState(steps);
|
|
1447
1444
|
|
|
1448
|
-
|
|
1449
|
-
|
|
1445
|
+
// Show each step with spinning avatar animation
|
|
1446
|
+
for (let i = 0; i < steps.length; i++) {
|
|
1447
|
+
startupState = setStepActive(startupState, i);
|
|
1448
|
+
|
|
1449
|
+
// Animate spinning avatar (16 frames at 60ms = ~1s per step for full rotation)
|
|
1450
|
+
const framesPerStep = 16;
|
|
1451
|
+
for (let f = 0; f < framesPerStep; f++) {
|
|
1452
|
+
write(cursor.moveTo(1, 1) + screen.clearDown + "\n" + renderStartup(startupState));
|
|
1453
|
+
startupState = incrementFrame(startupState);
|
|
1454
|
+
await new Promise((r) => dntShim.setTimeout(r, 60));
|
|
1455
|
+
}
|
|
1450
1456
|
}
|
|
1451
1457
|
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
"",
|
|
1457
|
-
...allComplete,
|
|
1458
|
-
"",
|
|
1459
|
-
].join("\n");
|
|
1460
|
-
|
|
1461
|
-
write(cursor.moveTo(1, 1) + screen.clearDown + finalContent);
|
|
1462
|
-
await new Promise((r) => dntShim.setTimeout(r, 300));
|
|
1458
|
+
// Mark all steps done - logo fills up and holds before transitioning
|
|
1459
|
+
startupState = setStepActive(startupState, steps.length);
|
|
1460
|
+
write(cursor.moveTo(1, 1) + screen.clearDown + "\n" + renderStartup(startupState));
|
|
1461
|
+
await new Promise((r) => dntShim.setTimeout(r, 400));
|
|
1463
1462
|
|
|
1464
1463
|
// Don't exit alternate screen - let app.start() continue in it
|
|
1465
|
-
//
|
|
1464
|
+
// Dashboard takes over directly from here
|
|
1466
1465
|
}
|
|
1467
1466
|
|
|
1468
1467
|
export type { AppState } from "./state.js";
|
package/src/src/cli/app/state.ts
CHANGED
|
@@ -103,6 +103,8 @@ export interface AppState {
|
|
|
103
103
|
authProviderIndex: number;
|
|
104
104
|
/** New project option index (0=template, 1=example, 2=scratch) */
|
|
105
105
|
newProjectIndex: number;
|
|
106
|
+
/** Show expanded help */
|
|
107
|
+
showHelp: boolean;
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
export function createInitialState(): AppState {
|
|
@@ -153,6 +155,7 @@ export function createInitialState(): AppState {
|
|
|
153
155
|
logScroll: 0,
|
|
154
156
|
authProviderIndex: 0,
|
|
155
157
|
newProjectIndex: 0,
|
|
158
|
+
showHelp: false,
|
|
156
159
|
};
|
|
157
160
|
}
|
|
158
161
|
|
|
@@ -339,6 +342,10 @@ export function toggleLogsExpanded(): StateUpdater {
|
|
|
339
342
|
});
|
|
340
343
|
}
|
|
341
344
|
|
|
345
|
+
export function toggleHelp(): StateUpdater {
|
|
346
|
+
return (state) => ({ ...state, showHelp: !state.showHelp });
|
|
347
|
+
}
|
|
348
|
+
|
|
342
349
|
export function scrollLogs(direction: "up" | "down"): StateUpdater {
|
|
343
350
|
return (state) => {
|
|
344
351
|
if (!state.logsExpanded) return state;
|