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.
- package/LICENSE +21 -0
- package/README.md +206 -0
- package/agents/grid-executor.md +62 -0
- package/agents/grid-guard.md +72 -0
- package/agents/grid-planner.md +70 -0
- package/agents/grid-recognizer.md +100 -0
- package/bin/install.js +276 -0
- package/cli/__init__.py +7 -0
- package/cli/main.py +385 -0
- package/commands/grid/VERSION +1 -0
- package/commands/grid/help.md +54 -0
- package/commands/grid/init.md +51 -0
- package/commands/grid/mcp.md +159 -0
- package/commands/grid.md +12 -0
- package/config/grid.yaml +46 -0
- package/core/__init__.py +45 -0
- package/core/block.py +207 -0
- package/core/cluster.py +228 -0
- package/core/disc.py +254 -0
- package/core/energy.py +267 -0
- package/core/grid.py +326 -0
- package/core/io_tower.py +242 -0
- package/core/program.py +268 -0
- package/core/recognizer.py +294 -0
- package/core/thread.py +180 -0
- package/package.json +37 -0
- package/templates/__init__.py +14 -0
- package/templates/status.py +223 -0
- package/templates/welcome.py +101 -0
|
@@ -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()
|