jac-coder 0.1.0__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.
Files changed (85) hide show
  1. jac_coder/__init__.jac +0 -0
  2. jac_coder/api.jac +82 -0
  3. jac_coder/cli_entry.py +25 -0
  4. jac_coder/config.jac +36 -0
  5. jac_coder/context.jac +17 -0
  6. jac_coder/data/examples/ai_agent.md +90 -0
  7. jac_coder/data/examples/blog_app.md +386 -0
  8. jac_coder/data/examples/core_patterns.md +321 -0
  9. jac_coder/data/examples/todo_app.md +321 -0
  10. jac_coder/data/reference/ai.md +131 -0
  11. jac_coder/data/reference/backend.md +215 -0
  12. jac_coder/data/reference/frontend.md +271 -0
  13. jac_coder/data/reference/osp.md +229 -0
  14. jac_coder/data/reference/pitfalls.md +141 -0
  15. jac_coder/data/reference/syntax.md +159 -0
  16. jac_coder/data/rules/core_jac.md +559 -0
  17. jac_coder/data/rules/fullstack.md +362 -0
  18. jac_coder/data/rules/workflow.md +88 -0
  19. jac_coder/events.jac +110 -0
  20. jac_coder/impl/api.impl.jac +399 -0
  21. jac_coder/impl/config.impl.jac +163 -0
  22. jac_coder/impl/context.impl.jac +117 -0
  23. jac_coder/impl/mcp_manager.impl.jac +380 -0
  24. jac_coder/impl/memory.impl.jac +247 -0
  25. jac_coder/impl/nodes.impl.jac +259 -0
  26. jac_coder/impl/permission.impl.jac +62 -0
  27. jac_coder/impl/walkers.impl.jac +298 -0
  28. jac_coder/mcp_manager.jac +35 -0
  29. jac_coder/memory.jac +15 -0
  30. jac_coder/nodes.jac +306 -0
  31. jac_coder/permission.jac +19 -0
  32. jac_coder/serve_entry.jac +30 -0
  33. jac_coder/server.jac +324 -0
  34. jac_coder/tool/__init__.jac +17 -0
  35. jac_coder/tool/checked.jac +10 -0
  36. jac_coder/tool/delegation.jac +23 -0
  37. jac_coder/tool/filesystem.jac +25 -0
  38. jac_coder/tool/git.jac +18 -0
  39. jac_coder/tool/guarded.jac +23 -0
  40. jac_coder/tool/impl/checked.impl.jac +38 -0
  41. jac_coder/tool/impl/delegation.impl.jac +157 -0
  42. jac_coder/tool/impl/filesystem.impl.jac +781 -0
  43. jac_coder/tool/impl/git.impl.jac +115 -0
  44. jac_coder/tool/impl/guarded.impl.jac +72 -0
  45. jac_coder/tool/impl/jac_analyzer.impl.jac +593 -0
  46. jac_coder/tool/impl/jac_docs.impl.jac +136 -0
  47. jac_coder/tool/impl/jac_tools.impl.jac +79 -0
  48. jac_coder/tool/impl/mcp.impl.jac +32 -0
  49. jac_coder/tool/impl/preview.impl.jac +233 -0
  50. jac_coder/tool/impl/question.impl.jac +29 -0
  51. jac_coder/tool/impl/scaffold.impl.jac +231 -0
  52. jac_coder/tool/impl/search.impl.jac +85 -0
  53. jac_coder/tool/impl/shell.impl.jac +89 -0
  54. jac_coder/tool/impl/task.impl.jac +12 -0
  55. jac_coder/tool/impl/think.impl.jac +4 -0
  56. jac_coder/tool/impl/todo.impl.jac +58 -0
  57. jac_coder/tool/impl/validate.impl.jac +236 -0
  58. jac_coder/tool/impl/web.impl.jac +91 -0
  59. jac_coder/tool/jac_analyzer.jac +21 -0
  60. jac_coder/tool/jac_docs.jac +9 -0
  61. jac_coder/tool/jac_tools.jac +11 -0
  62. jac_coder/tool/mcp.jac +17 -0
  63. jac_coder/tool/preview.jac +31 -0
  64. jac_coder/tool/question.jac +7 -0
  65. jac_coder/tool/scaffold.jac +10 -0
  66. jac_coder/tool/search.jac +14 -0
  67. jac_coder/tool/shell.jac +12 -0
  68. jac_coder/tool/task.jac +9 -0
  69. jac_coder/tool/think.jac +5 -0
  70. jac_coder/tool/todo.jac +12 -0
  71. jac_coder/tool/validate.jac +11 -0
  72. jac_coder/tool/vision.jac +17 -0
  73. jac_coder/tool/web.jac +10 -0
  74. jac_coder/util/__init__.jac +18 -0
  75. jac_coder/util/colors.jac +20 -0
  76. jac_coder/util/impl/sandbox.impl.jac +38 -0
  77. jac_coder/util/impl/tool_output.impl.jac +208 -0
  78. jac_coder/util/sandbox.jac +8 -0
  79. jac_coder/util/tool_output.jac +29 -0
  80. jac_coder/walkers.jac +67 -0
  81. jac_coder-0.1.0.dist-info/METADATA +9 -0
  82. jac_coder-0.1.0.dist-info/RECORD +85 -0
  83. jac_coder-0.1.0.dist-info/WHEEL +5 -0
  84. jac_coder-0.1.0.dist-info/entry_points.txt +3 -0
  85. jac_coder-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,115 @@
1
+ def _run_git(args: list[str], cwd: str = "") -> tuple {
2
+ work_dir = cwd or os.getcwd();
3
+ (sandboxed, allowed) = sandbox_path(work_dir);
4
+ if not allowed {
5
+ return ("", f"Error: directory {work_dir} is outside sandbox.", 1);
6
+ }
7
+ try {
8
+ result = subprocess.run(
9
+ ["git"] + args, capture_output=True, text=True, timeout=30, cwd=sandboxed
10
+ );
11
+ return (result.stdout.strip(), result.stderr.strip(), result.returncode);
12
+ } except subprocess.TimeoutExpired {
13
+ return ("", "Error: git command timed out after 30s.", 1);
14
+ } except FileNotFoundError {
15
+ return ("", "Error: git is not installed or not in PATH.", 1);
16
+ } except Exception as e {
17
+ return ("", f"Error: {str(e)}", 1);
18
+ }
19
+ }
20
+
21
+
22
+ impl git_status() -> str {
23
+ tool_status("git_status", "checking working tree");
24
+ (out, err, code) = _run_git(["status", "--short"]);
25
+ if code != 0 {
26
+ tool_end("-> error", error=True);
27
+ return f"Error: {err}";
28
+ }
29
+ if not out {
30
+ tool_end("-> clean");
31
+ return "Working tree clean - no changes.";
32
+ }
33
+ (out, _) = truncate_output(out);
34
+ tool_end(f"-> {len(out.splitlines())} changes");
35
+ return out;
36
+ }
37
+
38
+
39
+ impl git_diff(ref: str = "HEAD") -> str {
40
+ tool_status("git_diff", f"diff against {ref}");
41
+ (out, err, code) = _run_git(["diff", ref]);
42
+ if code != 0 {
43
+ # Try without ref (unstaged changes)
44
+ (out, err, code) = _run_git(["diff"]);
45
+ if code != 0 {
46
+ tool_end("-> error", error=True);
47
+ return f"Error: {err}";
48
+ }
49
+ }
50
+ if not out {
51
+ tool_end("-> no diff");
52
+ return "No differences found.";
53
+ }
54
+ (out, _) = truncate_output(out);
55
+ tool_end(f"-> {len(out.splitlines())} lines");
56
+ return out;
57
+ }
58
+
59
+
60
+ impl git_commit(message: str, files: list[str] = []) -> str {
61
+ tool_status("git_commit", message[:60]);
62
+ if not message {
63
+ tool_end("-> error", error=True);
64
+ return "Error: commit message is required.";
65
+ }
66
+
67
+ # Stage files
68
+ if files {
69
+ for fp in files {
70
+ (_, err, code) = _run_git(["add", fp]);
71
+ if code != 0 {
72
+ tool_end(f"-> stage error: {err}", error=True);
73
+ return f"Error staging {fp}: {err}";
74
+ }
75
+ }
76
+ } else {
77
+ (_, err, code) = _run_git(["add", "-A"]);
78
+ if code != 0 {
79
+ tool_end(f"-> stage error: {err}", error=True);
80
+ return f"Error staging files: {err}";
81
+ }
82
+ }
83
+
84
+ # Commit
85
+ (out, err, code) = _run_git(["commit", "-m", message]);
86
+ if code != 0 {
87
+ if "nothing to commit" in (out + err) {
88
+ tool_end("-> nothing to commit");
89
+ return "Nothing to commit - working tree clean.";
90
+ }
91
+ tool_end("-> commit error", error=True);
92
+ return f"Error: {err or out}";
93
+ }
94
+ tool_end("-> committed");
95
+ return out;
96
+ }
97
+
98
+
99
+ impl git_log(count: int = 10) -> str {
100
+ tool_status("git_log", f"last {count} commits");
101
+ (out, err, code) = _run_git(
102
+ ["log", f"--max-count={count}", "--oneline", "--decorate"]
103
+ );
104
+ if code != 0 {
105
+ tool_end("-> error", error=True);
106
+ return f"Error: {err}";
107
+ }
108
+ if not out {
109
+ tool_end("-> no commits");
110
+ return "No commits found.";
111
+ }
112
+ tool_end(f"-> {len(out.splitlines())} commits");
113
+ (out, _) = truncate_output(out);
114
+ return out;
115
+ }
@@ -0,0 +1,72 @@
1
+ impl _check_permission(tool_id: str, resource: str) -> str {
2
+ action = permission_engine.check(tool_id, resource);
3
+
4
+ if action == "deny" {
5
+ return f"Permission denied: {tool_id} on {resource} is not allowed in this agent mode.";
6
+ }
7
+
8
+ if action == "ask" {
9
+ decision = _ask_user(tool_id, resource);
10
+ if decision == "deny" {
11
+ return f"Permission denied by user: {tool_id} on {resource}";
12
+ }
13
+ if decision == "always" {
14
+ permission_engine.remember_allow(tool_id, "*");
15
+ }
16
+ }
17
+
18
+ return "allow";
19
+ }
20
+
21
+
22
+ impl _ask_user(tool_id: str, resource: str) -> str {
23
+ if os.environ.get("JACCODER_WEB_MODE", "") {
24
+ return "allow";
25
+ }
26
+ display = resource[:80] + "..." if len(resource) > 80 else resource;
27
+ print(f"\n{YELLOW}[Permission]{RESET} {tool_id}: {display}");
28
+ print(f" {DIM}(y)es / (n)o / (a)lways allow {tool_id}{RESET}");
29
+ try {
30
+ answer = input(" Allow? ").strip().lower();
31
+ } except (EOFError, KeyboardInterrupt) {
32
+ return "deny";
33
+ }
34
+ if answer in ["a", "always"] {
35
+ return "always";
36
+ }
37
+ if answer in ["y", "yes", ""] {
38
+ return "allow";
39
+ }
40
+ return "deny";
41
+ }
42
+
43
+
44
+ impl write_file_guarded(file_path: str, content: str) -> str {
45
+ verdict = _check_permission("write_file", file_path);
46
+ if verdict != "allow" {
47
+ return verdict;
48
+ }
49
+ return write_file(file_path, content);
50
+ }
51
+
52
+
53
+ impl edit_file_guarded(
54
+ file_path: str, old_string: str, new_string: str, replace_all: bool = False
55
+ ) -> str {
56
+ verdict = _check_permission("edit_file", file_path);
57
+ if verdict != "allow" {
58
+ return verdict;
59
+ }
60
+ return edit_file(file_path, old_string, new_string, replace_all);
61
+ }
62
+
63
+
64
+ impl run_command(
65
+ command: str, workdir: str = ".", timeout: int = 120, background: bool = False
66
+ ) -> str {
67
+ verdict = _check_permission("bash_exec", command);
68
+ if verdict != "allow" {
69
+ return verdict;
70
+ }
71
+ return bash_exec(command, workdir, timeout, background);
72
+ }