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/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
+ });
@@ -0,0 +1,7 @@
1
+ """
2
+ CLI - Command line interface for The Grid.
3
+ """
4
+
5
+ from .main import main, GridCLI
6
+
7
+ __all__ = ["main", "GridCLI"]
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