voidx 1.0.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 (126) hide show
  1. voidx/__init__.py +3 -0
  2. voidx/agent/__init__.py +0 -0
  3. voidx/agent/agents.py +439 -0
  4. voidx/agent/attachments.py +235 -0
  5. voidx/agent/graph.py +463 -0
  6. voidx/agent/graph_components/__init__.py +1 -0
  7. voidx/agent/graph_components/compaction.py +268 -0
  8. voidx/agent/graph_components/permissions.py +139 -0
  9. voidx/agent/graph_components/run_loop.py +532 -0
  10. voidx/agent/graph_components/runtime.py +14 -0
  11. voidx/agent/graph_components/streaming.py +351 -0
  12. voidx/agent/graph_components/subagent.py +278 -0
  13. voidx/agent/graph_components/tool_execution.py +208 -0
  14. voidx/agent/runtime_context.py +368 -0
  15. voidx/agent/slash.py +466 -0
  16. voidx/agent/slash_components/__init__.py +1 -0
  17. voidx/agent/slash_components/code_ide.py +68 -0
  18. voidx/agent/slash_components/lsp.py +105 -0
  19. voidx/agent/slash_components/mcp.py +332 -0
  20. voidx/agent/slash_components/model.py +419 -0
  21. voidx/agent/slash_components/runtime.py +55 -0
  22. voidx/agent/slash_components/skills.py +94 -0
  23. voidx/agent/state.py +32 -0
  24. voidx/agent/task_state.py +278 -0
  25. voidx/agent/tool_filters.py +27 -0
  26. voidx/config.py +707 -0
  27. voidx/llm/__init__.py +0 -0
  28. voidx/llm/catalog.py +188 -0
  29. voidx/llm/compaction.py +267 -0
  30. voidx/llm/context.py +43 -0
  31. voidx/llm/instruction.py +220 -0
  32. voidx/llm/provider.py +312 -0
  33. voidx/llm/usage.py +341 -0
  34. voidx/lsp/__init__.py +30 -0
  35. voidx/lsp/client.py +259 -0
  36. voidx/lsp/config.py +172 -0
  37. voidx/lsp/detector.py +512 -0
  38. voidx/lsp/errors.py +19 -0
  39. voidx/lsp/manager.py +280 -0
  40. voidx/lsp/schema.py +179 -0
  41. voidx/lsp/service.py +103 -0
  42. voidx/main.py +154 -0
  43. voidx/mcp/__init__.py +33 -0
  44. voidx/mcp/client.py +458 -0
  45. voidx/mcp/manager.py +267 -0
  46. voidx/mcp/schema.py +112 -0
  47. voidx/mcp/tool.py +122 -0
  48. voidx/mcp_servers/__init__.py +1 -0
  49. voidx/mcp_servers/web.py +104 -0
  50. voidx/memory/__init__.py +0 -0
  51. voidx/memory/context_frames.py +188 -0
  52. voidx/memory/model_profiles.py +98 -0
  53. voidx/memory/runtime_state.py +240 -0
  54. voidx/memory/session.py +272 -0
  55. voidx/memory/store.py +245 -0
  56. voidx/memory/transcript.py +137 -0
  57. voidx/permission/__init__.py +28 -0
  58. voidx/permission/engine.py +430 -0
  59. voidx/permission/evaluate.py +114 -0
  60. voidx/permission/sandbox.py +280 -0
  61. voidx/permission/schema.py +24 -0
  62. voidx/permission/service.py +314 -0
  63. voidx/permission/wildcard.py +34 -0
  64. voidx/skills/__init__.py +18 -0
  65. voidx/skills/bundled/superpowers/receiving-code-review/SKILL.md +30 -0
  66. voidx/skills/bundled/superpowers/requesting-code-review/SKILL.md +27 -0
  67. voidx/skills/bundled/superpowers/systematic-debugging/SKILL.md +36 -0
  68. voidx/skills/bundled/superpowers/test-driven-development/SKILL.md +33 -0
  69. voidx/skills/bundled/superpowers/verification-before-completion/SKILL.md +31 -0
  70. voidx/skills/bundled/superpowers/writing-plans/SKILL.md +27 -0
  71. voidx/skills/policy.py +97 -0
  72. voidx/skills/registry.py +162 -0
  73. voidx/skills/schema.py +47 -0
  74. voidx/skills/service.py +199 -0
  75. voidx/tools/__init__.py +0 -0
  76. voidx/tools/agent.py +81 -0
  77. voidx/tools/base.py +86 -0
  78. voidx/tools/bash.py +105 -0
  79. voidx/tools/file_ops.py +193 -0
  80. voidx/tools/lsp.py +155 -0
  81. voidx/tools/registry.py +104 -0
  82. voidx/tools/repomap.py +238 -0
  83. voidx/tools/search.py +162 -0
  84. voidx/tools/task_status.py +57 -0
  85. voidx/tools/task_tracker.py +81 -0
  86. voidx/tools/todo.py +82 -0
  87. voidx/tools/web_content.py +357 -0
  88. voidx/tools/web_mcp.py +107 -0
  89. voidx/tools/webfetch.py +155 -0
  90. voidx/tools/websearch.py +276 -0
  91. voidx/ui/__init__.py +0 -0
  92. voidx/ui/app.py +1033 -0
  93. voidx/ui/app_components/__init__.py +1 -0
  94. voidx/ui/app_components/clipboard_image.py +245 -0
  95. voidx/ui/app_components/commands.py +18 -0
  96. voidx/ui/app_components/controls.py +29 -0
  97. voidx/ui/app_components/file_picker.py +115 -0
  98. voidx/ui/app_components/formatting.py +187 -0
  99. voidx/ui/app_components/git_changes.py +51 -0
  100. voidx/ui/app_components/rendering.py +1169 -0
  101. voidx/ui/browse.py +160 -0
  102. voidx/ui/capture.py +169 -0
  103. voidx/ui/code_ide.py +251 -0
  104. voidx/ui/commands.py +83 -0
  105. voidx/ui/console.py +381 -0
  106. voidx/ui/console_components/__init__.py +1 -0
  107. voidx/ui/console_components/formatting.py +96 -0
  108. voidx/ui/console_components/streaming.py +253 -0
  109. voidx/ui/diff.py +331 -0
  110. voidx/ui/dock.py +372 -0
  111. voidx/ui/dock_components/__init__.py +1 -0
  112. voidx/ui/dock_components/formatting.py +123 -0
  113. voidx/ui/dock_components/nodes.py +401 -0
  114. voidx/ui/dock_components/state.py +51 -0
  115. voidx/ui/event_components/__init__.py +1 -0
  116. voidx/ui/event_components/schema.py +249 -0
  117. voidx/ui/events.py +341 -0
  118. voidx/ui/session_changes.py +163 -0
  119. voidx/ui/startup.py +161 -0
  120. voidx/ui/transcript.py +148 -0
  121. voidx/ui/tree.py +316 -0
  122. voidx-1.0.0.dist-info/METADATA +59 -0
  123. voidx-1.0.0.dist-info/RECORD +126 -0
  124. voidx-1.0.0.dist-info/WHEEL +5 -0
  125. voidx-1.0.0.dist-info/entry_points.txt +2 -0
  126. voidx-1.0.0.dist-info/top_level.txt +1 -0
voidx/ui/transcript.py ADDED
@@ -0,0 +1,148 @@
1
+ """Serialize and restore OutputTree snapshots for session resume."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections import defaultdict
6
+ from typing import Literal, cast
7
+
8
+ from voidx.memory.transcript import TranscriptNodeRow
9
+ from voidx.ui.tree import OutputNode, OutputTree
10
+
11
+ NodeType = Literal[
12
+ "root",
13
+ "startup",
14
+ "turn",
15
+ "tool_call",
16
+ "tool_result",
17
+ "subagent",
18
+ "message",
19
+ "assistant",
20
+ "thought",
21
+ "status",
22
+ "permission",
23
+ "error",
24
+ "warn",
25
+ "diff",
26
+ ]
27
+ Status = Literal["running", "done", "error"]
28
+ _NODE_TYPES = set(NodeType.__args__)
29
+ _STATUSES = set(Status.__args__)
30
+
31
+
32
+ def tree_to_transcript_rows(session_id: str, tree: OutputTree) -> tuple[list[TranscriptNodeRow], int]:
33
+ rows: list[TranscriptNodeRow] = []
34
+ turn_id = -1
35
+ next_node_id = 0
36
+ sort_order = 0
37
+
38
+ def add_node(node: OutputNode, parent_node_id: int | None) -> None:
39
+ nonlocal next_node_id, sort_order
40
+ if _is_blank_separator(node):
41
+ return
42
+ node_id = next_node_id
43
+ next_node_id += 1
44
+ metadata = {
45
+ "tree_id": node.id,
46
+ "header_style": node.header_style,
47
+ "agent_name": node.agent_name,
48
+ "step_info": node.step_info,
49
+ "meta": node.meta,
50
+ "payload": node.payload,
51
+ }
52
+ rows.append(
53
+ TranscriptNodeRow(
54
+ session_id=session_id,
55
+ turn_id=turn_id,
56
+ node_id=node_id,
57
+ parent_node_id=parent_node_id,
58
+ sort_order=sort_order,
59
+ node_type=node.node_type,
60
+ header=node.header,
61
+ body_lines=list(node.body_lines),
62
+ status=node.status,
63
+ collapsed=node.collapsed,
64
+ elapsed=node.elapsed,
65
+ message_id=node.message_id,
66
+ tool_call_id=node.tool_call_id,
67
+ agent_run_id=node.agent_run_id,
68
+ metadata={key: value for key, value in metadata.items() if value not in (None, "", {})},
69
+ )
70
+ )
71
+ sort_order += 1
72
+ for child in node.children:
73
+ add_node(child, node_id)
74
+
75
+ for child in tree.root.children:
76
+ if child.node_type == "startup":
77
+ continue
78
+ if _is_blank_separator(child):
79
+ continue
80
+ if child.node_type == "turn":
81
+ turn_id += 1
82
+ next_node_id = 0
83
+ sort_order = 0
84
+ elif turn_id < 0:
85
+ continue
86
+ add_node(child, None)
87
+
88
+ return rows, max(turn_id + 1, 0)
89
+
90
+
91
+ def transcript_rows_to_tree(rows: list[TranscriptNodeRow]) -> OutputTree:
92
+ tree = OutputTree()
93
+ by_turn: dict[int, list[TranscriptNodeRow]] = defaultdict(list)
94
+ for row in rows:
95
+ by_turn[row.turn_id].append(row)
96
+
97
+ for turn_id in sorted(by_turn):
98
+ nodes: dict[int, OutputNode] = {}
99
+ pending = sorted(by_turn[turn_id], key=lambda row: (row.sort_order, row.node_id))
100
+ for row in pending:
101
+ metadata = row.metadata
102
+ payload = metadata.get("payload")
103
+ node = OutputNode(
104
+ id=f"t{turn_id}:n{row.node_id}",
105
+ node_type=_node_type(row.node_type),
106
+ header=row.header,
107
+ header_style=str(metadata.get("header_style") or ""),
108
+ body_lines=list(row.body_lines),
109
+ collapsed=row.collapsed,
110
+ status=_status(row.status),
111
+ elapsed=row.elapsed,
112
+ agent_name=_optional_str(metadata.get("agent_name")),
113
+ step_info=_optional_str(metadata.get("step_info")),
114
+ meta=_optional_str(metadata.get("meta")),
115
+ tool_call_id=row.tool_call_id,
116
+ agent_run_id=row.agent_run_id,
117
+ message_id=row.message_id,
118
+ payload=payload if isinstance(payload, dict) else {},
119
+ )
120
+ nodes[row.node_id] = node
121
+ parent = tree.root if row.parent_node_id is None else nodes.get(row.parent_node_id)
122
+ if parent is not None:
123
+ tree.add_node(parent, node)
124
+
125
+ tree.mark_dirty()
126
+ return tree
127
+
128
+
129
+ def _is_blank_separator(node: OutputNode) -> bool:
130
+ return node.node_type == "message" and not node.header and not node.body_lines and not node.children
131
+
132
+
133
+ def _optional_str(value: object) -> str | None:
134
+ if value is None:
135
+ return None
136
+ return str(value)
137
+
138
+
139
+ def _node_type(value: str) -> NodeType:
140
+ if value in _NODE_TYPES:
141
+ return cast(NodeType, value)
142
+ return "message"
143
+
144
+
145
+ def _status(value: str) -> Status:
146
+ if value in _STATUSES:
147
+ return cast(Status, value)
148
+ return "running"
voidx/ui/tree.py ADDED
@@ -0,0 +1,316 @@
1
+ """Tree-structured output — OutputNode, OutputTree, box-drawing renderer."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from dataclasses import dataclass, field
7
+ from typing import Any
8
+ from typing import Literal
9
+
10
+
11
+ @dataclass
12
+ class OutputNode:
13
+ """A single node in the output tree."""
14
+ id: str
15
+ parent: OutputNode | None = None
16
+ children: list[OutputNode] = field(default_factory=list)
17
+ depth: int = 0
18
+
19
+ node_type: Literal[
20
+ "root",
21
+ "startup",
22
+ "turn",
23
+ "tool_call",
24
+ "tool_result",
25
+ "subagent",
26
+ "message",
27
+ "assistant",
28
+ "thought",
29
+ "status",
30
+ "permission",
31
+ "error",
32
+ "warn",
33
+ "diff",
34
+ ] = "message"
35
+
36
+ header: str = "" # Always visible (collapse summary)
37
+ header_style: str = "" # Rich style for header
38
+ body_lines: list[str] = field(default_factory=list) # Hidden when collapsed
39
+
40
+ collapsed: bool = False
41
+ status: Literal["running", "done", "error"] = "running"
42
+ elapsed: float | None = None
43
+ agent_name: str | None = None
44
+ step_info: str | None = None
45
+ meta: str | None = None
46
+ tool_call_id: str | None = None
47
+ agent_run_id: str | None = None
48
+ message_id: int | None = None
49
+ payload: dict[str, Any] = field(default_factory=dict)
50
+
51
+ _is_last_sibling: bool = False # Set by parent when children are finalised
52
+
53
+ @property
54
+ def collapse_summary(self) -> str:
55
+ """One-line summary shown when collapsed."""
56
+ if self.node_type == "thought" and self.meta:
57
+ return self.meta
58
+ elif self.node_type == "status":
59
+ return self.header[:120] if self.header else self.meta or ""
60
+ elif self.node_type == "subagent" and self.agent_name:
61
+ steps = self.step_info or ""
62
+ elapsed = f"{self.elapsed:.1f}s" if self.elapsed else ""
63
+ meta = " ".join(filter(None, [self.agent_name, steps, elapsed]))
64
+ return f"\u25bc {meta}"
65
+ elif self.node_type == "tool_call":
66
+ parts = [self.header]
67
+ if self.elapsed:
68
+ parts.append(f"({self.elapsed:.1f}s)")
69
+ return " ".join(parts)
70
+ elif self.node_type == "tool_result":
71
+ preview = self.header[:80] or (self.body_lines[0][:80] if self.body_lines else "")
72
+ return preview
73
+ else:
74
+ return self.header[:80] if self.header else ""
75
+
76
+ def add_child(self, child: OutputNode) -> None:
77
+ """Add a child node, updating its parent, depth, and sibling flags."""
78
+ child.parent = self
79
+ child.depth = self.depth + 1
80
+ # Update all existing children's _is_last_sibling
81
+ for c in self.children:
82
+ c._is_last_sibling = False
83
+ child._is_last_sibling = True
84
+ self.children.append(child)
85
+
86
+
87
+ class OutputTree:
88
+ """Tree container with box-drawing renderer."""
89
+
90
+ BOX_BRANCH = "[dim]├─[/dim] "
91
+ BOX_LAST = "[dim]└─[/dim] "
92
+ BOX_VERT = " "
93
+ BOX_SPACE = " "
94
+
95
+ def __init__(self):
96
+ self.root = OutputNode(id="root", node_type="root", depth=0)
97
+ self._counter = 0
98
+ self._all: dict[str, OutputNode] = {} # id → node lookup
99
+ self._click_map: dict[int, str] = {} # backward compat
100
+ self._dirty: bool = True
101
+ self._cached_lines: list[str] = []
102
+ self._cached_width: int = 0
103
+
104
+ def mark_dirty(self) -> None:
105
+ self._dirty = True
106
+
107
+ def new_node(self, parent: OutputNode, *, node_id: str | None = None, **kwargs) -> OutputNode:
108
+ """Create a new node under parent. Auto-assigns id."""
109
+ if node_id is None:
110
+ self._counter += 1
111
+ node_id = f"n{self._counter}"
112
+ node = OutputNode(id=node_id, **kwargs)
113
+ self.add_node(parent, node)
114
+ self._sync_counter(node.id)
115
+ return node
116
+
117
+ def add_node(self, parent: OutputNode, node: OutputNode) -> None:
118
+ """Attach an existing node and register its subtree."""
119
+ parent.add_child(node)
120
+ self._register_subtree(node)
121
+ self._sync_counter(node.id)
122
+ self.mark_dirty()
123
+
124
+ def extend_from(self, other: OutputTree) -> None:
125
+ """Append another tree's root children to this tree."""
126
+ for child in list(other.root.children):
127
+ self.add_node(self.root, child)
128
+
129
+ def _register_subtree(self, node: OutputNode) -> None:
130
+ self._all[node.id] = node
131
+ for child in node.children:
132
+ child.parent = node
133
+ child.depth = node.depth + 1
134
+ self._register_subtree(child)
135
+
136
+ def _sync_counter(self, node_id: str) -> None:
137
+ match = re.fullmatch(r"n(\d+)", node_id)
138
+ if match:
139
+ self._counter = max(self._counter, int(match.group(1)))
140
+
141
+ def get(self, node_id: str) -> OutputNode | None:
142
+ return self._all.get(node_id)
143
+
144
+ def expand(self, node_id: str) -> OutputNode | None:
145
+ node = self._all.get(node_id)
146
+ if node:
147
+ node.collapsed = False
148
+ self.mark_dirty()
149
+ return node
150
+
151
+ def collapse(self, node_id: str) -> OutputNode | None:
152
+ node = self._all.get(node_id)
153
+ if node:
154
+ node.collapsed = True
155
+ self.mark_dirty()
156
+ return node
157
+
158
+ def expand_all(self) -> None:
159
+ for node in self._all.values():
160
+ node.collapsed = False
161
+ self.mark_dirty()
162
+
163
+ def collapse_all(self, max_depth: int = 0) -> None:
164
+ for node in self._all.values():
165
+ if node.depth > max_depth:
166
+ node.collapsed = True
167
+ self.mark_dirty()
168
+
169
+ # ── rendering ──────────────────────────────────────────────────────────
170
+
171
+ def render(self, console_width: int = 80) -> list[str]:
172
+ """Flatten tree to lines with box-drawing characters.
173
+
174
+ Returns list of plain strings (no Rich markup needed at this level —
175
+ markup can be embedded in header/body_lines by the caller).
176
+ """
177
+ if not self._dirty and self._cached_width == console_width:
178
+ return self._cached_lines
179
+
180
+ self._click_map.clear()
181
+ lines: list[str] = []
182
+ line_map: dict[int, str] = {}
183
+ self._walk_render(self.root, [], lines, line_map)
184
+ # Populate backward-compat _click_map
185
+ self._click_map = dict(line_map)
186
+
187
+ self._cached_lines = lines
188
+ self._cached_width = console_width
189
+ self._dirty = False
190
+ return lines
191
+
192
+ def render_with_line_map(self, console_width: int = 80) -> tuple[list[str], dict[int, str]]:
193
+ """Like render() but also returns a map of line_number → node_id
194
+ for mouse click targeting."""
195
+ self.render(console_width)
196
+ return self._cached_lines, self._click_map
197
+
198
+ def render_expanded(self, node_id: str, console_width: int = 80) -> list[str]:
199
+ """Render a single collapsed node's subtree as an expanded view."""
200
+ node = self._all.get(node_id)
201
+ if not node:
202
+ return []
203
+
204
+ lines: list[str] = []
205
+ # Title bar
206
+ lines.append(f" \u2500\u2500 [bold]Expanded[/bold] " + "\u2500" * (console_width - 13))
207
+
208
+ # Temporarily expand this node for rendering
209
+ was_collapsed = node.collapsed
210
+ node.collapsed = False
211
+
212
+ # Render children with box-drawing (like depth 1 nodes)
213
+ new_parts = [" "]
214
+ for child in node.children:
215
+ self._walk_render(child, new_parts, lines, None)
216
+
217
+ node.collapsed = was_collapsed
218
+
219
+ lines.append(" " + "\u2500" * (console_width - 4))
220
+ return lines
221
+
222
+ def click_at_row(self, row: int) -> str | None:
223
+ return self._click_map.get(row)
224
+
225
+ # ── internal walk ──────────────────────────────────────────────────────
226
+
227
+ def _walk_render(self, node: OutputNode, prefix_parts: list[str],
228
+ lines: list[str], line_map: dict[int, str] | None = None) -> None:
229
+ """Recursive depth-first walk to render the tree.
230
+
231
+ Depth 0 (root): not rendered, iterate children directly.
232
+ Depth 1 (turns): no box-drawing connector — header only.
233
+ Depth 2+ (nested): dim connector on the first header, spaces after that.
234
+ """
235
+ if node is self.root:
236
+ prev = None
237
+ for child in node.children:
238
+ if prev is not None and prev.node_type == "turn" and child.node_type == "message" and child.header:
239
+ lines.append("")
240
+ prev = child
241
+ self._walk_render(child, [], lines, line_map)
242
+ return
243
+
244
+ # ── depth 1: no box-drawing ────────────────────────────────────
245
+ if node.depth == 1:
246
+ if node.collapsed:
247
+ line = node.collapse_summary
248
+ lines.append(line)
249
+ if line_map is not None:
250
+ line_map[len(lines) - 1] = node.id
251
+ return
252
+
253
+ line = node.header if node.header else ""
254
+ lines.append(line)
255
+ if line_map is not None and _is_clickable(node):
256
+ line_map[len(lines) - 1] = node.id
257
+
258
+ # Body lines — plain spaces continuation
259
+ for bl in node.body_lines:
260
+ lines.append(bl)
261
+
262
+ # Children get box-drawing, indented under this node
263
+ new_parts = [" "]
264
+ for child in node.children:
265
+ self._walk_render(child, new_parts, lines, line_map)
266
+ return
267
+
268
+ # ── depth >= 2: full box-drawing ───────────────────────────────
269
+ indent = "".join(prefix_parts)
270
+ connector = self.BOX_LAST if node._is_last_sibling else self.BOX_BRANCH
271
+ is_first_sibling = (
272
+ node.parent is not None
273
+ and bool(node.parent.children)
274
+ and node.parent.children[0] is node
275
+ )
276
+ suppress_connector = node.parent is not None and node.parent.node_type == "assistant"
277
+ prefix = indent + connector
278
+ aligned_prefix = indent + self.BOX_SPACE if suppress_connector else (
279
+ prefix if is_first_sibling else indent + self.BOX_SPACE
280
+ )
281
+ inline_tool_result = (
282
+ node.node_type == "tool_result"
283
+ and node.parent is not None
284
+ and node.parent.node_type == "tool_call"
285
+ )
286
+
287
+ if node.collapsed:
288
+ line = f"{indent if inline_tool_result else aligned_prefix}{node.collapse_summary}"
289
+ lines.append(line)
290
+ if line_map is not None:
291
+ line_map[len(lines) - 1] = node.id
292
+ return
293
+
294
+ # Header line
295
+ current_prefix = indent if inline_tool_result else aligned_prefix
296
+ line = f"{current_prefix}{node.header}" if node.header else current_prefix
297
+ lines.append(line)
298
+ if line_map is not None and _is_clickable(node):
299
+ line_map[len(lines) - 1] = node.id
300
+
301
+ # Continuation for body lines and children
302
+ cont_suffix = self.BOX_SPACE if suppress_connector or node._is_last_sibling else self.BOX_VERT
303
+ cont = indent if inline_tool_result else indent + cont_suffix
304
+
305
+ # Body lines
306
+ for bl in node.body_lines:
307
+ lines.append(f"{cont}{bl}")
308
+
309
+ # Children
310
+ new_parts = prefix_parts if inline_tool_result else prefix_parts + [cont_suffix]
311
+ for child in node.children:
312
+ self._walk_render(child, new_parts, lines, line_map)
313
+
314
+
315
+ def _is_clickable(node: OutputNode) -> bool:
316
+ return node.node_type in {"subagent", "tool_call", "tool_result", "thought", "status"}
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: voidx
3
+ Version: 1.0.0
4
+ Summary: A coding agent that quantifies everything and solves with tools, not fuzzy prompts.
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: langgraph>=0.3.0
8
+ Requires-Dist: langchain>=0.3.0
9
+ Requires-Dist: langchain-anthropic>=0.3.0
10
+ Requires-Dist: langchain-openai>=0.3.0
11
+ Requires-Dist: pydantic>=2.10.0
12
+ Requires-Dist: pydantic-settings>=2.7.0
13
+ Requires-Dist: typer>=0.15.0
14
+ Requires-Dist: rich>=13.9.0
15
+ Requires-Dist: prompt_toolkit>=3.0.0
16
+ Requires-Dist: tiktoken>=0.8.0
17
+ Requires-Dist: httpx>=0.28.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: build>=1.2.0; extra == "dev"
20
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
21
+ Requires-Dist: pytest-asyncio>=0.25.0; extra == "dev"
22
+
23
+ # voidx
24
+
25
+ voidx is a terminal AI coding agent built in Python.
26
+
27
+ ## Install
28
+
29
+ Python users can install the canonical package from PyPI:
30
+
31
+ ```bash
32
+ pip install voidx
33
+ voidx
34
+ ```
35
+
36
+ Node users can install the npm launcher. The launcher requires Python 3.11+
37
+ on the machine and installs the matching Python package into an isolated
38
+ user-local virtual environment on first run:
39
+
40
+ ```bash
41
+ npm install -g @voidx/cli
42
+ voidx
43
+ ```
44
+
45
+ ## Useful Commands
46
+
47
+ ```bash
48
+ voidx version
49
+ voidx sessions
50
+ voidx -w /path/to/project
51
+ ```
52
+
53
+ ## Development
54
+
55
+ ```bash
56
+ .venv/bin/python -m pytest
57
+ .venv/bin/python scripts/package.py --format all --clean
58
+ npm --prefix npm run check
59
+ ```
@@ -0,0 +1,126 @@
1
+ voidx/__init__.py,sha256=cbFWhQdBBpYLCU3yVfbepYoZHOd3nECdp591GzGB8sM,80
2
+ voidx/config.py,sha256=pr0oeagA-czlViW94gAaTt8WmArBZCxvvEK3aCh-fl4,27067
3
+ voidx/main.py,sha256=qblhaac_b56Gn506EUsnZsUNh1lFH_Sfbpxr2p9OAqw,4408
4
+ voidx/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ voidx/agent/agents.py,sha256=xfonoOsO1l21aHe8bSMyb7EP0XeDq3Q3aueHtd8nv9Q,17490
6
+ voidx/agent/attachments.py,sha256=oumjx2JUzgppi2kQRyFh0agDSf3FbLLDHKwyAQOXBjI,7609
7
+ voidx/agent/graph.py,sha256=eiAoAIzxK71rdu8HQ7RouM2SkZKD-qDAkWvAad8TnX8,19349
8
+ voidx/agent/runtime_context.py,sha256=TurBVymv13eWpY0vqL84VHd15Hc_2XE8PaB75Kx8CUI,14207
9
+ voidx/agent/slash.py,sha256=eA8h1aWpl_C7pFrK9siH8asbVodefnNeQ0vOLTm2grM,19676
10
+ voidx/agent/state.py,sha256=uRc-OI1TTxoNWFmKcvOVNSxn_WDjeKQ5TbhYbtdPwoo,1447
11
+ voidx/agent/task_state.py,sha256=y_QslX_ua36DpvNRTwHWLxsuMa-4N7o50A_rMxwOOoo,7478
12
+ voidx/agent/tool_filters.py,sha256=8DXNXvJJUxws17MDQRGo43L3Sv_EKltXwhlYUiNvdLA,808
13
+ voidx/agent/graph_components/__init__.py,sha256=M0w0W4Jjl4m8NVbShKPi3JEdhjjjqxySVCz1L7OOcIA,43
14
+ voidx/agent/graph_components/compaction.py,sha256=wd24z_9fokOumGIwQuUVfvzny-yPFhPWIugEIJDjULw,11408
15
+ voidx/agent/graph_components/permissions.py,sha256=P1e__ymk5a0G4FyJidekgiWHtD_g9YE61fTVcBNkMy0,5142
16
+ voidx/agent/graph_components/run_loop.py,sha256=XcZdMbaaYkdZEyXX3Wte7s-hHE7C5poDBxmpxZmv_S8,23272
17
+ voidx/agent/graph_components/runtime.py,sha256=55DzCKs4vpIo61Khh3k4cMk1jAd7rB5TeCmeZ3MknRA,319
18
+ voidx/agent/graph_components/streaming.py,sha256=tbG1JvQEJjigtPN7qMx4omc2wRozefl2noeqCmBexuc,11106
19
+ voidx/agent/graph_components/subagent.py,sha256=rAVm6MRhGldlaI2sA-h_rcn59oRTPtV_ZTIHwnt2Eig,11417
20
+ voidx/agent/graph_components/tool_execution.py,sha256=oJEWAwrT-Cz0bj70y55tcsmfr-363TYno4ZCeL3ErTg,8192
21
+ voidx/agent/slash_components/__init__.py,sha256=lEUeU7ejcX7QmFRU-8Xo67rZYPl0g8lRU8Jpa4xNUK0,47
22
+ voidx/agent/slash_components/code_ide.py,sha256=M5g67iR17htr7ys4LF5j4Fj4a9m-5PoyhO2P6Dr4rXE,2662
23
+ voidx/agent/slash_components/lsp.py,sha256=4n65NxSjFrn6nAwZEwi6Tog4r2jcO0aKQztL9jENErg,4480
24
+ voidx/agent/slash_components/mcp.py,sha256=gU1p0ljZcsmGmBCYsuVXHEzLRNRfzW1jIIkhe2PXXpo,12846
25
+ voidx/agent/slash_components/model.py,sha256=q4pYSZyKECqHZ0iVPSyEzRaJODTZgCgfsnLM30-Tyb0,17326
26
+ voidx/agent/slash_components/runtime.py,sha256=FMzg1gx37bh0PZ7c45NvVlgvdbQbiIIXAJqT-2GupLk,1297
27
+ voidx/agent/slash_components/skills.py,sha256=vgJ_I9cZJJKJdoyq5QhX9ncPjcgqborHE_9eREW95tQ,3767
28
+ voidx/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ voidx/llm/catalog.py,sha256=y37LmfjV2T3KNk_kMQo3OKBgEgYkQZatVScXTaMgJZA,5951
30
+ voidx/llm/compaction.py,sha256=pr7XLqOFTObtu3qZB6xtn5K24HyX4DoIDRfn_YsNk08,10331
31
+ voidx/llm/context.py,sha256=Fqptw-YmaY6mXQMWbtHyVbmaotLuA1km4Pc2INwJQAo,1320
32
+ voidx/llm/instruction.py,sha256=hN07LRvsBh5v0znNyTqrE96HUeht-jpPkIP5CVK_dVo,8367
33
+ voidx/llm/provider.py,sha256=lfdqtIvAI1X_KVZkggrERt6tg0lTArlEWR0AtX7i0uM,10693
34
+ voidx/llm/usage.py,sha256=MkqdJmnmxiCDCiS4QkQSpFQORhYrZeWY1Kk1FAQSNgI,12162
35
+ voidx/lsp/__init__.py,sha256=pQvnIVHVTA2n0qxxEKUOleSHba6N1ac4xX5-C7ft8_Y,604
36
+ voidx/lsp/client.py,sha256=DoxNk9IWVlnusOiKC4Z2ZqklOE5CWQHuSiounb6EfuA,9681
37
+ voidx/lsp/config.py,sha256=L0GSWy-qQdfYdo72P6UwDTZBJT9jmG6MEKsAQ0gd8qc,5761
38
+ voidx/lsp/detector.py,sha256=6Q7HbmJrHq7SatYLml1zWt6093ZYbEUwT8TcCLEYlFM,18498
39
+ voidx/lsp/errors.py,sha256=A8TfktAfPqOqXjRIgA9Lhbf3Po2uSi9GxMtB8DZpv04,429
40
+ voidx/lsp/manager.py,sha256=8-RX4L_PStNtmjXh-CLEoRykrl-ondqc3mtfI-0PSlk,11215
41
+ voidx/lsp/schema.py,sha256=Ytf09PJHsrejNymP_u_LGSkcHVWdISYKnfM2J1cQps4,5078
42
+ voidx/lsp/service.py,sha256=Oq4RX4PCQXxHF-WqkrxtZkORq0ptqS-KNJpFm9FeQVw,3815
43
+ voidx/mcp/__init__.py,sha256=dG3cWqRBffqzqfWRNT1sPRCB8aQyUdCVYTaswtgczP8,1100
44
+ voidx/mcp/client.py,sha256=ij4fHad3_0t6j-SMsNXhQOtvRTD3tQUOJaCVLTv5tPE,17932
45
+ voidx/mcp/manager.py,sha256=VfHWXQZhLblmTw-rQJs7E0YVU5r6R1IGy42AbBYwIpo,10172
46
+ voidx/mcp/schema.py,sha256=ERdiBojFxfRZKjXAlQ4r8RjtafdjB-AB1lE4i-3Wq7o,3096
47
+ voidx/mcp/tool.py,sha256=B7kzzleLoTzzRC2STqVOqcDfB918jhcMvc0M616wE3s,4810
48
+ voidx/mcp_servers/__init__.py,sha256=A2CS-VzGlluE3xSu53Sd-_gjL__gIFIS-MVi0NtbCVY,47
49
+ voidx/mcp_servers/web.py,sha256=wTz9kYQYCLDf9XygL8wp2vVdBXXUi8Q_XeNrq8QxNns,3104
50
+ voidx/memory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
+ voidx/memory/context_frames.py,sha256=R_pGZ-w5gvKIyCOiN_NWFcROmrpA04r4C-wDJR_BV7E,5945
52
+ voidx/memory/model_profiles.py,sha256=YM_dq2wZGR2VFfCBRNJ_EUyekcWL7EcAZsz77TkerEo,2853
53
+ voidx/memory/runtime_state.py,sha256=15WPe4JbarXQZwq4ikw35cXzPLX_5xE1EbPdcqIkN6U,9333
54
+ voidx/memory/session.py,sha256=WeqXDltdCsngj50xWWidNkfx-rHt1DYseRfPNDYuo8k,9598
55
+ voidx/memory/store.py,sha256=D3v7wXb0MWZJWJQLPMt3zuVCtuI1UepyeqNiF-gsB9Q,9084
56
+ voidx/memory/transcript.py,sha256=vGAhbNCsIUOSKmhZQBe7pxNttVaFi0Qv4awvj_-qA44,4586
57
+ voidx/permission/__init__.py,sha256=8nBMbD4Rsk91W_vPcStX5M55P8IZwK8p7f4wWyBGZaU,884
58
+ voidx/permission/engine.py,sha256=3XSjyYm5p5DVwwOxNZLOqu3AnPbWKeppx6oLIK-F87Q,16420
59
+ voidx/permission/evaluate.py,sha256=xjY7yz1GMesyQW-A75czBOS1GMcPKIZ-Up0YzAsjvWs,4234
60
+ voidx/permission/sandbox.py,sha256=dE7Rr1zkwFJzqF6j85tK4x3P4sf3V1QON06DSv5cQ_A,9786
61
+ voidx/permission/schema.py,sha256=imnZwSNyUNWcKBjGz5KlsIYWsmQC6T6nFQZXOtERNPo,530
62
+ voidx/permission/service.py,sha256=Av47zZ_Jr3Rp_uIwbV-tDRqP_-KI_pWBMdCO9M--KT8,12715
63
+ voidx/permission/wildcard.py,sha256=-TEuGPye-dqzcqfa00eseiKZUPusYOZkPJf5Wc8XJOY,986
64
+ voidx/skills/__init__.py,sha256=tKe6ccKAbdLf_0JxpXe1aCcGEsdw0dcyoV1kwdtSGk8,485
65
+ voidx/skills/policy.py,sha256=WWbtM8_MTewhGAezueLzYxT8oOAYYIgGxMTDI9cCBBQ,2584
66
+ voidx/skills/registry.py,sha256=gsAL6b9uLoMcAZZ8IkKAHgKCsCdLTkfPDA0xqrKGH0M,5312
67
+ voidx/skills/schema.py,sha256=xeassMfow1eM77GgpBgiNAQR-jvvXGRgPM-XwTy72oA,948
68
+ voidx/skills/service.py,sha256=XkL8MgGMTPUZKKdxWZSeioeIojJRU7DU1Lz3fcsH9qk,6510
69
+ voidx/skills/bundled/superpowers/receiving-code-review/SKILL.md,sha256=zTphlJ-Fk2StA_UByTkGpa_3soKzDG0aU-7bp3bPvKc,988
70
+ voidx/skills/bundled/superpowers/requesting-code-review/SKILL.md,sha256=hs-7C4GDZGDGSaLMYa2VCtQ8SBHMdzAlMuy4D06tfuY,830
71
+ voidx/skills/bundled/superpowers/systematic-debugging/SKILL.md,sha256=KCqyBK2SiL-kamdMXBijJH25xnXc1iicGqSDDvy5WSc,1069
72
+ voidx/skills/bundled/superpowers/test-driven-development/SKILL.md,sha256=69pdcd9XkkVRzSrpQSxHIleCGoJGLDkP14PXJgih1Fw,1036
73
+ voidx/skills/bundled/superpowers/verification-before-completion/SKILL.md,sha256=o7Umc5ErT5N-tIk33qwqUhp3Q3Tr0AFQLm-Vnd5HBd8,828
74
+ voidx/skills/bundled/superpowers/writing-plans/SKILL.md,sha256=TDEcXJPCQOEkQ703Z9_xjUx0CzDoN2XKZrq1h-fjHho,858
75
+ voidx/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
+ voidx/tools/agent.py,sha256=Cc5fb2XUfepcIWHUqq7D9PO4-jE2Pf-_anBgExx4IGE,3031
77
+ voidx/tools/base.py,sha256=4K2KB7lwsqOwISIi6M11jHWOeH1awkv8orNENHqOWRQ,2546
78
+ voidx/tools/bash.py,sha256=5YLKGPOth4uPIZF8W75y9B5_VZ5Hd6sIl65tkMPyMGc,3994
79
+ voidx/tools/file_ops.py,sha256=ZopwEvOLv_zURbjP0X7HpGAiIA6WIznMXT4SLbg65V4,7458
80
+ voidx/tools/lsp.py,sha256=1CCnARGRCImXC428XFTAUKVXMWIPnd-E-7D2IWhh_XA,6282
81
+ voidx/tools/registry.py,sha256=RruXcNEn4eNhKz61twOdljyVPzLVJN_hsb_fFpwoCRc,3834
82
+ voidx/tools/repomap.py,sha256=ozEHkjBpwcekxHCAIpqHvj2V0ujROHjbNlW6MGt2A6I,8057
83
+ voidx/tools/search.py,sha256=lv7gXsvRN8Vb5b5JAMszXMcE_8cyax3FSxRd4t2jluQ,6061
84
+ voidx/tools/task_status.py,sha256=G19AOQm3KaUQxWgdZ6R6jSItDCruvR0BuNUHYMD6Y5A,1946
85
+ voidx/tools/task_tracker.py,sha256=MaE6ewu5lGuFfajRDytAWrjFIiaknO2rS8XcJWvenK8,2823
86
+ voidx/tools/todo.py,sha256=8UiZ8llSel2Qb4StEwIrNgtEqxxKaXKRmK_2ACsA9FU,2801
87
+ voidx/tools/web_content.py,sha256=khU1tWcVBGRT9iaNkZdRhyPdGZGWtfAb4JzSnXN1acs,9958
88
+ voidx/tools/web_mcp.py,sha256=B8tK-FdERnrrLJyjVhiN1Q9T6f3A1jErqbkAX-C_gtA,3123
89
+ voidx/tools/webfetch.py,sha256=_z79THxotG3c8HwzUeKjzDG8WYhhLFTz4pt9QBUDYYY,5687
90
+ voidx/tools/websearch.py,sha256=rv7PeoMQYWXLYRrrBTZ8ABk_vLZp3m-U_MfVcj0xb_E,9542
91
+ voidx/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
+ voidx/ui/app.py,sha256=MOzupIRGpNSLHUYl54Doz10gGESDCiyUqJd7OSjWvc4,39159
93
+ voidx/ui/browse.py,sha256=w3Tv3GYEnbSGpvJ4-SmErNORd0OpcWgiJSzTYP_evdQ,6282
94
+ voidx/ui/capture.py,sha256=dKnrxM1SvcHP9xRhdp-7eWCf8SlVCSkZexK02qWABzA,6341
95
+ voidx/ui/code_ide.py,sha256=MclNUfmjSW-O0qwfx05kZWSIseRuxM_ctzi42qSr2oc,8357
96
+ voidx/ui/commands.py,sha256=f_QOjXxboTqTfnACGgJkm-TGBvkcsuV74NDmtu9ijBU,4187
97
+ voidx/ui/console.py,sha256=GqiDe8B68tp4dLXbHzD3z5qwYjeNeMd6MEvIikRvxWo,13574
98
+ voidx/ui/diff.py,sha256=0iRWaJyy3kiilgcizJff1750DbflLsnM9pISxlAJeYI,10353
99
+ voidx/ui/dock.py,sha256=RzsXzO0m-H4rsuo9Xebsoc1g_iH_Yw6suiH7C0wJ8G0,12229
100
+ voidx/ui/events.py,sha256=THuiVXEyUiRe3ZjLrcmlifpHlcprRWlPIMNX8X0cflQ,13208
101
+ voidx/ui/session_changes.py,sha256=ks8_ARBNDZCOPM8AYUmA8ooy3G5AQxjLq769QMUv5Lo,4716
102
+ voidx/ui/startup.py,sha256=mpz_YFb2-2pZFJcumhfGqZK5dwfBRFMdOHzuwTsKbxQ,5037
103
+ voidx/ui/transcript.py,sha256=vA5VVi5AynouNOuTlOrbsDlymE4BYxn7ar5c6IIqi1w,4671
104
+ voidx/ui/tree.py,sha256=7_pfgB3qj6EQanZ1m2n7pNKmqBjn1sxqROapEhkXw8M,11867
105
+ voidx/ui/app_components/__init__.py,sha256=RPNDe1VgSFbouRJ3nwYZ83lrkZCSpuegCNvPEGJwyC0,49
106
+ voidx/ui/app_components/clipboard_image.py,sha256=np2GgvWkhIh5QRn8ul3tFAXg_SHelLZfmUuNGD06oPg,7612
107
+ voidx/ui/app_components/commands.py,sha256=oB54KUUSyCwTHcQH0Hs1mVO5fxYQHEf_iILwooB_Eyo,597
108
+ voidx/ui/app_components/controls.py,sha256=wlhdBpzF-pPXXmyktJIb86YctT1__gjCbDT3M6syzLw,944
109
+ voidx/ui/app_components/file_picker.py,sha256=wRuPsTh4YZxpY7J0yOvVmfDGTILGi92A9kvJeyZqpDQ,3387
110
+ voidx/ui/app_components/formatting.py,sha256=VDiecSTKjLgoyQBwCCXJ8QzVMBpoFvOtdtFc5uxj3BE,5978
111
+ voidx/ui/app_components/git_changes.py,sha256=5Mynt5d7nKvwdDEe_TVXWBrhxn-AUTlIa_HD8H-wbtc,1516
112
+ voidx/ui/app_components/rendering.py,sha256=JI-h1dEc4L2Gt4dp-JkonKFtsl3yBN1wFChkD1keIHk,47643
113
+ voidx/ui/console_components/__init__.py,sha256=sV9ymVuyfe4IF9VwDcBMjZ-kbyj76TqBLPxZ8_wvH_I,50
114
+ voidx/ui/console_components/formatting.py,sha256=JPklqWgVNhDXosVNwKSTue5g8kFs59NPvi9hfKTrxWM,2790
115
+ voidx/ui/console_components/streaming.py,sha256=SXDRhuh55nRf2VwfX2kUqVZVYp72CikTtsupy-yn4dA,8719
116
+ voidx/ui/dock_components/__init__.py,sha256=B1wAKH0dBEvzLq9GtyQ3PRqVhB0JXjKwcCpkxzO_v1A,48
117
+ voidx/ui/dock_components/formatting.py,sha256=FHpuyutSRNshfElOoL3AIrIwbgCWCPr4xFJXdZCXfyk,3341
118
+ voidx/ui/dock_components/nodes.py,sha256=WNxmF_KZsqumUKdpweWB2GFWC01DpQOXPac5bXtlpd8,13736
119
+ voidx/ui/dock_components/state.py,sha256=uiWmwFlZg8435YMVgDEo9I1LX7-SRkz5TcU3ZtF49qw,1254
120
+ voidx/ui/event_components/__init__.py,sha256=8qa8UbaxRSeopM_6698e2bWq9Puy6zp-x4JPAYkcky0,42
121
+ voidx/ui/event_components/schema.py,sha256=UNOcjmFCgQSjiILzeo3sE-WPXOKolnwhhqRut7mHhO8,5854
122
+ voidx-1.0.0.dist-info/METADATA,sha256=HBRznaII0q9s1Hm1Vd2hzaTWrC21OK_xhDnPI8fsV18,1379
123
+ voidx-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
124
+ voidx-1.0.0.dist-info/entry_points.txt,sha256=hS_l7aI4XL-9UB1-4NhFGWTUgPj3Cii37-UmkCSvWrM,41
125
+ voidx-1.0.0.dist-info/top_level.txt,sha256=DG4cfADJBiWwfHkId7vpqd-zAbLvbqFTpiXU5w1lzXQ,6
126
+ voidx-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ voidx = voidx.main:cli
@@ -0,0 +1 @@
1
+ voidx