the-grid-cc 1.1.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.
@@ -0,0 +1,223 @@
1
+ """
2
+ Status Display - Real-time Grid status visualization.
3
+
4
+ "I fight for the Users."
5
+ """
6
+
7
+ from typing import Optional, TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from core.grid import Grid
11
+ from core.cluster import Cluster
12
+ from core.block import Block
13
+ from core.thread import Thread
14
+ from core.program import Program
15
+ from core.energy import EnergyPool, EnergyLevel
16
+
17
+ # Import enums at runtime (they don't cause circular imports)
18
+ from core.thread import ThreadStatus
19
+ from core.energy import EnergyLevel
20
+
21
+
22
+ def render_cluster_status(cluster: "Cluster") -> str:
23
+ """
24
+ Render detailed Cluster status.
25
+
26
+ Returns formatted string showing Cluster with all Blocks and Threads.
27
+ """
28
+ WIDTH = 75
29
+
30
+ # Header with energy
31
+ energy_display = ""
32
+ if cluster.energy_pool:
33
+ energy_display = f"Energy: {cluster.energy_pool.remaining}"
34
+
35
+ # Calculate padding for header
36
+ header_content = f"CLUSTER: {cluster.name}"
37
+ padding = WIDTH - len(header_content) - len(energy_display) - 4
38
+
39
+ lines = [
40
+ "╔" + "═" * WIDTH + "╗",
41
+ f"║ {header_content}{' ' * padding}{energy_display} ║",
42
+ "╠" + "═" * WIDTH + "╣",
43
+ "║" + " " * WIDTH + "║",
44
+ ]
45
+
46
+ # Render each Block
47
+ for block_id in cluster.block_order:
48
+ block = cluster.blocks[block_id]
49
+ block_lines = render_block(block, WIDTH - 4)
50
+ for line in block_lines:
51
+ # Pad line to exact width
52
+ padded = line + " " * (WIDTH - 2 - len(line))
53
+ lines.append(f"║ {padded} ║")
54
+ lines.append("║" + " " * WIDTH + "║")
55
+
56
+ # I/O Tower checkpoints
57
+ for checkpoint in cluster.io_tower_checkpoints:
58
+ content = f"⛯ I/O TOWER: {checkpoint}"
59
+ padded = content + " " * (WIDTH - 2 - len(content))
60
+ lines.append(f"║ {padded} ║")
61
+
62
+ lines.append("║" + " " * WIDTH + "║")
63
+ lines.append("╚" + "═" * WIDTH + "╝")
64
+
65
+ return "\n".join(lines)
66
+
67
+
68
+ def render_block(block: "Block", width: int = 71) -> list[str]:
69
+ """Render a Block with its Threads."""
70
+ inner_width = width - 2 # Account for box chars
71
+
72
+ header_text = f"─ BLOCK: {block.name} "
73
+ header = "┌" + header_text + "─" * (inner_width - len(header_text)) + "┐"
74
+ lines = [header]
75
+
76
+ for thread_id in block.thread_order:
77
+ thread = block.threads[thread_id]
78
+ lines.append(render_thread_line(thread, inner_width))
79
+
80
+ lines.append("└" + "─" * inner_width + "┘")
81
+ return lines
82
+
83
+
84
+ def render_thread_line(thread: "Thread", width: int = 69) -> str:
85
+ """Render a single Thread status line."""
86
+ icon = thread.program_icon()
87
+ ptype = "Recognizer" if thread.program_type == "recognizer" else "Program"
88
+
89
+ if thread.status == ThreadStatus.BLOCKED:
90
+ action = f"Blocked by: {', '.join(thread.blocked_by[:2])}"
91
+ if len(thread.blocked_by) > 2:
92
+ action += "..."
93
+ else:
94
+ action = thread.current_action
95
+
96
+ # Truncate action if too long
97
+ if len(action) > 25:
98
+ action = action[:22] + "..."
99
+
100
+ progress = f"{thread.status_icon()} {thread.progress:.0f}%"
101
+
102
+ content = f" {icon} {thread.name:<14} {ptype:<10} {action:<25} {progress}"
103
+ # Pad to width
104
+ padded = content + " " * (width - len(content) - 1)
105
+ return f"│{padded}│"
106
+
107
+
108
+ def render_energy_flow(grid: "Grid") -> str:
109
+ """Render energy flow visualization."""
110
+ lines = [
111
+ "ENERGY FLOW",
112
+ "═" * 40,
113
+ grid.energy.grid_pool.summary(),
114
+ ]
115
+
116
+ # Show cluster pools
117
+ for pool_id, pool in grid.energy.pools.items():
118
+ if pool_id.startswith("cluster:"):
119
+ lines.append(f" └─ {pool.summary()}")
120
+
121
+ # Show block pools under this cluster
122
+ for block_id, block_pool in grid.energy.pools.items():
123
+ if block_id.startswith("block:") and block_pool.parent == pool:
124
+ lines.append(f" ├─ {block_pool.summary()}")
125
+
126
+ return "\n".join(lines)
127
+
128
+
129
+ def render_program_tree(program: "Program", indent: int = 0) -> list[str]:
130
+ """Render a Program and its children as a tree."""
131
+ prefix = " " * indent
132
+ icon = program.status_icon()
133
+
134
+ line = f"{prefix}{icon} {program.name}"
135
+ if program.disc.energy_allocated > 0:
136
+ energy_pct = program.energy_percentage()
137
+ line += f" [{energy_pct:.0f}%]"
138
+ line += f" - {program.current_action}"
139
+
140
+ lines = [line]
141
+
142
+ for child in program.children:
143
+ lines.extend(render_program_tree(child, indent + 1))
144
+
145
+ return lines
146
+
147
+
148
+ def render_grid_summary(grid: "Grid") -> str:
149
+ """Render Grid summary status."""
150
+ summary = grid.get_status_summary()
151
+
152
+ lines = [
153
+ "╔" + "═" * 50 + "╗",
154
+ "║ THE GRID - Status Summary" + " " * 23 + "║",
155
+ "╠" + "═" * 50 + "╣",
156
+ f"║ Status: {summary['status']:<29}║",
157
+ f"║ Clusters: {summary['clusters']:<29}║",
158
+ f"║ Active Programs: {summary['active_programs']:<29}║",
159
+ f"║ Programs Spawned: {summary['programs_spawned']:<29}║",
160
+ f"║ Programs Derezzed:{summary['programs_derezzed']:<29}║",
161
+ f"║ Cycles Completed: {summary['cycles_completed']:<29}║",
162
+ "╠" + "═" * 50 + "╣",
163
+ f"║ Energy Remaining: {summary['energy_remaining']:,} " + " " * 20 + "║",
164
+ f"║ Energy Consumed: {summary['energy_consumed']:,}" + " " * 20 + "║",
165
+ "╚" + "═" * 50 + "╝",
166
+ ]
167
+
168
+ return "\n".join(lines)
169
+
170
+
171
+ def render_controls() -> str:
172
+ """Render control key display."""
173
+ return """
174
+ [P] Pause [R] Resume [D] Disc (view context) [E] Energy status [Q] Quit
175
+ """.strip()
176
+
177
+
178
+ def render_full_status(grid: "Grid") -> str:
179
+ """Render full Grid status with all Clusters."""
180
+ lines = [grid.render_status()]
181
+
182
+ for cluster in grid.clusters.values():
183
+ lines.append("")
184
+ lines.append(render_cluster_status(cluster))
185
+
186
+ lines.append("")
187
+ lines.append(render_controls())
188
+
189
+ return "\n".join(lines)
190
+
191
+
192
+ def get_status_icon(status: str) -> str:
193
+ """Get icon for status string."""
194
+ icons = {
195
+ "pending": "○",
196
+ "running": "◐",
197
+ "blocked": "◌",
198
+ "completed": "●",
199
+ "failed": "✗",
200
+ "derezzed": "◯",
201
+ "initializing": "○",
202
+ "spawning": "◎",
203
+ "waiting": "◑",
204
+ }
205
+ return icons.get(status.lower(), "?")
206
+
207
+
208
+ def get_energy_level_color(level: EnergyLevel) -> str:
209
+ """Get ANSI color for energy level."""
210
+ colors = {
211
+ EnergyLevel.FULL: "\033[92m", # Green
212
+ EnergyLevel.NORMAL: "\033[94m", # Blue
213
+ EnergyLevel.LOW: "\033[93m", # Yellow
214
+ EnergyLevel.CRITICAL: "\033[91m", # Red
215
+ }
216
+ return colors.get(level, "")
217
+
218
+
219
+ def render_progress_bar(progress: float, width: int = 20, filled_char: str = "█", empty_char: str = "░") -> str:
220
+ """Render a progress bar."""
221
+ filled = int((progress / 100) * width)
222
+ empty = width - filled
223
+ return filled_char * filled + empty_char * empty
@@ -0,0 +1,101 @@
1
+ """
2
+ Welcome Screen - The Portal to The Grid.
3
+
4
+ "The Grid. A digital frontier."
5
+ """
6
+
7
+ from typing import Optional, TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from core.grid import Grid
11
+
12
+
13
+ WELCOME_BANNER = """
14
+ ╔═══════════════════════════════════════════════════════════════════════════╗
15
+ ║ ║
16
+ ║ ████████╗██╗ ██╗███████╗ ██████╗ ██████╗ ██╗██████╗ ║
17
+ ║ ╚══██╔══╝██║ ██║██╔════╝ ██╔════╝ ██╔══██╗██║██╔══██╗ ║
18
+ ║ ██║ ███████║█████╗ ██║ ███╗██████╔╝██║██║ ██║ ║
19
+ ║ ██║ ██╔══██║██╔══╝ ██║ ██║██╔══██╗██║██║ ██║ ║
20
+ ║ ██║ ██║ ██║███████╗ ╚██████╔╝██║ ██║██║██████╔╝ ║
21
+ ║ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝╚═════╝ ║
22
+ ║ ║
23
+ ║ « A Digital Frontier » ║
24
+ ║ ║
25
+ """
26
+
27
+
28
+ def render_welcome(grid: Optional["Grid"] = None) -> str:
29
+ """
30
+ Render the welcome screen.
31
+
32
+ Args:
33
+ grid: Optional existing Grid instance for status display
34
+
35
+ Returns:
36
+ Formatted welcome screen string
37
+ """
38
+ WIDTH = 75 # Inner width (between ║ chars)
39
+ lines = [WELCOME_BANNER.strip()]
40
+
41
+ # Status section
42
+ lines.append("╠" + "═" * WIDTH + "╣")
43
+ lines.append("║" + " " * WIDTH + "║")
44
+
45
+ if grid:
46
+ # Show existing Grid status
47
+ energy_bar = grid.get_energy_bar(20)
48
+ energy_pct = f"{grid.energy_percentage():.0f}%"
49
+ status_line = f" GRID STATUS {energy_bar} {energy_pct} Energy"
50
+ lines.append("║" + status_line + " " * (WIDTH - len(status_line)) + "║")
51
+ prog_line = f" Active Programs {len(grid.active_programs)}"
52
+ lines.append("║" + prog_line + " " * (WIDTH - len(prog_line)) + "║")
53
+ clust_line = f" Clusters {len(grid.clusters)}"
54
+ lines.append("║" + clust_line + " " * (WIDTH - len(clust_line)) + "║")
55
+ cyc_line = f" Cycles completed {grid.cycles_completed}"
56
+ lines.append("║" + cyc_line + " " * (WIDTH - len(cyc_line)) + "║")
57
+ else:
58
+ # Show empty Grid status
59
+ lines.append("║ GRID STATUS ████████████████████ 100% Energy ║")
60
+ lines.append("║ Active Programs 0 ║")
61
+ lines.append("║ Clusters 0 ║")
62
+ lines.append("║ Cycles completed 0 ║")
63
+
64
+ lines.append("║" + " " * WIDTH + "║")
65
+
66
+ # Input prompt section
67
+ lines.append("╠" + "═" * WIDTH + "╣")
68
+ lines.append("║" + " " * WIDTH + "║")
69
+ lines.append("║ What would you like to build? ║")
70
+ lines.append("║ ▸ _ ║")
71
+ lines.append("║" + " " * WIDTH + "║")
72
+ lines.append("║ Examples: ║")
73
+ lines.append("║ • \"a REST API for user authentication\" ║")
74
+ lines.append("║ • \"a CLI tool that converts markdown to PDF\" ║")
75
+ lines.append("║ • \"fix the bug in my login form\" ║")
76
+ lines.append("║" + " " * WIDTH + "║")
77
+ lines.append("╚" + "═" * WIDTH + "╝")
78
+
79
+ return "\n".join(lines)
80
+
81
+
82
+ def render_minimal_welcome() -> str:
83
+ """Render a minimal welcome banner."""
84
+ return """
85
+ ╔═══════════════════════════════════════════════════════════════════╗
86
+ ║ THE GRID « A Digital Frontier » ║
87
+ ╚═══════════════════════════════════════════════════════════════════╝
88
+ """.strip()
89
+
90
+
91
+ def render_goodbye() -> str:
92
+ """Render goodbye message."""
93
+ return """
94
+ ╔═══════════════════════════════════════════════════════════════════════════════╗
95
+ ║ ║
96
+ ║ End of Line ║
97
+ ║ ║
98
+ ║ The Grid thanks you, User. ║
99
+ ║ ║
100
+ ╚═══════════════════════════════════════════════════════════════════════════════╝
101
+ """.strip()