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,229 @@
1
+ # Object-Spatial Programming — Nodes, Edges, Walkers
2
+
3
+ ## Node Definition
4
+
5
+ Nodes are data containers that live in the graph. Connected to `root`, they auto-persist (SQLite).
6
+
7
+ ```jac
8
+ node Session {
9
+ has id: str = "";
10
+ has chat_history: list[dict] = [];
11
+
12
+ def postinit {
13
+ if not self.id { self.id = str(uuid4()); }
14
+ }
15
+ }
16
+
17
+ node City {
18
+ has name: str;
19
+ has population: int = 0;
20
+ }
21
+ ```
22
+
23
+ ## Edge Definition
24
+
25
+ Edges define typed relationships between nodes.
26
+
27
+ ```jac
28
+ edge Road {
29
+ has distance: float = 0.0;
30
+ }
31
+
32
+ edge Knows {
33
+ has since: int;
34
+ has strength: float = 1.0;
35
+ }
36
+ ```
37
+
38
+ ## Graph Construction and Connection
39
+
40
+ ```jac
41
+ # Connect with default edge
42
+ a ++> b;
43
+
44
+ # Connect with typed edge
45
+ alice +>:Knows(since=2020):+> bob;
46
+
47
+ # Create + connect in one step (returns list — use [0])
48
+ new_node = (here ++> Session(id="abc"))[0];
49
+
50
+ # Chain connections
51
+ root ++> Router() ++> BuildHandler();
52
+
53
+ # Connect to root (auto-persists)
54
+ root ++> City(name="NYC", population=8_300_000);
55
+ ```
56
+
57
+ ## Graph Querying
58
+
59
+ ```jac
60
+ # Query all connected nodes of a type
61
+ sessions = [-->][?:Session];
62
+ cities = [root-->][?:City];
63
+
64
+ # Query with filter condition
65
+ active = [-->][?:Session](?status == "active");
66
+ big_cities = [root-->][?:City](?population > 1_000_000);
67
+
68
+ # Query by edge type
69
+ friends = [->:Knows:->];
70
+
71
+ # Chained query
72
+ handlers = [root-->][?:Router]-->[?:BuildHandler];
73
+
74
+ # Delete edge
75
+ a del--> b;
76
+
77
+ # Delete node
78
+ del node;
79
+ ```
80
+
81
+ ## Walker Definition
82
+
83
+ Walkers traverse the graph and execute abilities on each visited node.
84
+
85
+ ```jac
86
+ walker Explorer {
87
+ has visited: list[str] = [];
88
+
89
+ can visit_city with City entry {
90
+ self.visited.append(here.name);
91
+ print(f"Visiting {here.name}");
92
+ visit [-->]; # continue to connected nodes
93
+ }
94
+ }
95
+
96
+ # Spawn walker from root
97
+ result = root spawn Explorer();
98
+ ```
99
+
100
+ ## Walker Traversal Commands
101
+
102
+ ```jac
103
+ visit [-->]; # Visit all outgoing nodes
104
+ visit [-->][?:City]; # Visit only City nodes
105
+ visit [<--]; # Back-traverse (incoming)
106
+ visit [-->][?:Router] else { # Fallback if none found
107
+ router = (here ++> Router())[0];
108
+ visit router;
109
+ };
110
+
111
+ report {"data": value}; # Emit data from walker
112
+ disengage; # Stop walker entirely
113
+ ```
114
+
115
+ ## Context Keywords
116
+
117
+ | Keyword | Meaning | Used In |
118
+ |---------|---------|---------|
119
+ | `here` | Current node being visited | Walker abilities |
120
+ | `visitor` | The walker visiting this node | Node abilities |
121
+ | `self` | The archetype instance | Any method |
122
+ | `root` | Graph root node | Anywhere |
123
+
124
+ ```jac
125
+ # Walker ability — here is the node, self is the walker
126
+ walker Collector {
127
+ has items: list = [];
128
+ can collect with DataNode entry {
129
+ self.items.append(here.value);
130
+ visit [-->];
131
+ }
132
+ }
133
+
134
+ # Node ability — here is this node, visitor is the walker
135
+ node DataNode {
136
+ has value: int;
137
+ can respond with Collector entry {
138
+ print(f"Walker has {len(visitor.items)} items");
139
+ }
140
+ }
141
+ ```
142
+
143
+ ## disengage vs return
144
+
145
+ - `return` — exits current ability only. Walker continues to next queued node.
146
+ - `disengage` — stops walker entirely. No more traversal.
147
+
148
+ ```jac
149
+ walker Search {
150
+ has target: str;
151
+ can check with Item entry {
152
+ if here.name == self.target {
153
+ report here;
154
+ disengage; # found it, stop everything
155
+ }
156
+ visit [-->]; # keep searching
157
+ }
158
+ }
159
+ ```
160
+
161
+ ## Walker Spawn and Reports
162
+
163
+ ```jac
164
+ # Spawn walker and get result
165
+ result = root spawn GetData();
166
+ data = result.reports[0]; # Access first reported value
167
+
168
+ # Walker that reports
169
+ walker GetData {
170
+ can fetch with Root entry {
171
+ items = [{"id": str(i.id)} for i in [-->][?:Item]];
172
+ report {"items": items};
173
+ }
174
+ }
175
+ ```
176
+
177
+ ## Lazy Graph Creation Pattern
178
+
179
+ ```jac
180
+ visit [-->][?:Router] else {
181
+ router = (here ++> Router())[0];
182
+ visit router;
183
+ };
184
+ ```
185
+
186
+ ## Walker as REST Endpoint
187
+
188
+ ```jac
189
+ walker :pub search_items {
190
+ has query: str;
191
+ static has as_query: list = ["query"]; # for GET params
192
+ can find with Root entry {
193
+ matches = [i for i in [-->][?:Item] if self.query in i.name];
194
+ report {"results": matches};
195
+ }
196
+ }
197
+ ```
198
+
199
+ ## Parent-Child Graph Patterns
200
+
201
+ ```jac
202
+ node Category { has name: str; }
203
+ node Item { has title: str; }
204
+
205
+ # Hierarchy: root → Category → Item
206
+ def:pub add_category(name: str) -> dict {
207
+ cat = (root ++> Category(name=name))[0];
208
+ return {"name": cat.name};
209
+ }
210
+
211
+ def:pub add_item(category_name: str, title: str) -> dict {
212
+ for cat in [root-->][?:Category] {
213
+ if cat.name == category_name {
214
+ item = (cat ++> Item(title=title))[0];
215
+ return {"title": item.title};
216
+ }
217
+ }
218
+ return {"error": "Category not found"};
219
+ }
220
+
221
+ def:pub get_items_by_category(category_name: str) -> list {
222
+ for cat in [root-->][?:Category] {
223
+ if cat.name == category_name {
224
+ return [{"title": i.title} for i in [cat-->][?:Item]];
225
+ }
226
+ }
227
+ return [];
228
+ }
229
+ ```
@@ -0,0 +1,141 @@
1
+ # Runtime Gotchas — Passes Compilation, Crashes at Runtime
2
+
3
+ ## JS Constructors Need Reflect.construct
4
+
5
+ In .cl.jac, `ClassName()` without `new` returns wrong type or throws. Jac has no `new` keyword.
6
+
7
+ ```jac
8
+ # WRONG — Date() returns string, not Date object
9
+ year = Date().getFullYear(); # CRASH
10
+
11
+ # RIGHT
12
+ year = Reflect.construct(Date, []).getFullYear();
13
+ ws = Reflect.construct(WebSocket, ["ws://localhost"]);
14
+ ```
15
+
16
+ **Safe statics (no Reflect needed):** `Date.now()`, `JSON.parse()`, `JSON.stringify()`, `Math.random()`, `Math.floor()`
17
+
18
+ **Always need Reflect.construct:** Date, WebSocket, TextDecoder, TextEncoder, URL, URLSearchParams, FormData, AbortController, RegExp, Error, Worker, Headers, Request, Response, Uint8Array, ArrayBuffer, Blob, File, FileReader, MutationObserver, ResizeObserver, IntersectionObserver
19
+
20
+ ## Browser Global Name Conflicts
21
+
22
+ Do NOT define functions with names that shadow browser globals:
23
+
24
+ ```jac
25
+ # WRONG — shadows window.open
26
+ def open(url: str) -> None { ... }
27
+
28
+ # RIGHT
29
+ def handleOpen(url: str) -> None { ... }
30
+ ```
31
+
32
+ **Avoid as function names:** open, close, print, focus, blur, scroll, fetch, stop, find, alert, confirm, prompt
33
+
34
+ ## Callback-in-Lambda Bug
35
+
36
+ Jac compiles `callback(arg)` inside a lambda as `new callback(arg)`. Crashes silently.
37
+
38
+ ```jac
39
+ # WRONG — lambda compiles to new onMessage(msg), crashes
40
+ ws.onmessage = lambda(e: any) -> None { onMessage(e.data); };
41
+
42
+ # RIGHT — named handler with .call()
43
+ msgHandler = onMessage;
44
+ def handle_ws_message(e: any) -> None {
45
+ msgHandler.call(None, e.data);
46
+ }
47
+ ws.onmessage = handle_ws_message;
48
+ ```
49
+
50
+ ## Undefined Property Access Crashes
51
+
52
+ The #1 runtime crash in .cl.jac. Happens when accessing property on `undefined`.
53
+
54
+ ```jac
55
+ # WRONG — crashes if parent doesn't pass "items" prop
56
+ items = props.items; # undefined!
57
+ return <div>{[... for item in items]}</div>; # CRASH
58
+
59
+ # RIGHT — always default props
60
+ items = props.items or [];
61
+ title = props.title or "";
62
+
63
+ # WRONG — chaining on undefined
64
+ data = result.reports[0].items; # CRASH if reports empty
65
+
66
+ # RIGHT — guard each level
67
+ if result and result.reports and len(result.reports) > 0 {
68
+ data = result.reports[0].items or [];
69
+ }
70
+ ```
71
+
72
+ ## Number and Boolean Display in JSX
73
+
74
+ Jac doesn't auto-convert to strings in JSX.
75
+
76
+ ```jac
77
+ # WRONG — may render nothing
78
+ <span>{count}</span>
79
+
80
+ # RIGHT
81
+ <span>{str(count)}</span>
82
+ <p>{str(item["price"])}</p>
83
+ ```
84
+
85
+ ## sv import kwargs Are Broken
86
+
87
+ In .cl.jac, kwargs compile to a single dict argument. Server gets wrong data.
88
+
89
+ ```jac
90
+ # WRONG — server receives {"a": {"a":2, "b":4, "op":"add"}}
91
+ resp = await calc(a=2, b=4, op="add");
92
+
93
+ # RIGHT — positional, order matches def:pub signature
94
+ resp = await calc(2, 4, "add");
95
+ ```
96
+
97
+ ## State List Mutation Doesn't Re-render
98
+
99
+ `.append()` mutates in place — React won't detect the change.
100
+
101
+ ```jac
102
+ # WRONG — no re-render
103
+ items.append(newItem);
104
+
105
+ # RIGHT — new reference triggers re-render
106
+ items = items + [newItem];
107
+ ```
108
+
109
+ ## Comments Inside JSX Break Rendering
110
+
111
+ ```jac
112
+ # WRONG — all of these crash
113
+ return <div>
114
+ {# comment}
115
+ <!-- comment -->
116
+ {/* comment */}
117
+ </div>;
118
+
119
+ # RIGHT — comments above JSX only
120
+ # Render the list
121
+ return <div>...</div>;
122
+ ```
123
+
124
+ ## .impl.jac Parse Error Breaks Entire File
125
+
126
+ A single syntax error in an `.impl.jac` file causes ALL implementations in that file to have 0 body items. The compiler won't report which implementation failed — they all silently become empty. Always double-check syntax in impl files.
127
+
128
+ ## Missing :pub on Exports
129
+
130
+ - Components in `.cl.jac` need `def:pub` to be importable
131
+ - Walkers need `walker :pub` for REST API
132
+ - `app()` in main.jac MUST be `def:pub`
133
+ - Hooks need `def:pub` to be importable
134
+
135
+ ```jac
136
+ # WRONG — not importable
137
+ def Header() -> JsxElement { ... }
138
+
139
+ # RIGHT
140
+ def:pub Header() -> JsxElement { ... }
141
+ ```
@@ -0,0 +1,159 @@
1
+ # Jac Language Syntax Reference
2
+
3
+ ## Variables and Types
4
+
5
+ **Builtin types:** int, float, str, bool, bytes, list, tuple, set, dict, any, type, None
6
+
7
+ **Generic types:** `list[str]`, `dict[str, int]`, `set[int]`, `tuple[str, int]`, `Type | None`
8
+
9
+ ```jac
10
+ # Field declarations in archetypes
11
+ obj Example {
12
+ has name: str; # Required field
13
+ has count: int = 0; # With default
14
+ has items: list[str] = []; # Generic type
15
+ has data: dict | None = None; # Optional
16
+ }
17
+
18
+ # Module-level global
19
+ glob config: dict = {};
20
+
21
+ # Local variables
22
+ x: int = 42; # Annotated
23
+ name = "hello"; # Type inferred
24
+ ```
25
+
26
+ Type annotations are **required** on `has` fields and function signatures.
27
+
28
+ ## Functions and Methods
29
+
30
+ ```jac
31
+ # Standalone function
32
+ def greet(name: str, greeting: str = "Hello") -> str {
33
+ return f"{greeting}, {name}!";
34
+ }
35
+
36
+ # Object with methods
37
+ obj Person {
38
+ has name: str;
39
+ has age: int = 0;
40
+
41
+ def postinit { print(f"Created {self.name}"); }
42
+ def greet() -> str { return f"Hi, I'm {self.name}"; }
43
+ def is_adult() -> bool { return self.age >= 18; }
44
+ }
45
+
46
+ # Inheritance
47
+ obj Student(Person) { has grade: str = "A"; }
48
+
49
+ # Static method
50
+ obj Utils {
51
+ static def helper() -> int { return 42; }
52
+ }
53
+ ```
54
+
55
+ ## Enums
56
+
57
+ ```jac
58
+ enum Color { RED = "red", GREEN = "green", BLUE = "blue" }
59
+ enum Direction { NORTH, SOUTH, EAST, WEST }
60
+
61
+ # Usage
62
+ c = Color.RED;
63
+ print(c.value); # "red"
64
+ ```
65
+
66
+ ## Control Flow
67
+
68
+ ```jac
69
+ # if/elif/else
70
+ if x > 0 { print("positive"); }
71
+ elif x == 0 { print("zero"); }
72
+ else { print("negative"); }
73
+
74
+ # Inline conditional
75
+ result = "yes" if condition else "no";
76
+
77
+ # Loops
78
+ for item in items { print(item); }
79
+ for (i, x) in enumerate(items) { print(i, x); }
80
+ for (k, v) in my_dict.items() { print(k, v); }
81
+ while count < 10 { count += 1; }
82
+
83
+ # Match/case (uses colons, not braces)
84
+ match value {
85
+ case "add":
86
+ result = a + b;
87
+ case "sub":
88
+ result = a - b;
89
+ case _:
90
+ result = 0;
91
+ }
92
+
93
+ # Exception handling
94
+ try { result = risky(); }
95
+ except ValueError as e { print(f"Error: {e}"); }
96
+ finally { cleanup(); }
97
+ ```
98
+
99
+ ## Comprehensions
100
+
101
+ ```jac
102
+ squares = [x ** 2 for x in range(10)];
103
+ filtered = [x for x in items if x > 0];
104
+ mapping = {k: v for (k, v) in items.items() if v > 0};
105
+ ```
106
+
107
+ ## String Methods
108
+
109
+ All Python string methods work in Jac:
110
+
111
+ ```jac
112
+ name.lower(); name.upper(); name.strip();
113
+ name.split(","); name.replace("old", "new");
114
+ name.startswith("prefix"); name.endswith("suffix");
115
+ ",".join(items); name.find("sub");
116
+ f"Hello, {name}!"; # f-strings supported
117
+ ```
118
+
119
+ ## Access Modifiers
120
+
121
+ | Modifier | Meaning | Use Case |
122
+ |----------|---------|----------|
123
+ | `:pub` | Public | REST endpoint, importable component/hook |
124
+ | `:priv` | Private (auth) | Per-user endpoint, requires login |
125
+ | `:protect` | Protected | Module-internal helper |
126
+ | *(none)* | Default | Module-scoped, not exposed |
127
+
128
+ ```jac
129
+ walker :pub get_tasks { ... } # Public API
130
+ walker :priv add_task { ... } # Authenticated
131
+ def :protect validate(x: str) -> bool { ... }
132
+ def:pub get_items() -> list { ... } # Public function endpoint
133
+ ```
134
+
135
+ ## Module Entry Point
136
+
137
+ ```jac
138
+ with entry {
139
+ print("Module loaded");
140
+ root spawn MyWalker();
141
+ }
142
+ ```
143
+
144
+ ## Imports
145
+
146
+ ```jac
147
+ # Python standard library
148
+ import from os { path }
149
+ import from datetime { datetime }
150
+ import from pathlib { Path }
151
+ import os;
152
+ import json;
153
+
154
+ # Jac modules (relative)
155
+ import from .submodule { Helper }
156
+ import from jac_coder.nodes { Session }
157
+
158
+ # NEVER use import:py — it's deprecated
159
+ ```