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.
Files changed (26) hide show
  1. {errorai-0.9.0 → errorai-1.1.0}/ErrorAI.egg-info/PKG-INFO +1 -1
  2. {errorai-0.9.0 → errorai-1.1.0}/PKG-INFO +1 -1
  3. errorai-1.1.0/errorai/cli.py +172 -0
  4. {errorai-0.9.0 → errorai-1.1.0}/errorai/runtime.py +8 -2
  5. {errorai-0.9.0 → errorai-1.1.0}/pyproject.toml +1 -1
  6. errorai-0.9.0/errorai/cli.py +0 -67
  7. {errorai-0.9.0 → errorai-1.1.0}/ErrorAI.egg-info/SOURCES.txt +0 -0
  8. {errorai-0.9.0 → errorai-1.1.0}/ErrorAI.egg-info/dependency_links.txt +0 -0
  9. {errorai-0.9.0 → errorai-1.1.0}/ErrorAI.egg-info/entry_points.txt +0 -0
  10. {errorai-0.9.0 → errorai-1.1.0}/ErrorAI.egg-info/requires.txt +0 -0
  11. {errorai-0.9.0 → errorai-1.1.0}/ErrorAI.egg-info/top_level.txt +0 -0
  12. {errorai-0.9.0 → errorai-1.1.0}/README.md +0 -0
  13. {errorai-0.9.0 → errorai-1.1.0}/errorai/__init__.py +0 -0
  14. {errorai-0.9.0 → errorai-1.1.0}/errorai/__main__.py +0 -0
  15. {errorai-0.9.0 → errorai-1.1.0}/errorai/bootstrap.py +0 -0
  16. {errorai-0.9.0 → errorai-1.1.0}/errorai/compat.py +0 -0
  17. {errorai-0.9.0 → errorai-1.1.0}/errorai/config.py +0 -0
  18. {errorai-0.9.0 → errorai-1.1.0}/errorai/environment.py +0 -0
  19. {errorai-0.9.0 → errorai-1.1.0}/errorai/pipeline.py +0 -0
  20. {errorai-0.9.0 → errorai-1.1.0}/errorai/providers.py +0 -0
  21. {errorai-0.9.0 → errorai-1.1.0}/errorai/universal.py +0 -0
  22. {errorai-0.9.0 → errorai-1.1.0}/setup.cfg +0 -0
  23. {errorai-0.9.0 → errorai-1.1.0}/tests/test_bootstrap.py +0 -0
  24. {errorai-0.9.0 → errorai-1.1.0}/tests/test_config.py +0 -0
  25. {errorai-0.9.0 → errorai-1.1.0}/tests/test_runtime.py +0 -0
  26. {errorai-0.9.0 → errorai-1.1.0}/tests/test_safety.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErrorAI
3
- Version: 0.9.0
3
+ Version: 1.1.0
4
4
  Summary: Python-only autonomous runtime that watches/analyzes errors with safe local auto-fix fallbacks.
5
5
  Author: Aswanth R
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErrorAI
3
- Version: 0.9.0
3
+ Version: 1.1.0
4
4
  Summary: Python-only autonomous runtime that watches/analyzes errors with safe local auto-fix fallbacks.
5
5
  Author: Aswanth R
6
6
  License: MIT
@@ -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
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ErrorAI"
7
- version = "0.9.0"
7
+ version = "1.1.0"
8
8
  description = "Python-only autonomous runtime that watches/analyzes errors with safe local auto-fix fallbacks."
9
9
  readme = "README.md"
10
10
  authors = [
@@ -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