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,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
+ ]