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,294 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Recognizer - Validation Programs that scan for anomalies.
|
|
3
|
+
|
|
4
|
+
"Recognizers patrol The Grid, ensuring order and quality."
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from typing import Optional, Any
|
|
10
|
+
from enum import Enum
|
|
11
|
+
import uuid
|
|
12
|
+
|
|
13
|
+
from .program import Program, ProgramType, ProgramStatus
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ValidationResult(Enum):
|
|
17
|
+
"""Result of a Recognizer scan."""
|
|
18
|
+
VALID = "valid" # All checks passed
|
|
19
|
+
RECTIFY_NEEDED = "rectify_needed" # Issues found, can be fixed
|
|
20
|
+
DEREZ = "derez" # Critical failure, reject
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class RecognizerType(Enum):
|
|
24
|
+
"""Type of Recognizer."""
|
|
25
|
+
CODE = "code" # Code quality validation
|
|
26
|
+
ARCHITECTURE = "architecture" # Design validation
|
|
27
|
+
SECURITY = "security" # Security scanning
|
|
28
|
+
CONSISTENCY = "consistency" # Artifact alignment
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class ValidationIssue:
|
|
33
|
+
"""An issue found during validation."""
|
|
34
|
+
severity: str # low, medium, high, critical
|
|
35
|
+
category: str
|
|
36
|
+
message: str
|
|
37
|
+
location: Optional[str] = None
|
|
38
|
+
suggestion: Optional[str] = None
|
|
39
|
+
|
|
40
|
+
def to_dict(self) -> dict:
|
|
41
|
+
return {
|
|
42
|
+
"severity": self.severity,
|
|
43
|
+
"category": self.category,
|
|
44
|
+
"message": self.message,
|
|
45
|
+
"location": self.location,
|
|
46
|
+
"suggestion": self.suggestion,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class ScanResult:
|
|
52
|
+
"""Result of a Recognizer scan."""
|
|
53
|
+
result: ValidationResult
|
|
54
|
+
issues: list[ValidationIssue] = field(default_factory=list)
|
|
55
|
+
passed_checks: int = 0
|
|
56
|
+
total_checks: int = 0
|
|
57
|
+
scan_duration: float = 0.0
|
|
58
|
+
details: dict = field(default_factory=dict)
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def passed(self) -> bool:
|
|
62
|
+
return self.result == ValidationResult.VALID
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def pass_rate(self) -> float:
|
|
66
|
+
if self.total_checks == 0:
|
|
67
|
+
return 0.0
|
|
68
|
+
return (self.passed_checks / self.total_checks) * 100
|
|
69
|
+
|
|
70
|
+
def summary(self) -> str:
|
|
71
|
+
status = "✓ VALID" if self.passed else "✗ ISSUES FOUND"
|
|
72
|
+
return (
|
|
73
|
+
f"{status}\n"
|
|
74
|
+
f" Checks: {self.passed_checks}/{self.total_checks} passed ({self.pass_rate:.0f}%)\n"
|
|
75
|
+
f" Issues: {len(self.issues)}\n"
|
|
76
|
+
f" Duration: {self.scan_duration:.2f}s"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Recognizer(Program):
|
|
81
|
+
"""
|
|
82
|
+
Recognizer - Validation Program that scans for anomalies.
|
|
83
|
+
|
|
84
|
+
Recognizers are special Programs that validate work before
|
|
85
|
+
it can proceed. They ensure quality and consistency.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def __init__(
|
|
89
|
+
self,
|
|
90
|
+
name: str,
|
|
91
|
+
target: str,
|
|
92
|
+
recognizer_type: RecognizerType,
|
|
93
|
+
criteria: list[str] = None,
|
|
94
|
+
parent: Optional[Program] = None,
|
|
95
|
+
energy_budget: int = 50,
|
|
96
|
+
):
|
|
97
|
+
super().__init__(
|
|
98
|
+
name=name,
|
|
99
|
+
purpose=f"Validate {target}",
|
|
100
|
+
parent=parent,
|
|
101
|
+
energy_budget=energy_budget,
|
|
102
|
+
program_type=ProgramType.RECOGNIZER,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
self.target = target
|
|
106
|
+
self.recognizer_type = recognizer_type
|
|
107
|
+
self.criteria = criteria or []
|
|
108
|
+
|
|
109
|
+
# Scan results
|
|
110
|
+
self.scan_result: Optional[ScanResult] = None
|
|
111
|
+
self.issues: list[ValidationIssue] = []
|
|
112
|
+
|
|
113
|
+
def add_criterion(self, criterion: str) -> None:
|
|
114
|
+
"""Add a validation criterion."""
|
|
115
|
+
if criterion not in self.criteria:
|
|
116
|
+
self.criteria.append(criterion)
|
|
117
|
+
|
|
118
|
+
def scan(self, artifacts: list[Any] = None) -> ScanResult:
|
|
119
|
+
"""
|
|
120
|
+
Perform validation scan.
|
|
121
|
+
|
|
122
|
+
This is a template method - actual validation logic would
|
|
123
|
+
be implemented by specific Recognizer subclasses or external
|
|
124
|
+
validation functions.
|
|
125
|
+
"""
|
|
126
|
+
self.start()
|
|
127
|
+
start_time = datetime.now()
|
|
128
|
+
|
|
129
|
+
issues = []
|
|
130
|
+
passed = 0
|
|
131
|
+
total = len(self.criteria)
|
|
132
|
+
|
|
133
|
+
# Placeholder validation logic
|
|
134
|
+
# In real implementation, this would check actual artifacts
|
|
135
|
+
for criterion in self.criteria:
|
|
136
|
+
# Each criterion is checked
|
|
137
|
+
# For now, all pass (placeholder)
|
|
138
|
+
passed += 1
|
|
139
|
+
|
|
140
|
+
duration = (datetime.now() - start_time).total_seconds()
|
|
141
|
+
|
|
142
|
+
# Determine result
|
|
143
|
+
if not issues:
|
|
144
|
+
result = ValidationResult.VALID
|
|
145
|
+
elif any(i.severity == "critical" for i in issues):
|
|
146
|
+
result = ValidationResult.DEREZ
|
|
147
|
+
else:
|
|
148
|
+
result = ValidationResult.RECTIFY_NEEDED
|
|
149
|
+
|
|
150
|
+
self.scan_result = ScanResult(
|
|
151
|
+
result=result,
|
|
152
|
+
issues=issues,
|
|
153
|
+
passed_checks=passed,
|
|
154
|
+
total_checks=total,
|
|
155
|
+
scan_duration=duration,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
self.issues = issues
|
|
159
|
+
|
|
160
|
+
if result == ValidationResult.VALID:
|
|
161
|
+
self.complete(self.scan_result)
|
|
162
|
+
else:
|
|
163
|
+
self.fail(f"Validation failed: {len(issues)} issues found")
|
|
164
|
+
|
|
165
|
+
return self.scan_result
|
|
166
|
+
|
|
167
|
+
def add_issue(
|
|
168
|
+
self,
|
|
169
|
+
severity: str,
|
|
170
|
+
category: str,
|
|
171
|
+
message: str,
|
|
172
|
+
location: str = None,
|
|
173
|
+
suggestion: str = None,
|
|
174
|
+
) -> ValidationIssue:
|
|
175
|
+
"""Add a validation issue."""
|
|
176
|
+
issue = ValidationIssue(
|
|
177
|
+
severity=severity,
|
|
178
|
+
category=category,
|
|
179
|
+
message=message,
|
|
180
|
+
location=location,
|
|
181
|
+
suggestion=suggestion,
|
|
182
|
+
)
|
|
183
|
+
self.issues.append(issue)
|
|
184
|
+
return issue
|
|
185
|
+
|
|
186
|
+
def summary(self) -> str:
|
|
187
|
+
"""Get Recognizer summary."""
|
|
188
|
+
lines = [
|
|
189
|
+
f"Recognizer: {self.name} [{self.id}]",
|
|
190
|
+
f" Type: {self.recognizer_type.value}",
|
|
191
|
+
f" Target: {self.target}",
|
|
192
|
+
f" Criteria: {len(self.criteria)}",
|
|
193
|
+
f" Status: {self.status.value}",
|
|
194
|
+
]
|
|
195
|
+
if self.scan_result:
|
|
196
|
+
lines.append(f" Result: {self.scan_result.result.value}")
|
|
197
|
+
lines.append(f" Issues: {len(self.issues)}")
|
|
198
|
+
return "\n".join(lines)
|
|
199
|
+
|
|
200
|
+
def to_dict(self) -> dict:
|
|
201
|
+
"""Serialize Recognizer to dictionary."""
|
|
202
|
+
base = super().to_dict()
|
|
203
|
+
base.update({
|
|
204
|
+
"recognizer_type": self.recognizer_type.value,
|
|
205
|
+
"target": self.target,
|
|
206
|
+
"criteria": self.criteria,
|
|
207
|
+
"issues": [i.to_dict() for i in self.issues],
|
|
208
|
+
"scan_result": {
|
|
209
|
+
"result": self.scan_result.result.value,
|
|
210
|
+
"passed_checks": self.scan_result.passed_checks,
|
|
211
|
+
"total_checks": self.scan_result.total_checks,
|
|
212
|
+
"pass_rate": self.scan_result.pass_rate,
|
|
213
|
+
} if self.scan_result else None,
|
|
214
|
+
})
|
|
215
|
+
return base
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
# Factory functions for common Recognizer types
|
|
219
|
+
|
|
220
|
+
def create_code_recognizer(
|
|
221
|
+
target: str,
|
|
222
|
+
criteria: list[str] = None,
|
|
223
|
+
) -> Recognizer:
|
|
224
|
+
"""Create a code quality Recognizer."""
|
|
225
|
+
default_criteria = [
|
|
226
|
+
"No syntax errors",
|
|
227
|
+
"Tests pass",
|
|
228
|
+
"No linting errors",
|
|
229
|
+
"Type checks pass",
|
|
230
|
+
]
|
|
231
|
+
return Recognizer(
|
|
232
|
+
name=f"code-validator-{target}",
|
|
233
|
+
target=target,
|
|
234
|
+
recognizer_type=RecognizerType.CODE,
|
|
235
|
+
criteria=criteria or default_criteria,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def create_security_recognizer(
|
|
240
|
+
target: str,
|
|
241
|
+
criteria: list[str] = None,
|
|
242
|
+
) -> Recognizer:
|
|
243
|
+
"""Create a security Recognizer."""
|
|
244
|
+
default_criteria = [
|
|
245
|
+
"No hardcoded secrets",
|
|
246
|
+
"No SQL injection vulnerabilities",
|
|
247
|
+
"No XSS vulnerabilities",
|
|
248
|
+
"Input validation present",
|
|
249
|
+
"Authentication required for protected routes",
|
|
250
|
+
]
|
|
251
|
+
return Recognizer(
|
|
252
|
+
name=f"security-scanner-{target}",
|
|
253
|
+
target=target,
|
|
254
|
+
recognizer_type=RecognizerType.SECURITY,
|
|
255
|
+
criteria=criteria or default_criteria,
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def create_architecture_recognizer(
|
|
260
|
+
target: str,
|
|
261
|
+
criteria: list[str] = None,
|
|
262
|
+
) -> Recognizer:
|
|
263
|
+
"""Create an architecture Recognizer."""
|
|
264
|
+
default_criteria = [
|
|
265
|
+
"Follows established patterns",
|
|
266
|
+
"Separation of concerns",
|
|
267
|
+
"No circular dependencies",
|
|
268
|
+
"Consistent naming conventions",
|
|
269
|
+
]
|
|
270
|
+
return Recognizer(
|
|
271
|
+
name=f"architecture-validator-{target}",
|
|
272
|
+
target=target,
|
|
273
|
+
recognizer_type=RecognizerType.ARCHITECTURE,
|
|
274
|
+
criteria=criteria or default_criteria,
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def create_consistency_recognizer(
|
|
279
|
+
target: str,
|
|
280
|
+
criteria: list[str] = None,
|
|
281
|
+
) -> Recognizer:
|
|
282
|
+
"""Create a consistency Recognizer."""
|
|
283
|
+
default_criteria = [
|
|
284
|
+
"All artifacts aligned",
|
|
285
|
+
"Documentation matches implementation",
|
|
286
|
+
"API contracts satisfied",
|
|
287
|
+
"Schema consistency",
|
|
288
|
+
]
|
|
289
|
+
return Recognizer(
|
|
290
|
+
name=f"consistency-checker-{target}",
|
|
291
|
+
target=target,
|
|
292
|
+
recognizer_type=RecognizerType.CONSISTENCY,
|
|
293
|
+
criteria=criteria or default_criteria,
|
|
294
|
+
)
|
package/core/thread.py
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Thread - Single unit of execution on The Grid.
|
|
3
|
+
|
|
4
|
+
"The smallest unit of computation on The Grid."
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from typing import Optional, Callable, Any
|
|
10
|
+
from enum import Enum
|
|
11
|
+
import uuid
|
|
12
|
+
|
|
13
|
+
from .disc import IdentityDisc
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ThreadStatus(Enum):
|
|
17
|
+
"""Status of a Thread."""
|
|
18
|
+
PENDING = "pending"
|
|
19
|
+
RUNNING = "running"
|
|
20
|
+
BLOCKED = "blocked"
|
|
21
|
+
COMPLETED = "completed"
|
|
22
|
+
FAILED = "failed"
|
|
23
|
+
DEREZZED = "derezzed"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class ThreadResult:
|
|
28
|
+
"""Result of Thread execution."""
|
|
29
|
+
success: bool
|
|
30
|
+
output: Any = None
|
|
31
|
+
error: Optional[str] = None
|
|
32
|
+
cycles_used: int = 0
|
|
33
|
+
energy_consumed: int = 0
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Thread:
|
|
37
|
+
"""
|
|
38
|
+
Thread - Single unit of execution (atomic operation).
|
|
39
|
+
|
|
40
|
+
Threads are the smallest executable units on The Grid.
|
|
41
|
+
They perform a single, focused task.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
name: str,
|
|
47
|
+
purpose: str,
|
|
48
|
+
block_id: str,
|
|
49
|
+
program_type: str = "program", # program or recognizer
|
|
50
|
+
blocked_by: list[str] = None,
|
|
51
|
+
):
|
|
52
|
+
self.id = str(uuid.uuid4())[:8]
|
|
53
|
+
self.name = name
|
|
54
|
+
self.purpose = purpose
|
|
55
|
+
self.block_id = block_id
|
|
56
|
+
self.program_type = program_type
|
|
57
|
+
self.blocked_by = blocked_by or []
|
|
58
|
+
|
|
59
|
+
self.status = ThreadStatus.PENDING
|
|
60
|
+
self.created_at = datetime.now()
|
|
61
|
+
self.started_at: Optional[datetime] = None
|
|
62
|
+
self.completed_at: Optional[datetime] = None
|
|
63
|
+
|
|
64
|
+
# Progress tracking
|
|
65
|
+
self.progress = 0.0 # 0-100
|
|
66
|
+
self.current_action = "Waiting"
|
|
67
|
+
self.cycles_completed = 0
|
|
68
|
+
self.max_cycles = 10
|
|
69
|
+
|
|
70
|
+
# Results
|
|
71
|
+
self.result: Optional[ThreadResult] = None
|
|
72
|
+
|
|
73
|
+
# Identity Disc
|
|
74
|
+
self.disc = IdentityDisc(
|
|
75
|
+
program_id=f"thread:{self.id}",
|
|
76
|
+
purpose=purpose,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def can_start(self, completed_threads: set[str]) -> bool:
|
|
80
|
+
"""Check if all blocking threads are completed."""
|
|
81
|
+
if not self.blocked_by:
|
|
82
|
+
return True
|
|
83
|
+
return all(t in completed_threads for t in self.blocked_by)
|
|
84
|
+
|
|
85
|
+
def start(self) -> None:
|
|
86
|
+
"""Start Thread execution."""
|
|
87
|
+
self.status = ThreadStatus.RUNNING
|
|
88
|
+
self.started_at = datetime.now()
|
|
89
|
+
self.current_action = "Starting..."
|
|
90
|
+
|
|
91
|
+
def update_progress(self, progress: float, action: str = None) -> None:
|
|
92
|
+
"""Update Thread progress."""
|
|
93
|
+
self.progress = min(100.0, max(0.0, progress))
|
|
94
|
+
if action:
|
|
95
|
+
self.current_action = action
|
|
96
|
+
self.cycles_completed += 1
|
|
97
|
+
|
|
98
|
+
def complete(self, result: ThreadResult) -> None:
|
|
99
|
+
"""Mark Thread as completed."""
|
|
100
|
+
self.status = ThreadStatus.COMPLETED
|
|
101
|
+
self.completed_at = datetime.now()
|
|
102
|
+
self.result = result
|
|
103
|
+
self.progress = 100.0
|
|
104
|
+
self.current_action = "Completed"
|
|
105
|
+
|
|
106
|
+
def fail(self, error: str) -> None:
|
|
107
|
+
"""Mark Thread as failed."""
|
|
108
|
+
self.status = ThreadStatus.FAILED
|
|
109
|
+
self.completed_at = datetime.now()
|
|
110
|
+
self.result = ThreadResult(success=False, error=error)
|
|
111
|
+
self.current_action = f"Failed: {error}"
|
|
112
|
+
|
|
113
|
+
def derez(self) -> None:
|
|
114
|
+
"""Mark Thread as derezzed."""
|
|
115
|
+
self.status = ThreadStatus.DEREZZED
|
|
116
|
+
self.disc.derez()
|
|
117
|
+
|
|
118
|
+
def duration(self) -> Optional[float]:
|
|
119
|
+
"""Get execution duration in seconds."""
|
|
120
|
+
if not self.started_at:
|
|
121
|
+
return None
|
|
122
|
+
end = self.completed_at or datetime.now()
|
|
123
|
+
return (end - self.started_at).total_seconds()
|
|
124
|
+
|
|
125
|
+
def status_icon(self) -> str:
|
|
126
|
+
"""Get status icon for display."""
|
|
127
|
+
icons = {
|
|
128
|
+
ThreadStatus.PENDING: "○",
|
|
129
|
+
ThreadStatus.RUNNING: "◐",
|
|
130
|
+
ThreadStatus.BLOCKED: "◌",
|
|
131
|
+
ThreadStatus.COMPLETED: "●",
|
|
132
|
+
ThreadStatus.FAILED: "✗",
|
|
133
|
+
ThreadStatus.DEREZZED: "◯",
|
|
134
|
+
}
|
|
135
|
+
return icons.get(self.status, "?")
|
|
136
|
+
|
|
137
|
+
def program_icon(self) -> str:
|
|
138
|
+
"""Get program type icon."""
|
|
139
|
+
return "◈" if self.program_type == "recognizer" else "○"
|
|
140
|
+
|
|
141
|
+
def progress_bar(self, width: int = 10) -> str:
|
|
142
|
+
"""Get visual progress bar."""
|
|
143
|
+
filled = int((self.progress / 100) * width)
|
|
144
|
+
empty = width - filled
|
|
145
|
+
return "█" * filled + "░" * empty
|
|
146
|
+
|
|
147
|
+
def display_line(self) -> str:
|
|
148
|
+
"""Get single-line display for status views."""
|
|
149
|
+
icon = self.program_icon()
|
|
150
|
+
ptype = "Recognizer" if self.program_type == "recognizer" else "Program"
|
|
151
|
+
|
|
152
|
+
if self.status == ThreadStatus.BLOCKED:
|
|
153
|
+
action = f"Blocked by: {', '.join(self.blocked_by)}"
|
|
154
|
+
else:
|
|
155
|
+
action = self.current_action
|
|
156
|
+
|
|
157
|
+
progress = f"{self.status_icon()} {self.progress:.0f}%"
|
|
158
|
+
|
|
159
|
+
return f" {icon} {self.name:<16} {ptype:<10} {action:<30} {progress}"
|
|
160
|
+
|
|
161
|
+
def to_dict(self) -> dict:
|
|
162
|
+
"""Serialize Thread to dictionary."""
|
|
163
|
+
return {
|
|
164
|
+
"id": self.id,
|
|
165
|
+
"name": self.name,
|
|
166
|
+
"purpose": self.purpose,
|
|
167
|
+
"block_id": self.block_id,
|
|
168
|
+
"program_type": self.program_type,
|
|
169
|
+
"status": self.status.value,
|
|
170
|
+
"progress": self.progress,
|
|
171
|
+
"current_action": self.current_action,
|
|
172
|
+
"cycles_completed": self.cycles_completed,
|
|
173
|
+
"blocked_by": self.blocked_by,
|
|
174
|
+
"created_at": self.created_at.isoformat(),
|
|
175
|
+
"started_at": self.started_at.isoformat() if self.started_at else None,
|
|
176
|
+
"completed_at": self.completed_at.isoformat() if self.completed_at else None,
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
def __repr__(self) -> str:
|
|
180
|
+
return f"Thread(id={self.id}, name={self.name}, status={self.status.value})"
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "the-grid-cc",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Agent orchestration for Claude Code. You talk to MCP. MCP handles the rest.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"the-grid-cc": "./bin/install.js",
|
|
8
|
+
"grid": "./bin/install.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "python3 cli/main.py",
|
|
12
|
+
"test": "python3 -c \"from core import Grid; print('OK')\""
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/JamesWeatherhead/grid.git"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"ai",
|
|
20
|
+
"agents",
|
|
21
|
+
"orchestration",
|
|
22
|
+
"claude",
|
|
23
|
+
"claude-code",
|
|
24
|
+
"tron",
|
|
25
|
+
"natural-language",
|
|
26
|
+
"subagents"
|
|
27
|
+
],
|
|
28
|
+
"author": "James Weatherhead & Claude",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/JamesWeatherhead/grid/issues"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/JamesWeatherhead/grid#readme",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=16.0.0"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Templates - Visual display components for The Grid.
|
|
3
|
+
|
|
4
|
+
Import functions directly from the modules:
|
|
5
|
+
from templates.welcome import render_welcome
|
|
6
|
+
from templates.status import render_cluster_status
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__version__ = "1.0.0"
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"welcome",
|
|
13
|
+
"status",
|
|
14
|
+
]
|