valheim-oz-dsm 1.6.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -10,10 +10,20 @@ var __export = (target, all) => {
10
10
  };
11
11
 
12
12
  // src/rcon/types.ts
13
- var RconError;
13
+ var PacketType, RconError, ValheimCommands, ValheimEvents, ValheimGlobalKeys;
14
14
  var init_types = __esm({
15
15
  "src/rcon/types.ts"() {
16
16
  "use strict";
17
+ PacketType = {
18
+ /** Authentication request */
19
+ SERVERDATA_AUTH: 3,
20
+ /** Authentication response */
21
+ SERVERDATA_AUTH_RESPONSE: 2,
22
+ /** Execute command */
23
+ SERVERDATA_EXECCOMMAND: 2,
24
+ /** Command response */
25
+ SERVERDATA_RESPONSE_VALUE: 0
26
+ };
17
27
  RconError = class extends Error {
18
28
  constructor(code, message) {
19
29
  super(message);
@@ -21,6 +31,81 @@ var init_types = __esm({
21
31
  this.name = "RconError";
22
32
  }
23
33
  };
34
+ ValheimCommands = {
35
+ // Server Management
36
+ /** Force save world */
37
+ SAVE: "save",
38
+ /** Get server info */
39
+ INFO: "info",
40
+ /** Ping server */
41
+ PING: "ping",
42
+ // Player Management
43
+ /** Kick player */
44
+ kick: (player) => `kick ${player}`,
45
+ /** Ban player */
46
+ ban: (player) => `ban ${player}`,
47
+ /** Unban player */
48
+ unban: (player) => `unban ${player}`,
49
+ /** List banned players */
50
+ BANNED: "banned",
51
+ /** List permitted players */
52
+ PERMITTED: "permitted",
53
+ // Time Control
54
+ /** Sleep through night (skip to morning) */
55
+ SLEEP: "sleep",
56
+ /** Skip time by seconds */
57
+ skiptime: (seconds) => `skiptime ${seconds}`,
58
+ // Events
59
+ /** Trigger specific event */
60
+ event: (eventName) => `event ${eventName}`,
61
+ /** Trigger random event */
62
+ RANDOMEVENT: "randomevent",
63
+ /** Stop current event */
64
+ STOPEVENT: "stopevent",
65
+ // World Management
66
+ /** Remove all dropped items */
67
+ REMOVEDROPS: "removedrops",
68
+ /** Set a global key */
69
+ setkey: (key) => `setkey ${key}`,
70
+ /** Remove a global key */
71
+ removekey: (key) => `removekey ${key}`,
72
+ /** Reset all global keys */
73
+ RESETKEYS: "resetkeys",
74
+ /** List all global keys */
75
+ LISTKEYS: "listkeys",
76
+ // Performance
77
+ /** Set LOD bias (0-5, lower = better performance) */
78
+ lodbias: (value) => `lodbias ${value}`,
79
+ /** Set LOD distance (100-6000) */
80
+ loddist: (value) => `loddist ${value}`
81
+ };
82
+ ValheimEvents = {
83
+ ARMY_EIKTHYR: "army_eikthyr",
84
+ ARMY_THEELDER: "army_theelder",
85
+ ARMY_BONEMASS: "army_bonemass",
86
+ ARMY_MODER: "army_moder",
87
+ ARMY_GOBLIN: "army_goblin",
88
+ FORESTTROLLS: "foresttrolls",
89
+ SKELETONS: "skeletons",
90
+ BLOBS: "blobs",
91
+ WOLVES: "wolves",
92
+ BATS: "bats",
93
+ SERPENTS: "serpents"
94
+ };
95
+ ValheimGlobalKeys = {
96
+ DEFEATED_EIKTHYR: "defeated_eikthyr",
97
+ DEFEATED_GDKING: "defeated_gdking",
98
+ // The Elder
99
+ DEFEATED_BONEMASS: "defeated_bonemass",
100
+ DEFEATED_DRAGON: "defeated_dragon",
101
+ // Moder
102
+ DEFEATED_GOBLINKING: "defeated_goblinking",
103
+ // Yagluth
104
+ DEFEATED_QUEEN: "defeated_queen",
105
+ KILLED_TROLL: "KilledTroll",
106
+ KILLED_BAT: "KilledBat",
107
+ KILLED_SURTLING: "KilledSurtling"
108
+ };
24
109
  }
25
110
  });
26
111
 
@@ -373,6 +458,415 @@ var init_client = __esm({
373
458
  }
374
459
  });
375
460
 
461
+ // src/rcon/manager.ts
462
+ var RconManager, rconManager;
463
+ var init_manager = __esm({
464
+ "src/rcon/manager.ts"() {
465
+ "use strict";
466
+ init_client();
467
+ RconManager = class {
468
+ client = null;
469
+ config = null;
470
+ state = "disconnected";
471
+ reconnectTimer = null;
472
+ pollTimer = null;
473
+ reconnectAttempts = 0;
474
+ maxReconnectAttempts = 10;
475
+ reconnectDelay = 5e3;
476
+ // 5 seconds
477
+ pollInterval = 1e4;
478
+ // 10 seconds
479
+ onConnectionStateChange = null;
480
+ onPlayerListUpdate = null;
481
+ lastKnownPlayers = [];
482
+ enabled = false;
483
+ /**
484
+ * Initialize the RCON manager
485
+ * @param config RCON configuration
486
+ * @param options Optional callbacks and settings
487
+ */
488
+ initialize(config, options = {}) {
489
+ this.config = config;
490
+ this.enabled = config.enabled;
491
+ this.onConnectionStateChange = options.onConnectionStateChange ?? null;
492
+ this.onPlayerListUpdate = options.onPlayerListUpdate ?? null;
493
+ if (options.pollInterval) {
494
+ this.pollInterval = options.pollInterval;
495
+ }
496
+ if (this.enabled) {
497
+ this.connect();
498
+ }
499
+ }
500
+ /**
501
+ * Connect to RCON server
502
+ */
503
+ async connect() {
504
+ if (!this.config || !this.enabled) {
505
+ return false;
506
+ }
507
+ if (this.state === "connected" || this.state === "connecting") {
508
+ return true;
509
+ }
510
+ this.setState("connecting");
511
+ this.reconnectAttempts = 0;
512
+ try {
513
+ this.client = new RconClient({
514
+ host: "localhost",
515
+ port: this.config.port,
516
+ password: this.config.password,
517
+ timeout: this.config.timeout
518
+ });
519
+ await this.client.connect();
520
+ this.setState("connected");
521
+ this.reconnectAttempts = 0;
522
+ this.startPlayerListPolling();
523
+ return true;
524
+ } catch (_error) {
525
+ this.setState("error");
526
+ this.client = null;
527
+ if (this.config.autoReconnect && this.enabled) {
528
+ this.scheduleReconnect();
529
+ }
530
+ return false;
531
+ }
532
+ }
533
+ /**
534
+ * Disconnect from RCON server
535
+ */
536
+ disconnect() {
537
+ this.enabled = false;
538
+ this.clearTimers();
539
+ if (this.client) {
540
+ this.client.disconnect();
541
+ this.client = null;
542
+ }
543
+ this.setState("disconnected");
544
+ this.lastKnownPlayers = [];
545
+ }
546
+ /**
547
+ * Send a command to the RCON server
548
+ * @param command Command to send
549
+ * @returns Response from server, or null if not connected
550
+ */
551
+ async send(command) {
552
+ if (!this.client || this.state !== "connected") {
553
+ return null;
554
+ }
555
+ try {
556
+ const response = await this.client.send(command);
557
+ return response;
558
+ } catch (_error) {
559
+ this.setState("error");
560
+ if (this.config?.autoReconnect && this.enabled) {
561
+ this.scheduleReconnect();
562
+ }
563
+ return null;
564
+ }
565
+ }
566
+ /**
567
+ * Get the current player list from the server
568
+ * @returns Array of player names, or empty array if unavailable
569
+ */
570
+ async getPlayerList() {
571
+ const response = await this.send("status");
572
+ if (!response) {
573
+ return [];
574
+ }
575
+ const players = this.parsePlayerList(response);
576
+ return players;
577
+ }
578
+ /**
579
+ * Parse player names from status command response
580
+ * @param statusText Raw status response from server
581
+ * @returns Array of player names
582
+ */
583
+ parsePlayerList(statusText) {
584
+ const players = [];
585
+ const lines = statusText.split("\n");
586
+ for (const line of lines) {
587
+ if (line.includes("players:")) {
588
+ const match = line.match(/players:\s*(.+)/);
589
+ if (match?.[1]) {
590
+ const names = match[1].split(",").map((n) => n.trim()).filter((n) => n.length > 0);
591
+ players.push(...names);
592
+ }
593
+ }
594
+ }
595
+ return players;
596
+ }
597
+ /**
598
+ * Start polling for player list updates
599
+ */
600
+ startPlayerListPolling() {
601
+ this.stopPlayerListPolling();
602
+ this.pollTimer = setInterval(async () => {
603
+ if (this.state !== "connected") {
604
+ return;
605
+ }
606
+ const players = await this.getPlayerList();
607
+ if (this.hasPlayerListChanged(players)) {
608
+ this.lastKnownPlayers = players;
609
+ if (this.onPlayerListUpdate) {
610
+ this.onPlayerListUpdate(players);
611
+ }
612
+ }
613
+ }, this.pollInterval);
614
+ }
615
+ /**
616
+ * Stop polling for player list
617
+ */
618
+ stopPlayerListPolling() {
619
+ if (this.pollTimer) {
620
+ clearInterval(this.pollTimer);
621
+ this.pollTimer = null;
622
+ }
623
+ }
624
+ /**
625
+ * Check if player list has changed
626
+ */
627
+ hasPlayerListChanged(newPlayers) {
628
+ if (newPlayers.length !== this.lastKnownPlayers.length) {
629
+ return true;
630
+ }
631
+ const sorted1 = [...newPlayers].sort();
632
+ const sorted2 = [...this.lastKnownPlayers].sort();
633
+ return !sorted1.every((name, i) => name === sorted2[i]);
634
+ }
635
+ /**
636
+ * Schedule a reconnect attempt
637
+ */
638
+ scheduleReconnect() {
639
+ if (this.reconnectTimer) {
640
+ return;
641
+ }
642
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
643
+ return;
644
+ }
645
+ this.reconnectAttempts++;
646
+ const delay = this.reconnectDelay * this.reconnectAttempts;
647
+ this.reconnectTimer = setTimeout(async () => {
648
+ this.reconnectTimer = null;
649
+ await this.connect();
650
+ }, delay);
651
+ }
652
+ /**
653
+ * Update the connection state and notify listeners
654
+ */
655
+ setState(newState) {
656
+ if (this.state === newState) {
657
+ return;
658
+ }
659
+ this.state = newState;
660
+ if (this.onConnectionStateChange) {
661
+ this.onConnectionStateChange(newState);
662
+ }
663
+ }
664
+ /**
665
+ * Clear all timers
666
+ */
667
+ clearTimers() {
668
+ if (this.reconnectTimer) {
669
+ clearTimeout(this.reconnectTimer);
670
+ this.reconnectTimer = null;
671
+ }
672
+ this.stopPlayerListPolling();
673
+ }
674
+ /**
675
+ * Get the current connection state
676
+ */
677
+ getState() {
678
+ return this.state;
679
+ }
680
+ /**
681
+ * Check if RCON is connected
682
+ */
683
+ isConnected() {
684
+ return this.state === "connected";
685
+ }
686
+ /**
687
+ * Get the last known player list
688
+ */
689
+ getLastKnownPlayers() {
690
+ return [...this.lastKnownPlayers];
691
+ }
692
+ /**
693
+ * Kick a player from the server
694
+ * @param playerName Player name to kick
695
+ * @returns Response message
696
+ */
697
+ async kickPlayer(playerName) {
698
+ return this.send(`kick ${playerName}`);
699
+ }
700
+ /**
701
+ * Ban a player from the server
702
+ * @param playerName Player name to ban
703
+ * @returns Response message
704
+ */
705
+ async banPlayer(playerName) {
706
+ return this.send(`ban ${playerName}`);
707
+ }
708
+ /**
709
+ * Unban a player
710
+ * @param playerName Player name to unban
711
+ * @returns Response message
712
+ */
713
+ async unbanPlayer(playerName) {
714
+ return this.send(`unban ${playerName}`);
715
+ }
716
+ /**
717
+ * Get list of banned players
718
+ * @returns Array of banned player names/IDs
719
+ */
720
+ async getBannedPlayers() {
721
+ const response = await this.send("banned");
722
+ if (!response) return [];
723
+ return response.split("\n").filter((line) => line.trim().length > 0);
724
+ }
725
+ /**
726
+ * Get server information
727
+ * @returns Server info response
728
+ */
729
+ async getServerInfo() {
730
+ return this.send("info");
731
+ }
732
+ /**
733
+ * Ping the server
734
+ * @returns Ping response
735
+ */
736
+ async pingServer() {
737
+ return this.send("ping");
738
+ }
739
+ /**
740
+ * Trigger a random event
741
+ * @param eventName Event name (e.g., "army_eikthyr")
742
+ * @returns Response message
743
+ */
744
+ async triggerEvent(eventName) {
745
+ return this.send(`event ${eventName}`);
746
+ }
747
+ /**
748
+ * Trigger a random event
749
+ * @returns Response message
750
+ */
751
+ async triggerRandomEvent() {
752
+ return this.send("randomevent");
753
+ }
754
+ /**
755
+ * Stop the current event
756
+ * @returns Response message
757
+ */
758
+ async stopEvent() {
759
+ return this.send("stopevent");
760
+ }
761
+ /**
762
+ * Skip time by specified seconds
763
+ * @param seconds Number of seconds to skip
764
+ * @returns Response message
765
+ */
766
+ async skipTime(seconds) {
767
+ return this.send(`skiptime ${seconds}`);
768
+ }
769
+ /**
770
+ * Sleep through the night
771
+ * @returns Response message
772
+ */
773
+ async sleep() {
774
+ return this.send("sleep");
775
+ }
776
+ /**
777
+ * Remove all dropped items from the world
778
+ * @returns Response message
779
+ */
780
+ async removeDrops() {
781
+ return this.send("removedrops");
782
+ }
783
+ /**
784
+ * Set a global key
785
+ * @param key Global key name
786
+ * @returns Response message
787
+ */
788
+ async setGlobalKey(key) {
789
+ return this.send(`setkey ${key}`);
790
+ }
791
+ /**
792
+ * Remove a global key
793
+ * @param key Global key name
794
+ * @returns Response message
795
+ */
796
+ async removeGlobalKey(key) {
797
+ return this.send(`removekey ${key}`);
798
+ }
799
+ /**
800
+ * Reset all global keys
801
+ * @returns Response message
802
+ */
803
+ async resetGlobalKeys() {
804
+ return this.send("resetkeys");
805
+ }
806
+ /**
807
+ * List all global keys
808
+ * @returns Array of global key names
809
+ */
810
+ async listGlobalKeys() {
811
+ const response = await this.send("listkeys");
812
+ if (!response) return [];
813
+ return response.split("\n").filter((line) => line.trim().length > 0);
814
+ }
815
+ /**
816
+ * Set LOD bias (0-5, lower = better performance)
817
+ * @param value LOD bias value
818
+ * @returns Response message
819
+ */
820
+ async setLodBias(value) {
821
+ return this.send(`lodbias ${value}`);
822
+ }
823
+ /**
824
+ * Set LOD distance (100-6000)
825
+ * @param value LOD distance value
826
+ * @returns Response message
827
+ */
828
+ async setLodDistance(value) {
829
+ return this.send(`loddist ${value}`);
830
+ }
831
+ /**
832
+ * Clean up resources
833
+ */
834
+ cleanup() {
835
+ this.disconnect();
836
+ }
837
+ };
838
+ rconManager = new RconManager();
839
+ }
840
+ });
841
+
842
+ // src/rcon/mod.ts
843
+ var mod_exports = {};
844
+ __export(mod_exports, {
845
+ PacketType: () => PacketType,
846
+ RconClient: () => RconClient,
847
+ RconError: () => RconError,
848
+ ValheimCommands: () => ValheimCommands,
849
+ ValheimEvents: () => ValheimEvents,
850
+ ValheimGlobalKeys: () => ValheimGlobalKeys,
851
+ createAuthPacket: () => createAuthPacket,
852
+ createCommandPacket: () => createCommandPacket,
853
+ decodePacket: () => decodePacket,
854
+ encodePacket: () => encodePacket,
855
+ isAuthFailure: () => isAuthFailure,
856
+ isAuthResponse: () => isAuthResponse,
857
+ isAuthSuccess: () => isAuthSuccess,
858
+ rconManager: () => rconManager
859
+ });
860
+ var init_mod = __esm({
861
+ "src/rcon/mod.ts"() {
862
+ "use strict";
863
+ init_client();
864
+ init_manager();
865
+ init_protocol();
866
+ init_types();
867
+ }
868
+ });
869
+
376
870
  // src/cli/args.ts
377
871
  import { z } from "zod";
378
872
  var PortSchema = z.number().int().min(1024).max(65535);
@@ -919,11 +1413,11 @@ var defaultConfig = {
919
1413
  refreshRate: 1e3
920
1414
  },
921
1415
  rcon: {
922
- enabled: false,
1416
+ enabled: true,
923
1417
  port: 25575,
924
- password: "",
1418
+ password: "valheim-rcon",
925
1419
  timeout: 5e3,
926
- autoReconnect: false
1420
+ autoReconnect: true
927
1421
  },
928
1422
  worlds: [],
929
1423
  activeWorld: null,
@@ -1026,11 +1520,11 @@ var TuiConfigSchema = z2.object({
1026
1520
  refreshRate: z2.number().int().min(100).max(5e3).default(1e3)
1027
1521
  });
1028
1522
  var RconConfigSchema = z2.object({
1029
- enabled: z2.boolean().default(false),
1523
+ enabled: z2.boolean().default(true),
1030
1524
  port: z2.number().int().min(1024, "Port must be >= 1024").max(65535, "Port must be <= 65535").default(25575),
1031
- password: z2.string().default(""),
1525
+ password: z2.string().default("valheim-rcon"),
1032
1526
  timeout: z2.number().int().min(1e3).max(6e4).default(5e3),
1033
- autoReconnect: z2.boolean().default(false)
1527
+ autoReconnect: z2.boolean().default(true)
1034
1528
  });
1035
1529
  var AppConfigSchema = z2.object({
1036
1530
  version: z2.number().int().default(1),
@@ -2496,13 +2990,7 @@ function createProgressBar(percent) {
2496
2990
 
2497
2991
  // src/cli/commands/rcon.ts
2498
2992
  import * as readline from "readline";
2499
-
2500
- // src/rcon/mod.ts
2501
- init_client();
2502
- init_protocol();
2503
- init_types();
2504
-
2505
- // src/cli/commands/rcon.ts
2993
+ init_mod();
2506
2994
  async function rconCommand(args) {
2507
2995
  const config = await loadConfig();
2508
2996
  const host = args.host ?? "localhost";
@@ -2640,6 +3128,7 @@ async function interactiveRcon(args) {
2640
3128
  }
2641
3129
 
2642
3130
  // src/server/commands.ts
3131
+ init_mod();
2643
3132
  import * as fs5 from "fs/promises";
2644
3133
  import { dirname, join } from "path";
2645
3134
 
@@ -2670,8 +3159,11 @@ function parseEvent(line) {
2670
3159
  return { type: "player_join", name: match[1] };
2671
3160
  }
2672
3161
  }
2673
- if (line.includes("Closing socket")) {
2674
- return null;
3162
+ if (line.includes("Destroying abandoned non persistent zdo")) {
3163
+ const playerMatch = line.match(/owner (\S+)/);
3164
+ if (playerMatch?.[1]) {
3165
+ return { type: "player_leave", name: playerMatch[1] };
3166
+ }
2675
3167
  }
2676
3168
  if (line.includes("World saved")) {
2677
3169
  return { type: "world_saved" };
@@ -4368,13 +4860,16 @@ Error deleting world: ${error2.message}`);
4368
4860
  }
4369
4861
  }
4370
4862
 
4863
+ // src/mod.ts
4864
+ init_mod();
4865
+
4371
4866
  // src/tui/mod.ts
4372
4867
  import { withFullScreen } from "fullscreen-ink";
4373
4868
  import React2 from "react";
4374
4869
 
4375
4870
  // src/tui/App.tsx
4376
- import { Box as Box17, useApp, useInput as useInput10 } from "ink";
4377
- import { useEffect as useEffect12 } from "react";
4871
+ import { Box as Box22, useApp, useInput as useInput15 } from "ink";
4872
+ import { useEffect as useEffect14 } from "react";
4378
4873
 
4379
4874
  // src/tui/components/Header.tsx
4380
4875
  import { Box as Box2, Text as Text2 } from "ink";
@@ -4383,7 +4878,7 @@ import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useSta
4383
4878
  // package.json
4384
4879
  var package_default = {
4385
4880
  name: "valheim-oz-dsm",
4386
- version: "1.6.1",
4881
+ version: "1.8.0",
4387
4882
  description: "Land of OZ - Valheim Dedicated Server Manager",
4388
4883
  type: "module",
4389
4884
  bin: {
@@ -4550,13 +5045,13 @@ var useStore = create((set) => ({
4550
5045
  },
4551
5046
  // Initial RCON state
4552
5047
  rcon: {
4553
- enabled: false,
5048
+ enabled: true,
4554
5049
  connected: false,
4555
5050
  port: 25575,
4556
- password: "",
5051
+ password: "valheim-rcon",
4557
5052
  host: "localhost",
4558
5053
  timeout: 5e3,
4559
- autoReconnect: false
5054
+ autoReconnect: true
4560
5055
  },
4561
5056
  // Initial worlds state
4562
5057
  worlds: {
@@ -4605,6 +5100,9 @@ var useStore = create((set) => ({
4605
5100
  players: state.server.players.filter((p) => p !== name)
4606
5101
  }
4607
5102
  })),
5103
+ setPlayers: (players) => set((state) => ({
5104
+ server: { ...state.server, players }
5105
+ })),
4608
5106
  incrementUptime: () => set((state) => ({
4609
5107
  server: { ...state.server, uptime: state.server.uptime + 1 }
4610
5108
  })),
@@ -43497,22 +43995,328 @@ var Console = () => {
43497
43995
  };
43498
43996
 
43499
43997
  // src/tui/screens/Dashboard.tsx
43500
- import { Box as Box11, Text as Text11, useInput as useInput4 } from "ink";
43501
- import { useEffect as useEffect7, useState as useState6 } from "react";
43998
+ import { Box as Box16, Text as Text16, useInput as useInput9 } from "ink";
43999
+ import { useEffect as useEffect9, useState as useState11 } from "react";
43502
44000
 
43503
- // src/tui/components/Modal.tsx
44001
+ // src/tui/components/EventManager.tsx
44002
+ init_mod();
43504
44003
  import { Box as Box9, Text as Text9, useInput as useInput3 } from "ink";
44004
+ import { useState as useState5 } from "react";
43505
44005
  import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
44006
+ var EVENT_LIST = [
44007
+ {
44008
+ key: ValheimEvents.ARMY_EIKTHYR,
44009
+ name: "Eikthyr Army",
44010
+ description: "Eikthyr rallies the creatures"
44011
+ },
44012
+ {
44013
+ key: ValheimEvents.ARMY_THEELDER,
44014
+ name: "The Elder's Hunt",
44015
+ description: "The Elder is hunting you"
44016
+ },
44017
+ {
44018
+ key: ValheimEvents.ARMY_BONEMASS,
44019
+ name: "Bonemass Army",
44020
+ description: "A foul smell from the swamp"
44021
+ },
44022
+ {
44023
+ key: ValheimEvents.ARMY_MODER,
44024
+ name: "Moder's Hunt",
44025
+ description: "You are being hunted"
44026
+ },
44027
+ {
44028
+ key: ValheimEvents.ARMY_GOBLIN,
44029
+ name: "Goblin Horde",
44030
+ description: "The horde is attacking"
44031
+ },
44032
+ {
44033
+ key: ValheimEvents.FORESTTROLLS,
44034
+ name: "Forest Trolls",
44035
+ description: "The forest is moving"
44036
+ },
44037
+ {
44038
+ key: ValheimEvents.SKELETONS,
44039
+ name: "Skeletons",
44040
+ description: "Skeleton surprise"
44041
+ },
44042
+ {
44043
+ key: ValheimEvents.BLOBS,
44044
+ name: "Blobs",
44045
+ description: "Blob attack"
44046
+ },
44047
+ {
44048
+ key: ValheimEvents.WOLVES,
44049
+ name: "Wolves",
44050
+ description: "You are being hunted"
44051
+ },
44052
+ {
44053
+ key: ValheimEvents.BATS,
44054
+ name: "Bats",
44055
+ description: "Bat swarm"
44056
+ },
44057
+ {
44058
+ key: ValheimEvents.SERPENTS,
44059
+ name: "Serpents",
44060
+ description: "Sea serpents"
44061
+ }
44062
+ ];
44063
+ var EventManager = ({ onClose }) => {
44064
+ const rconConnected = useStore((s) => s.rcon.connected);
44065
+ const addLog = useStore((s) => s.actions.addLog);
44066
+ const [selectedIndex, setSelectedIndex] = useState5(0);
44067
+ const handleTriggerEvent = async (eventKey, eventName) => {
44068
+ const response = await rconManager.triggerEvent(eventKey);
44069
+ if (response) {
44070
+ addLog("info", `Triggered event: ${eventName}`);
44071
+ } else {
44072
+ addLog("error", `Failed to trigger event: ${eventName}`);
44073
+ }
44074
+ };
44075
+ const handleRandomEvent = async () => {
44076
+ const response = await rconManager.triggerRandomEvent();
44077
+ if (response) {
44078
+ addLog("info", `Triggered random event: ${response}`);
44079
+ } else {
44080
+ addLog("error", "Failed to trigger random event");
44081
+ }
44082
+ };
44083
+ const handleStopEvent = async () => {
44084
+ const response = await rconManager.stopEvent();
44085
+ if (response) {
44086
+ addLog("info", `Stopped event: ${response}`);
44087
+ } else {
44088
+ addLog("error", "Failed to stop event");
44089
+ }
44090
+ };
44091
+ useInput3((input, key) => {
44092
+ if (key.escape || input === "q" || input === "Q") {
44093
+ onClose();
44094
+ return;
44095
+ }
44096
+ if (key.upArrow) {
44097
+ setSelectedIndex(Math.max(0, selectedIndex - 1));
44098
+ } else if (key.downArrow) {
44099
+ setSelectedIndex(Math.min(EVENT_LIST.length - 1, selectedIndex + 1));
44100
+ }
44101
+ if (key.return) {
44102
+ const selectedEvent = EVENT_LIST[selectedIndex];
44103
+ handleTriggerEvent(selectedEvent.key, selectedEvent.name);
44104
+ } else if (input === "r" || input === "R") {
44105
+ handleRandomEvent();
44106
+ } else if (input === "x" || input === "X") {
44107
+ handleStopEvent();
44108
+ }
44109
+ });
44110
+ if (!rconConnected) {
44111
+ return /* @__PURE__ */ jsxs8(
44112
+ Box9,
44113
+ {
44114
+ flexDirection: "column",
44115
+ borderStyle: "round",
44116
+ borderColor: theme.error,
44117
+ padding: 1,
44118
+ width: 60,
44119
+ children: [
44120
+ /* @__PURE__ */ jsx9(Box9, { marginBottom: 1, children: /* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.error, children: "\u26A0 Event Manager" }) }),
44121
+ /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "RCON not connected" }),
44122
+ /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Event management requires RCON connection" }),
44123
+ /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "[Esc/Q] Close" }) })
44124
+ ]
44125
+ }
44126
+ );
44127
+ }
44128
+ return /* @__PURE__ */ jsxs8(
44129
+ Box9,
44130
+ {
44131
+ flexDirection: "column",
44132
+ borderStyle: "round",
44133
+ borderColor: theme.primary,
44134
+ padding: 1,
44135
+ width: 70,
44136
+ height: 25,
44137
+ children: [
44138
+ /* @__PURE__ */ jsx9(Box9, { marginBottom: 1, children: /* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.primary, children: "Event Manager" }) }),
44139
+ /* @__PURE__ */ jsx9(Box9, { marginBottom: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Use \u2191\u2193 to select, [Enter] Trigger, [R] Random, [X] Stop" }) }),
44140
+ /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", flexGrow: 1, children: EVENT_LIST.map((event, index) => /* @__PURE__ */ jsxs8(Box9, { marginLeft: 1, children: [
44141
+ /* @__PURE__ */ jsxs8(
44142
+ Text9,
44143
+ {
44144
+ color: index === selectedIndex ? theme.primary : theme.secondary,
44145
+ bold: index === selectedIndex,
44146
+ children: [
44147
+ index === selectedIndex ? "\u2192 " : " ",
44148
+ event.name
44149
+ ]
44150
+ }
44151
+ ),
44152
+ /* @__PURE__ */ jsxs8(Text9, { dimColor: true, children: [
44153
+ " - ",
44154
+ event.description
44155
+ ] })
44156
+ ] }, event.key)) }),
44157
+ /* @__PURE__ */ jsxs8(Box9, { marginTop: 1, flexDirection: "column", children: [
44158
+ /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "[Enter] Trigger Selected" }),
44159
+ /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "[R] Random Event [X] Stop Event" }),
44160
+ /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "[Esc/Q] Close" })
44161
+ ] })
44162
+ ]
44163
+ }
44164
+ );
44165
+ };
44166
+
44167
+ // src/tui/components/GlobalKeysManager.tsx
44168
+ init_mod();
44169
+ import { Box as Box10, Text as Text10, useInput as useInput4 } from "ink";
44170
+ import { useEffect as useEffect5, useState as useState6 } from "react";
44171
+ import { Fragment, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
44172
+ var BOSS_KEYS = [
44173
+ { key: ValheimGlobalKeys.DEFEATED_EIKTHYR, name: "Eikthyr" },
44174
+ { key: ValheimGlobalKeys.DEFEATED_GDKING, name: "The Elder" },
44175
+ { key: ValheimGlobalKeys.DEFEATED_BONEMASS, name: "Bonemass" },
44176
+ { key: ValheimGlobalKeys.DEFEATED_DRAGON, name: "Moder" },
44177
+ { key: ValheimGlobalKeys.DEFEATED_GOBLINKING, name: "Yagluth" },
44178
+ { key: ValheimGlobalKeys.DEFEATED_QUEEN, name: "The Queen" }
44179
+ ];
44180
+ var GlobalKeysManager = ({ onClose }) => {
44181
+ const rconConnected = useStore((s) => s.rcon.connected);
44182
+ const addLog = useStore((s) => s.actions.addLog);
44183
+ const [selectedIndex, setSelectedIndex] = useState6(0);
44184
+ const [activeKeys, setActiveKeys] = useState6([]);
44185
+ const [loading, setLoading] = useState6(true);
44186
+ useEffect5(() => {
44187
+ const loadKeys = async () => {
44188
+ setLoading(true);
44189
+ const keys = await rconManager.listGlobalKeys();
44190
+ setActiveKeys(keys);
44191
+ setLoading(false);
44192
+ };
44193
+ if (rconConnected) {
44194
+ loadKeys();
44195
+ }
44196
+ }, [rconConnected]);
44197
+ const isBossDefeated = (bossKey) => {
44198
+ return activeKeys.some(
44199
+ (key) => key.toLowerCase().includes(bossKey.toLowerCase())
44200
+ );
44201
+ };
44202
+ const handleToggleKey = async (keyName, isActive) => {
44203
+ if (isActive) {
44204
+ const response = await rconManager.removeGlobalKey(keyName);
44205
+ if (response) {
44206
+ addLog("info", `Removed key: ${keyName}`);
44207
+ const keys = await rconManager.listGlobalKeys();
44208
+ setActiveKeys(keys);
44209
+ } else {
44210
+ addLog("error", `Failed to remove key: ${keyName}`);
44211
+ }
44212
+ } else {
44213
+ const response = await rconManager.setGlobalKey(keyName);
44214
+ if (response) {
44215
+ addLog("info", `Set key: ${keyName}`);
44216
+ const keys = await rconManager.listGlobalKeys();
44217
+ setActiveKeys(keys);
44218
+ } else {
44219
+ addLog("error", `Failed to set key: ${keyName}`);
44220
+ }
44221
+ }
44222
+ };
44223
+ const handleResetAll = async () => {
44224
+ const response = await rconManager.resetGlobalKeys();
44225
+ if (response) {
44226
+ addLog("warn", "Reset all global keys");
44227
+ setActiveKeys([]);
44228
+ } else {
44229
+ addLog("error", "Failed to reset keys");
44230
+ }
44231
+ };
44232
+ useInput4((input, key) => {
44233
+ if (key.escape || input === "q" || input === "Q") {
44234
+ onClose();
44235
+ return;
44236
+ }
44237
+ if (key.upArrow) {
44238
+ setSelectedIndex(Math.max(0, selectedIndex - 1));
44239
+ } else if (key.downArrow) {
44240
+ setSelectedIndex(Math.min(BOSS_KEYS.length - 1, selectedIndex + 1));
44241
+ }
44242
+ if (input === " " || key.return) {
44243
+ const selected = BOSS_KEYS[selectedIndex];
44244
+ const isActive = isBossDefeated(selected.key);
44245
+ handleToggleKey(selected.key, isActive);
44246
+ } else if (input === "r" || input === "R") {
44247
+ handleResetAll();
44248
+ }
44249
+ });
44250
+ if (!rconConnected) {
44251
+ return /* @__PURE__ */ jsxs9(
44252
+ Box10,
44253
+ {
44254
+ flexDirection: "column",
44255
+ borderStyle: "round",
44256
+ borderColor: theme.error,
44257
+ padding: 1,
44258
+ width: 60,
44259
+ children: [
44260
+ /* @__PURE__ */ jsx10(Box10, { marginBottom: 1, children: /* @__PURE__ */ jsx10(Text10, { bold: true, color: theme.error, children: "\u26A0 Global Keys Manager" }) }),
44261
+ /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "RCON not connected" }),
44262
+ /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "Key management requires RCON connection" }),
44263
+ /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "[Esc/Q] Close" }) })
44264
+ ]
44265
+ }
44266
+ );
44267
+ }
44268
+ return /* @__PURE__ */ jsxs9(
44269
+ Box10,
44270
+ {
44271
+ flexDirection: "column",
44272
+ borderStyle: "round",
44273
+ borderColor: theme.primary,
44274
+ padding: 1,
44275
+ width: 60,
44276
+ children: [
44277
+ /* @__PURE__ */ jsx10(Box10, { marginBottom: 1, children: /* @__PURE__ */ jsx10(Text10, { bold: true, color: theme.primary, children: "Boss Progression" }) }),
44278
+ loading ? /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "Loading keys..." }) : /* @__PURE__ */ jsxs9(Fragment, { children: [
44279
+ /* @__PURE__ */ jsx10(Box10, { marginBottom: 1, children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "Use \u2191\u2193 to select, [Space/Enter] to toggle" }) }),
44280
+ /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: BOSS_KEYS.map((boss, index) => {
44281
+ const defeated = isBossDefeated(boss.key);
44282
+ return /* @__PURE__ */ jsx10(Box10, { marginLeft: 1, children: /* @__PURE__ */ jsxs9(
44283
+ Text10,
44284
+ {
44285
+ color: index === selectedIndex ? theme.primary : theme.secondary,
44286
+ bold: index === selectedIndex,
44287
+ children: [
44288
+ index === selectedIndex ? "\u2192 " : " ",
44289
+ defeated ? "\u2611" : "\u2610",
44290
+ " ",
44291
+ boss.name
44292
+ ]
44293
+ }
44294
+ ) }, boss.key);
44295
+ }) }),
44296
+ /* @__PURE__ */ jsx10(Box10, { marginTop: 2, flexDirection: "column", children: /* @__PURE__ */ jsx10(Text10, { color: theme.warning, children: "\u26A0\uFE0F Warning: Affects world progression" }) })
44297
+ ] }),
44298
+ /* @__PURE__ */ jsxs9(Box10, { marginTop: 1, flexDirection: "column", children: [
44299
+ /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "[Space/Enter] Toggle [R] Reset All" }),
44300
+ /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "[Esc/Q] Close" })
44301
+ ] })
44302
+ ]
44303
+ }
44304
+ );
44305
+ };
44306
+
44307
+ // src/tui/components/Modal.tsx
44308
+ import { Box as Box11, Text as Text11, useInput as useInput5 } from "ink";
44309
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
43506
44310
  var Modal = (props) => {
43507
44311
  const { title, children, width = 50 } = props;
43508
44312
  const closeModal = useStore((s) => s.actions.closeModal);
43509
- useInput3((_input, key) => {
44313
+ useInput5((_input, key) => {
43510
44314
  if (key.escape) {
43511
44315
  closeModal();
43512
44316
  }
43513
44317
  });
43514
- return /* @__PURE__ */ jsxs8(
43515
- Box9,
44318
+ return /* @__PURE__ */ jsxs10(
44319
+ Box11,
43516
44320
  {
43517
44321
  flexDirection: "column",
43518
44322
  width,
@@ -43522,36 +44326,36 @@ var Modal = (props) => {
43522
44326
  paddingX: 2,
43523
44327
  paddingY: 1,
43524
44328
  children: [
43525
- /* @__PURE__ */ jsxs8(Box9, { justifyContent: "space-between", marginBottom: 1, children: [
43526
- /* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.primary, children: title }),
43527
- /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "[ESC to close]" })
44329
+ /* @__PURE__ */ jsxs10(Box11, { justifyContent: "space-between", marginBottom: 1, children: [
44330
+ /* @__PURE__ */ jsx11(Text11, { bold: true, color: theme.primary, children: title }),
44331
+ /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "[ESC to close]" })
43528
44332
  ] }),
43529
- /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", children })
44333
+ /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", children })
43530
44334
  ]
43531
44335
  }
43532
44336
  );
43533
44337
  };
43534
44338
  var ConfirmModal = (props) => {
43535
44339
  const { message, onConfirm, onCancel } = props;
43536
- useInput3((input, key) => {
44340
+ useInput5((input, key) => {
43537
44341
  if (input === "y" || input === "Y") {
43538
44342
  onConfirm();
43539
44343
  } else if (input === "n" || input === "N" || key.escape) {
43540
44344
  onCancel();
43541
44345
  }
43542
44346
  });
43543
- return /* @__PURE__ */ jsxs8(Modal, { title: "Confirm", width: 40, children: [
43544
- /* @__PURE__ */ jsx9(Text9, { children: message }),
43545
- /* @__PURE__ */ jsxs8(Box9, { marginTop: 1, children: [
43546
- /* @__PURE__ */ jsx9(Text9, { color: theme.success, children: "[Y] Yes" }),
43547
- /* @__PURE__ */ jsx9(Text9, {}),
43548
- /* @__PURE__ */ jsx9(Text9, { color: theme.error, children: "[N] No" })
44347
+ return /* @__PURE__ */ jsxs10(Modal, { title: "Confirm", width: 40, children: [
44348
+ /* @__PURE__ */ jsx11(Text11, { children: message }),
44349
+ /* @__PURE__ */ jsxs10(Box11, { marginTop: 1, children: [
44350
+ /* @__PURE__ */ jsx11(Text11, { color: theme.success, children: "[Y] Yes" }),
44351
+ /* @__PURE__ */ jsx11(Text11, {}),
44352
+ /* @__PURE__ */ jsx11(Text11, { color: theme.error, children: "[N] No" })
43549
44353
  ] })
43550
44354
  ] });
43551
44355
  };
43552
44356
  var DeleteWorldModal = (props) => {
43553
44357
  const { worldName, backupCount, onConfirm, onCancel } = props;
43554
- useInput3((input, key) => {
44358
+ useInput5((input, key) => {
43555
44359
  if (backupCount > 0) {
43556
44360
  if (input === "y" || input === "Y") {
43557
44361
  onConfirm(true);
@@ -43569,66 +44373,364 @@ var DeleteWorldModal = (props) => {
43569
44373
  }
43570
44374
  });
43571
44375
  if (backupCount > 0) {
43572
- return /* @__PURE__ */ jsxs8(Modal, { title: "Delete World", width: 50, children: [
43573
- /* @__PURE__ */ jsxs8(Text9, { children: [
44376
+ return /* @__PURE__ */ jsxs10(Modal, { title: "Delete World", width: 50, children: [
44377
+ /* @__PURE__ */ jsxs10(Text11, { children: [
43574
44378
  'Delete world "',
43575
44379
  worldName,
43576
44380
  '"?'
43577
44381
  ] }),
43578
- /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text9, { dimColor: true, children: [
44382
+ /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { dimColor: true, children: [
43579
44383
  "This world has ",
43580
44384
  backupCount,
43581
44385
  " backup",
43582
44386
  backupCount === 1 ? "" : "s",
43583
44387
  "."
43584
44388
  ] }) }),
43585
- /* @__PURE__ */ jsxs8(Box9, { marginTop: 1, flexDirection: "column", children: [
43586
- /* @__PURE__ */ jsx9(Text9, { color: theme.success, children: "[Y] Delete world and backups" }),
43587
- /* @__PURE__ */ jsx9(Text9, { color: theme.warning, children: "[N] Delete world only" }),
43588
- /* @__PURE__ */ jsx9(Text9, { color: theme.error, children: "[Esc] Cancel" })
44389
+ /* @__PURE__ */ jsxs10(Box11, { marginTop: 1, flexDirection: "column", children: [
44390
+ /* @__PURE__ */ jsx11(Text11, { color: theme.success, children: "[Y] Delete world and backups" }),
44391
+ /* @__PURE__ */ jsx11(Text11, { color: theme.warning, children: "[N] Delete world only" }),
44392
+ /* @__PURE__ */ jsx11(Text11, { color: theme.error, children: "[Esc] Cancel" })
43589
44393
  ] })
43590
44394
  ] });
43591
44395
  }
43592
- return /* @__PURE__ */ jsxs8(Modal, { title: "Confirm", width: 40, children: [
43593
- /* @__PURE__ */ jsxs8(Text9, { children: [
44396
+ return /* @__PURE__ */ jsxs10(Modal, { title: "Confirm", width: 40, children: [
44397
+ /* @__PURE__ */ jsxs10(Text11, { children: [
43594
44398
  'Delete world "',
43595
44399
  worldName,
43596
44400
  '"? This cannot be undone!'
43597
44401
  ] }),
43598
- /* @__PURE__ */ jsxs8(Box9, { marginTop: 1, children: [
43599
- /* @__PURE__ */ jsx9(Text9, { color: theme.success, children: "[Y] Yes" }),
43600
- /* @__PURE__ */ jsx9(Text9, {}),
43601
- /* @__PURE__ */ jsx9(Text9, { color: theme.error, children: "[N] No" })
44402
+ /* @__PURE__ */ jsxs10(Box11, { marginTop: 1, children: [
44403
+ /* @__PURE__ */ jsx11(Text11, { color: theme.success, children: "[Y] Yes" }),
44404
+ /* @__PURE__ */ jsx11(Text11, {}),
44405
+ /* @__PURE__ */ jsx11(Text11, { color: theme.error, children: "[N] No" })
43602
44406
  ] })
43603
44407
  ] });
43604
44408
  };
43605
44409
 
44410
+ // src/tui/components/PlayerManager.tsx
44411
+ init_mod();
44412
+ import { Box as Box12, Text as Text12, useInput as useInput6 } from "ink";
44413
+ import { useState as useState7 } from "react";
44414
+ import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
44415
+ var PlayerManager = ({ onClose }) => {
44416
+ const players = useStore((s) => s.server.players);
44417
+ const rconConnected = useStore((s) => s.rcon.connected);
44418
+ const addLog = useStore((s) => s.actions.addLog);
44419
+ const [selectedIndex, setSelectedIndex] = useState7(0);
44420
+ const [view, setView] = useState7("players");
44421
+ const [bannedPlayers, setBannedPlayers] = useState7([]);
44422
+ const [loading, setLoading] = useState7(false);
44423
+ const loadBannedPlayers = async () => {
44424
+ setLoading(true);
44425
+ const banned = await rconManager.getBannedPlayers();
44426
+ setBannedPlayers(banned);
44427
+ setLoading(false);
44428
+ };
44429
+ const handleKick = async (playerName) => {
44430
+ const response = await rconManager.kickPlayer(playerName);
44431
+ if (response) {
44432
+ addLog("info", `Kicked ${playerName}: ${response}`);
44433
+ } else {
44434
+ addLog("error", `Failed to kick ${playerName}`);
44435
+ }
44436
+ };
44437
+ const handleBan = async (playerName) => {
44438
+ const response = await rconManager.banPlayer(playerName);
44439
+ if (response) {
44440
+ addLog("warn", `Banned ${playerName}: ${response}`);
44441
+ } else {
44442
+ addLog("error", `Failed to ban ${playerName}`);
44443
+ }
44444
+ };
44445
+ const handleUnban = async (playerIdentifier) => {
44446
+ const response = await rconManager.unbanPlayer(playerIdentifier);
44447
+ if (response) {
44448
+ addLog("info", `Unbanned ${playerIdentifier}: ${response}`);
44449
+ await loadBannedPlayers();
44450
+ } else {
44451
+ addLog("error", `Failed to unban ${playerIdentifier}`);
44452
+ }
44453
+ };
44454
+ useInput6((input, key) => {
44455
+ if (key.escape || input === "q" || input === "Q") {
44456
+ onClose();
44457
+ return;
44458
+ }
44459
+ if (input === "t" || input === "T") {
44460
+ if (view === "players") {
44461
+ setView("banned");
44462
+ loadBannedPlayers();
44463
+ } else {
44464
+ setView("players");
44465
+ }
44466
+ setSelectedIndex(0);
44467
+ return;
44468
+ }
44469
+ const currentList = view === "players" ? players : bannedPlayers;
44470
+ const maxIndex = Math.max(0, currentList.length - 1);
44471
+ if (key.upArrow) {
44472
+ setSelectedIndex(Math.max(0, selectedIndex - 1));
44473
+ } else if (key.downArrow) {
44474
+ setSelectedIndex(Math.min(maxIndex, selectedIndex + 1));
44475
+ }
44476
+ if (view === "players" && players.length > 0) {
44477
+ const selectedPlayer = players[selectedIndex];
44478
+ if (input === "k" || input === "K") {
44479
+ handleKick(selectedPlayer);
44480
+ } else if (input === "b" || input === "B") {
44481
+ handleBan(selectedPlayer);
44482
+ }
44483
+ } else if (view === "banned" && bannedPlayers.length > 0) {
44484
+ const selectedBanned = bannedPlayers[selectedIndex];
44485
+ if (input === "u" || input === "U") {
44486
+ handleUnban(selectedBanned);
44487
+ }
44488
+ }
44489
+ });
44490
+ if (!rconConnected) {
44491
+ return /* @__PURE__ */ jsxs11(
44492
+ Box12,
44493
+ {
44494
+ flexDirection: "column",
44495
+ borderStyle: "round",
44496
+ borderColor: theme.error,
44497
+ padding: 1,
44498
+ width: 60,
44499
+ children: [
44500
+ /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Text12, { bold: true, color: theme.error, children: "\u26A0 Player Management" }) }),
44501
+ /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "RCON not connected" }),
44502
+ /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Player management requires RCON connection" }),
44503
+ /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "[Esc/Q] Close" }) })
44504
+ ]
44505
+ }
44506
+ );
44507
+ }
44508
+ return /* @__PURE__ */ jsxs11(
44509
+ Box12,
44510
+ {
44511
+ flexDirection: "column",
44512
+ borderStyle: "round",
44513
+ borderColor: theme.primary,
44514
+ padding: 1,
44515
+ width: 70,
44516
+ children: [
44517
+ /* @__PURE__ */ jsxs11(Box12, { marginBottom: 1, children: [
44518
+ /* @__PURE__ */ jsx12(Text12, { bold: true, color: theme.primary, children: "Player Management" }),
44519
+ /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: " - " }),
44520
+ /* @__PURE__ */ jsxs11(Text12, { color: view === "players" ? theme.success : theme.muted, children: [
44521
+ "[T] ",
44522
+ view === "players" ? "Online Players" : "Banned Players"
44523
+ ] })
44524
+ ] }),
44525
+ view === "players" ? /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", children: players.length === 0 ? /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "No players currently online" }) : /* @__PURE__ */ jsxs11(Fragment2, { children: [
44526
+ /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Use \u2191\u2193 to select, [K] Kick, [B] Ban" }) }),
44527
+ players.map((player, index) => /* @__PURE__ */ jsx12(Box12, { marginLeft: 1, children: /* @__PURE__ */ jsxs11(
44528
+ Text12,
44529
+ {
44530
+ color: index === selectedIndex ? theme.primary : theme.secondary,
44531
+ bold: index === selectedIndex,
44532
+ children: [
44533
+ index === selectedIndex ? "\u2192 " : " ",
44534
+ player
44535
+ ]
44536
+ }
44537
+ ) }, player))
44538
+ ] }) }) : /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", children: loading ? /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Loading banned players..." }) : bannedPlayers.length === 0 ? /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "No banned players" }) : /* @__PURE__ */ jsxs11(Fragment2, { children: [
44539
+ /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Use \u2191\u2193 to select, [U] Unban" }) }),
44540
+ bannedPlayers.map((banned, index) => /* @__PURE__ */ jsx12(Box12, { marginLeft: 1, children: /* @__PURE__ */ jsxs11(
44541
+ Text12,
44542
+ {
44543
+ color: index === selectedIndex ? theme.warning : theme.secondary,
44544
+ bold: index === selectedIndex,
44545
+ children: [
44546
+ index === selectedIndex ? "\u2192 " : " ",
44547
+ banned
44548
+ ]
44549
+ }
44550
+ ) }, banned))
44551
+ ] }) }),
44552
+ /* @__PURE__ */ jsx12(Box12, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "[Esc/Q] Close [T] Toggle View" }) })
44553
+ ]
44554
+ }
44555
+ );
44556
+ };
44557
+
44558
+ // src/tui/components/ServerInfoModal.tsx
44559
+ init_mod();
44560
+ import { Box as Box14, Text as Text14, useInput as useInput7 } from "ink";
44561
+ import { useEffect as useEffect7, useState as useState9 } from "react";
44562
+
43606
44563
  // src/tui/components/Spinner.tsx
43607
- import { Box as Box10, Text as Text10 } from "ink";
43608
- import { useEffect as useEffect5, useState as useState5 } from "react";
43609
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
44564
+ import { Box as Box13, Text as Text13 } from "ink";
44565
+ import { useEffect as useEffect6, useState as useState8 } from "react";
44566
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
43610
44567
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
43611
44568
  var SPINNER_INTERVAL = 80;
43612
44569
  var Spinner = (props) => {
43613
44570
  const { label, color = valheimPalette.mandarin } = props;
43614
- const [frame, setFrame] = useState5(0);
43615
- useEffect5(() => {
44571
+ const [frame, setFrame] = useState8(0);
44572
+ useEffect6(() => {
43616
44573
  const timer = setInterval(() => {
43617
44574
  setFrame((f) => (f + 1) % SPINNER_FRAMES.length);
43618
44575
  }, SPINNER_INTERVAL);
43619
44576
  return () => clearInterval(timer);
43620
44577
  }, []);
43621
- return /* @__PURE__ */ jsxs9(Box10, { children: [
43622
- /* @__PURE__ */ jsx10(Text10, { color, children: SPINNER_FRAMES[frame] }),
43623
- label && /* @__PURE__ */ jsxs9(Text10, { children: [
44578
+ return /* @__PURE__ */ jsxs12(Box13, { children: [
44579
+ /* @__PURE__ */ jsx13(Text13, { color, children: SPINNER_FRAMES[frame] }),
44580
+ label && /* @__PURE__ */ jsxs12(Text13, { children: [
43624
44581
  " ",
43625
44582
  label
43626
44583
  ] })
43627
44584
  ] });
43628
44585
  };
43629
44586
 
44587
+ // src/tui/components/ServerInfoModal.tsx
44588
+ import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
44589
+ var ServerInfoModal = ({ onClose }) => {
44590
+ const [info2, setInfo] = useState9("");
44591
+ const [ping, setPing] = useState9("");
44592
+ const [loading, setLoading] = useState9(true);
44593
+ useEffect7(() => {
44594
+ const fetchInfo = async () => {
44595
+ setLoading(true);
44596
+ const [infoResponse, pingResponse] = await Promise.all([
44597
+ rconManager.getServerInfo(),
44598
+ rconManager.pingServer()
44599
+ ]);
44600
+ setInfo(infoResponse || "No info available");
44601
+ setPing(pingResponse || "");
44602
+ setLoading(false);
44603
+ };
44604
+ fetchInfo();
44605
+ }, []);
44606
+ useInput7((input, key) => {
44607
+ if (key.escape || input === "q" || input === "Q") {
44608
+ onClose();
44609
+ }
44610
+ });
44611
+ return /* @__PURE__ */ jsxs13(
44612
+ Box14,
44613
+ {
44614
+ flexDirection: "column",
44615
+ borderStyle: "round",
44616
+ borderColor: theme.primary,
44617
+ padding: 1,
44618
+ width: 70,
44619
+ children: [
44620
+ /* @__PURE__ */ jsx14(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Text14, { bold: true, color: theme.primary, children: "Server Information" }) }),
44621
+ loading ? /* @__PURE__ */ jsx14(Box14, { marginY: 2, children: /* @__PURE__ */ jsx14(Spinner, { label: "Fetching server info..." }) }) : /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", children: [
44622
+ /* @__PURE__ */ jsx14(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Text14, { bold: true, children: "Info:" }) }),
44623
+ /* @__PURE__ */ jsx14(Box14, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx14(Text14, { children: info2 }) }),
44624
+ ping && /* @__PURE__ */ jsxs13(Fragment3, { children: [
44625
+ /* @__PURE__ */ jsx14(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Text14, { bold: true, children: "Ping:" }) }),
44626
+ /* @__PURE__ */ jsx14(Box14, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx14(Text14, { color: theme.success, children: ping }) })
44627
+ ] })
44628
+ ] }),
44629
+ /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "[Esc/Q] Close" }) })
44630
+ ]
44631
+ }
44632
+ );
44633
+ };
44634
+
44635
+ // src/tui/components/TimeControl.tsx
44636
+ init_mod();
44637
+ import { Box as Box15, Text as Text15, useInput as useInput8 } from "ink";
44638
+ import { useState as useState10 } from "react";
44639
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
44640
+ var TIME_OPTIONS = [
44641
+ { index: 0, label: "Sleep (Skip to morning)", seconds: 0 },
44642
+ { index: 1, label: "Skip 1 hour", seconds: 3600 },
44643
+ { index: 2, label: "Skip 3 hours", seconds: 10800 },
44644
+ { index: 3, label: "Skip 6 hours", seconds: 21600 },
44645
+ { index: 4, label: "Skip 12 hours", seconds: 43200 },
44646
+ { index: 5, label: "Skip 1 day", seconds: 86400 }
44647
+ ];
44648
+ var TimeControl = ({ onClose }) => {
44649
+ const rconConnected = useStore((s) => s.rcon.connected);
44650
+ const addLog = useStore((s) => s.actions.addLog);
44651
+ const [selectedIndex, setSelectedIndex] = useState10(0);
44652
+ const handleTimeSkip = async (seconds, label) => {
44653
+ if (seconds === 0) {
44654
+ const response = await rconManager.sleep();
44655
+ if (response) {
44656
+ addLog("info", `Sleeping through night: ${response}`);
44657
+ } else {
44658
+ addLog("error", "Failed to sleep");
44659
+ }
44660
+ } else {
44661
+ const response = await rconManager.skipTime(seconds);
44662
+ if (response) {
44663
+ addLog("info", `${label}: ${response}`);
44664
+ } else {
44665
+ addLog("error", `Failed to skip time: ${label}`);
44666
+ }
44667
+ }
44668
+ };
44669
+ useInput8((input, key) => {
44670
+ if (key.escape || input === "q" || input === "Q") {
44671
+ onClose();
44672
+ return;
44673
+ }
44674
+ if (key.upArrow) {
44675
+ setSelectedIndex(Math.max(0, selectedIndex - 1));
44676
+ } else if (key.downArrow) {
44677
+ setSelectedIndex(Math.min(TIME_OPTIONS.length - 1, selectedIndex + 1));
44678
+ }
44679
+ if (key.return) {
44680
+ const selected = TIME_OPTIONS[selectedIndex];
44681
+ handleTimeSkip(selected.seconds, selected.label);
44682
+ }
44683
+ });
44684
+ if (!rconConnected) {
44685
+ return /* @__PURE__ */ jsxs14(
44686
+ Box15,
44687
+ {
44688
+ flexDirection: "column",
44689
+ borderStyle: "round",
44690
+ borderColor: theme.error,
44691
+ padding: 1,
44692
+ width: 60,
44693
+ children: [
44694
+ /* @__PURE__ */ jsx15(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsx15(Text15, { bold: true, color: theme.error, children: "\u26A0 Time Control" }) }),
44695
+ /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "RCON not connected" }),
44696
+ /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "Time control requires RCON connection" }),
44697
+ /* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "[Esc/Q] Close" }) })
44698
+ ]
44699
+ }
44700
+ );
44701
+ }
44702
+ return /* @__PURE__ */ jsxs14(
44703
+ Box15,
44704
+ {
44705
+ flexDirection: "column",
44706
+ borderStyle: "round",
44707
+ borderColor: theme.primary,
44708
+ padding: 1,
44709
+ width: 50,
44710
+ children: [
44711
+ /* @__PURE__ */ jsx15(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsx15(Text15, { bold: true, color: theme.primary, children: "Time Control" }) }),
44712
+ /* @__PURE__ */ jsx15(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "Use \u2191\u2193 to select, [Enter] to execute" }) }),
44713
+ /* @__PURE__ */ jsx15(Box15, { flexDirection: "column", children: TIME_OPTIONS.map((option) => /* @__PURE__ */ jsx15(Box15, { marginLeft: 1, children: /* @__PURE__ */ jsxs14(
44714
+ Text15,
44715
+ {
44716
+ color: option.index === selectedIndex ? theme.primary : theme.secondary,
44717
+ bold: option.index === selectedIndex,
44718
+ children: [
44719
+ option.index === selectedIndex ? "\u2192 " : " ",
44720
+ option.label
44721
+ ]
44722
+ }
44723
+ ) }, option.index)) }),
44724
+ /* @__PURE__ */ jsx15(Box15, { marginTop: 2, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "\u26A0\uFE0F Warning: Time skip affects all players" }) }),
44725
+ /* @__PURE__ */ jsx15(Box15, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "[Enter] Execute [Esc/Q] Close" }) })
44726
+ ]
44727
+ }
44728
+ );
44729
+ };
44730
+
43630
44731
  // src/tui/hooks/useServer.ts
43631
- import { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef3 } from "react";
44732
+ init_mod();
44733
+ import { useCallback as useCallback3, useEffect as useEffect8, useRef as useRef3 } from "react";
43632
44734
 
43633
44735
  // src/tui/serverManager.ts
43634
44736
  var watchdog = null;
@@ -43883,7 +44985,7 @@ function useServer() {
43883
44985
  actions.addLog("error", `Failed to attach to running server: ${error2}`);
43884
44986
  }
43885
44987
  }, [actions, createWatchdogEvents]);
43886
- useEffect6(() => {
44988
+ useEffect8(() => {
43887
44989
  if (hasCheckedForRunning.current) return;
43888
44990
  hasCheckedForRunning.current = true;
43889
44991
  checkAndAttach().catch((error2) => {
@@ -44022,13 +45124,66 @@ function useServer() {
44022
45124
  actions.addLog("error", `Failed to detach: ${error2}`);
44023
45125
  }
44024
45126
  }, [actions]);
44025
- useEffect6(() => {
45127
+ useEffect8(() => {
44026
45128
  if (status !== "online") return;
44027
45129
  const interval = setInterval(() => {
44028
45130
  actions.incrementUptime();
44029
45131
  }, 1e3);
44030
45132
  return () => clearInterval(interval);
44031
45133
  }, [status, actions]);
45134
+ useEffect8(() => {
45135
+ if (!rcon.enabled) {
45136
+ if (rconManager.isConnected()) {
45137
+ rconManager.disconnect();
45138
+ actions.setRconConnected(false);
45139
+ }
45140
+ return;
45141
+ }
45142
+ rconManager.initialize(
45143
+ {
45144
+ host: "localhost",
45145
+ port: rcon.port,
45146
+ password: rcon.password,
45147
+ timeout: rcon.timeout,
45148
+ enabled: rcon.enabled,
45149
+ autoReconnect: rcon.autoReconnect
45150
+ },
45151
+ {
45152
+ onConnectionStateChange: (state) => {
45153
+ const connected = state === "connected";
45154
+ actions.setRconConnected(connected);
45155
+ if (connected) {
45156
+ actions.addLog("info", "RCON connected");
45157
+ } else if (state === "error") {
45158
+ actions.addLog("warn", "RCON connection error");
45159
+ } else if (state === "disconnected") {
45160
+ actions.addLog("info", "RCON disconnected");
45161
+ }
45162
+ },
45163
+ onPlayerListUpdate: (players) => {
45164
+ actions.setPlayers(players);
45165
+ },
45166
+ pollInterval: 1e4
45167
+ // Poll every 10 seconds
45168
+ }
45169
+ );
45170
+ return () => {
45171
+ rconManager.disconnect();
45172
+ };
45173
+ }, [rcon, actions]);
45174
+ useEffect8(() => {
45175
+ if (status === "online" && rcon.enabled && !rconManager.isConnected()) {
45176
+ const timer = setTimeout(() => {
45177
+ rconManager.connect().catch((error2) => {
45178
+ actions.addLog("warn", `RCON connection failed: ${error2}`);
45179
+ });
45180
+ }, 3e3);
45181
+ return () => clearTimeout(timer);
45182
+ }
45183
+ if (status === "offline" && rconManager.isConnected()) {
45184
+ rconManager.disconnect();
45185
+ }
45186
+ }, [status, rcon.enabled, actions]);
44032
45187
  return {
44033
45188
  status,
44034
45189
  start,
@@ -44050,7 +45205,7 @@ function useServer() {
44050
45205
  }
44051
45206
 
44052
45207
  // src/tui/screens/Dashboard.tsx
44053
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
45208
+ import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
44054
45209
  function formatUptime2(seconds) {
44055
45210
  if (seconds === 0) return "N/A";
44056
45211
  const hours = Math.floor(seconds / 3600);
@@ -44112,6 +45267,8 @@ var Dashboard = () => {
44112
45267
  const memoryUsage = useStore((s) => s.server.memoryUsage);
44113
45268
  const startupPhase = useStore((s) => s.server.startupPhase);
44114
45269
  const config = useStore((s) => s.config);
45270
+ const rconConfig = useStore((s) => s.rcon);
45271
+ const rconConnected = useStore((s) => s.rcon.connected);
44115
45272
  const modalOpen = useStore((s) => s.ui.modalOpen);
44116
45273
  const openModal = useStore((s) => s.actions.openModal);
44117
45274
  const closeModal = useStore((s) => s.actions.closeModal);
@@ -44147,12 +45304,12 @@ var Dashboard = () => {
44147
45304
  const setValheimBuildId = useStore((s) => s.actions.setValheimBuildId);
44148
45305
  const resetValheimInstall = useStore((s) => s.actions.resetValheimInstall);
44149
45306
  const { start, stop, restart, update, forceSave } = useServer();
44150
- const [isUpdating2, setIsUpdating] = useState6(false);
44151
- const [updateProgress, setUpdateProgress] = useState6("");
44152
- const [startupTaskRegistered, setStartupTaskRegistered] = useState6(null);
44153
- const [startupTaskProcessing, setStartupTaskProcessing] = useState6(false);
45307
+ const [isUpdating2, setIsUpdating] = useState11(false);
45308
+ const [updateProgress, setUpdateProgress] = useState11("");
45309
+ const [startupTaskRegistered, setStartupTaskRegistered] = useState11(null);
45310
+ const [startupTaskProcessing, setStartupTaskProcessing] = useState11(false);
44154
45311
  const statusColor = getStatusColor(status);
44155
- useEffect7(() => {
45312
+ useEffect9(() => {
44156
45313
  const checkSteamCmd2 = async () => {
44157
45314
  try {
44158
45315
  const installed = await isSteamCmdInstalled();
@@ -44167,7 +45324,7 @@ var Dashboard = () => {
44167
45324
  };
44168
45325
  checkSteamCmd2();
44169
45326
  }, [setSteamCmdInstalled, setSteamCmdPath]);
44170
- useEffect7(() => {
45327
+ useEffect9(() => {
44171
45328
  if (steamCmdInstalled !== true) return;
44172
45329
  const checkValheim = async () => {
44173
45330
  try {
@@ -44198,7 +45355,7 @@ var Dashboard = () => {
44198
45355
  setValheimBuildId,
44199
45356
  addLog
44200
45357
  ]);
44201
- useEffect7(() => {
45358
+ useEffect9(() => {
44202
45359
  if (steamCmdInstalled === true && valheimInstalled === false && !valheimInstalling) {
44203
45360
  const autoInstallValheim = async () => {
44204
45361
  setValheimInstalling(true);
@@ -44257,7 +45414,7 @@ var Dashboard = () => {
44257
45414
  resetValheimInstall,
44258
45415
  addLog
44259
45416
  ]);
44260
- useEffect7(() => {
45417
+ useEffect9(() => {
44261
45418
  const checkStartupTask = async () => {
44262
45419
  try {
44263
45420
  const registered = await isStartupTaskRegistered();
@@ -44399,7 +45556,7 @@ var Dashboard = () => {
44399
45556
  setStartupTaskProcessing(false);
44400
45557
  }
44401
45558
  };
44402
- useInput4((input) => {
45559
+ useInput9((input) => {
44403
45560
  if (modalOpen || isUpdating2 || steamCmdInstalling || valheimInstalling || startupTaskProcessing)
44404
45561
  return;
44405
45562
  if (input === "s" || input === "S") {
@@ -44411,7 +45568,7 @@ var Dashboard = () => {
44411
45568
  if (input === "x" || input === "X") {
44412
45569
  if (status === "online") {
44413
45570
  openModal(
44414
- /* @__PURE__ */ jsx11(
45571
+ /* @__PURE__ */ jsx16(
44415
45572
  ConfirmModal,
44416
45573
  {
44417
45574
  message: "Stop the server? Players will be disconnected.",
@@ -44425,7 +45582,7 @@ var Dashboard = () => {
44425
45582
  if (input === "r" || input === "R") {
44426
45583
  if (status === "online") {
44427
45584
  openModal(
44428
- /* @__PURE__ */ jsx11(
45585
+ /* @__PURE__ */ jsx16(
44429
45586
  ConfirmModal,
44430
45587
  {
44431
45588
  message: "Restart the server? Players will be briefly disconnected.",
@@ -44439,7 +45596,7 @@ var Dashboard = () => {
44439
45596
  if (input === "u" || input === "U") {
44440
45597
  if (status === "offline" && steamCmdInstalled && valheimInstalled) {
44441
45598
  openModal(
44442
- /* @__PURE__ */ jsx11(
45599
+ /* @__PURE__ */ jsx16(
44443
45600
  ConfirmModal,
44444
45601
  {
44445
45602
  message: "Update server via SteamCMD? This may take a few minutes.",
@@ -44453,7 +45610,7 @@ var Dashboard = () => {
44453
45610
  if (input === "i" || input === "I") {
44454
45611
  if (!steamCmdInstalled && !steamCmdInstalling) {
44455
45612
  openModal(
44456
- /* @__PURE__ */ jsx11(
45613
+ /* @__PURE__ */ jsx16(
44457
45614
  ConfirmModal,
44458
45615
  {
44459
45616
  message: "Install SteamCMD? This is required to download and update Valheim.",
@@ -44468,7 +45625,7 @@ var Dashboard = () => {
44468
45625
  if (steamCmdInstalled && !valheimInstalling) {
44469
45626
  const action = valheimInstalled === false ? "Install" : "Reinstall/Verify";
44470
45627
  openModal(
44471
- /* @__PURE__ */ jsx11(
45628
+ /* @__PURE__ */ jsx16(
44472
45629
  ConfirmModal,
44473
45630
  {
44474
45631
  message: `${action} Valheim Dedicated Server? This may take several minutes.`,
@@ -44487,7 +45644,7 @@ var Dashboard = () => {
44487
45644
  if (input === "k" || input === "K") {
44488
45645
  if (status === "online" || status === "starting" || status === "stopping") {
44489
45646
  openModal(
44490
- /* @__PURE__ */ jsx11(
45647
+ /* @__PURE__ */ jsx16(
44491
45648
  ConfirmModal,
44492
45649
  {
44493
45650
  message: "Force kill the server? Data may be lost!",
@@ -44502,7 +45659,7 @@ var Dashboard = () => {
44502
45659
  if (startupTaskRegistered === null) return;
44503
45660
  const action = startupTaskRegistered ? "Remove" : "Enable";
44504
45661
  openModal(
44505
- /* @__PURE__ */ jsx11(
45662
+ /* @__PURE__ */ jsx16(
44506
45663
  ConfirmModal,
44507
45664
  {
44508
45665
  message: `${action} auto-start at login? The server manager will ${startupTaskRegistered ? "no longer" : ""} start automatically when you log in.`,
@@ -44512,256 +45669,336 @@ var Dashboard = () => {
44512
45669
  )
44513
45670
  );
44514
45671
  }
45672
+ if (rconConnected && status === "online") {
45673
+ if (input === "p" || input === "P") {
45674
+ openModal(/* @__PURE__ */ jsx16(PlayerManager, { onClose: closeModal }));
45675
+ }
45676
+ if (input === "n" || input === "N") {
45677
+ openModal(/* @__PURE__ */ jsx16(ServerInfoModal, { onClose: closeModal }));
45678
+ }
45679
+ if (input === "e" || input === "E") {
45680
+ openModal(/* @__PURE__ */ jsx16(EventManager, { onClose: closeModal }));
45681
+ }
45682
+ if (input === "t" || input === "T") {
45683
+ openModal(/* @__PURE__ */ jsx16(TimeControl, { onClose: closeModal }));
45684
+ }
45685
+ if (input === "g" || input === "G") {
45686
+ openModal(/* @__PURE__ */ jsx16(GlobalKeysManager, { onClose: closeModal }));
45687
+ }
45688
+ if (input === "d" || input === "D") {
45689
+ openModal(
45690
+ /* @__PURE__ */ jsx16(
45691
+ ConfirmModal,
45692
+ {
45693
+ message: "Remove all dropped items from the world? This cannot be undone.",
45694
+ onConfirm: async () => {
45695
+ closeModal();
45696
+ const { rconManager: rconManager2 } = await Promise.resolve().then(() => (init_mod(), mod_exports));
45697
+ const response = await rconManager2.removeDrops();
45698
+ addLog("info", `Remove drops: ${response || "Done"}`);
45699
+ },
45700
+ onCancel: closeModal
45701
+ }
45702
+ )
45703
+ );
45704
+ }
45705
+ }
44515
45706
  });
44516
45707
  const renderStatusWithLoading = () => {
44517
45708
  if (status === "starting") {
44518
45709
  const phaseDesc = getPhaseDescription(startupPhase);
44519
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
44520
- /* @__PURE__ */ jsxs10(Box11, { children: [
44521
- /* @__PURE__ */ jsx11(Spinner, {}),
44522
- /* @__PURE__ */ jsxs10(Text11, { color: statusColor, bold: true, children: [
45710
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
45711
+ /* @__PURE__ */ jsxs15(Box16, { children: [
45712
+ /* @__PURE__ */ jsx16(Spinner, {}),
45713
+ /* @__PURE__ */ jsxs15(Text16, { color: statusColor, bold: true, children: [
44523
45714
  " ",
44524
45715
  "STARTING"
44525
45716
  ] })
44526
45717
  ] }),
44527
- phaseDesc && /* @__PURE__ */ jsx11(Box11, { marginLeft: 2, children: /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: phaseDesc }) })
45718
+ phaseDesc && /* @__PURE__ */ jsx16(Box16, { marginLeft: 2, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: phaseDesc }) })
44528
45719
  ] });
44529
45720
  }
44530
45721
  if (status === "stopping") {
44531
- return /* @__PURE__ */ jsxs10(Box11, { children: [
44532
- /* @__PURE__ */ jsx11(Spinner, {}),
44533
- /* @__PURE__ */ jsxs10(Text11, { color: statusColor, bold: true, children: [
45722
+ return /* @__PURE__ */ jsxs15(Box16, { children: [
45723
+ /* @__PURE__ */ jsx16(Spinner, {}),
45724
+ /* @__PURE__ */ jsxs15(Text16, { color: statusColor, bold: true, children: [
44534
45725
  " ",
44535
45726
  "STOPPING"
44536
45727
  ] })
44537
45728
  ] });
44538
45729
  }
44539
45730
  if (status === "online" && startupPhase === "ready") {
44540
- return /* @__PURE__ */ jsx11(Text11, { color: statusColor, bold: true, children: "\u25CF ONLINE (Ready to join)" });
45731
+ return /* @__PURE__ */ jsx16(Text16, { color: statusColor, bold: true, children: "\u25CF ONLINE (Ready to join)" });
44541
45732
  }
44542
- return /* @__PURE__ */ jsxs10(Text11, { color: statusColor, bold: true, children: [
45733
+ return /* @__PURE__ */ jsxs15(Text16, { color: statusColor, bold: true, children: [
44543
45734
  "\u25CF ",
44544
45735
  status.toUpperCase()
44545
45736
  ] });
44546
45737
  };
44547
45738
  if (isUpdating2) {
44548
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
44549
- /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsx11(Text11, { bold: true, color: theme.primary, children: "\u2500 Dashboard \u2500" }) }),
44550
- /* @__PURE__ */ jsxs10(
44551
- Box11,
45739
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
45740
+ /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { bold: true, color: theme.primary, children: "\u2500 Dashboard \u2500" }) }),
45741
+ /* @__PURE__ */ jsxs15(
45742
+ Box16,
44552
45743
  {
44553
45744
  flexDirection: "column",
44554
45745
  alignItems: "center",
44555
45746
  justifyContent: "center",
44556
45747
  flexGrow: 1,
44557
45748
  children: [
44558
- /* @__PURE__ */ jsx11(Spinner, { label: "Updating server..." }),
44559
- updateProgress && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: updateProgress }) }),
44560
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Please wait, this may take several minutes..." }) })
45749
+ /* @__PURE__ */ jsx16(Spinner, { label: "Updating server..." }),
45750
+ updateProgress && /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: updateProgress }) }),
45751
+ /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Please wait, this may take several minutes..." }) })
44561
45752
  ]
44562
45753
  }
44563
45754
  )
44564
45755
  ] });
44565
45756
  }
44566
45757
  if (steamCmdInstalling) {
44567
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
44568
- /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsx11(Text11, { bold: true, color: theme.primary, children: "\u2500 Dashboard \u2500" }) }),
44569
- /* @__PURE__ */ jsxs10(
44570
- Box11,
45758
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
45759
+ /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { bold: true, color: theme.primary, children: "\u2500 Dashboard \u2500" }) }),
45760
+ /* @__PURE__ */ jsxs15(
45761
+ Box16,
44571
45762
  {
44572
45763
  flexDirection: "column",
44573
45764
  alignItems: "center",
44574
45765
  justifyContent: "center",
44575
45766
  flexGrow: 1,
44576
45767
  children: [
44577
- /* @__PURE__ */ jsx11(Spinner, { label: "Installing SteamCMD..." }),
44578
- steamCmdProgress && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { dimColor: true, children: [
45768
+ /* @__PURE__ */ jsx16(Spinner, { label: "Installing SteamCMD..." }),
45769
+ steamCmdProgress && /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsxs15(Text16, { dimColor: true, children: [
44579
45770
  steamCmdProgress,
44580
45771
  steamCmdPercent > 0 && ` (${steamCmdPercent}%)`
44581
45772
  ] }) }),
44582
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Please wait..." }) })
45773
+ /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Please wait..." }) })
44583
45774
  ]
44584
45775
  }
44585
45776
  )
44586
45777
  ] });
44587
45778
  }
44588
45779
  if (valheimInstalling) {
44589
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
44590
- /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsx11(Text11, { bold: true, color: theme.primary, children: "\u2500 Dashboard \u2500" }) }),
44591
- /* @__PURE__ */ jsxs10(
44592
- Box11,
45780
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
45781
+ /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { bold: true, color: theme.primary, children: "\u2500 Dashboard \u2500" }) }),
45782
+ /* @__PURE__ */ jsxs15(
45783
+ Box16,
44593
45784
  {
44594
45785
  flexDirection: "column",
44595
45786
  alignItems: "center",
44596
45787
  justifyContent: "center",
44597
45788
  flexGrow: 1,
44598
45789
  children: [
44599
- /* @__PURE__ */ jsx11(Spinner, { label: "Installing Valheim Dedicated Server..." }),
44600
- valheimProgress && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { dimColor: true, children: [
45790
+ /* @__PURE__ */ jsx16(Spinner, { label: "Installing Valheim Dedicated Server..." }),
45791
+ valheimProgress && /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsxs15(Text16, { dimColor: true, children: [
44601
45792
  valheimProgress,
44602
45793
  valheimPercent > 0 && ` (${valheimPercent}%)`
44603
45794
  ] }) }),
44604
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Please wait, this may take several minutes..." }) })
45795
+ /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Please wait, this may take several minutes..." }) })
44605
45796
  ]
44606
45797
  }
44607
45798
  )
44608
45799
  ] });
44609
45800
  }
44610
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
44611
- /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsx11(Text11, { bold: true, color: theme.primary, children: "\u2500 Dashboard \u2500" }) }),
44612
- /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginBottom: 1, children: [
44613
- /* @__PURE__ */ jsx11(Text11, { bold: true, children: "SteamCMD" }),
44614
- /* @__PURE__ */ jsxs10(Box11, { marginLeft: 2, flexDirection: "column", children: [
44615
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44616
- /* @__PURE__ */ jsx11(Text11, { children: "Status: " }),
44617
- steamCmdInstalled === null ? /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Checking..." }) : steamCmdInstalled ? /* @__PURE__ */ jsx11(Text11, { color: theme.success, children: "\u25CF Installed" }) : /* @__PURE__ */ jsx11(Text11, { color: theme.warning, children: "\u25CB Not Installed" })
45801
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
45802
+ /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { bold: true, color: theme.primary, children: "\u2500 Dashboard \u2500" }) }),
45803
+ /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginBottom: 1, children: [
45804
+ /* @__PURE__ */ jsx16(Text16, { bold: true, children: "SteamCMD" }),
45805
+ /* @__PURE__ */ jsxs15(Box16, { marginLeft: 2, flexDirection: "column", children: [
45806
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45807
+ /* @__PURE__ */ jsx16(Text16, { children: "Status: " }),
45808
+ steamCmdInstalled === null ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Checking..." }) : steamCmdInstalled ? /* @__PURE__ */ jsx16(Text16, { color: theme.success, children: "\u25CF Installed" }) : /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: "\u25CB Not Installed" })
44618
45809
  ] }),
44619
- steamCmdInstalled && steamCmdPath && /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44620
- /* @__PURE__ */ jsx11(Text11, { children: "Location: " }),
44621
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: steamCmdPath })
45810
+ steamCmdInstalled && steamCmdPath && /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45811
+ /* @__PURE__ */ jsx16(Text16, { children: "Location: " }),
45812
+ /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: steamCmdPath })
44622
45813
  ] })
44623
45814
  ] })
44624
45815
  ] }),
44625
- /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginBottom: 1, children: [
44626
- /* @__PURE__ */ jsx11(Text11, { bold: true, children: "Valheim Dedicated Server" }),
44627
- /* @__PURE__ */ jsxs10(Box11, { marginLeft: 2, flexDirection: "column", children: [
44628
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44629
- /* @__PURE__ */ jsx11(Text11, { children: "Status: " }),
44630
- steamCmdInstalled !== true ? /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Waiting for SteamCMD..." }) : valheimInstalled === null ? /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Checking..." }) : valheimInstalled ? /* @__PURE__ */ jsx11(Text11, { color: theme.success, children: "\u25CF Installed" }) : /* @__PURE__ */ jsx11(Text11, { color: theme.warning, children: "\u25CB Not Installed" })
45816
+ /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginBottom: 1, children: [
45817
+ /* @__PURE__ */ jsx16(Text16, { bold: true, children: "Valheim Dedicated Server" }),
45818
+ /* @__PURE__ */ jsxs15(Box16, { marginLeft: 2, flexDirection: "column", children: [
45819
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45820
+ /* @__PURE__ */ jsx16(Text16, { children: "Status: " }),
45821
+ steamCmdInstalled !== true ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Waiting for SteamCMD..." }) : valheimInstalled === null ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Checking..." }) : valheimInstalled ? /* @__PURE__ */ jsx16(Text16, { color: theme.success, children: "\u25CF Installed" }) : /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: "\u25CB Not Installed" })
44631
45822
  ] }),
44632
- valheimInstalled && valheimVerified !== null && /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44633
- /* @__PURE__ */ jsx11(Text11, { children: "Verified: " }),
44634
- valheimVerified ? /* @__PURE__ */ jsx11(Text11, { color: theme.success, children: "\u25CF Yes" }) : /* @__PURE__ */ jsx11(Text11, { color: theme.error, children: "\u25CB Files Missing" })
45823
+ valheimInstalled && valheimVerified !== null && /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45824
+ /* @__PURE__ */ jsx16(Text16, { children: "Verified: " }),
45825
+ valheimVerified ? /* @__PURE__ */ jsx16(Text16, { color: theme.success, children: "\u25CF Yes" }) : /* @__PURE__ */ jsx16(Text16, { color: theme.error, children: "\u25CB Files Missing" })
44635
45826
  ] }),
44636
- valheimInstalled && valheimBuildId && /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44637
- /* @__PURE__ */ jsx11(Text11, { children: "Build ID: " }),
44638
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: valheimBuildId })
45827
+ valheimInstalled && valheimBuildId && /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45828
+ /* @__PURE__ */ jsx16(Text16, { children: "Build ID: " }),
45829
+ /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: valheimBuildId })
44639
45830
  ] }),
44640
- valheimInstalled && valheimPath && /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44641
- /* @__PURE__ */ jsx11(Text11, { children: "Location: " }),
44642
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: valheimPath })
45831
+ valheimInstalled && valheimPath && /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45832
+ /* @__PURE__ */ jsx16(Text16, { children: "Location: " }),
45833
+ /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: valheimPath })
44643
45834
  ] })
44644
45835
  ] })
44645
45836
  ] }),
44646
- /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginBottom: 1, children: [
44647
- /* @__PURE__ */ jsx11(Text11, { bold: true, children: "Server Status" }),
44648
- /* @__PURE__ */ jsxs10(Box11, { marginLeft: 2, flexDirection: "column", children: [
44649
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44650
- /* @__PURE__ */ jsx11(Text11, { children: "Status: " }),
45837
+ /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginBottom: 1, children: [
45838
+ /* @__PURE__ */ jsx16(Text16, { bold: true, children: "Server Status" }),
45839
+ /* @__PURE__ */ jsxs15(Box16, { marginLeft: 2, flexDirection: "column", children: [
45840
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45841
+ /* @__PURE__ */ jsx16(Text16, { children: "Status: " }),
44651
45842
  renderStatusWithLoading()
44652
45843
  ] }),
44653
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44654
- /* @__PURE__ */ jsx11(Text11, { children: "Server Name: " }),
44655
- /* @__PURE__ */ jsx11(Text11, { color: theme.primary, children: config.serverName })
45844
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45845
+ /* @__PURE__ */ jsx16(Text16, { children: "Server Name: " }),
45846
+ /* @__PURE__ */ jsx16(Text16, { color: theme.primary, children: config.serverName })
44656
45847
  ] }),
44657
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44658
- /* @__PURE__ */ jsx11(Text11, { children: "World: " }),
44659
- /* @__PURE__ */ jsx11(Text11, { color: theme.primary, children: config.world })
45848
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45849
+ /* @__PURE__ */ jsx16(Text16, { children: "World: " }),
45850
+ /* @__PURE__ */ jsx16(Text16, { color: theme.primary, children: config.world })
45851
+ ] }),
45852
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45853
+ /* @__PURE__ */ jsx16(Text16, { children: "Port: " }),
45854
+ /* @__PURE__ */ jsx16(Text16, { children: config.port })
44660
45855
  ] }),
44661
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44662
- /* @__PURE__ */ jsx11(Text11, { children: "Port: " }),
44663
- /* @__PURE__ */ jsx11(Text11, { children: config.port })
45856
+ version && /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45857
+ /* @__PURE__ */ jsx16(Text16, { children: "Version: " }),
45858
+ /* @__PURE__ */ jsx16(Text16, { children: version }),
45859
+ updateAvailable && /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: " (Update available!)" })
44664
45860
  ] }),
44665
- version && /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44666
- /* @__PURE__ */ jsx11(Text11, { children: "Version: " }),
44667
- /* @__PURE__ */ jsx11(Text11, { children: version }),
44668
- updateAvailable && /* @__PURE__ */ jsx11(Text11, { color: theme.warning, children: " (Update available!)" })
45861
+ pid && /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45862
+ /* @__PURE__ */ jsx16(Text16, { children: "PID: " }),
45863
+ /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: pid })
44669
45864
  ] }),
44670
- pid && /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44671
- /* @__PURE__ */ jsx11(Text11, { children: "PID: " }),
44672
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: pid })
45865
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45866
+ /* @__PURE__ */ jsx16(Text16, { children: "Uptime: " }),
45867
+ /* @__PURE__ */ jsx16(Text16, { children: formatUptime2(uptime) })
44673
45868
  ] }),
44674
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44675
- /* @__PURE__ */ jsx11(Text11, { children: "Uptime: " }),
44676
- /* @__PURE__ */ jsx11(Text11, { children: formatUptime2(uptime) })
45869
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45870
+ /* @__PURE__ */ jsx16(Text16, { children: "Last Save: " }),
45871
+ /* @__PURE__ */ jsx16(Text16, { children: formatLastSave(lastSave) })
44677
45872
  ] }),
44678
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44679
- /* @__PURE__ */ jsx11(Text11, { children: "Last Save: " }),
44680
- /* @__PURE__ */ jsx11(Text11, { children: formatLastSave(lastSave) })
45873
+ memoryUsage !== null && memoryUsage > 0 && /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45874
+ /* @__PURE__ */ jsx16(Text16, { children: "Memory: " }),
45875
+ /* @__PURE__ */ jsx16(Text16, { children: formatBytes(memoryUsage) })
45876
+ ] })
45877
+ ] })
45878
+ ] }),
45879
+ /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginBottom: 1, children: [
45880
+ /* @__PURE__ */ jsx16(Text16, { bold: true, children: "RCON Status" }),
45881
+ /* @__PURE__ */ jsxs15(Box16, { marginLeft: 2, flexDirection: "column", children: [
45882
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45883
+ /* @__PURE__ */ jsx16(Text16, { children: "RCON: " }),
45884
+ rconConfig.enabled ? rconConnected ? /* @__PURE__ */ jsx16(Text16, { color: theme.success, children: "\u25CF Connected" }) : status === "online" ? /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: "\u25CB Connecting..." }) : /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "\u25CB Waiting for server..." }) : /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "\u25CB Disabled" })
44681
45885
  ] }),
44682
- memoryUsage !== null && memoryUsage > 0 && /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44683
- /* @__PURE__ */ jsx11(Text11, { children: "Memory: " }),
44684
- /* @__PURE__ */ jsx11(Text11, { children: formatBytes(memoryUsage) })
45886
+ rconConfig.enabled && /* @__PURE__ */ jsxs15(Fragment4, { children: [
45887
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45888
+ /* @__PURE__ */ jsx16(Text16, { children: "Port: " }),
45889
+ /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: rconConfig.port })
45890
+ ] }),
45891
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45892
+ /* @__PURE__ */ jsx16(Text16, { children: "Auto-reconnect: " }),
45893
+ /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: rconConfig.autoReconnect ? "Enabled" : "Disabled" })
45894
+ ] })
44685
45895
  ] })
44686
45896
  ] })
44687
45897
  ] }),
44688
- /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginBottom: 1, children: [
44689
- /* @__PURE__ */ jsxs10(Text11, { bold: true, children: [
45898
+ /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginBottom: 1, children: [
45899
+ /* @__PURE__ */ jsxs15(Text16, { bold: true, children: [
44690
45900
  "Players (",
44691
45901
  players.length,
44692
45902
  ")"
44693
45903
  ] }),
44694
- /* @__PURE__ */ jsx11(Box11, { marginLeft: 2, flexDirection: "column", children: players.length === 0 ? /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "No players connected" }) : players.map((player) => /* @__PURE__ */ jsx11(Box11, { flexShrink: 0, children: /* @__PURE__ */ jsxs10(Text11, { color: theme.primary, children: [
45904
+ /* @__PURE__ */ jsx16(Box16, { marginLeft: 2, flexDirection: "column", children: players.length === 0 ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "No players connected" }) : players.map((player) => /* @__PURE__ */ jsx16(Box16, { flexShrink: 0, children: /* @__PURE__ */ jsxs15(Text16, { color: theme.primary, children: [
44695
45905
  "\u2022 ",
44696
45906
  player
44697
45907
  ] }) }, player)) })
44698
45908
  ] }),
44699
- /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginBottom: 1, children: [
44700
- /* @__PURE__ */ jsx11(Text11, { bold: true, children: "Auto-start" }),
44701
- /* @__PURE__ */ jsxs10(Box11, { marginLeft: 2, flexShrink: 0, children: [
44702
- /* @__PURE__ */ jsx11(Text11, { children: "Status: " }),
44703
- startupTaskRegistered === null ? /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Checking..." }) : startupTaskRegistered ? /* @__PURE__ */ jsx11(Text11, { color: theme.success, children: "\u25CF Enabled" }) : /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "\u25CB Disabled" })
45909
+ /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginBottom: 1, children: [
45910
+ /* @__PURE__ */ jsx16(Text16, { bold: true, children: "Auto-start" }),
45911
+ /* @__PURE__ */ jsxs15(Box16, { marginLeft: 2, flexShrink: 0, children: [
45912
+ /* @__PURE__ */ jsx16(Text16, { children: "Status: " }),
45913
+ startupTaskRegistered === null ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Checking..." }) : startupTaskRegistered ? /* @__PURE__ */ jsx16(Text16, { color: theme.success, children: "\u25CF Enabled" }) : /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "\u25CB Disabled" })
44704
45914
  ] })
44705
45915
  ] }),
44706
- /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
44707
- /* @__PURE__ */ jsx11(Text11, { bold: true, children: "Quick Actions" }),
44708
- /* @__PURE__ */ jsxs10(Box11, { marginLeft: 2, marginTop: 1, flexDirection: "column", children: [
44709
- steamCmdInstalled === false && /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, flexShrink: 0, children: /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44710
- /* @__PURE__ */ jsx11(Text11, { color: theme.info, children: "[I] " }),
44711
- /* @__PURE__ */ jsx11(Text11, { children: "Install SteamCMD" }),
44712
- /* @__PURE__ */ jsx11(Text11, { color: theme.warning, children: " (required)" })
45916
+ /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
45917
+ /* @__PURE__ */ jsx16(Text16, { bold: true, children: "Quick Actions" }),
45918
+ /* @__PURE__ */ jsxs15(Box16, { marginLeft: 2, marginTop: 1, flexDirection: "column", children: [
45919
+ steamCmdInstalled === false && /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, flexShrink: 0, children: /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45920
+ /* @__PURE__ */ jsx16(Text16, { color: theme.info, children: "[I] " }),
45921
+ /* @__PURE__ */ jsx16(Text16, { children: "Install SteamCMD" }),
45922
+ /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: " (required)" })
44713
45923
  ] }) }),
44714
- steamCmdInstalled && valheimInstalled === false && !valheimInstalling && /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, flexShrink: 0, children: /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44715
- /* @__PURE__ */ jsx11(Text11, { color: theme.info, children: "[V] " }),
44716
- /* @__PURE__ */ jsx11(Text11, { children: "Install Valheim Server" }),
44717
- /* @__PURE__ */ jsx11(Text11, { color: theme.warning, children: " (required)" })
45924
+ steamCmdInstalled && valheimInstalled === false && !valheimInstalling && /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, flexShrink: 0, children: /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45925
+ /* @__PURE__ */ jsx16(Text16, { color: theme.info, children: "[V] " }),
45926
+ /* @__PURE__ */ jsx16(Text16, { children: "Install Valheim Server" }),
45927
+ /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: " (required)" })
44718
45928
  ] }) }),
44719
- steamCmdInstalled && valheimInstalled && valheimVerified === false && /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, flexShrink: 0, children: /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44720
- /* @__PURE__ */ jsx11(Text11, { color: theme.warning, children: "[V] " }),
44721
- /* @__PURE__ */ jsx11(Text11, { children: "Reinstall Valheim Server" }),
44722
- /* @__PURE__ */ jsx11(Text11, { color: theme.error, children: " (verification failed)" })
45929
+ steamCmdInstalled && valheimInstalled && valheimVerified === false && /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, flexShrink: 0, children: /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45930
+ /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: "[V] " }),
45931
+ /* @__PURE__ */ jsx16(Text16, { children: "Reinstall Valheim Server" }),
45932
+ /* @__PURE__ */ jsx16(Text16, { color: theme.error, children: " (verification failed)" })
44723
45933
  ] }) }),
44724
- steamCmdInstalled && valheimInstalled ? status === "offline" ? /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
44725
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44726
- /* @__PURE__ */ jsx11(Text11, { color: theme.success, children: "[S] " }),
44727
- /* @__PURE__ */ jsx11(Text11, { children: "Start Server" })
45934
+ steamCmdInstalled && valheimInstalled ? status === "offline" ? /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
45935
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45936
+ /* @__PURE__ */ jsx16(Text16, { color: theme.success, children: "[S] " }),
45937
+ /* @__PURE__ */ jsx16(Text16, { children: "Start Server" })
44728
45938
  ] }),
44729
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44730
- /* @__PURE__ */ jsx11(Text11, { color: theme.info, children: "[U] " }),
44731
- /* @__PURE__ */ jsx11(Text11, { children: "Update Server" }),
44732
- updateAvailable && /* @__PURE__ */ jsx11(Text11, { color: theme.warning, children: " \u2605" })
45939
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45940
+ /* @__PURE__ */ jsx16(Text16, { color: theme.info, children: "[U] " }),
45941
+ /* @__PURE__ */ jsx16(Text16, { children: "Update Server" }),
45942
+ updateAvailable && /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: " \u2605" })
44733
45943
  ] }),
44734
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44735
- /* @__PURE__ */ jsx11(Text11, { color: theme.info, children: "[V] " }),
44736
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Verify/Reinstall Server" })
45944
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45945
+ /* @__PURE__ */ jsx16(Text16, { color: theme.info, children: "[V] " }),
45946
+ /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Verify/Reinstall Server" })
44737
45947
  ] })
44738
- ] }) : status === "online" ? /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
44739
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44740
- /* @__PURE__ */ jsx11(Text11, { color: theme.error, children: "[X] " }),
44741
- /* @__PURE__ */ jsx11(Text11, { children: "Stop Server" })
45948
+ ] }) : status === "online" ? /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
45949
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45950
+ /* @__PURE__ */ jsx16(Text16, { color: theme.error, children: "[X] " }),
45951
+ /* @__PURE__ */ jsx16(Text16, { children: "Stop Server" })
45952
+ ] }),
45953
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45954
+ /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: "[R] " }),
45955
+ /* @__PURE__ */ jsx16(Text16, { children: "Restart Server" })
44742
45956
  ] }),
44743
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44744
- /* @__PURE__ */ jsx11(Text11, { color: theme.warning, children: "[R] " }),
44745
- /* @__PURE__ */ jsx11(Text11, { children: "Restart Server" })
45957
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45958
+ /* @__PURE__ */ jsx16(Text16, { color: theme.info, children: "[F] " }),
45959
+ /* @__PURE__ */ jsx16(Text16, { children: "Force Save" })
44746
45960
  ] }),
44747
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44748
- /* @__PURE__ */ jsx11(Text11, { color: theme.info, children: "[F] " }),
44749
- /* @__PURE__ */ jsx11(Text11, { children: "Force Save" })
45961
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45962
+ /* @__PURE__ */ jsx16(Text16, { color: theme.error, children: "[K] " }),
45963
+ /* @__PURE__ */ jsx16(Text16, { children: "Kill Process" })
44750
45964
  ] }),
44751
- /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44752
- /* @__PURE__ */ jsx11(Text11, { color: theme.error, children: "[K] " }),
44753
- /* @__PURE__ */ jsx11(Text11, { children: "Kill Process" })
45965
+ rconConnected && /* @__PURE__ */ jsxs15(Fragment4, { children: [
45966
+ /* @__PURE__ */ jsx16(Box16, { marginTop: 1, flexShrink: 0, children: /* @__PURE__ */ jsx16(Text16, { bold: true, color: theme.primary, children: "RCON Admin:" }) }),
45967
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45968
+ /* @__PURE__ */ jsx16(Text16, { color: theme.primary, children: "[P] " }),
45969
+ /* @__PURE__ */ jsx16(Text16, { children: "Player Manager" })
45970
+ ] }),
45971
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45972
+ /* @__PURE__ */ jsx16(Text16, { color: theme.info, children: "[N] " }),
45973
+ /* @__PURE__ */ jsx16(Text16, { children: "Server Info" })
45974
+ ] }),
45975
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45976
+ /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: "[E] " }),
45977
+ /* @__PURE__ */ jsx16(Text16, { children: "Event Manager" })
45978
+ ] }),
45979
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45980
+ /* @__PURE__ */ jsx16(Text16, { color: theme.info, children: "[T] " }),
45981
+ /* @__PURE__ */ jsx16(Text16, { children: "Time Control" })
45982
+ ] }),
45983
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45984
+ /* @__PURE__ */ jsx16(Text16, { color: theme.primary, children: "[G] " }),
45985
+ /* @__PURE__ */ jsx16(Text16, { children: "Boss Progress" })
45986
+ ] }),
45987
+ /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
45988
+ /* @__PURE__ */ jsx16(Text16, { color: theme.error, children: "[D] " }),
45989
+ /* @__PURE__ */ jsx16(Text16, { children: "Remove Drops" })
45990
+ ] })
44754
45991
  ] })
44755
- ] }) : /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
44756
- /* @__PURE__ */ jsx11(Spinner, { label: `Server is ${status}...` }),
44757
- /* @__PURE__ */ jsxs10(Box11, { marginTop: 1, flexShrink: 0, children: [
44758
- /* @__PURE__ */ jsx11(Text11, { color: theme.error, children: "[K] " }),
44759
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Force Kill (if stuck)" })
45992
+ ] }) : /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
45993
+ /* @__PURE__ */ jsx16(Spinner, { label: `Server is ${status}...` }),
45994
+ /* @__PURE__ */ jsxs15(Box16, { marginTop: 1, flexShrink: 0, children: [
45995
+ /* @__PURE__ */ jsx16(Text16, { color: theme.error, children: "[K] " }),
45996
+ /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Force Kill (if stuck)" })
44760
45997
  ] })
44761
- ] }) : steamCmdInstalled === null ? /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Checking installation status..." }) : !steamCmdInstalled ? /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Install SteamCMD to manage server" }) : valheimInstalled === null ? /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Checking Valheim installation..." }) : /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Install Valheim to manage server" }),
44762
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, flexShrink: 0, children: startupTaskProcessing ? /* @__PURE__ */ jsx11(Spinner, { label: "Updating auto-start..." }) : startupTaskRegistered === null ? /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Checking auto-start status..." }) : /* @__PURE__ */ jsxs10(Box11, { flexShrink: 0, children: [
44763
- /* @__PURE__ */ jsxs10(
44764
- Text11,
45998
+ ] }) : steamCmdInstalled === null ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Checking installation status..." }) : !steamCmdInstalled ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Install SteamCMD to manage server" }) : valheimInstalled === null ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Checking Valheim installation..." }) : /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Install Valheim to manage server" }),
45999
+ /* @__PURE__ */ jsx16(Box16, { marginTop: 1, flexShrink: 0, children: startupTaskProcessing ? /* @__PURE__ */ jsx16(Spinner, { label: "Updating auto-start..." }) : startupTaskRegistered === null ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Checking auto-start status..." }) : /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
46000
+ /* @__PURE__ */ jsxs15(
46001
+ Text16,
44765
46002
  {
44766
46003
  color: startupTaskRegistered ? theme.warning : theme.success,
44767
46004
  children: [
@@ -44770,7 +46007,7 @@ var Dashboard = () => {
44770
46007
  ]
44771
46008
  }
44772
46009
  ),
44773
- /* @__PURE__ */ jsxs10(Text11, { children: [
46010
+ /* @__PURE__ */ jsxs15(Text16, { children: [
44774
46011
  startupTaskRegistered ? "Disable" : "Enable",
44775
46012
  " Auto-start"
44776
46013
  ] })
@@ -44781,13 +46018,13 @@ var Dashboard = () => {
44781
46018
  };
44782
46019
 
44783
46020
  // src/tui/screens/Settings.tsx
44784
- import { Box as Box15, Text as Text15, useInput as useInput8 } from "ink";
44785
- import { useCallback as useCallback5, useMemo as useMemo4, useState as useState10 } from "react";
46021
+ import { Box as Box20, Text as Text20, useInput as useInput13 } from "ink";
46022
+ import { useCallback as useCallback5, useMemo as useMemo4, useState as useState15 } from "react";
44786
46023
 
44787
46024
  // src/tui/components/NumberInput.tsx
44788
- import { Box as Box12, Text as Text12, useInput as useInput5 } from "ink";
44789
- import { useEffect as useEffect8, useState as useState7 } from "react";
44790
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
46025
+ import { Box as Box17, Text as Text17, useInput as useInput10 } from "ink";
46026
+ import { useEffect as useEffect10, useState as useState12 } from "react";
46027
+ import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
44791
46028
  var NumberInput = ({
44792
46029
  value,
44793
46030
  onChange,
@@ -44801,15 +46038,15 @@ var NumberInput = ({
44801
46038
  label,
44802
46039
  width = 10
44803
46040
  }) => {
44804
- const [editMode, setEditMode] = useState7(false);
44805
- const [editBuffer, setEditBuffer] = useState7("");
44806
- const [cursorVisible, setCursorVisible] = useState7(true);
44807
- useEffect8(() => {
46041
+ const [editMode, setEditMode] = useState12(false);
46042
+ const [editBuffer, setEditBuffer] = useState12("");
46043
+ const [cursorVisible, setCursorVisible] = useState12(true);
46044
+ useEffect10(() => {
44808
46045
  if (editMode) {
44809
46046
  setEditBuffer(String(value));
44810
46047
  }
44811
46048
  }, [editMode, value]);
44812
- useEffect8(() => {
46049
+ useEffect10(() => {
44813
46050
  if (!focus || !editMode) {
44814
46051
  setCursorVisible(false);
44815
46052
  return;
@@ -44830,7 +46067,7 @@ var NumberInput = ({
44830
46067
  }
44831
46068
  setEditMode(false);
44832
46069
  };
44833
- useInput5(
46070
+ useInput10(
44834
46071
  (input, key) => {
44835
46072
  if (!focus) return;
44836
46073
  if (key.escape) {
@@ -44901,38 +46138,38 @@ var NumberInput = ({
44901
46138
  const padding = " ".repeat(paddingLength);
44902
46139
  const atMin = value <= min;
44903
46140
  const atMax = value >= max;
44904
- return /* @__PURE__ */ jsxs11(Box12, { children: [
44905
- label && /* @__PURE__ */ jsx12(Box12, { marginRight: 1, children: /* @__PURE__ */ jsxs11(Text12, { children: [
46141
+ return /* @__PURE__ */ jsxs16(Box17, { children: [
46142
+ label && /* @__PURE__ */ jsx17(Box17, { marginRight: 1, children: /* @__PURE__ */ jsxs16(Text17, { children: [
44906
46143
  label,
44907
46144
  ":"
44908
46145
  ] }) }),
44909
- /* @__PURE__ */ jsxs11(Box12, { children: [
44910
- focus && !editMode && /* @__PURE__ */ jsx12(Text12, { color: atMin ? theme.muted : theme.primary, children: atMin ? " " : "\u25C0" }),
44911
- /* @__PURE__ */ jsx12(
44912
- Box12,
46146
+ /* @__PURE__ */ jsxs16(Box17, { children: [
46147
+ focus && !editMode && /* @__PURE__ */ jsx17(Text17, { color: atMin ? theme.muted : theme.primary, children: atMin ? " " : "\u25C0" }),
46148
+ /* @__PURE__ */ jsx17(
46149
+ Box17,
44913
46150
  {
44914
46151
  borderStyle: editMode ? "single" : void 0,
44915
46152
  borderColor: editMode ? theme.primary : void 0,
44916
46153
  marginX: focus && !editMode ? 1 : 0,
44917
- children: /* @__PURE__ */ jsxs11(Text12, { color: focus ? theme.primary : void 0, bold: focus, children: [
46154
+ children: /* @__PURE__ */ jsxs16(Text17, { color: focus ? theme.primary : void 0, bold: focus, children: [
44918
46155
  displayValue,
44919
- editMode && cursorVisible && /* @__PURE__ */ jsx12(Text12, { inverse: true, children: " " }),
44920
- suffix && /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: suffix }),
46156
+ editMode && cursorVisible && /* @__PURE__ */ jsx17(Text17, { inverse: true, children: " " }),
46157
+ suffix && /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: suffix }),
44921
46158
  padding
44922
46159
  ] })
44923
46160
  }
44924
46161
  ),
44925
- focus && !editMode && /* @__PURE__ */ jsx12(Text12, { color: atMax ? theme.muted : theme.primary, children: atMax ? " " : "\u25B6" })
46162
+ focus && !editMode && /* @__PURE__ */ jsx17(Text17, { color: atMax ? theme.muted : theme.primary, children: atMax ? " " : "\u25B6" })
44926
46163
  ] }),
44927
- focus && !editMode && /* @__PURE__ */ jsx12(Box12, { marginLeft: 1, children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "[\u2191/\u2193 or type]" }) }),
44928
- editMode && /* @__PURE__ */ jsx12(Box12, { marginLeft: 1, children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "[Enter to save, Esc to cancel]" }) })
46164
+ focus && !editMode && /* @__PURE__ */ jsx17(Box17, { marginLeft: 1, children: /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "[\u2191/\u2193 or type]" }) }),
46165
+ editMode && /* @__PURE__ */ jsx17(Box17, { marginLeft: 1, children: /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "[Enter to save, Esc to cancel]" }) })
44929
46166
  ] });
44930
46167
  };
44931
46168
 
44932
46169
  // src/tui/components/SelectInput.tsx
44933
- import { Box as Box13, Text as Text13, useInput as useInput6 } from "ink";
44934
- import { useMemo as useMemo3, useState as useState8 } from "react";
44935
- import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
46170
+ import { Box as Box18, Text as Text18, useInput as useInput11 } from "ink";
46171
+ import { useMemo as useMemo3, useState as useState13 } from "react";
46172
+ import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
44936
46173
  function SelectInput({
44937
46174
  options,
44938
46175
  value,
@@ -44945,12 +46182,12 @@ function SelectInput({
44945
46182
  maxVisible = 5,
44946
46183
  expanded: initialExpanded = false
44947
46184
  }) {
44948
- const [expanded, setExpanded] = useState8(initialExpanded);
44949
- const [highlightIndex, setHighlightIndex] = useState8(() => {
46185
+ const [expanded, setExpanded] = useState13(initialExpanded);
46186
+ const [highlightIndex, setHighlightIndex] = useState13(() => {
44950
46187
  const idx = options.findIndex((opt) => opt.value === value);
44951
46188
  return idx >= 0 ? idx : 0;
44952
46189
  });
44953
- const [filter, setFilter] = useState8("");
46190
+ const [filter, setFilter] = useState13("");
44954
46191
  const filteredOptions = useMemo3(() => {
44955
46192
  if (!filter) return options;
44956
46193
  const lowerFilter = filter.toLowerCase();
@@ -44970,7 +46207,7 @@ function SelectInput({
44970
46207
  );
44971
46208
  const selectedOption = options.find((opt) => opt.value === value);
44972
46209
  const displayLabel = selectedOption?.label ?? placeholder;
44973
- useInput6(
46210
+ useInput11(
44974
46211
  (input, key) => {
44975
46212
  if (!focus) return;
44976
46213
  if (!expanded) {
@@ -45047,23 +46284,23 @@ function SelectInput({
45047
46284
  },
45048
46285
  { isActive: focus }
45049
46286
  );
45050
- return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", children: [
45051
- /* @__PURE__ */ jsxs12(Box13, { children: [
45052
- label && /* @__PURE__ */ jsx13(Box13, { marginRight: 1, children: /* @__PURE__ */ jsxs12(Text13, { children: [
46287
+ return /* @__PURE__ */ jsxs17(Box18, { flexDirection: "column", children: [
46288
+ /* @__PURE__ */ jsxs17(Box18, { children: [
46289
+ label && /* @__PURE__ */ jsx18(Box18, { marginRight: 1, children: /* @__PURE__ */ jsxs17(Text18, { children: [
45053
46290
  label,
45054
46291
  ":"
45055
46292
  ] }) }),
45056
- /* @__PURE__ */ jsxs12(Box13, { children: [
45057
- /* @__PURE__ */ jsx13(Text13, { color: focus ? theme.primary : void 0, bold: focus, children: displayLabel }),
45058
- /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
46293
+ /* @__PURE__ */ jsxs17(Box18, { children: [
46294
+ /* @__PURE__ */ jsx18(Text18, { color: focus ? theme.primary : void 0, bold: focus, children: displayLabel }),
46295
+ /* @__PURE__ */ jsxs17(Text18, { dimColor: true, children: [
45059
46296
  " ",
45060
46297
  expanded ? "\u25B2" : "\u25BC"
45061
46298
  ] })
45062
46299
  ] }),
45063
- focus && !expanded && /* @__PURE__ */ jsx13(Box13, { marginLeft: 1, children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "[Enter to expand, \u2191/\u2193 to change]" }) })
46300
+ focus && !expanded && /* @__PURE__ */ jsx18(Box18, { marginLeft: 1, children: /* @__PURE__ */ jsx18(Text18, { dimColor: true, children: "[Enter to expand, \u2191/\u2193 to change]" }) })
45064
46301
  ] }),
45065
- expanded && /* @__PURE__ */ jsxs12(
45066
- Box13,
46302
+ expanded && /* @__PURE__ */ jsxs17(
46303
+ Box18,
45067
46304
  {
45068
46305
  flexDirection: "column",
45069
46306
  marginTop: 1,
@@ -45071,22 +46308,22 @@ function SelectInput({
45071
46308
  borderColor: theme.primary,
45072
46309
  paddingX: 1,
45073
46310
  children: [
45074
- filter && /* @__PURE__ */ jsxs12(Box13, { marginBottom: 1, children: [
45075
- /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "Filter: " }),
45076
- /* @__PURE__ */ jsx13(Text13, { color: theme.primary, children: filter })
46311
+ filter && /* @__PURE__ */ jsxs17(Box18, { marginBottom: 1, children: [
46312
+ /* @__PURE__ */ jsx18(Text18, { dimColor: true, children: "Filter: " }),
46313
+ /* @__PURE__ */ jsx18(Text18, { color: theme.primary, children: filter })
45077
46314
  ] }),
45078
- scrollOffset > 0 && /* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
46315
+ scrollOffset > 0 && /* @__PURE__ */ jsx18(Box18, { children: /* @__PURE__ */ jsxs17(Text18, { dimColor: true, children: [
45079
46316
  " \u2191 more (",
45080
46317
  scrollOffset,
45081
46318
  ")"
45082
46319
  ] }) }),
45083
- filteredOptions.length === 0 ? /* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "No matches" }) }) : visibleOptions.map((option, visibleIdx) => {
46320
+ filteredOptions.length === 0 ? /* @__PURE__ */ jsx18(Box18, { children: /* @__PURE__ */ jsx18(Text18, { dimColor: true, children: "No matches" }) }) : visibleOptions.map((option, visibleIdx) => {
45084
46321
  const actualIdx = scrollOffset + visibleIdx;
45085
46322
  const isHighlighted = actualIdx === highlightIndex;
45086
46323
  const isSelected = option.value === value;
45087
- return /* @__PURE__ */ jsxs12(Box13, { paddingY: 0, children: [
45088
- /* @__PURE__ */ jsxs12(
45089
- Text13,
46324
+ return /* @__PURE__ */ jsxs17(Box18, { paddingY: 0, children: [
46325
+ /* @__PURE__ */ jsxs17(
46326
+ Text18,
45090
46327
  {
45091
46328
  color: isHighlighted ? theme.primary : isSelected ? theme.success : void 0,
45092
46329
  bold: isHighlighted,
@@ -45097,18 +46334,18 @@ function SelectInput({
45097
46334
  ]
45098
46335
  }
45099
46336
  ),
45100
- option.description && /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
46337
+ option.description && /* @__PURE__ */ jsxs17(Text18, { dimColor: true, children: [
45101
46338
  " - ",
45102
46339
  option.description
45103
46340
  ] })
45104
46341
  ] }, String(option.value));
45105
46342
  }),
45106
- scrollOffset + maxVisible < filteredOptions.length && /* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
46343
+ scrollOffset + maxVisible < filteredOptions.length && /* @__PURE__ */ jsx18(Box18, { children: /* @__PURE__ */ jsxs17(Text18, { dimColor: true, children: [
45107
46344
  "\u2193 more (",
45108
46345
  filteredOptions.length - scrollOffset - maxVisible,
45109
46346
  ")"
45110
46347
  ] }) }),
45111
- /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "\u2191/\u2193 navigate \u2022 Enter select \u2022 Esc close \u2022 type to filter" }) })
46348
+ /* @__PURE__ */ jsx18(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx18(Text18, { dimColor: true, children: "\u2191/\u2193 navigate \u2022 Enter select \u2022 Esc close \u2022 type to filter" }) })
45112
46349
  ]
45113
46350
  }
45114
46351
  )
@@ -45116,9 +46353,9 @@ function SelectInput({
45116
46353
  }
45117
46354
 
45118
46355
  // src/tui/components/TextInput.tsx
45119
- import { Box as Box14, Text as Text14, useInput as useInput7 } from "ink";
45120
- import { useEffect as useEffect9, useState as useState9 } from "react";
45121
- import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
46356
+ import { Box as Box19, Text as Text19, useInput as useInput12 } from "ink";
46357
+ import { useEffect as useEffect11, useState as useState14 } from "react";
46358
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
45122
46359
  var TextInput = ({
45123
46360
  value,
45124
46361
  onChange,
@@ -45131,12 +46368,12 @@ var TextInput = ({
45131
46368
  focus = true,
45132
46369
  label
45133
46370
  }) => {
45134
- const [cursorPosition, setCursorPosition] = useState9(value.length);
45135
- const [cursorVisible, setCursorVisible] = useState9(true);
45136
- useEffect9(() => {
46371
+ const [cursorPosition, setCursorPosition] = useState14(value.length);
46372
+ const [cursorVisible, setCursorVisible] = useState14(true);
46373
+ useEffect11(() => {
45137
46374
  setCursorPosition(value.length);
45138
46375
  }, [value.length]);
45139
- useEffect9(() => {
46376
+ useEffect11(() => {
45140
46377
  if (!focus) {
45141
46378
  setCursorVisible(false);
45142
46379
  return;
@@ -45147,7 +46384,7 @@ var TextInput = ({
45147
46384
  setCursorVisible(true);
45148
46385
  return () => clearInterval(interval);
45149
46386
  }, [focus]);
45150
- useInput7(
46387
+ useInput12(
45151
46388
  (input, key) => {
45152
46389
  if (!focus) return;
45153
46390
  if (key.return) {
@@ -45203,29 +46440,29 @@ var TextInput = ({
45203
46440
  const paddingLength = Math.max(0, width - contentLength);
45204
46441
  const padding = " ".repeat(paddingLength);
45205
46442
  const showPlaceholder = value.length === 0 && placeholder;
45206
- return /* @__PURE__ */ jsxs13(Box14, { children: [
45207
- label && /* @__PURE__ */ jsx14(Box14, { marginRight: 1, children: /* @__PURE__ */ jsxs13(Text14, { children: [
46443
+ return /* @__PURE__ */ jsxs18(Box19, { children: [
46444
+ label && /* @__PURE__ */ jsx19(Box19, { marginRight: 1, children: /* @__PURE__ */ jsxs18(Text19, { children: [
45208
46445
  label,
45209
46446
  ":"
45210
46447
  ] }) }),
45211
- /* @__PURE__ */ jsx14(
45212
- Box14,
46448
+ /* @__PURE__ */ jsx19(
46449
+ Box19,
45213
46450
  {
45214
46451
  borderStyle: focus ? "single" : void 0,
45215
46452
  borderColor: focus ? theme.primary : void 0,
45216
46453
  paddingX: focus ? 0 : 0,
45217
- children: showPlaceholder && !focus ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: placeholder }) : /* @__PURE__ */ jsxs13(Text14, { children: [
45218
- /* @__PURE__ */ jsx14(Text14, { children: beforeCursor }),
45219
- /* @__PURE__ */ jsx14(
45220
- Text14,
46454
+ children: showPlaceholder && !focus ? /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: placeholder }) : /* @__PURE__ */ jsxs18(Text19, { children: [
46455
+ /* @__PURE__ */ jsx19(Text19, { children: beforeCursor }),
46456
+ /* @__PURE__ */ jsx19(
46457
+ Text19,
45221
46458
  {
45222
46459
  inverse: focus && cursorVisible,
45223
46460
  color: focus ? theme.primary : void 0,
45224
46461
  children: cursorChar
45225
46462
  }
45226
46463
  ),
45227
- /* @__PURE__ */ jsx14(Text14, { children: afterCursor }),
45228
- /* @__PURE__ */ jsx14(Text14, { children: padding })
46464
+ /* @__PURE__ */ jsx19(Text19, { children: afterCursor }),
46465
+ /* @__PURE__ */ jsx19(Text19, { children: padding })
45229
46466
  ] })
45230
46467
  }
45231
46468
  )
@@ -45233,7 +46470,7 @@ var TextInput = ({
45233
46470
  };
45234
46471
 
45235
46472
  // src/tui/hooks/useWorlds.ts
45236
- import { useCallback as useCallback4, useEffect as useEffect10 } from "react";
46473
+ import { useCallback as useCallback4, useEffect as useEffect12 } from "react";
45237
46474
  function useWorlds() {
45238
46475
  const worlds = useStore((s) => s.worlds.worlds);
45239
46476
  const loading = useStore((s) => s.worlds.loading);
@@ -45409,7 +46646,7 @@ function useWorlds() {
45409
46646
  }
45410
46647
 
45411
46648
  // src/tui/screens/Settings.tsx
45412
- import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
46649
+ import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
45413
46650
  var SECTION_LABELS = {
45414
46651
  server: "Server",
45415
46652
  modifiers: "Difficulty Modifiers",
@@ -45489,10 +46726,10 @@ var Settings = () => {
45489
46726
  const editingField = useStore((s) => s.ui.editingField);
45490
46727
  const setEditingField = useStore((s) => s.actions.setEditingField);
45491
46728
  const addLog = useStore((s) => s.actions.addLog);
45492
- const [selectedIndex, setSelectedIndex] = useState10(0);
45493
- const [localValue, setLocalValue] = useState10("");
45494
- const [scrollOffset, setScrollOffset] = useState10(0);
45495
- const [expandedSections, setExpandedSections] = useState10(
46729
+ const [selectedIndex, setSelectedIndex] = useState15(0);
46730
+ const [localValue, setLocalValue] = useState15("");
46731
+ const [scrollOffset, setScrollOffset] = useState15(0);
46732
+ const [expandedSections, setExpandedSections] = useState15(
45496
46733
  () => /* @__PURE__ */ new Set(["server"])
45497
46734
  );
45498
46735
  const MAX_VISIBLE_ROWS = 15;
@@ -45856,7 +47093,7 @@ var Settings = () => {
45856
47093
  const cancelEdit = useCallback5(() => {
45857
47094
  setEditingField(null);
45858
47095
  }, [setEditingField]);
45859
- useInput8(
47096
+ useInput13(
45860
47097
  (input, key) => {
45861
47098
  if (isEditing) return;
45862
47099
  if (key.upArrow || input === "k") {
@@ -45912,14 +47149,14 @@ var Settings = () => {
45912
47149
  const itemCount = settings.filter(
45913
47150
  (s) => s.section === item.section
45914
47151
  ).length;
45915
- return /* @__PURE__ */ jsxs14(Box15, { flexShrink: 0, minHeight: 1, children: [
45916
- /* @__PURE__ */ jsx15(Text15, { color: isSelected ? theme.primary : void 0, children: isSelected ? "\u25B6 " : " " }),
45917
- /* @__PURE__ */ jsxs14(Text15, { bold: true, color: isSelected ? theme.primary : theme.secondary, children: [
47152
+ return /* @__PURE__ */ jsxs19(Box20, { flexShrink: 0, minHeight: 1, children: [
47153
+ /* @__PURE__ */ jsx20(Text20, { color: isSelected ? theme.primary : void 0, children: isSelected ? "\u25B6 " : " " }),
47154
+ /* @__PURE__ */ jsxs19(Text20, { bold: true, color: isSelected ? theme.primary : theme.secondary, children: [
45918
47155
  isExpanded ? "\u25BC" : "\u25B6",
45919
47156
  " ",
45920
47157
  item.label
45921
47158
  ] }),
45922
- /* @__PURE__ */ jsxs14(Text15, { dimColor: true, children: [
47159
+ /* @__PURE__ */ jsxs19(Text20, { dimColor: true, children: [
45923
47160
  " (",
45924
47161
  itemCount,
45925
47162
  ")"
@@ -45933,13 +47170,13 @@ var Settings = () => {
45933
47170
  switch (setting.type) {
45934
47171
  case "text":
45935
47172
  case "password":
45936
- return /* @__PURE__ */ jsxs14(Box15, { flexShrink: 0, minHeight: 1, children: [
45937
- /* @__PURE__ */ jsxs14(Text15, { color: theme.primary, children: [
47173
+ return /* @__PURE__ */ jsxs19(Box20, { flexShrink: 0, minHeight: 1, children: [
47174
+ /* @__PURE__ */ jsxs19(Text20, { color: theme.primary, children: [
45938
47175
  " \u25B6 ",
45939
47176
  setting.label,
45940
47177
  ": "
45941
47178
  ] }),
45942
- /* @__PURE__ */ jsx15(
47179
+ /* @__PURE__ */ jsx20(
45943
47180
  TextInput,
45944
47181
  {
45945
47182
  value: localValue,
@@ -45952,13 +47189,13 @@ var Settings = () => {
45952
47189
  )
45953
47190
  ] }, setting.key);
45954
47191
  case "number":
45955
- return /* @__PURE__ */ jsxs14(Box15, { flexShrink: 0, minHeight: 1, children: [
45956
- /* @__PURE__ */ jsxs14(Text15, { color: theme.primary, children: [
47192
+ return /* @__PURE__ */ jsxs19(Box20, { flexShrink: 0, minHeight: 1, children: [
47193
+ /* @__PURE__ */ jsxs19(Text20, { color: theme.primary, children: [
45957
47194
  " \u25B6 ",
45958
47195
  setting.label,
45959
47196
  ": "
45960
47197
  ] }),
45961
- /* @__PURE__ */ jsx15(
47198
+ /* @__PURE__ */ jsx20(
45962
47199
  NumberInput,
45963
47200
  {
45964
47201
  value: localValue,
@@ -45974,13 +47211,13 @@ var Settings = () => {
45974
47211
  )
45975
47212
  ] }, setting.key);
45976
47213
  case "select":
45977
- return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", flexShrink: 0, children: [
45978
- /* @__PURE__ */ jsx15(Box15, { flexShrink: 0, children: /* @__PURE__ */ jsxs14(Text15, { color: theme.primary, children: [
47214
+ return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", flexShrink: 0, children: [
47215
+ /* @__PURE__ */ jsx20(Box20, { flexShrink: 0, children: /* @__PURE__ */ jsxs19(Text20, { color: theme.primary, children: [
45979
47216
  " \u25B6 ",
45980
47217
  setting.label,
45981
47218
  ": "
45982
47219
  ] }) }),
45983
- /* @__PURE__ */ jsx15(Box15, { marginLeft: 4, children: /* @__PURE__ */ jsx15(
47220
+ /* @__PURE__ */ jsx20(Box20, { marginLeft: 4, children: /* @__PURE__ */ jsx20(
45984
47221
  SelectInput,
45985
47222
  {
45986
47223
  options: setting.options ?? [],
@@ -46003,15 +47240,15 @@ var Settings = () => {
46003
47240
  }
46004
47241
  }
46005
47242
  const displayValue = setting.type === "toggle" ? value ? "Yes" : "No" : setting.type === "password" ? value ? "********" : "(none)" : setting.type === "select" ? setting.options?.find((o) => o.value === value)?.label ?? value : `${value}${setting.suffix ?? ""}`;
46006
- return /* @__PURE__ */ jsxs14(Box15, { flexShrink: 0, minHeight: 1, children: [
46007
- /* @__PURE__ */ jsx15(Text15, { color: isSelected ? theme.primary : void 0, children: isSelected ? " \u25B6 " : " " }),
46008
- /* @__PURE__ */ jsxs14(Text15, { bold: isSelected, color: isSelected ? theme.primary : void 0, children: [
47243
+ return /* @__PURE__ */ jsxs19(Box20, { flexShrink: 0, minHeight: 1, children: [
47244
+ /* @__PURE__ */ jsx20(Text20, { color: isSelected ? theme.primary : void 0, children: isSelected ? " \u25B6 " : " " }),
47245
+ /* @__PURE__ */ jsxs19(Text20, { bold: isSelected, color: isSelected ? theme.primary : void 0, children: [
46009
47246
  setting.label,
46010
47247
  ":"
46011
47248
  ] }),
46012
- /* @__PURE__ */ jsx15(Text15, { children: " " }),
46013
- /* @__PURE__ */ jsx15(
46014
- Text15,
47249
+ /* @__PURE__ */ jsx20(Text20, { children: " " }),
47250
+ /* @__PURE__ */ jsx20(
47251
+ Text20,
46015
47252
  {
46016
47253
  color: setting.type === "toggle" ? value ? theme.success : theme.error : theme.secondary,
46017
47254
  children: displayValue
@@ -46019,36 +47256,36 @@ var Settings = () => {
46019
47256
  )
46020
47257
  ] }, setting.key);
46021
47258
  };
46022
- return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", flexGrow: 1, padding: 1, overflow: "hidden", children: [
46023
- /* @__PURE__ */ jsx15(Box15, { marginBottom: 1, flexShrink: 0, minHeight: 1, children: /* @__PURE__ */ jsx15(Text15, { bold: true, color: theme.primary, children: "\u2500 Settings \u2500" }) }),
46024
- /* @__PURE__ */ jsx15(Box15, { marginBottom: 1, flexShrink: 0, minHeight: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: isEditing ? "Enter to save, Esc to cancel" : "\u2191/\u2193 navigate \u2022 Enter expand/edit \u2022 Tab collapse all" }) }),
46025
- hasMoreAbove && /* @__PURE__ */ jsx15(Box15, { flexShrink: 0, minHeight: 1, children: /* @__PURE__ */ jsxs14(Text15, { dimColor: true, children: [
47259
+ return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", flexGrow: 1, padding: 1, overflow: "hidden", children: [
47260
+ /* @__PURE__ */ jsx20(Box20, { marginBottom: 1, flexShrink: 0, minHeight: 1, children: /* @__PURE__ */ jsx20(Text20, { bold: true, color: theme.primary, children: "\u2500 Settings \u2500" }) }),
47261
+ /* @__PURE__ */ jsx20(Box20, { marginBottom: 1, flexShrink: 0, minHeight: 1, children: /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: isEditing ? "Enter to save, Esc to cancel" : "\u2191/\u2193 navigate \u2022 Enter expand/edit \u2022 Tab collapse all" }) }),
47262
+ hasMoreAbove && /* @__PURE__ */ jsx20(Box20, { flexShrink: 0, minHeight: 1, children: /* @__PURE__ */ jsxs19(Text20, { dimColor: true, children: [
46026
47263
  " \u2191 ",
46027
47264
  scrollOffset,
46028
47265
  " more above"
46029
47266
  ] }) }),
46030
- /* @__PURE__ */ jsx15(Box15, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: visibleItems.map((item, visibleIdx) => {
47267
+ /* @__PURE__ */ jsx20(Box20, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: visibleItems.map((item, visibleIdx) => {
46031
47268
  const globalIndex = scrollOffset + visibleIdx;
46032
47269
  return renderNavItem(item, globalIndex);
46033
47270
  }) }),
46034
- hasMoreBelow && /* @__PURE__ */ jsx15(Box15, { flexShrink: 0, minHeight: 1, children: /* @__PURE__ */ jsxs14(Text15, { dimColor: true, children: [
47271
+ hasMoreBelow && /* @__PURE__ */ jsx20(Box20, { flexShrink: 0, minHeight: 1, children: /* @__PURE__ */ jsxs19(Text20, { dimColor: true, children: [
46035
47272
  " ",
46036
47273
  "\u2193 ",
46037
47274
  navItems.length - scrollOffset - MAX_VISIBLE_ROWS,
46038
47275
  " more below"
46039
47276
  ] }) }),
46040
- rcon.enabled && /* @__PURE__ */ jsxs14(Box15, { marginTop: 1, flexShrink: 0, minHeight: 1, children: [
46041
- /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "RCON Status: " }),
46042
- /* @__PURE__ */ jsx15(Text15, { color: rcon.connected ? theme.success : theme.error, children: rcon.connected ? "Connected" : "Disconnected" })
47277
+ rcon.enabled && /* @__PURE__ */ jsxs19(Box20, { marginTop: 1, flexShrink: 0, minHeight: 1, children: [
47278
+ /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "RCON Status: " }),
47279
+ /* @__PURE__ */ jsx20(Text20, { color: rcon.connected ? theme.success : theme.error, children: rcon.connected ? "Connected" : "Disconnected" })
46043
47280
  ] }),
46044
- /* @__PURE__ */ jsx15(Box15, { marginTop: 1, flexShrink: 0, minHeight: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "Note: Restart server for changes to take effect" }) })
47281
+ /* @__PURE__ */ jsx20(Box20, { marginTop: 1, flexShrink: 0, minHeight: 1, children: /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "Note: Restart server for changes to take effect" }) })
46045
47282
  ] });
46046
47283
  };
46047
47284
 
46048
47285
  // src/tui/screens/Worlds.tsx
46049
- import { Box as Box16, Text as Text16, useInput as useInput9 } from "ink";
46050
- import { useCallback as useCallback6, useEffect as useEffect11, useState as useState11 } from "react";
46051
- import { Fragment, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
47286
+ import { Box as Box21, Text as Text21, useInput as useInput14 } from "ink";
47287
+ import { useCallback as useCallback6, useEffect as useEffect13, useState as useState16 } from "react";
47288
+ import { Fragment as Fragment5, jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
46052
47289
  function formatBytes2(bytes) {
46053
47290
  if (bytes === 0) return "0 B";
46054
47291
  const k = 1024;
@@ -46101,16 +47338,16 @@ var Worlds = () => {
46101
47338
  const serverStatus = useStore((s) => s.server.status);
46102
47339
  const worldGenerating = useStore((s) => s.server.worldGenerating);
46103
47340
  const setEditingField = useStore((s) => s.actions.setEditingField);
46104
- const [mode, setModeInternal] = useState11("list");
46105
- const [inputPath, setInputPath] = useState11("");
46106
- const [newWorldName, setNewWorldName] = useState11("");
46107
- const [newWorldSeed, setNewWorldSeed] = useState11("");
46108
- const [createStep, setCreateStep] = useState11("name");
46109
- const [loading, setLoading] = useState11(false);
46110
- const [operationStatus, setOperationStatus] = useState11("");
46111
- const [pendingConfigSelected, setPendingConfigSelected] = useState11(false);
46112
- const [prevServerStatus, setPrevServerStatus] = useState11(serverStatus);
46113
- const [prevWorldGenerating, setPrevWorldGenerating] = useState11(worldGenerating);
47341
+ const [mode, setModeInternal] = useState16("list");
47342
+ const [inputPath, setInputPath] = useState16("");
47343
+ const [newWorldName, setNewWorldName] = useState16("");
47344
+ const [newWorldSeed, setNewWorldSeed] = useState16("");
47345
+ const [createStep, setCreateStep] = useState16("name");
47346
+ const [loading, setLoading] = useState16(false);
47347
+ const [operationStatus, setOperationStatus] = useState16("");
47348
+ const [pendingConfigSelected, setPendingConfigSelected] = useState16(false);
47349
+ const [prevServerStatus, setPrevServerStatus] = useState16(serverStatus);
47350
+ const [prevWorldGenerating, setPrevWorldGenerating] = useState16(worldGenerating);
46114
47351
  const hasPendingConfig = config.world && !worlds.some((w) => w.name === config.world);
46115
47352
  const otherPendingWorlds = pendingWorldNames.filter(
46116
47353
  (name) => name !== config.world && !worlds.some((w) => w.name === name)
@@ -46123,10 +47360,10 @@ var Worlds = () => {
46123
47360
  },
46124
47361
  [setEditingField]
46125
47362
  );
46126
- useEffect11(() => {
47363
+ useEffect13(() => {
46127
47364
  refresh();
46128
47365
  }, [refresh]);
46129
- useEffect11(() => {
47366
+ useEffect13(() => {
46130
47367
  if (prevServerStatus !== "online" && serverStatus === "online") {
46131
47368
  const timer = setTimeout(() => {
46132
47369
  refresh();
@@ -46136,14 +47373,14 @@ var Worlds = () => {
46136
47373
  }
46137
47374
  setPrevServerStatus(serverStatus);
46138
47375
  }, [serverStatus, prevServerStatus, refresh, addLog]);
46139
- useEffect11(() => {
47376
+ useEffect13(() => {
46140
47377
  if (prevWorldGenerating && !worldGenerating) {
46141
47378
  refresh();
46142
47379
  addLog("info", "Refreshed worlds list after world generation completed");
46143
47380
  }
46144
47381
  setPrevWorldGenerating(worldGenerating);
46145
47382
  }, [worldGenerating, prevWorldGenerating, refresh, addLog]);
46146
- useEffect11(() => {
47383
+ useEffect13(() => {
46147
47384
  if (!hasPendingConfig && pendingConfigSelected) {
46148
47385
  setPendingConfigSelected(false);
46149
47386
  }
@@ -46290,7 +47527,7 @@ var Worlds = () => {
46290
47527
  },
46291
47528
  [closeModal, getSelectedWorld, config.world, deleteWorld2, refresh, addLog]
46292
47529
  );
46293
- useInput9(
47530
+ useInput14(
46294
47531
  (input, key) => {
46295
47532
  if (modalOpen || loading) return;
46296
47533
  if (key.upArrow || input === "k") {
@@ -46343,7 +47580,7 @@ var Worlds = () => {
46343
47580
  const world = getSelectedWorld();
46344
47581
  if (world && world.name !== config.world) {
46345
47582
  openModal(
46346
- /* @__PURE__ */ jsx16(
47583
+ /* @__PURE__ */ jsx21(
46347
47584
  DeleteWorldModal,
46348
47585
  {
46349
47586
  worldName: world.name,
@@ -46408,27 +47645,27 @@ var Worlds = () => {
46408
47645
  handleBackup
46409
47646
  ]);
46410
47647
  if (worldsLoading && worlds.length === 0) {
46411
- return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
46412
- /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { bold: true, color: theme.primary, children: "\u2500 Worlds \u2500" }) }),
46413
- /* @__PURE__ */ jsx16(Spinner, { label: "Loading worlds..." })
47648
+ return /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
47649
+ /* @__PURE__ */ jsx21(Box21, { marginBottom: 1, children: /* @__PURE__ */ jsx21(Text21, { bold: true, color: theme.primary, children: "\u2500 Worlds \u2500" }) }),
47650
+ /* @__PURE__ */ jsx21(Spinner, { label: "Loading worlds..." })
46414
47651
  ] });
46415
47652
  }
46416
47653
  if (error2 && worlds.length === 0) {
46417
- return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
46418
- /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { bold: true, color: theme.primary, children: "\u2500 Worlds \u2500" }) }),
46419
- /* @__PURE__ */ jsxs15(Text16, { color: theme.error, children: [
47654
+ return /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
47655
+ /* @__PURE__ */ jsx21(Box21, { marginBottom: 1, children: /* @__PURE__ */ jsx21(Text21, { bold: true, color: theme.primary, children: "\u2500 Worlds \u2500" }) }),
47656
+ /* @__PURE__ */ jsxs20(Text21, { color: theme.error, children: [
46420
47657
  "Error: ",
46421
47658
  error2
46422
47659
  ] }),
46423
- /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Press R to retry" }) })
47660
+ /* @__PURE__ */ jsx21(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Press R to retry" }) })
46424
47661
  ] });
46425
47662
  }
46426
47663
  if (mode === "create") {
46427
- return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
46428
- /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { bold: true, color: theme.primary, children: "\u2500 Create New World \u2500" }) }),
46429
- loading ? /* @__PURE__ */ jsx16(Spinner, { label: operationStatus }) : createStep === "name" ? /* @__PURE__ */ jsxs15(Fragment, { children: [
46430
- /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { children: "Enter a name for your new world:" }) }),
46431
- /* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsx16(
47664
+ return /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
47665
+ /* @__PURE__ */ jsx21(Box21, { marginBottom: 1, children: /* @__PURE__ */ jsx21(Text21, { bold: true, color: theme.primary, children: "\u2500 Create New World \u2500" }) }),
47666
+ loading ? /* @__PURE__ */ jsx21(Spinner, { label: operationStatus }) : createStep === "name" ? /* @__PURE__ */ jsxs20(Fragment5, { children: [
47667
+ /* @__PURE__ */ jsx21(Box21, { marginBottom: 1, children: /* @__PURE__ */ jsx21(Text21, { children: "Enter a name for your new world:" }) }),
47668
+ /* @__PURE__ */ jsx21(Box21, { children: /* @__PURE__ */ jsx21(
46432
47669
  TextInput,
46433
47670
  {
46434
47671
  value: newWorldName,
@@ -46439,14 +47676,14 @@ var Worlds = () => {
46439
47676
  focus: true
46440
47677
  }
46441
47678
  ) }),
46442
- /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Enter to continue, Esc to cancel" }) })
46443
- ] }) : /* @__PURE__ */ jsxs15(Fragment, { children: [
46444
- /* @__PURE__ */ jsxs15(Box16, { marginBottom: 1, children: [
46445
- /* @__PURE__ */ jsx16(Text16, { children: "World: " }),
46446
- /* @__PURE__ */ jsx16(Text16, { color: theme.primary, bold: true, children: newWorldName })
47679
+ /* @__PURE__ */ jsx21(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Enter to continue, Esc to cancel" }) })
47680
+ ] }) : /* @__PURE__ */ jsxs20(Fragment5, { children: [
47681
+ /* @__PURE__ */ jsxs20(Box21, { marginBottom: 1, children: [
47682
+ /* @__PURE__ */ jsx21(Text21, { children: "World: " }),
47683
+ /* @__PURE__ */ jsx21(Text21, { color: theme.primary, bold: true, children: newWorldName })
46447
47684
  ] }),
46448
- /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { children: "Enter a seed (optional, leave empty for random):" }) }),
46449
- /* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsx16(
47685
+ /* @__PURE__ */ jsx21(Box21, { marginBottom: 1, children: /* @__PURE__ */ jsx21(Text21, { children: "Enter a seed (optional, leave empty for random):" }) }),
47686
+ /* @__PURE__ */ jsx21(Box21, { children: /* @__PURE__ */ jsx21(
46450
47687
  TextInput,
46451
47688
  {
46452
47689
  value: newWorldSeed,
@@ -46457,26 +47694,26 @@ var Worlds = () => {
46457
47694
  focus: true
46458
47695
  }
46459
47696
  ) }),
46460
- /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Enter to create world, Esc to cancel" }) }),
46461
- /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: "Note: Start the server to generate the world files" }) })
47697
+ /* @__PURE__ */ jsx21(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Enter to create world, Esc to cancel" }) }),
47698
+ /* @__PURE__ */ jsx21(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text21, { color: theme.warning, children: "Note: Start the server to generate the world files" }) })
46462
47699
  ] })
46463
47700
  ] });
46464
47701
  }
46465
47702
  if (mode !== "list") {
46466
47703
  const modeTitle = mode === "import" ? "Import World" : mode === "export" ? "Export World" : "Backup World";
46467
47704
  const modeHint = mode === "import" ? "Enter path to world folder or .db file" : mode === "export" ? `Export "${selectedWorld}" to path` : `Backup "${selectedWorld}" to path`;
46468
- return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
46469
- /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsxs15(Text16, { bold: true, color: theme.primary, children: [
47705
+ return /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
47706
+ /* @__PURE__ */ jsx21(Box21, { marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text21, { bold: true, color: theme.primary, children: [
46470
47707
  "\u2500 ",
46471
47708
  modeTitle,
46472
47709
  " \u2500"
46473
47710
  ] }) }),
46474
- loading ? /* @__PURE__ */ jsx16(Spinner, { label: operationStatus }) : /* @__PURE__ */ jsxs15(Fragment, { children: [
46475
- /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsxs15(Text16, { children: [
47711
+ loading ? /* @__PURE__ */ jsx21(Spinner, { label: operationStatus }) : /* @__PURE__ */ jsxs20(Fragment5, { children: [
47712
+ /* @__PURE__ */ jsx21(Box21, { marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text21, { children: [
46476
47713
  modeHint,
46477
47714
  ":"
46478
47715
  ] }) }),
46479
- /* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsx16(
47716
+ /* @__PURE__ */ jsx21(Box21, { children: /* @__PURE__ */ jsx21(
46480
47717
  TextInput,
46481
47718
  {
46482
47719
  value: inputPath,
@@ -46487,19 +47724,19 @@ var Worlds = () => {
46487
47724
  focus: true
46488
47725
  }
46489
47726
  ) }),
46490
- /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Enter to confirm, Esc to cancel" }) })
47727
+ /* @__PURE__ */ jsx21(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Enter to confirm, Esc to cancel" }) })
46491
47728
  ] })
46492
47729
  ] });
46493
47730
  }
46494
- return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", flexGrow: 1, padding: 1, overflow: "hidden", children: [
46495
- /* @__PURE__ */ jsxs15(Box16, { marginBottom: 1, children: [
46496
- /* @__PURE__ */ jsx16(Text16, { bold: true, color: theme.primary, children: "\u2500 Worlds \u2500" }),
46497
- worldsLoading && /* @__PURE__ */ jsx16(Spinner, {})
47731
+ return /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", flexGrow: 1, padding: 1, overflow: "hidden", children: [
47732
+ /* @__PURE__ */ jsxs20(Box21, { marginBottom: 1, children: [
47733
+ /* @__PURE__ */ jsx21(Text21, { bold: true, color: theme.primary, children: "\u2500 Worlds \u2500" }),
47734
+ worldsLoading && /* @__PURE__ */ jsx21(Spinner, {})
46498
47735
  ] }),
46499
- /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "\u2191/\u2193 Navigate | Enter Set Active | N New | I Import | E Export | B Backup | D Delete | R Refresh" }) }),
46500
- /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", overflow: "hidden", children: [
46501
- hasPendingConfig && /* @__PURE__ */ jsxs15(
46502
- Box16,
47736
+ /* @__PURE__ */ jsx21(Box21, { marginBottom: 1, children: /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "\u2191/\u2193 Navigate | Enter Set Active | N New | I Import | E Export | B Backup | D Delete | R Refresh" }) }),
47737
+ /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", overflow: "hidden", children: [
47738
+ hasPendingConfig && /* @__PURE__ */ jsxs20(
47739
+ Box21,
46503
47740
  {
46504
47741
  flexDirection: "column",
46505
47742
  flexShrink: 0,
@@ -46508,33 +47745,33 @@ var Worlds = () => {
46508
47745
  paddingX: pendingConfigSelected || worlds.length === 0 ? 1 : 0,
46509
47746
  marginBottom: 1,
46510
47747
  children: [
46511
- /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
46512
- /* @__PURE__ */ jsx16(
46513
- Text16,
47748
+ /* @__PURE__ */ jsxs20(Box21, { flexShrink: 0, children: [
47749
+ /* @__PURE__ */ jsx21(
47750
+ Text21,
46514
47751
  {
46515
47752
  color: pendingConfigSelected ? theme.primary : void 0,
46516
47753
  bold: true,
46517
47754
  children: config.world
46518
47755
  }
46519
47756
  ),
46520
- /* @__PURE__ */ jsx16(Text16, { color: theme.success, children: " (Active)" }),
46521
- worldGenerating ? /* @__PURE__ */ jsxs15(Box16, { marginLeft: 1, children: [
46522
- /* @__PURE__ */ jsx16(Spinner, {}),
46523
- /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: " Generating..." })
46524
- ] }) : serverStatus === "starting" ? /* @__PURE__ */ jsxs15(Box16, { marginLeft: 1, children: [
46525
- /* @__PURE__ */ jsx16(Spinner, {}),
46526
- /* @__PURE__ */ jsx16(Text16, { color: theme.info, children: " Server starting..." })
46527
- ] }) : /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: " - Not generated" })
47757
+ /* @__PURE__ */ jsx21(Text21, { color: theme.success, children: " (Active)" }),
47758
+ worldGenerating ? /* @__PURE__ */ jsxs20(Box21, { marginLeft: 1, children: [
47759
+ /* @__PURE__ */ jsx21(Spinner, {}),
47760
+ /* @__PURE__ */ jsx21(Text21, { color: theme.warning, children: " Generating..." })
47761
+ ] }) : serverStatus === "starting" ? /* @__PURE__ */ jsxs20(Box21, { marginLeft: 1, children: [
47762
+ /* @__PURE__ */ jsx21(Spinner, {}),
47763
+ /* @__PURE__ */ jsx21(Text21, { color: theme.info, children: " Server starting..." })
47764
+ ] }) : /* @__PURE__ */ jsx21(Text21, { color: theme.warning, children: " - Not generated" })
46528
47765
  ] }),
46529
- /* @__PURE__ */ jsx16(Box16, { marginLeft: 2, flexShrink: 0, children: worldGenerating ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "New world is being generated (this may take ~1 minute)" }) : /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Start the server to generate this world" }) })
47766
+ /* @__PURE__ */ jsx21(Box21, { marginLeft: 2, flexShrink: 0, children: worldGenerating ? /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "New world is being generated (this may take ~1 minute)" }) : /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Start the server to generate this world" }) })
46530
47767
  ]
46531
47768
  }
46532
47769
  ),
46533
- worlds.length === 0 && !config.world ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "No worlds found. Press N to create one." }) : worlds.map((world) => {
47770
+ worlds.length === 0 && !config.world ? /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "No worlds found. Press N to create one." }) : worlds.map((world) => {
46534
47771
  const isSelected = world.name === selectedWorld;
46535
47772
  const isActive = world.name === config.world;
46536
- return /* @__PURE__ */ jsxs15(
46537
- Box16,
47773
+ return /* @__PURE__ */ jsxs20(
47774
+ Box21,
46538
47775
  {
46539
47776
  flexDirection: "column",
46540
47777
  flexShrink: 0,
@@ -46543,11 +47780,11 @@ var Worlds = () => {
46543
47780
  paddingX: isSelected ? 1 : 0,
46544
47781
  marginBottom: 1,
46545
47782
  children: [
46546
- /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
46547
- /* @__PURE__ */ jsx16(Text16, { color: isSelected ? theme.primary : void 0, bold: true, children: world.name }),
46548
- isActive && /* @__PURE__ */ jsx16(Text16, { color: theme.success, children: " (Active)" }),
46549
- world.pendingSave && /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: " - Pending Save" }),
46550
- world.backups && world.backups.length > 0 && /* @__PURE__ */ jsxs15(Text16, { color: theme.info, children: [
47783
+ /* @__PURE__ */ jsxs20(Box21, { flexShrink: 0, children: [
47784
+ /* @__PURE__ */ jsx21(Text21, { color: isSelected ? theme.primary : void 0, bold: true, children: world.name }),
47785
+ isActive && /* @__PURE__ */ jsx21(Text21, { color: theme.success, children: " (Active)" }),
47786
+ world.pendingSave && /* @__PURE__ */ jsx21(Text21, { color: theme.warning, children: " - Pending Save" }),
47787
+ world.backups && world.backups.length > 0 && /* @__PURE__ */ jsxs20(Text21, { color: theme.info, children: [
46551
47788
  " ",
46552
47789
  "[",
46553
47790
  world.backups.length,
@@ -46556,27 +47793,27 @@ var Worlds = () => {
46556
47793
  "]"
46557
47794
  ] })
46558
47795
  ] }),
46559
- /* @__PURE__ */ jsx16(Box16, { marginLeft: 2, flexShrink: 0, children: world.pendingSave ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "World generated but not yet saved to disk" }) : /* @__PURE__ */ jsxs15(Fragment, { children: [
46560
- /* @__PURE__ */ jsxs15(Text16, { dimColor: true, children: [
47796
+ /* @__PURE__ */ jsx21(Box21, { marginLeft: 2, flexShrink: 0, children: world.pendingSave ? /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "World generated but not yet saved to disk" }) : /* @__PURE__ */ jsxs20(Fragment5, { children: [
47797
+ /* @__PURE__ */ jsxs20(Text21, { dimColor: true, children: [
46561
47798
  "Size: ",
46562
47799
  formatBytes2(world.size)
46563
47800
  ] }),
46564
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: " | " }),
46565
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: getSourceLabel(world.source) })
47801
+ /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: " | " }),
47802
+ /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: getSourceLabel(world.source) })
46566
47803
  ] }) }),
46567
- !world.pendingSave && /* @__PURE__ */ jsx16(Box16, { marginLeft: 2, flexShrink: 0, children: /* @__PURE__ */ jsxs15(Text16, { dimColor: true, children: [
47804
+ !world.pendingSave && /* @__PURE__ */ jsx21(Box21, { marginLeft: 2, flexShrink: 0, children: /* @__PURE__ */ jsxs20(Text21, { dimColor: true, children: [
46568
47805
  "Modified: ",
46569
47806
  formatDate(world.modified)
46570
47807
  ] }) }),
46571
- isSelected && world.backups && world.backups.length > 0 && /* @__PURE__ */ jsxs15(Box16, { marginLeft: 2, flexDirection: "column", flexShrink: 0, children: [
46572
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Backups:" }),
46573
- world.backups.slice(0, 3).map((backup) => /* @__PURE__ */ jsx16(Box16, { marginLeft: 2, children: /* @__PURE__ */ jsxs15(Text16, { dimColor: true, children: [
47808
+ isSelected && world.backups && world.backups.length > 0 && /* @__PURE__ */ jsxs20(Box21, { marginLeft: 2, flexDirection: "column", flexShrink: 0, children: [
47809
+ /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Backups:" }),
47810
+ world.backups.slice(0, 3).map((backup) => /* @__PURE__ */ jsx21(Box21, { marginLeft: 2, children: /* @__PURE__ */ jsxs20(Text21, { dimColor: true, children: [
46574
47811
  "\u2022",
46575
47812
  " ",
46576
47813
  formatBackupTimestamp(backup.backupTimestamp ?? ""),
46577
47814
  backup.pendingSave ? " (pending)" : ` (${formatBytes2(backup.size)})`
46578
47815
  ] }) }, backup.name)),
46579
- world.backups.length > 3 && /* @__PURE__ */ jsx16(Box16, { marginLeft: 2, children: /* @__PURE__ */ jsxs15(Text16, { dimColor: true, children: [
47816
+ world.backups.length > 3 && /* @__PURE__ */ jsx21(Box21, { marginLeft: 2, children: /* @__PURE__ */ jsxs20(Text21, { dimColor: true, children: [
46580
47817
  "... and ",
46581
47818
  world.backups.length - 3,
46582
47819
  " more"
@@ -46587,30 +47824,30 @@ var Worlds = () => {
46587
47824
  world.name
46588
47825
  );
46589
47826
  }),
46590
- otherPendingWorlds.map((name) => /* @__PURE__ */ jsxs15(
46591
- Box16,
47827
+ otherPendingWorlds.map((name) => /* @__PURE__ */ jsxs20(
47828
+ Box21,
46592
47829
  {
46593
47830
  flexDirection: "column",
46594
47831
  flexShrink: 0,
46595
47832
  marginBottom: 1,
46596
47833
  children: [
46597
- /* @__PURE__ */ jsxs15(Box16, { flexShrink: 0, children: [
46598
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: name }),
46599
- /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: " - Not generated" })
47834
+ /* @__PURE__ */ jsxs20(Box21, { flexShrink: 0, children: [
47835
+ /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: name }),
47836
+ /* @__PURE__ */ jsx21(Text21, { color: theme.warning, children: " - Not generated" })
46600
47837
  ] }),
46601
- /* @__PURE__ */ jsx16(Box16, { marginLeft: 2, flexShrink: 0, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Set as active and start the server to generate" }) })
47838
+ /* @__PURE__ */ jsx21(Box21, { marginLeft: 2, flexShrink: 0, children: /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Set as active and start the server to generate" }) })
46602
47839
  ]
46603
47840
  },
46604
47841
  `pending-${name}`
46605
47842
  ))
46606
47843
  ] }),
46607
- operationStatus && /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: operationStatus }) }),
46608
- serverStatus !== "offline" && /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { color: theme.warning, children: "Stop the server to change or delete worlds" }) })
47844
+ operationStatus && /* @__PURE__ */ jsx21(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: operationStatus }) }),
47845
+ serverStatus !== "offline" && /* @__PURE__ */ jsx21(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text21, { color: theme.warning, children: "Stop the server to change or delete worlds" }) })
46609
47846
  ] });
46610
47847
  };
46611
47848
 
46612
47849
  // src/tui/App.tsx
46613
- import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
47850
+ import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
46614
47851
  var screens = {
46615
47852
  dashboard: Dashboard,
46616
47853
  settings: Settings,
@@ -46627,11 +47864,11 @@ var App = () => {
46627
47864
  const openModal = useStore((s) => s.actions.openModal);
46628
47865
  const addLog = useStore((s) => s.actions.addLog);
46629
47866
  useConfigSync();
46630
- useEffect12(() => {
47867
+ useEffect14(() => {
46631
47868
  addLog("info", "TUI started");
46632
47869
  addLog("info", "Press 1-4 to navigate, ? for help, Q to quit");
46633
47870
  }, [addLog]);
46634
- useInput10((input, key) => {
47871
+ useInput15((input, key) => {
46635
47872
  if (modalOpen || editingField) return;
46636
47873
  if (input === "q" || input === "Q" || key.ctrl && input === "c") {
46637
47874
  addLog("info", "Shutting down...");
@@ -46640,7 +47877,7 @@ var App = () => {
46640
47877
  return;
46641
47878
  }
46642
47879
  if (input === "?") {
46643
- openModal(/* @__PURE__ */ jsx17(HelpOverlay, {}));
47880
+ openModal(/* @__PURE__ */ jsx22(HelpOverlay, {}));
46644
47881
  return;
46645
47882
  }
46646
47883
  if (input === "1") setScreen("dashboard");
@@ -46649,25 +47886,25 @@ var App = () => {
46649
47886
  if (input === "4") setScreen("console");
46650
47887
  });
46651
47888
  const ScreenComponent = screens[activeScreen] ?? Dashboard;
46652
- return /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", height: "100%", width: "100%", children: [
46653
- /* @__PURE__ */ jsx17(Header, {}),
46654
- /* @__PURE__ */ jsxs16(Box17, { flexGrow: 1, flexDirection: "row", height: "100%", children: [
46655
- /* @__PURE__ */ jsx17(Menu, {}),
46656
- /* @__PURE__ */ jsx17(
46657
- Box17,
47889
+ return /* @__PURE__ */ jsxs21(Box22, { flexDirection: "column", height: "100%", width: "100%", children: [
47890
+ /* @__PURE__ */ jsx22(Header, {}),
47891
+ /* @__PURE__ */ jsxs21(Box22, { flexGrow: 1, flexDirection: "row", height: "100%", children: [
47892
+ /* @__PURE__ */ jsx22(Menu, {}),
47893
+ /* @__PURE__ */ jsx22(
47894
+ Box22,
46658
47895
  {
46659
47896
  flexGrow: 1,
46660
47897
  borderStyle: "single",
46661
47898
  borderColor: theme.muted,
46662
47899
  flexDirection: "column",
46663
47900
  height: "100%",
46664
- children: /* @__PURE__ */ jsx17(ScreenComponent, {})
47901
+ children: /* @__PURE__ */ jsx22(ScreenComponent, {})
46665
47902
  }
46666
47903
  )
46667
47904
  ] }),
46668
- /* @__PURE__ */ jsx17(LogFeed, {}),
46669
- modalOpen && modalContent && /* @__PURE__ */ jsx17(
46670
- Box17,
47905
+ /* @__PURE__ */ jsx22(LogFeed, {}),
47906
+ modalOpen && modalContent && /* @__PURE__ */ jsx22(
47907
+ Box22,
46671
47908
  {
46672
47909
  position: "absolute",
46673
47910
  flexDirection: "column",
@@ -46685,20 +47922,20 @@ var App = () => {
46685
47922
  // src/tui/components/PathInput.tsx
46686
47923
  import fs10 from "fs/promises";
46687
47924
  import path8 from "path";
46688
- import { Box as Box18, Text as Text17, useInput as useInput11 } from "ink";
46689
- import { useEffect as useEffect13, useState as useState12 } from "react";
46690
- import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
47925
+ import { Box as Box23, Text as Text22, useInput as useInput16 } from "ink";
47926
+ import { useEffect as useEffect15, useState as useState17 } from "react";
47927
+ import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
46691
47928
 
46692
47929
  // src/tui/components/StatusBar.tsx
46693
- import { Box as Box19, Text as Text18 } from "ink";
46694
- import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
47930
+ import { Box as Box24, Text as Text23 } from "ink";
47931
+ import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
46695
47932
 
46696
47933
  // src/tui/components/Toggle.tsx
46697
- import { Box as Box20, Text as Text19, useInput as useInput12 } from "ink";
46698
- import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
47934
+ import { Box as Box25, Text as Text24, useInput as useInput17 } from "ink";
47935
+ import { jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
46699
47936
 
46700
47937
  // src/tui/hooks/useLogs.ts
46701
- import { useCallback as useCallback7, useEffect as useEffect14 } from "react";
47938
+ import { useCallback as useCallback7, useEffect as useEffect16 } from "react";
46702
47939
 
46703
47940
  // src/tui/mod.ts
46704
47941
  function launchTui() {
@@ -46706,7 +47943,7 @@ function launchTui() {
46706
47943
  }
46707
47944
 
46708
47945
  // src/mod.ts
46709
- var VERSION2 = "1.6.1";
47946
+ var VERSION2 = "1.8.0";
46710
47947
  var APP_NAME = "Land of OZ - Valheim DSM";
46711
47948
 
46712
47949
  // main.ts