Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.

Commit 4cbc64e

Browse files
staticoclaude
andcommitted
Capitalize roles with colors, add log rotation
- Role names now uppercase (CLIENT, ROUTER, TRACKER, etc.) - Roles colored by type: Client=green, Router/Repeater=purple, Tracker=cyan, Sensor/TAK=orange, Mute/Hidden=gray - Error log auto-truncates to last 1MB at startup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4009773 commit 4cbc64e

3 files changed

Lines changed: 53 additions & 19 deletions

File tree

src/index.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from "react";
22
import { render } from "ink";
3-
import { appendFileSync, mkdirSync, existsSync } from "fs";
3+
import { appendFileSync, mkdirSync, existsSync, statSync, readFileSync, writeFileSync } from "fs";
44
import { join } from "path";
55
import { homedir } from "os";
66
import { PacketStore, NodeStore } from "./protocol";
@@ -11,6 +11,24 @@ import { getSetting, DEFAULT_MESHVIEW_URL } from "./settings";
1111
// Global error handler - append errors to log file
1212
const ERROR_LOG_DIR = join(homedir(), ".config", "meshtastic-cli");
1313
const ERROR_LOG_PATH = join(ERROR_LOG_DIR, "error.log");
14+
const MAX_LOG_SIZE = 1024 * 1024; // 1 MB
15+
16+
// Truncate log file if it exceeds max size
17+
function truncateLogIfNeeded() {
18+
try {
19+
if (!existsSync(ERROR_LOG_PATH)) return;
20+
const stats = statSync(ERROR_LOG_PATH);
21+
if (stats.size > MAX_LOG_SIZE) {
22+
const content = readFileSync(ERROR_LOG_PATH, "utf-8");
23+
const truncated = content.slice(-MAX_LOG_SIZE);
24+
// Find first complete entry (starts with newline + timestamp)
25+
const firstEntry = truncated.indexOf("\n[");
26+
writeFileSync(ERROR_LOG_PATH, firstEntry > 0 ? truncated.slice(firstEntry) : truncated);
27+
}
28+
} catch {
29+
// Ignore truncation errors
30+
}
31+
}
1432

1533
function logError(type: string, error: Error | unknown) {
1634
try {
@@ -28,6 +46,9 @@ function logError(type: string, error: Error | unknown) {
2846
}
2947
}
3048

49+
// Check log size at startup
50+
truncateLogIfNeeded();
51+
3152
process.on("uncaughtException", (error) => {
3253
logError("UNCAUGHT EXCEPTION", error);
3354
console.error("Fatal error:", error.message);

src/ui/components/DMPanel.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,15 +281,24 @@ function MessageRow({ message, nodeStore, isOwn, isSelected, textWidth }: Messag
281281

282282
// Role name mappings
283283
const ROLE_NAMES: Record<number, string> = {
284-
0: "Client", 1: "Mute", 2: "Router", 3: "RtrClnt", 4: "Repeater",
285-
5: "Tracker", 6: "Sensor", 7: "TAK", 8: "Hidden", 9: "L&F", 10: "TAK+Trk",
284+
0: "CLIENT", 1: "MUTE", 2: "ROUTER", 3: "RTR_CLI", 4: "REPEAT",
285+
5: "TRACKER", 6: "SENSOR", 7: "TAK", 8: "HIDDEN", 9: "L&F", 10: "TAK_TRK",
286286
};
287287

288288
function formatRole(role?: number | null): string {
289289
if (role == null) return "-";
290290
return ROLE_NAMES[role] || `R${role}`;
291291
}
292292

293+
function getRoleColor(role?: number | null): string {
294+
if (role == null) return theme.fg.muted;
295+
if (role === 2 || role === 4) return theme.packet.nodeinfo; // Router/Repeater = purple
296+
if (role === 5) return theme.packet.position; // Tracker = cyan
297+
if (role === 6 || role === 7 || role === 10) return theme.packet.telemetry; // Sensor/TAK = orange
298+
if (role === 1 || role === 8) return theme.packet.routing; // Mute/Hidden = gray
299+
return theme.packet.message; // Client = green
300+
}
301+
293302
function formatLastHeard(timestamp?: number): string {
294303
if (!timestamp) return "never";
295304
const now = Date.now() / 1000;
@@ -349,7 +358,7 @@ function NodeInfoHeader({ nodeNum, nodeStore, deleteConfirm }: NodeInfoHeaderPro
349358
<Box paddingX={1}>
350359
{/* Line 2: Role, last heard, hops, hardware */}
351360
<Text color={theme.fg.muted}>Role:</Text>
352-
<Text color={theme.fg.secondary}>{role}</Text>
361+
<Text color={getRoleColor(node?.role)}>{role}</Text>
353362
<Text color={theme.fg.muted}> Heard:</Text>
354363
<Text color={theme.fg.secondary}>{lastHeard}</Text>
355364
<Text color={theme.fg.muted}> Hops:</Text>

src/ui/components/NodesPanel.tsx

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -392,17 +392,17 @@ function getBatteryColor(level?: number, voltage?: number): string {
392392
}
393393

394394
const ROLE_NAMES: Record<number, string> = {
395-
0: "Client",
396-
1: "Mute",
397-
2: "Router",
398-
3: "RtrClnt",
399-
4: "Repeater",
400-
5: "Tracker",
401-
6: "Sensor",
395+
0: "CLIENT",
396+
1: "MUTE",
397+
2: "ROUTER",
398+
3: "RTR_CLI",
399+
4: "REPEAT",
400+
5: "TRACKER",
401+
6: "SENSOR",
402402
7: "TAK",
403-
8: "Hidden",
403+
8: "HIDDEN",
404404
9: "L&F",
405-
10: "TAK+Trk",
405+
10: "TAK_TRK",
406406
};
407407

408408
function formatRole(role?: number | null): string {
@@ -412,12 +412,16 @@ function formatRole(role?: number | null): string {
412412

413413
function getRoleColor(role?: number | null): string {
414414
if (role == null) return theme.fg.muted;
415-
// Router/Repeater = infrastructure = purple
415+
// Router/Repeater = infrastructure = purple (like nodeinfo)
416416
if (role === 2 || role === 4) return theme.packet.nodeinfo;
417-
// Tracker/Sensor = cyan
418-
if (role === 5 || role === 6) return theme.packet.position;
419-
// TAK = orange
417+
// Tracker = cyan (like position)
418+
if (role === 5) return theme.packet.position;
419+
// Sensor = orange (like telemetry)
420+
if (role === 6) return theme.packet.telemetry;
421+
// TAK variants = orange
420422
if (role === 7 || role === 10) return theme.packet.telemetry;
421-
// Client (default) = normal
422-
return theme.fg.secondary;
423+
// Mute/Hidden = gray (like routing)
424+
if (role === 1 || role === 8) return theme.packet.routing;
425+
// Client (default) = green (like message)
426+
return theme.packet.message;
423427
}

0 commit comments

Comments
 (0)