ErrorAI 0.9.0__tar.gz → 1.1.0__tar.gz
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.
- {errorai-0.9.0 → errorai-1.1.0}/ErrorAI.egg-info/PKG-INFO +1 -1
- {errorai-0.9.0 → errorai-1.1.0}/PKG-INFO +1 -1
- errorai-1.1.0/errorai/cli.py +172 -0
- {errorai-0.9.0 → errorai-1.1.0}/errorai/runtime.py +8 -2
- {errorai-0.9.0 → errorai-1.1.0}/pyproject.toml +1 -1
- errorai-0.9.0/errorai/cli.py +0 -67
- {errorai-0.9.0 → errorai-1.1.0}/ErrorAI.egg-info/SOURCES.txt +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/ErrorAI.egg-info/dependency_links.txt +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/ErrorAI.egg-info/entry_points.txt +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/ErrorAI.egg-info/requires.txt +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/ErrorAI.egg-info/top_level.txt +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/README.md +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/errorai/__init__.py +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/errorai/__main__.py +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/errorai/bootstrap.py +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/errorai/compat.py +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/errorai/config.py +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/errorai/environment.py +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/errorai/pipeline.py +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/errorai/providers.py +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/errorai/universal.py +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/setup.cfg +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/tests/test_bootstrap.py +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/tests/test_config.py +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/tests/test_runtime.py +0 -0
- {errorai-0.9.0 → errorai-1.1.0}/tests/test_safety.py +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import ast
|
|
5
|
+
import traceback
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from .bootstrap import ensure_model
|
|
9
|
+
from .config import config_template, load_config
|
|
10
|
+
from .runtime import get_runtime
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def cmd_init(args) -> int:
|
|
14
|
+
root = Path.cwd()
|
|
15
|
+
config_path = root / ".errorai.toml"
|
|
16
|
+
if not config_path.exists() or args.force:
|
|
17
|
+
config_path.write_text(config_template(), encoding="utf-8")
|
|
18
|
+
print(f"[errorai] Wrote {config_path}")
|
|
19
|
+
else:
|
|
20
|
+
print(f"[errorai] Config already exists: {config_path}")
|
|
21
|
+
return 0
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def cmd_doctor(_args) -> int:
|
|
25
|
+
runtime = get_runtime().initialize()
|
|
26
|
+
status = runtime.status_report()
|
|
27
|
+
print("ErrorAI Doctor")
|
|
28
|
+
for key in (
|
|
29
|
+
"environment",
|
|
30
|
+
"can_watch_fs",
|
|
31
|
+
"can_apply_patches",
|
|
32
|
+
"mode",
|
|
33
|
+
"model_ready",
|
|
34
|
+
"model_mode",
|
|
35
|
+
"model_detail",
|
|
36
|
+
"dry_run",
|
|
37
|
+
"project_root",
|
|
38
|
+
):
|
|
39
|
+
print(f"- {key}: {status[key]}")
|
|
40
|
+
return 0
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def cmd_install_model(_args) -> int:
|
|
44
|
+
cfg = load_config()
|
|
45
|
+
status = ensure_model(cfg.model, explicit=True)
|
|
46
|
+
print(status.detail)
|
|
47
|
+
return 0 if status.ready else 1
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _prompt_fix() -> bool:
|
|
51
|
+
answer = input("Should I fix it [Y/N]: ").strip().lower()
|
|
52
|
+
return answer in {"y", "yes"}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _attempt_simple_syntax_fix(content: str, err: SyntaxError) -> tuple[str, bool, str]:
|
|
56
|
+
if err.msg and "expected ':'" in err.msg and err.lineno:
|
|
57
|
+
lines = content.splitlines()
|
|
58
|
+
idx = err.lineno - 1
|
|
59
|
+
if 0 <= idx < len(lines):
|
|
60
|
+
line = lines[idx].rstrip()
|
|
61
|
+
if line and not line.endswith(":"):
|
|
62
|
+
lines[idx] = line + ":"
|
|
63
|
+
return "\n".join(lines) + ("\n" if content.endswith("\n") else ""), True, "Added missing ':'"
|
|
64
|
+
return content, False, "No safe automatic syntax fix available"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _attempt_simple_runtime_fix(content: str, exc: Exception) -> tuple[str, bool, str]:
|
|
68
|
+
if isinstance(exc, TypeError) and "unsupported operand type(s) for +:" in str(exc):
|
|
69
|
+
# Minimal safe stub: no automatic source mutation yet.
|
|
70
|
+
return content, False, "Detected TypeError (+ with incompatible types), but no safe auto-fix rule matched"
|
|
71
|
+
return content, False, "No safe automatic runtime fix available"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def cmd_check(args) -> int:
|
|
75
|
+
file_path = Path(args.file_path).expanduser().resolve()
|
|
76
|
+
if not file_path.exists() or not file_path.is_file():
|
|
77
|
+
print(f"[errorai] File not found: {file_path}")
|
|
78
|
+
return 2
|
|
79
|
+
|
|
80
|
+
source = file_path.read_text(encoding="utf-8")
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
ast.parse(source, filename=str(file_path))
|
|
84
|
+
print(f"[errorai] ✅ No syntax errors in {file_path}")
|
|
85
|
+
return 0
|
|
86
|
+
except SyntaxError as err:
|
|
87
|
+
print(f"[errorai] ❌ SyntaxError in {file_path}")
|
|
88
|
+
print(f"[errorai] Line {err.lineno}, Col {err.offset}: {err.msg}")
|
|
89
|
+
if err.text:
|
|
90
|
+
print(f"[errorai] >> {err.text.rstrip()}")
|
|
91
|
+
|
|
92
|
+
if not _prompt_fix():
|
|
93
|
+
return 1
|
|
94
|
+
|
|
95
|
+
fixed_source, changed, detail = _attempt_simple_syntax_fix(source, err)
|
|
96
|
+
print(f"[errorai] {detail}")
|
|
97
|
+
|
|
98
|
+
if changed:
|
|
99
|
+
file_path.write_text(fixed_source, encoding="utf-8")
|
|
100
|
+
print(f"[errorai] Applied fix to {file_path}")
|
|
101
|
+
try:
|
|
102
|
+
ast.parse(fixed_source, filename=str(file_path))
|
|
103
|
+
print("[errorai] ✅ Re-check passed")
|
|
104
|
+
return 0
|
|
105
|
+
except SyntaxError as second:
|
|
106
|
+
print(f"[errorai] Still invalid after fix: {second}")
|
|
107
|
+
return 1
|
|
108
|
+
return 1
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def cmd_run(args) -> int:
|
|
112
|
+
file_path = Path(args.file_path).expanduser().resolve()
|
|
113
|
+
if not file_path.exists() or not file_path.is_file():
|
|
114
|
+
print(f"[errorai] File not found: {file_path}")
|
|
115
|
+
return 2
|
|
116
|
+
|
|
117
|
+
# Run syntax check first
|
|
118
|
+
check_result = cmd_check(argparse.Namespace(file_path=str(file_path)))
|
|
119
|
+
if check_result != 0:
|
|
120
|
+
return check_result
|
|
121
|
+
|
|
122
|
+
source = file_path.read_text(encoding="utf-8")
|
|
123
|
+
globals_dict = {"__name__": "__main__", "__file__": str(file_path)}
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
exec(compile(source, str(file_path), "exec"), globals_dict, globals_dict)
|
|
127
|
+
return 0
|
|
128
|
+
except Exception as exc:
|
|
129
|
+
print(f"[errorai] ❌ Runtime error: {type(exc).__name__}: {exc}")
|
|
130
|
+
if not _prompt_fix():
|
|
131
|
+
return 1
|
|
132
|
+
fixed_source, changed, detail = _attempt_simple_runtime_fix(source, exc)
|
|
133
|
+
print(f"[errorai] {detail}")
|
|
134
|
+
if changed:
|
|
135
|
+
file_path.write_text(fixed_source, encoding="utf-8")
|
|
136
|
+
print(f"[errorai] Applied runtime fix to {file_path}")
|
|
137
|
+
print("[errorai] Re-run with: errorai run <file path>")
|
|
138
|
+
return 0
|
|
139
|
+
print("[errorai] No fix applied")
|
|
140
|
+
traceback.print_exc()
|
|
141
|
+
return 1
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
145
|
+
parser = argparse.ArgumentParser(prog="errorai")
|
|
146
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
147
|
+
|
|
148
|
+
init_parser = sub.add_parser("init", help="Create default .errorai.toml config.")
|
|
149
|
+
init_parser.add_argument("--force", action="store_true", help="Overwrite existing config.")
|
|
150
|
+
init_parser.set_defaults(func=cmd_init)
|
|
151
|
+
|
|
152
|
+
doctor_parser = sub.add_parser("doctor", help="Check runtime readiness and fallback state.")
|
|
153
|
+
doctor_parser.set_defaults(func=cmd_doctor)
|
|
154
|
+
|
|
155
|
+
install_parser = sub.add_parser("install-model", help="Install or retry local model bootstrap.")
|
|
156
|
+
install_parser.set_defaults(func=cmd_install_model)
|
|
157
|
+
|
|
158
|
+
check_parser = sub.add_parser("check", help="Check a Python file for syntax errors and offer auto-fix.")
|
|
159
|
+
check_parser.add_argument("file_path", help="Path to .py file")
|
|
160
|
+
check_parser.set_defaults(func=cmd_check)
|
|
161
|
+
|
|
162
|
+
run_parser = sub.add_parser("run", help="Check then execute a Python file with runtime error interception.")
|
|
163
|
+
run_parser.add_argument("file_path", help="Path to .py file")
|
|
164
|
+
run_parser.set_defaults(func=cmd_run)
|
|
165
|
+
|
|
166
|
+
return parser
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def main(argv: list[str] | None = None) -> int:
|
|
170
|
+
parser = build_parser()
|
|
171
|
+
args = parser.parse_args(argv)
|
|
172
|
+
return args.func(args)
|
|
@@ -95,12 +95,18 @@ class RuntimeManager:
|
|
|
95
95
|
threading.excepthook = self._thread_excepthook
|
|
96
96
|
|
|
97
97
|
def _sys_excepthook(self, exc_type, exc_value, exc_tb):
|
|
98
|
-
self.process_exception(exc_type, exc_value, exc_tb)
|
|
98
|
+
handled = self.process_exception(exc_type, exc_value, exc_tb)
|
|
99
|
+
if handled:
|
|
100
|
+
print("[errorai] exception intercepted")
|
|
101
|
+
return
|
|
99
102
|
if self._orig_sys_hook:
|
|
100
103
|
self._orig_sys_hook(exc_type, exc_value, exc_tb)
|
|
101
104
|
|
|
102
105
|
def _thread_excepthook(self, args):
|
|
103
|
-
self.process_exception(args.exc_type, args.exc_value, args.exc_traceback)
|
|
106
|
+
handled = self.process_exception(args.exc_type, args.exc_value, args.exc_traceback)
|
|
107
|
+
if handled:
|
|
108
|
+
print("[errorai] thread exception intercepted")
|
|
109
|
+
return
|
|
104
110
|
if self._orig_thread_hook:
|
|
105
111
|
self._orig_thread_hook(args)
|
|
106
112
|
|
errorai-0.9.0/errorai/cli.py
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import argparse
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
from .bootstrap import ensure_model
|
|
7
|
-
from .config import config_template, load_config
|
|
8
|
-
from .runtime import get_runtime
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def cmd_init(args) -> int:
|
|
12
|
-
root = Path.cwd()
|
|
13
|
-
config_path = root / ".errorai.toml"
|
|
14
|
-
if not config_path.exists() or args.force:
|
|
15
|
-
config_path.write_text(config_template(), encoding="utf-8")
|
|
16
|
-
print(f"[errorai] Wrote {config_path}")
|
|
17
|
-
else:
|
|
18
|
-
print(f"[errorai] Config already exists: {config_path}")
|
|
19
|
-
return 0
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def cmd_doctor(_args) -> int:
|
|
23
|
-
runtime = get_runtime().initialize()
|
|
24
|
-
status = runtime.status_report()
|
|
25
|
-
print("ErrorAI Doctor")
|
|
26
|
-
for key in (
|
|
27
|
-
"environment",
|
|
28
|
-
"can_watch_fs",
|
|
29
|
-
"can_apply_patches",
|
|
30
|
-
"mode",
|
|
31
|
-
"model_ready",
|
|
32
|
-
"model_mode",
|
|
33
|
-
"model_detail",
|
|
34
|
-
"dry_run",
|
|
35
|
-
"project_root",
|
|
36
|
-
):
|
|
37
|
-
print(f"- {key}: {status[key]}")
|
|
38
|
-
return 0
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def cmd_install_model(_args) -> int:
|
|
42
|
-
cfg = load_config()
|
|
43
|
-
status = ensure_model(cfg.model, explicit=True)
|
|
44
|
-
print(status.detail)
|
|
45
|
-
return 0 if status.ready else 1
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def build_parser() -> argparse.ArgumentParser:
|
|
49
|
-
parser = argparse.ArgumentParser(prog="errorai")
|
|
50
|
-
sub = parser.add_subparsers(dest="command", required=True)
|
|
51
|
-
|
|
52
|
-
init_parser = sub.add_parser("init", help="Create default .errorai.toml config.")
|
|
53
|
-
init_parser.add_argument("--force", action="store_true", help="Overwrite existing config.")
|
|
54
|
-
init_parser.set_defaults(func=cmd_init)
|
|
55
|
-
|
|
56
|
-
doctor_parser = sub.add_parser("doctor", help="Check runtime readiness and fallback state.")
|
|
57
|
-
doctor_parser.set_defaults(func=cmd_doctor)
|
|
58
|
-
|
|
59
|
-
install_parser = sub.add_parser("install-model", help="Install or retry local model bootstrap.")
|
|
60
|
-
install_parser.set_defaults(func=cmd_install_model)
|
|
61
|
-
return parser
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def main(argv: list[str] | None = None) -> int:
|
|
65
|
-
parser = build_parser()
|
|
66
|
-
args = parser.parse_args(argv)
|
|
67
|
-
return args.func(args)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|