tamfis-code 0.2.3__py3-none-any.whl
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.
- tamfis_code/__init__.py +58 -0
- tamfis_code/__main__.py +4 -0
- tamfis_code/agents.py +371 -0
- tamfis_code/api_client.py +461 -0
- tamfis_code/cli.py +2351 -0
- tamfis_code/completion.py +137 -0
- tamfis_code/config.py +199 -0
- tamfis_code/doctor.py +173 -0
- tamfis_code/enforcer.py +318 -0
- tamfis_code/indexer.py +567 -0
- tamfis_code/instructions.py +121 -0
- tamfis_code/interactive.py +985 -0
- tamfis_code/local_chat.py +117 -0
- tamfis_code/local_tools.py +93 -0
- tamfis_code/mcp.py +538 -0
- tamfis_code/metrics.py +105 -0
- tamfis_code/providers.py +423 -0
- tamfis_code/references.py +336 -0
- tamfis_code/render.py +575 -0
- tamfis_code/runner.py +635 -0
- tamfis_code/runner_local.py +364 -0
- tamfis_code/safety.py +164 -0
- tamfis_code/screenshot.py +382 -0
- tamfis_code/sessions.py +253 -0
- tamfis_code/state.py +449 -0
- tamfis_code/tasks.py +42 -0
- tamfis_code/workspace.py +329 -0
- tamfis_code-0.2.3.dist-info/METADATA +78 -0
- tamfis_code-0.2.3.dist-info/RECORD +32 -0
- tamfis_code-0.2.3.dist-info/WHEEL +5 -0
- tamfis_code-0.2.3.dist-info/entry_points.txt +4 -0
- tamfis_code-0.2.3.dist-info/top_level.txt +1 -0
tamfis_code/enforcer.py
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TAMFIS-CODE Test Enforcer - Properly handles sibling directories
|
|
3
|
+
CWD: /home/tamfisgpt
|
|
4
|
+
- tamgpt6/ (backend, this repo)
|
|
5
|
+
- tamfis-frontend/ (React frontend, sibling)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
import subprocess
|
|
11
|
+
import json
|
|
12
|
+
import time
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from datetime import datetime
|
|
15
|
+
from typing import Dict, List, Optional, Any
|
|
16
|
+
|
|
17
|
+
# Import click for CLI integration
|
|
18
|
+
try:
|
|
19
|
+
import click
|
|
20
|
+
except ImportError:
|
|
21
|
+
click = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestEnforcer:
|
|
25
|
+
"""Test enforcer that properly handles sibling directories"""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
self.base = Path("/home/tamfisgpt")
|
|
29
|
+
self.backend = self.base / "tamgpt6"
|
|
30
|
+
self.frontend = self.base / "tamfis-frontend"
|
|
31
|
+
self.results = {
|
|
32
|
+
"timestamp": datetime.now().isoformat(),
|
|
33
|
+
"workspace": str(self.base),
|
|
34
|
+
"backend": str(self.backend),
|
|
35
|
+
"frontend": {
|
|
36
|
+
"exists": self.frontend.exists(),
|
|
37
|
+
"path": str(self.frontend),
|
|
38
|
+
},
|
|
39
|
+
"python": {"tests": [], "summary": {}},
|
|
40
|
+
"node": {"scripts": [], "summary": {}},
|
|
41
|
+
"frontend_tests": {"status": "checking", "results": []},
|
|
42
|
+
}
|
|
43
|
+
self._print = print
|
|
44
|
+
|
|
45
|
+
def _print_progress(self, message: str, status: str = "info", detail: str = ""):
|
|
46
|
+
"""Print progress with formatting"""
|
|
47
|
+
emojis = {
|
|
48
|
+
"info": "ℹ️",
|
|
49
|
+
"success": "✅",
|
|
50
|
+
"error": "❌",
|
|
51
|
+
"warning": "⚠️",
|
|
52
|
+
"running": "🔄",
|
|
53
|
+
"python": "🐍",
|
|
54
|
+
"node": "📦",
|
|
55
|
+
"frontend": "🎨",
|
|
56
|
+
"done": "🎉"
|
|
57
|
+
}
|
|
58
|
+
prefix = emojis.get(status, "ℹ️")
|
|
59
|
+
if detail:
|
|
60
|
+
self._print(f"{prefix} {message}\n └─ {detail}")
|
|
61
|
+
else:
|
|
62
|
+
self._print(f"{prefix} {message}")
|
|
63
|
+
sys.stdout.flush()
|
|
64
|
+
|
|
65
|
+
def _run_cmd(self, cmd: List[str], cwd: Optional[Path] = None, timeout: int = 120) -> Dict[str, Any]:
|
|
66
|
+
cwd = cwd or self.backend
|
|
67
|
+
try:
|
|
68
|
+
start = time.time()
|
|
69
|
+
result = subprocess.run(
|
|
70
|
+
cmd,
|
|
71
|
+
cwd=cwd,
|
|
72
|
+
capture_output=True,
|
|
73
|
+
text=True,
|
|
74
|
+
timeout=timeout
|
|
75
|
+
)
|
|
76
|
+
elapsed = time.time() - start
|
|
77
|
+
return {
|
|
78
|
+
"success": result.returncode == 0,
|
|
79
|
+
"returncode": result.returncode,
|
|
80
|
+
"stdout": result.stdout,
|
|
81
|
+
"stderr": result.stderr,
|
|
82
|
+
"elapsed": elapsed,
|
|
83
|
+
"cmd": " ".join(cmd)
|
|
84
|
+
}
|
|
85
|
+
except subprocess.TimeoutExpired:
|
|
86
|
+
return {
|
|
87
|
+
"success": False,
|
|
88
|
+
"error": f"Timeout after {timeout}s",
|
|
89
|
+
"elapsed": timeout,
|
|
90
|
+
"cmd": " ".join(cmd)
|
|
91
|
+
}
|
|
92
|
+
except Exception as e:
|
|
93
|
+
return {
|
|
94
|
+
"success": False,
|
|
95
|
+
"error": str(e),
|
|
96
|
+
"elapsed": 0,
|
|
97
|
+
"cmd": " ".join(cmd)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
def run(self) -> Dict[str, Any]:
|
|
101
|
+
"""Run all enforcements"""
|
|
102
|
+
self._print_progress("=" * 70, "info")
|
|
103
|
+
self._print_progress("🔧 TAMFIS-CODE Test Enforcer", "info")
|
|
104
|
+
self._print_progress("=" * 70, "info")
|
|
105
|
+
self._print_progress(f"📂 Workspace: {self.base}", "info")
|
|
106
|
+
self._print_progress(f"📂 Backend: {self.backend}", "info")
|
|
107
|
+
|
|
108
|
+
# Check frontend
|
|
109
|
+
if self.frontend.exists():
|
|
110
|
+
self._print_progress(f"🎨 Frontend: {self.frontend}", "success")
|
|
111
|
+
self.results["frontend"]["exists"] = True
|
|
112
|
+
else:
|
|
113
|
+
self._print_progress(f"🎨 Frontend: NOT FOUND at {self.frontend}", "error")
|
|
114
|
+
self.results["frontend"]["exists"] = False
|
|
115
|
+
|
|
116
|
+
# Run backend tests
|
|
117
|
+
self._run_backend_tests()
|
|
118
|
+
|
|
119
|
+
# Run frontend tests if it exists
|
|
120
|
+
if self.frontend.exists():
|
|
121
|
+
self._run_frontend_tests()
|
|
122
|
+
|
|
123
|
+
self._generate_summary()
|
|
124
|
+
return self.results
|
|
125
|
+
|
|
126
|
+
def _run_backend_tests(self):
|
|
127
|
+
"""Run backend (tamgpt6) tests"""
|
|
128
|
+
self._print_progress("", "info")
|
|
129
|
+
self._print_progress("🐍 Backend Tests (tamgpt6)", "python")
|
|
130
|
+
self._print_progress("-" * 50, "info")
|
|
131
|
+
|
|
132
|
+
test_dir = self.backend / "tests"
|
|
133
|
+
if not test_dir.exists():
|
|
134
|
+
self._print_progress("No tests directory found", "warning")
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
test_files = list(test_dir.glob("test_*.py"))
|
|
138
|
+
self._print_progress(f"📁 Found {len(test_files)} test files", "info")
|
|
139
|
+
|
|
140
|
+
passed = 0
|
|
141
|
+
for test_file in test_files:
|
|
142
|
+
self._print_progress(f"▶️ Running {test_file.name}...", "running")
|
|
143
|
+
result = self._run_cmd(
|
|
144
|
+
[sys.executable, "-m", "pytest", str(test_file), "-v", "--tb=short", "-q"],
|
|
145
|
+
cwd=self.backend,
|
|
146
|
+
timeout=60
|
|
147
|
+
)
|
|
148
|
+
if result["success"]:
|
|
149
|
+
passed += 1
|
|
150
|
+
self._print_progress(f"✅ {test_file.name} PASSED ({result['elapsed']:.2f}s)", "success")
|
|
151
|
+
else:
|
|
152
|
+
self._print_progress(f"❌ {test_file.name} FAILED ({result['elapsed']:.2f}s)", "error")
|
|
153
|
+
error_lines = [l for l in result["stdout"].split('\n') if 'FAILED' in l or 'ERROR' in l]
|
|
154
|
+
for line in error_lines[:3]:
|
|
155
|
+
self._print_progress(f" └─ {line.strip()}", "error")
|
|
156
|
+
|
|
157
|
+
self.results["python"]["summary"]["total"] = len(test_files)
|
|
158
|
+
self.results["python"]["summary"]["passed"] = passed
|
|
159
|
+
self._print_progress(f"📊 Summary: {passed}/{len(test_files)} test files passed",
|
|
160
|
+
"success" if passed == len(test_files) else "warning")
|
|
161
|
+
|
|
162
|
+
def _run_frontend_tests(self):
|
|
163
|
+
"""Run frontend (tamfis-frontend) tests - ACTUALLY access the sibling directory"""
|
|
164
|
+
self._print_progress("", "info")
|
|
165
|
+
self._print_progress("🎨 Frontend Tests (tamfis-frontend)", "frontend")
|
|
166
|
+
self._print_progress("-" * 50, "info")
|
|
167
|
+
|
|
168
|
+
if not self.frontend.exists():
|
|
169
|
+
self._print_progress("❌ Frontend directory not found", "error")
|
|
170
|
+
return
|
|
171
|
+
|
|
172
|
+
# List what's in the frontend directory
|
|
173
|
+
self._print_progress(f"📁 Checking frontend at: {self.frontend}", "info")
|
|
174
|
+
try:
|
|
175
|
+
files = list(self.frontend.iterdir())
|
|
176
|
+
self._print_progress(f"📁 Found {len(files)} items in frontend", "info")
|
|
177
|
+
for f in files[:10]:
|
|
178
|
+
self._print_progress(f" └─ {f.name}", "info")
|
|
179
|
+
except Exception as e:
|
|
180
|
+
self._print_progress(f"❌ Cannot read frontend directory: {e}", "error")
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
# Check package.json
|
|
184
|
+
pkg_file = self.frontend / "package.json"
|
|
185
|
+
if not pkg_file.exists():
|
|
186
|
+
self._print_progress("❌ No package.json found in frontend!", "error")
|
|
187
|
+
self.results["frontend_tests"]["status"] = "no_package"
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
self._print_progress("✅ package.json found!", "success")
|
|
191
|
+
|
|
192
|
+
# Read package.json
|
|
193
|
+
import json
|
|
194
|
+
with open(pkg_file) as f:
|
|
195
|
+
pkg = json.load(f)
|
|
196
|
+
scripts = pkg.get("scripts", {})
|
|
197
|
+
self._print_progress(f"📁 Found {len(scripts)} scripts in package.json", "info")
|
|
198
|
+
for script in scripts:
|
|
199
|
+
self._print_progress(f" └─ {script}: {scripts[script][:50]}...", "info")
|
|
200
|
+
|
|
201
|
+
# Check npm
|
|
202
|
+
npm_check = self._run_cmd(["npm", "--version"], cwd=self.frontend)
|
|
203
|
+
if not npm_check["success"]:
|
|
204
|
+
self._print_progress("❌ npm not available", "error")
|
|
205
|
+
self.results["frontend_tests"]["status"] = "no_npm"
|
|
206
|
+
return
|
|
207
|
+
self._print_progress(f"✅ npm {npm_check['stdout'].strip()} available", "success")
|
|
208
|
+
|
|
209
|
+
# Install dependencies if needed
|
|
210
|
+
node_modules = self.frontend / "node_modules"
|
|
211
|
+
if not node_modules.exists():
|
|
212
|
+
self._print_progress("📦 Installing npm dependencies... (this may take a while)", "running")
|
|
213
|
+
result = self._run_cmd(["npm", "install"], cwd=self.frontend, timeout=300)
|
|
214
|
+
if result["success"]:
|
|
215
|
+
self._print_progress("✅ Dependencies installed", "success")
|
|
216
|
+
else:
|
|
217
|
+
self._print_progress("❌ Dependency installation failed", "error")
|
|
218
|
+
self.results["frontend_tests"]["status"] = "install_failed"
|
|
219
|
+
return
|
|
220
|
+
|
|
221
|
+
# Run test scripts
|
|
222
|
+
test_scripts = ["test", "test:unit", "test:integration", "build", "typecheck", "dev"]
|
|
223
|
+
available = [s for s in test_scripts if s in scripts]
|
|
224
|
+
|
|
225
|
+
if not available:
|
|
226
|
+
self._print_progress("No test scripts found in package.json", "warning")
|
|
227
|
+
self.results["frontend_tests"]["status"] = "no_scripts"
|
|
228
|
+
return
|
|
229
|
+
|
|
230
|
+
self._print_progress(f"📁 Found {len(available)} scripts to run", "info")
|
|
231
|
+
|
|
232
|
+
results = []
|
|
233
|
+
for script in available:
|
|
234
|
+
self._print_progress(f"▶️ Running npm {script}...", "running")
|
|
235
|
+
result = self._run_cmd(["npm", "run", script], cwd=self.frontend, timeout=120)
|
|
236
|
+
if result["success"]:
|
|
237
|
+
self._print_progress(f"✅ npm {script} PASSED ({result['elapsed']:.2f}s)", "success")
|
|
238
|
+
else:
|
|
239
|
+
self._print_progress(f"❌ npm {script} FAILED ({result['elapsed']:.2f}s)", "error")
|
|
240
|
+
if result.get("stderr"):
|
|
241
|
+
error_lines = [l for l in result["stderr"].split('\n') if l.strip()]
|
|
242
|
+
for line in error_lines[:2]:
|
|
243
|
+
self._print_progress(f" └─ {line.strip()[:100]}", "error")
|
|
244
|
+
results.append({
|
|
245
|
+
"script": script,
|
|
246
|
+
"passed": result["success"],
|
|
247
|
+
"elapsed": result.get("elapsed", 0)
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
self.results["frontend_tests"]["results"] = results
|
|
251
|
+
self.results["frontend_tests"]["status"] = "done"
|
|
252
|
+
|
|
253
|
+
passed = sum(1 for r in results if r["passed"])
|
|
254
|
+
total = len(results)
|
|
255
|
+
self._print_progress(f"📊 Frontend Summary: {passed}/{total} scripts passed",
|
|
256
|
+
"success" if passed == total else "warning")
|
|
257
|
+
|
|
258
|
+
def _generate_summary(self):
|
|
259
|
+
"""Generate summary"""
|
|
260
|
+
self._print_progress("", "info")
|
|
261
|
+
self._print_progress("=" * 70, "info")
|
|
262
|
+
self._print_progress("📊 TEST ENFORCEMENT SUMMARY", "info")
|
|
263
|
+
self._print_progress("=" * 70, "info")
|
|
264
|
+
|
|
265
|
+
# Backend Python
|
|
266
|
+
py = self.results["python"]["summary"]
|
|
267
|
+
if py.get("total", 0) > 0:
|
|
268
|
+
passed = py.get("passed", 0)
|
|
269
|
+
total = py.get("total", 0)
|
|
270
|
+
self._print_progress(f"🐍 Backend: {passed}/{total} tests passed",
|
|
271
|
+
"success" if passed == total else "warning")
|
|
272
|
+
|
|
273
|
+
# Frontend
|
|
274
|
+
fe = self.results["frontend_tests"]
|
|
275
|
+
if fe.get("results"):
|
|
276
|
+
passed = sum(1 for r in fe["results"] if r["passed"])
|
|
277
|
+
total = len(fe["results"])
|
|
278
|
+
self._print_progress(f"🎨 Frontend: {passed}/{total} scripts passed",
|
|
279
|
+
"success" if passed == total else "warning")
|
|
280
|
+
else:
|
|
281
|
+
self._print_progress(f"🎨 Frontend: {fe.get('status', 'unknown')}", "warning")
|
|
282
|
+
|
|
283
|
+
self._print_progress("=" * 70, "info")
|
|
284
|
+
self._print_progress("✅ Test enforcement completed!", "success")
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def run_enforcer():
|
|
288
|
+
"""Run the test enforcer"""
|
|
289
|
+
enforcer = TestEnforcer()
|
|
290
|
+
return enforcer.run()
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def add_enforcer_command(cli):
|
|
294
|
+
"""Add enforcer command to CLI"""
|
|
295
|
+
if click is None:
|
|
296
|
+
return cli
|
|
297
|
+
|
|
298
|
+
@cli.command('enforce')
|
|
299
|
+
@click.option('--python', '-p', is_flag=True, help='Only run Python tests')
|
|
300
|
+
@click.option('--node', '-n', is_flag=True, help='Only run Node.js tests')
|
|
301
|
+
@click.option('--frontend', '-f', is_flag=True, help='Only run frontend tests')
|
|
302
|
+
def enforce_cmd(python: bool, node: bool, frontend: bool):
|
|
303
|
+
"""Enforce and run all tests with real-time progress"""
|
|
304
|
+
enforcer = TestEnforcer()
|
|
305
|
+
|
|
306
|
+
if python:
|
|
307
|
+
enforcer._run_backend_tests()
|
|
308
|
+
elif node:
|
|
309
|
+
# Run node tests (which is actually frontend)
|
|
310
|
+
enforcer._run_frontend_tests()
|
|
311
|
+
elif frontend:
|
|
312
|
+
enforcer._run_frontend_tests()
|
|
313
|
+
else:
|
|
314
|
+
enforcer.run()
|
|
315
|
+
|
|
316
|
+
print("\n✅ Test enforcement completed!")
|
|
317
|
+
|
|
318
|
+
return cli
|