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
package/bin/install.js
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* THE GRID - Installer
|
|
5
|
+
*
|
|
6
|
+
* "The Grid. A digital frontier."
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx the-grid-cc # Interactive install
|
|
10
|
+
* npx the-grid-cc --global # Install globally
|
|
11
|
+
* npx the-grid-cc --local # Install in current directory
|
|
12
|
+
* npx the-grid-cc --uninstall # Remove The Grid
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const { execSync, spawn } = require('child_process');
|
|
18
|
+
const readline = require('readline');
|
|
19
|
+
|
|
20
|
+
// TRON Colors (for terminal output)
|
|
21
|
+
const CYAN = '\x1b[36m';
|
|
22
|
+
const YELLOW = '\x1b[33m';
|
|
23
|
+
const GREEN = '\x1b[32m';
|
|
24
|
+
const RED = '\x1b[31m';
|
|
25
|
+
const DIM = '\x1b[2m';
|
|
26
|
+
const RESET = '\x1b[0m';
|
|
27
|
+
const BOLD = '\x1b[1m';
|
|
28
|
+
|
|
29
|
+
const BANNER = `
|
|
30
|
+
${CYAN}+============================================================+
|
|
31
|
+
| |
|
|
32
|
+
| M A S T E R C O N T R O L P R O G R A M |
|
|
33
|
+
| |
|
|
34
|
+
| "I fight for the Users." |
|
|
35
|
+
| |
|
|
36
|
+
+============================================================+${RESET}
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
const REPO_URL = 'https://github.com/JamesWeatherhead/grid.git';
|
|
40
|
+
|
|
41
|
+
// Parse command line args
|
|
42
|
+
const args = process.argv.slice(2);
|
|
43
|
+
const flags = {
|
|
44
|
+
global: args.includes('--global') || args.includes('-g'),
|
|
45
|
+
local: args.includes('--local') || args.includes('-l'),
|
|
46
|
+
uninstall: args.includes('--uninstall') || args.includes('-u'),
|
|
47
|
+
help: args.includes('--help') || args.includes('-h'),
|
|
48
|
+
yes: args.includes('--yes') || args.includes('-y'),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
function log(msg, color = RESET) {
|
|
52
|
+
console.log(`${color}${msg}${RESET}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function logStep(step, msg) {
|
|
56
|
+
console.log(`${CYAN}[${step}]${RESET} ${msg}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function logSuccess(msg) {
|
|
60
|
+
console.log(`${GREEN}✓${RESET} ${msg}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function logError(msg) {
|
|
64
|
+
console.log(`${RED}✗${RESET} ${msg}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function showHelp() {
|
|
68
|
+
console.log(`
|
|
69
|
+
${BANNER}
|
|
70
|
+
|
|
71
|
+
${BOLD}Usage:${RESET}
|
|
72
|
+
npx the-grid-cc Install to Claude Code
|
|
73
|
+
npx the-grid-cc --uninstall Remove The Grid
|
|
74
|
+
|
|
75
|
+
${BOLD}Options:${RESET}
|
|
76
|
+
-u, --uninstall Uninstall The Grid
|
|
77
|
+
-y, --yes Skip confirmation prompts
|
|
78
|
+
-h, --help Show this help
|
|
79
|
+
|
|
80
|
+
${BOLD}After Installation:${RESET}
|
|
81
|
+
In Claude Code, type: /grid
|
|
82
|
+
|
|
83
|
+
${DIM}"I fight for the Users."${RESET}
|
|
84
|
+
`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function checkGit() {
|
|
88
|
+
try {
|
|
89
|
+
execSync('git --version', { stdio: 'pipe' });
|
|
90
|
+
return true;
|
|
91
|
+
} catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function copyDir(src, dest) {
|
|
97
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
98
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
99
|
+
for (const entry of entries) {
|
|
100
|
+
const srcPath = path.join(src, entry.name);
|
|
101
|
+
const destPath = path.join(dest, entry.name);
|
|
102
|
+
if (entry.isDirectory()) {
|
|
103
|
+
copyDir(srcPath, destPath);
|
|
104
|
+
} else {
|
|
105
|
+
fs.copyFileSync(srcPath, destPath);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function install() {
|
|
111
|
+
console.log(BANNER);
|
|
112
|
+
|
|
113
|
+
const home = process.env.HOME || process.env.USERPROFILE;
|
|
114
|
+
const claudeDir = path.join(home, '.claude');
|
|
115
|
+
const commandsDir = path.join(claudeDir, 'commands');
|
|
116
|
+
const agentsDir = path.join(claudeDir, 'agents');
|
|
117
|
+
const tempDir = path.join(home, '.grid-temp');
|
|
118
|
+
|
|
119
|
+
// Check prerequisites
|
|
120
|
+
logStep('1/4', 'Checking prerequisites...');
|
|
121
|
+
|
|
122
|
+
if (!checkGit()) {
|
|
123
|
+
logError('Git is required but not found.');
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
logSuccess('Git found');
|
|
127
|
+
|
|
128
|
+
// Ensure .claude directories exist
|
|
129
|
+
fs.mkdirSync(commandsDir, { recursive: true });
|
|
130
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
131
|
+
logSuccess('Claude Code directories ready');
|
|
132
|
+
|
|
133
|
+
// Clone to temp
|
|
134
|
+
logStep('2/4', 'Downloading The Grid...');
|
|
135
|
+
if (fs.existsSync(tempDir)) {
|
|
136
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
execSync(`git clone --depth 1 ${REPO_URL} "${tempDir}"`, {
|
|
141
|
+
stdio: 'pipe',
|
|
142
|
+
encoding: 'utf8'
|
|
143
|
+
});
|
|
144
|
+
logSuccess('Download complete');
|
|
145
|
+
} catch (error) {
|
|
146
|
+
logError('Failed to clone repository');
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Copy commands and agents
|
|
151
|
+
logStep('3/4', 'Installing to Claude Code...');
|
|
152
|
+
try {
|
|
153
|
+
const srcCommands = path.join(tempDir, 'commands');
|
|
154
|
+
const srcAgents = path.join(tempDir, 'agents');
|
|
155
|
+
|
|
156
|
+
// Copy commands
|
|
157
|
+
if (fs.existsSync(srcCommands)) {
|
|
158
|
+
const entries = fs.readdirSync(srcCommands, { withFileTypes: true });
|
|
159
|
+
for (const entry of entries) {
|
|
160
|
+
const src = path.join(srcCommands, entry.name);
|
|
161
|
+
const dest = path.join(commandsDir, entry.name);
|
|
162
|
+
if (entry.isDirectory()) {
|
|
163
|
+
copyDir(src, dest);
|
|
164
|
+
} else {
|
|
165
|
+
fs.copyFileSync(src, dest);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
logSuccess('Commands installed');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Copy agents
|
|
172
|
+
if (fs.existsSync(srcAgents)) {
|
|
173
|
+
const entries = fs.readdirSync(srcAgents, { withFileTypes: true });
|
|
174
|
+
for (const entry of entries) {
|
|
175
|
+
const src = path.join(srcAgents, entry.name);
|
|
176
|
+
const dest = path.join(agentsDir, entry.name);
|
|
177
|
+
fs.copyFileSync(src, dest);
|
|
178
|
+
}
|
|
179
|
+
logSuccess('Agents installed');
|
|
180
|
+
}
|
|
181
|
+
} catch (error) {
|
|
182
|
+
logError('Failed to copy files');
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Cleanup
|
|
187
|
+
logStep('4/4', 'Cleaning up...');
|
|
188
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
189
|
+
logSuccess('Done');
|
|
190
|
+
|
|
191
|
+
// Success message
|
|
192
|
+
console.log(`
|
|
193
|
+
${GREEN}+============================================================+
|
|
194
|
+
| |
|
|
195
|
+
| THE GRID INSTALLED SUCCESSFULLY |
|
|
196
|
+
| |
|
|
197
|
+
+============================================================+${RESET}
|
|
198
|
+
|
|
199
|
+
${BOLD}Enter The Grid:${RESET}
|
|
200
|
+
In Claude Code, type: ${CYAN}/grid${RESET}
|
|
201
|
+
|
|
202
|
+
${BOLD}Files installed:${RESET}
|
|
203
|
+
${DIM}~/.claude/commands/grid.md${RESET}
|
|
204
|
+
${DIM}~/.claude/commands/grid/${RESET}
|
|
205
|
+
${DIM}~/.claude/agents/grid-*.md${RESET}
|
|
206
|
+
|
|
207
|
+
${DIM}"End of Line."${RESET}
|
|
208
|
+
`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async function uninstall() {
|
|
212
|
+
console.log(BANNER);
|
|
213
|
+
log('Uninstalling The Grid...', YELLOW);
|
|
214
|
+
|
|
215
|
+
const home = process.env.HOME || process.env.USERPROFILE;
|
|
216
|
+
const commandsDir = path.join(home, '.claude', 'commands');
|
|
217
|
+
const agentsDir = path.join(home, '.claude', 'agents');
|
|
218
|
+
|
|
219
|
+
let removed = false;
|
|
220
|
+
|
|
221
|
+
// Remove grid commands
|
|
222
|
+
const gridMd = path.join(commandsDir, 'grid.md');
|
|
223
|
+
const gridDir = path.join(commandsDir, 'grid');
|
|
224
|
+
|
|
225
|
+
if (fs.existsSync(gridMd)) {
|
|
226
|
+
fs.rmSync(gridMd);
|
|
227
|
+
logSuccess('Removed grid.md');
|
|
228
|
+
removed = true;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (fs.existsSync(gridDir)) {
|
|
232
|
+
fs.rmSync(gridDir, { recursive: true, force: true });
|
|
233
|
+
logSuccess('Removed grid/ commands');
|
|
234
|
+
removed = true;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Remove grid agents
|
|
238
|
+
const agentFiles = ['grid-planner.md', 'grid-executor.md', 'grid-recognizer.md', 'grid-guard.md'];
|
|
239
|
+
for (const file of agentFiles) {
|
|
240
|
+
const agentPath = path.join(agentsDir, file);
|
|
241
|
+
if (fs.existsSync(agentPath)) {
|
|
242
|
+
fs.rmSync(agentPath);
|
|
243
|
+
logSuccess(`Removed ${file}`);
|
|
244
|
+
removed = true;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (!removed) {
|
|
249
|
+
log('No Grid installations found.', DIM);
|
|
250
|
+
} else {
|
|
251
|
+
console.log(`
|
|
252
|
+
${GREEN}The Grid has been derezzed.${RESET}
|
|
253
|
+
|
|
254
|
+
${DIM}"End of Line."${RESET}
|
|
255
|
+
`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Main
|
|
260
|
+
async function main() {
|
|
261
|
+
if (flags.help) {
|
|
262
|
+
showHelp();
|
|
263
|
+
process.exit(0);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (flags.uninstall) {
|
|
267
|
+
await uninstall();
|
|
268
|
+
} else {
|
|
269
|
+
await install();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
main().catch((error) => {
|
|
274
|
+
logError(error.message);
|
|
275
|
+
process.exit(1);
|
|
276
|
+
});
|
package/cli/__init__.py
ADDED
package/cli/main.py
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
The Grid CLI - Entry point to the digital frontier.
|
|
4
|
+
|
|
5
|
+
"The Grid. A digital frontier. I tried to picture clusters of information
|
|
6
|
+
as they moved through the computer."
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
grid - Enter The Grid with welcome screen
|
|
10
|
+
grid status - Show Grid status
|
|
11
|
+
grid build <desc> - Build something from natural language
|
|
12
|
+
grid --help - Show help
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import sys
|
|
16
|
+
import argparse
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
# Add parent to path for imports
|
|
21
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
22
|
+
|
|
23
|
+
from core.grid import Grid, GridConfig
|
|
24
|
+
from core.cluster import Cluster
|
|
25
|
+
from core.block import Block
|
|
26
|
+
from core.program import Program
|
|
27
|
+
from templates.welcome import render_welcome, render_goodbye
|
|
28
|
+
from templates.status import render_full_status, render_grid_summary
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class GridCLI:
|
|
32
|
+
"""
|
|
33
|
+
The Grid CLI - Interactive interface to The Grid.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, config_path: Optional[Path] = None):
|
|
37
|
+
"""Initialize the CLI."""
|
|
38
|
+
self.config_path = config_path or Path(__file__).parent.parent / "config" / "grid.yaml"
|
|
39
|
+
self.grid: Optional[Grid] = None
|
|
40
|
+
|
|
41
|
+
def initialize_grid(self) -> Grid:
|
|
42
|
+
"""Initialize a new Grid instance."""
|
|
43
|
+
self.grid = Grid(
|
|
44
|
+
name="The Grid",
|
|
45
|
+
config_path=self.config_path if self.config_path.exists() else None,
|
|
46
|
+
)
|
|
47
|
+
return self.grid
|
|
48
|
+
|
|
49
|
+
def welcome(self) -> None:
|
|
50
|
+
"""Display the welcome screen."""
|
|
51
|
+
print(render_welcome(self.grid))
|
|
52
|
+
|
|
53
|
+
def goodbye(self) -> None:
|
|
54
|
+
"""Display the goodbye screen."""
|
|
55
|
+
print(render_goodbye())
|
|
56
|
+
|
|
57
|
+
def status(self) -> None:
|
|
58
|
+
"""Display Grid status."""
|
|
59
|
+
if not self.grid:
|
|
60
|
+
self.initialize_grid()
|
|
61
|
+
print(render_grid_summary(self.grid))
|
|
62
|
+
|
|
63
|
+
def full_status(self) -> None:
|
|
64
|
+
"""Display full Grid status with all Clusters."""
|
|
65
|
+
if not self.grid:
|
|
66
|
+
self.initialize_grid()
|
|
67
|
+
print(render_full_status(self.grid))
|
|
68
|
+
|
|
69
|
+
def parse_intent(self, description: str) -> dict:
|
|
70
|
+
"""
|
|
71
|
+
Parse natural language description into Grid structure.
|
|
72
|
+
|
|
73
|
+
This is a simplified parser - a full implementation would use
|
|
74
|
+
NLP or an LLM to understand complex requests.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
dict with cluster_name, blocks, and threads
|
|
78
|
+
"""
|
|
79
|
+
description = description.lower().strip()
|
|
80
|
+
|
|
81
|
+
# Extract key concepts
|
|
82
|
+
structure = {
|
|
83
|
+
"cluster_name": "project",
|
|
84
|
+
"purpose": description,
|
|
85
|
+
"blocks": [],
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# Detect project type and create appropriate structure
|
|
89
|
+
if any(word in description for word in ["api", "rest", "endpoint", "server"]):
|
|
90
|
+
structure["cluster_name"] = "api-project"
|
|
91
|
+
structure["blocks"] = [
|
|
92
|
+
{
|
|
93
|
+
"name": "design",
|
|
94
|
+
"purpose": "Design the API architecture",
|
|
95
|
+
"threads": [
|
|
96
|
+
{"name": "research", "purpose": "Research patterns and requirements"},
|
|
97
|
+
{"name": "architecture", "purpose": "Design system architecture"},
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "implement",
|
|
102
|
+
"purpose": "Implement the API",
|
|
103
|
+
"blocked_by": ["design"],
|
|
104
|
+
"threads": [
|
|
105
|
+
{"name": "models", "purpose": "Create data models"},
|
|
106
|
+
{"name": "routes", "purpose": "Create API endpoints"},
|
|
107
|
+
{"name": "middleware", "purpose": "Create middleware"},
|
|
108
|
+
{"name": "tests", "purpose": "Write tests", "blocked_by": ["models", "routes"]},
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"name": "verify",
|
|
113
|
+
"purpose": "Verify and validate",
|
|
114
|
+
"blocked_by": ["implement"],
|
|
115
|
+
"threads": [
|
|
116
|
+
{"name": "validate", "purpose": "Run validation", "type": "recognizer"},
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
elif any(word in description for word in ["cli", "command", "terminal", "tool"]):
|
|
122
|
+
structure["cluster_name"] = "cli-tool"
|
|
123
|
+
structure["blocks"] = [
|
|
124
|
+
{
|
|
125
|
+
"name": "design",
|
|
126
|
+
"purpose": "Design the CLI",
|
|
127
|
+
"threads": [
|
|
128
|
+
{"name": "requirements", "purpose": "Define requirements"},
|
|
129
|
+
{"name": "interface", "purpose": "Design command interface"},
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "implement",
|
|
134
|
+
"purpose": "Implement the CLI",
|
|
135
|
+
"blocked_by": ["design"],
|
|
136
|
+
"threads": [
|
|
137
|
+
{"name": "parser", "purpose": "Create argument parser"},
|
|
138
|
+
{"name": "commands", "purpose": "Implement commands"},
|
|
139
|
+
{"name": "output", "purpose": "Format output"},
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"name": "verify",
|
|
144
|
+
"purpose": "Test and verify",
|
|
145
|
+
"blocked_by": ["implement"],
|
|
146
|
+
"threads": [
|
|
147
|
+
{"name": "test", "purpose": "Run tests", "type": "recognizer"},
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
elif any(word in description for word in ["fix", "bug", "error", "issue"]):
|
|
153
|
+
structure["cluster_name"] = "bugfix"
|
|
154
|
+
structure["blocks"] = [
|
|
155
|
+
{
|
|
156
|
+
"name": "investigate",
|
|
157
|
+
"purpose": "Investigate the issue",
|
|
158
|
+
"threads": [
|
|
159
|
+
{"name": "reproduce", "purpose": "Reproduce the bug"},
|
|
160
|
+
{"name": "analyze", "purpose": "Analyze root cause"},
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"name": "fix",
|
|
165
|
+
"purpose": "Fix the bug",
|
|
166
|
+
"blocked_by": ["investigate"],
|
|
167
|
+
"threads": [
|
|
168
|
+
{"name": "implement", "purpose": "Implement the fix"},
|
|
169
|
+
{"name": "test", "purpose": "Test the fix"},
|
|
170
|
+
],
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"name": "verify",
|
|
174
|
+
"purpose": "Verify fix",
|
|
175
|
+
"blocked_by": ["fix"],
|
|
176
|
+
"threads": [
|
|
177
|
+
{"name": "validate", "purpose": "Validate fix", "type": "recognizer"},
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
]
|
|
181
|
+
|
|
182
|
+
else:
|
|
183
|
+
# Generic project structure
|
|
184
|
+
structure["cluster_name"] = "project"
|
|
185
|
+
structure["blocks"] = [
|
|
186
|
+
{
|
|
187
|
+
"name": "plan",
|
|
188
|
+
"purpose": "Plan the work",
|
|
189
|
+
"threads": [
|
|
190
|
+
{"name": "analyze", "purpose": "Analyze requirements"},
|
|
191
|
+
{"name": "design", "purpose": "Design solution"},
|
|
192
|
+
],
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"name": "execute",
|
|
196
|
+
"purpose": "Execute the work",
|
|
197
|
+
"blocked_by": ["plan"],
|
|
198
|
+
"threads": [
|
|
199
|
+
{"name": "implement", "purpose": "Implement solution"},
|
|
200
|
+
{"name": "test", "purpose": "Test implementation"},
|
|
201
|
+
],
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"name": "verify",
|
|
205
|
+
"purpose": "Verify completion",
|
|
206
|
+
"blocked_by": ["execute"],
|
|
207
|
+
"threads": [
|
|
208
|
+
{"name": "validate", "purpose": "Validate work", "type": "recognizer"},
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
return structure
|
|
214
|
+
|
|
215
|
+
def build_from_structure(self, structure: dict) -> Cluster:
|
|
216
|
+
"""Build Grid structure from parsed intent."""
|
|
217
|
+
if not self.grid:
|
|
218
|
+
self.initialize_grid()
|
|
219
|
+
|
|
220
|
+
# Create Cluster
|
|
221
|
+
cluster = self.grid.create_cluster(
|
|
222
|
+
name=structure["cluster_name"],
|
|
223
|
+
purpose=structure["purpose"],
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
# Create Blocks
|
|
227
|
+
block_map = {}
|
|
228
|
+
for block_def in structure["blocks"]:
|
|
229
|
+
blocked_by = [block_map[name].name for name in block_def.get("blocked_by", []) if name in block_map]
|
|
230
|
+
|
|
231
|
+
block = cluster.add_block(
|
|
232
|
+
name=block_def["name"],
|
|
233
|
+
purpose=block_def["purpose"],
|
|
234
|
+
blocked_by=blocked_by,
|
|
235
|
+
)
|
|
236
|
+
block_map[block_def["name"]] = block
|
|
237
|
+
|
|
238
|
+
# Create Threads
|
|
239
|
+
thread_map = {}
|
|
240
|
+
for thread_def in block_def.get("threads", []):
|
|
241
|
+
blocked_by_threads = thread_def.get("blocked_by", [])
|
|
242
|
+
|
|
243
|
+
thread = block.add_thread(
|
|
244
|
+
name=thread_def["name"],
|
|
245
|
+
purpose=thread_def["purpose"],
|
|
246
|
+
program_type=thread_def.get("type", "program"),
|
|
247
|
+
blocked_by=blocked_by_threads,
|
|
248
|
+
)
|
|
249
|
+
thread_map[thread_def["name"]] = thread
|
|
250
|
+
|
|
251
|
+
# Add I/O Tower checkpoint before commit
|
|
252
|
+
cluster.add_io_checkpoint("Human review required before commit")
|
|
253
|
+
|
|
254
|
+
return cluster
|
|
255
|
+
|
|
256
|
+
def build(self, description: str) -> None:
|
|
257
|
+
"""Build something from natural language description."""
|
|
258
|
+
# Parse intent
|
|
259
|
+
structure = self.parse_intent(description)
|
|
260
|
+
|
|
261
|
+
# Build structure
|
|
262
|
+
cluster = self.build_from_structure(structure)
|
|
263
|
+
|
|
264
|
+
# Display result
|
|
265
|
+
from templates.status import render_cluster_status
|
|
266
|
+
print()
|
|
267
|
+
print(render_cluster_status(cluster))
|
|
268
|
+
|
|
269
|
+
def run_interactive(self) -> None:
|
|
270
|
+
"""Run interactive mode."""
|
|
271
|
+
self.initialize_grid()
|
|
272
|
+
self.welcome()
|
|
273
|
+
|
|
274
|
+
while True:
|
|
275
|
+
try:
|
|
276
|
+
user_input = input("\n▸ ").strip()
|
|
277
|
+
|
|
278
|
+
# Filter out escape sequences (arrow keys, etc.)
|
|
279
|
+
import re
|
|
280
|
+
user_input = re.sub(r'\x1b\[[A-D]', '', user_input)
|
|
281
|
+
user_input = user_input.strip()
|
|
282
|
+
|
|
283
|
+
if not user_input:
|
|
284
|
+
continue
|
|
285
|
+
|
|
286
|
+
if user_input.lower() in ("quit", "exit", "q"):
|
|
287
|
+
self.goodbye()
|
|
288
|
+
break
|
|
289
|
+
|
|
290
|
+
if user_input.lower() == "status":
|
|
291
|
+
self.full_status()
|
|
292
|
+
continue
|
|
293
|
+
|
|
294
|
+
if user_input.lower() == "energy":
|
|
295
|
+
from templates.status import render_energy_flow
|
|
296
|
+
print(render_energy_flow(self.grid))
|
|
297
|
+
continue
|
|
298
|
+
|
|
299
|
+
if user_input.lower() == "help":
|
|
300
|
+
print("""
|
|
301
|
+
Commands:
|
|
302
|
+
status - Show Grid status
|
|
303
|
+
energy - Show energy flow
|
|
304
|
+
quit/exit - Exit The Grid
|
|
305
|
+
|
|
306
|
+
Or describe what you want to build:
|
|
307
|
+
"a REST API for user authentication"
|
|
308
|
+
"a CLI tool that converts markdown to PDF"
|
|
309
|
+
"fix the bug in my login form"
|
|
310
|
+
""")
|
|
311
|
+
continue
|
|
312
|
+
|
|
313
|
+
# Treat as build request
|
|
314
|
+
self.build(user_input)
|
|
315
|
+
|
|
316
|
+
except KeyboardInterrupt:
|
|
317
|
+
print("\n")
|
|
318
|
+
self.goodbye()
|
|
319
|
+
break
|
|
320
|
+
|
|
321
|
+
except EOFError:
|
|
322
|
+
print("\n")
|
|
323
|
+
self.goodbye()
|
|
324
|
+
break
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def main():
|
|
328
|
+
"""Main entry point."""
|
|
329
|
+
parser = argparse.ArgumentParser(
|
|
330
|
+
description="The Grid - A Digital Frontier",
|
|
331
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
332
|
+
epilog="""
|
|
333
|
+
Examples:
|
|
334
|
+
grid Enter The Grid interactively
|
|
335
|
+
grid status Show Grid status
|
|
336
|
+
grid build "a REST API" Build from description
|
|
337
|
+
grid --config /path/to/grid.yaml Use custom config
|
|
338
|
+
|
|
339
|
+
"The Grid. A digital frontier."
|
|
340
|
+
""",
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
parser.add_argument(
|
|
344
|
+
"command",
|
|
345
|
+
nargs="?",
|
|
346
|
+
default="interactive",
|
|
347
|
+
choices=["interactive", "status", "build"],
|
|
348
|
+
help="Command to run",
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
parser.add_argument(
|
|
352
|
+
"description",
|
|
353
|
+
nargs="?",
|
|
354
|
+
help="Description for build command",
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
parser.add_argument(
|
|
358
|
+
"--config",
|
|
359
|
+
type=Path,
|
|
360
|
+
help="Path to config file",
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
args = parser.parse_args()
|
|
364
|
+
|
|
365
|
+
cli = GridCLI(config_path=args.config)
|
|
366
|
+
|
|
367
|
+
if args.command == "status":
|
|
368
|
+
cli.initialize_grid()
|
|
369
|
+
cli.full_status()
|
|
370
|
+
|
|
371
|
+
elif args.command == "build":
|
|
372
|
+
if not args.description:
|
|
373
|
+
print("Error: build command requires a description")
|
|
374
|
+
print("Usage: grid build \"description of what to build\"")
|
|
375
|
+
sys.exit(1)
|
|
376
|
+
cli.initialize_grid()
|
|
377
|
+
cli.build(args.description)
|
|
378
|
+
|
|
379
|
+
else:
|
|
380
|
+
# Interactive mode
|
|
381
|
+
cli.run_interactive()
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
if __name__ == "__main__":
|
|
385
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.1.0
|