feat(FN-2729): merge fusion/fn-2729

- fix(FN-2729): silence ansi strip lint warning
- test(FN-2729): complete Step 10 — cover node health indicators
- feat(FN-2729): complete Step 9 — colorize CLI node status output
- feat(FN-2729): complete Step 8 — use NodeHealthDot in settings routing status
- test(FN-2729): align ListView node override option expectations
- feat(FN-2729): complete Step 7 — add bulk node status indicators
- fix(engine): prevent auto-merge cooldown loop on unresolvable conflicts
- feat(FN-2911): improve chat attachment compose and preview UX
- feat(FN-2921): merge fusion/fn-2921
- feat(FN-2909): merge fusion/fn-2909
- feat(FN-2914): merge fusion/fn-2914
- feat(FN-2902): merge fusion/fn-2902
- chore(release): v0.8.3
- Update changeset
- fix(tui): swap 3/4 panel hotkeys so they match the help text
- fix(tui): always show auth token and report accurate macOS memory usage

Fusion-Task-Id: FN-2729
This commit is contained in:
Fusion
2026-04-28 23:21:27 -07:00
committed by gsxdsm
parent 15e4cba5e9
commit 19d787d74d
18 changed files with 253 additions and 221 deletions

View File

@@ -1,6 +1,12 @@
import { CentralCore, type NodeConfig } from "@fusion/core";
import { createInterface } from "node:readline/promises";
const GREEN = "\x1b[32m";
const RED = "\x1b[31m";
const YELLOW = "\x1b[33m";
const GRAY = "\x1b[90m";
const RESET = "\x1b[0m";
// ── Options Interfaces ───────────────────────────────────────────────────────
/** Options for node list command. */
@@ -133,19 +139,51 @@ export function formatLastActivity(timestamp?: string | null): string {
*/
function getStatusIndicator(status: string): string {
switch (status) {
case "online": return "●";
case "offline": return "○";
case "error": return "✕";
case "connecting": return "◐";
default: return "○";
case "online":
return `${GREEN}${RESET}`;
case "offline":
return `${RED}${RESET}`;
case "error":
return `${RED}${RESET}`;
case "connecting":
return `${YELLOW}${RESET}`;
default:
return `${GRAY}${RESET}`;
}
}
function colorizeStatusText(status: string): string {
switch (status) {
case "online":
return `${GREEN}${status}${RESET}`;
case "offline":
case "error":
return `${RED}${status}${RESET}`;
case "connecting":
return `${YELLOW}${status}${RESET}`;
default:
return `${GRAY}${status}${RESET}`;
}
}
// eslint-disable-next-line no-control-regex
const ANSI_ESCAPE_PATTERN = new RegExp("\\u001b\\[[0-9;]*m", "g");
function stripAnsi(text: string): string {
return text.replace(ANSI_ESCAPE_PATTERN, "");
}
function visualPadEnd(text: string, minWidth: number): string {
const visibleLength = stripAnsi(text).length;
if (visibleLength >= minWidth) return text;
return `${text}${" ".repeat(minWidth - visibleLength)}`;
}
/**
* Get color-coded status string.
*/
function formatStatus(status: string): string {
return `${getStatusIndicator(status)} ${status}`;
return `${getStatusIndicator(status)} ${colorizeStatusText(status)}`;
}
// ── Core Command Functions ──────────────────────────────────────────────────
@@ -201,7 +239,7 @@ export async function runNodeList(options: NodeListOptions = {}): Promise<void>
for (const node of sorted) {
const name = node.name.padEnd(16);
const type = node.type.padEnd(8);
const statusStr = formatStatus(node.status).padEnd(12);
const statusStr = visualPadEnd(formatStatus(node.status), 12);
const max = String(node.maxConcurrent).padStart(3);
if (hasMetrics && node.systemMetrics) {
@@ -527,7 +565,7 @@ export async function runMeshStatus(options: MeshStatusOptions = {}): Promise<vo
for (const node of sorted) {
const name = node.name.padEnd(16);
const type = node.type.padEnd(8);
const statusStr = formatStatus(node.status).padEnd(12);
const statusStr = visualPadEnd(formatStatus(node.status), 12);
const url = node.type === "remote" ? (node.url ?? "-") : "(local)";
console.log(` ${name} ${type} ${statusStr} ${url}`);
}