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.
- voidx/__init__.py +3 -0
- voidx/agent/__init__.py +0 -0
- voidx/agent/agents.py +439 -0
- voidx/agent/attachments.py +235 -0
- voidx/agent/graph.py +463 -0
- voidx/agent/graph_components/__init__.py +1 -0
- voidx/agent/graph_components/compaction.py +268 -0
- voidx/agent/graph_components/permissions.py +139 -0
- voidx/agent/graph_components/run_loop.py +532 -0
- voidx/agent/graph_components/runtime.py +14 -0
- voidx/agent/graph_components/streaming.py +351 -0
- voidx/agent/graph_components/subagent.py +278 -0
- voidx/agent/graph_components/tool_execution.py +208 -0
- voidx/agent/runtime_context.py +368 -0
- voidx/agent/slash.py +466 -0
- voidx/agent/slash_components/__init__.py +1 -0
- voidx/agent/slash_components/code_ide.py +68 -0
- voidx/agent/slash_components/lsp.py +105 -0
- voidx/agent/slash_components/mcp.py +332 -0
- voidx/agent/slash_components/model.py +419 -0
- voidx/agent/slash_components/runtime.py +55 -0
- voidx/agent/slash_components/skills.py +94 -0
- voidx/agent/state.py +32 -0
- voidx/agent/task_state.py +278 -0
- voidx/agent/tool_filters.py +27 -0
- voidx/config.py +707 -0
- voidx/llm/__init__.py +0 -0
- voidx/llm/catalog.py +188 -0
- voidx/llm/compaction.py +267 -0
- voidx/llm/context.py +43 -0
- voidx/llm/instruction.py +220 -0
- voidx/llm/provider.py +312 -0
- voidx/llm/usage.py +341 -0
- voidx/lsp/__init__.py +30 -0
- voidx/lsp/client.py +259 -0
- voidx/lsp/config.py +172 -0
- voidx/lsp/detector.py +512 -0
- voidx/lsp/errors.py +19 -0
- voidx/lsp/manager.py +280 -0
- voidx/lsp/schema.py +179 -0
- voidx/lsp/service.py +103 -0
- voidx/main.py +154 -0
- voidx/mcp/__init__.py +33 -0
- voidx/mcp/client.py +458 -0
- voidx/mcp/manager.py +267 -0
- voidx/mcp/schema.py +112 -0
- voidx/mcp/tool.py +122 -0
- voidx/mcp_servers/__init__.py +1 -0
- voidx/mcp_servers/web.py +104 -0
- voidx/memory/__init__.py +0 -0
- voidx/memory/context_frames.py +188 -0
- voidx/memory/model_profiles.py +98 -0
- voidx/memory/runtime_state.py +240 -0
- voidx/memory/session.py +272 -0
- voidx/memory/store.py +245 -0
- voidx/memory/transcript.py +137 -0
- voidx/permission/__init__.py +28 -0
- voidx/permission/engine.py +430 -0
- voidx/permission/evaluate.py +114 -0
- voidx/permission/sandbox.py +280 -0
- voidx/permission/schema.py +24 -0
- voidx/permission/service.py +314 -0
- voidx/permission/wildcard.py +34 -0
- voidx/skills/__init__.py +18 -0
- voidx/skills/bundled/superpowers/receiving-code-review/SKILL.md +30 -0
- voidx/skills/bundled/superpowers/requesting-code-review/SKILL.md +27 -0
- voidx/skills/bundled/superpowers/systematic-debugging/SKILL.md +36 -0
- voidx/skills/bundled/superpowers/test-driven-development/SKILL.md +33 -0
- voidx/skills/bundled/superpowers/verification-before-completion/SKILL.md +31 -0
- voidx/skills/bundled/superpowers/writing-plans/SKILL.md +27 -0
- voidx/skills/policy.py +97 -0
- voidx/skills/registry.py +162 -0
- voidx/skills/schema.py +47 -0
- voidx/skills/service.py +199 -0
- voidx/tools/__init__.py +0 -0
- voidx/tools/agent.py +81 -0
- voidx/tools/base.py +86 -0
- voidx/tools/bash.py +105 -0
- voidx/tools/file_ops.py +193 -0
- voidx/tools/lsp.py +155 -0
- voidx/tools/registry.py +104 -0
- voidx/tools/repomap.py +238 -0
- voidx/tools/search.py +162 -0
- voidx/tools/task_status.py +57 -0
- voidx/tools/task_tracker.py +81 -0
- voidx/tools/todo.py +82 -0
- voidx/tools/web_content.py +357 -0
- voidx/tools/web_mcp.py +107 -0
- voidx/tools/webfetch.py +155 -0
- voidx/tools/websearch.py +276 -0
- voidx/ui/__init__.py +0 -0
- voidx/ui/app.py +1033 -0
- voidx/ui/app_components/__init__.py +1 -0
- voidx/ui/app_components/clipboard_image.py +245 -0
- voidx/ui/app_components/commands.py +18 -0
- voidx/ui/app_components/controls.py +29 -0
- voidx/ui/app_components/file_picker.py +115 -0
- voidx/ui/app_components/formatting.py +187 -0
- voidx/ui/app_components/git_changes.py +51 -0
- voidx/ui/app_components/rendering.py +1169 -0
- voidx/ui/browse.py +160 -0
- voidx/ui/capture.py +169 -0
- voidx/ui/code_ide.py +251 -0
- voidx/ui/commands.py +83 -0
- voidx/ui/console.py +381 -0
- voidx/ui/console_components/__init__.py +1 -0
- voidx/ui/console_components/formatting.py +96 -0
- voidx/ui/console_components/streaming.py +253 -0
- voidx/ui/diff.py +331 -0
- voidx/ui/dock.py +372 -0
- voidx/ui/dock_components/__init__.py +1 -0
- voidx/ui/dock_components/formatting.py +123 -0
- voidx/ui/dock_components/nodes.py +401 -0
- voidx/ui/dock_components/state.py +51 -0
- voidx/ui/event_components/__init__.py +1 -0
- voidx/ui/event_components/schema.py +249 -0
- voidx/ui/events.py +341 -0
- voidx/ui/session_changes.py +163 -0
- voidx/ui/startup.py +161 -0
- voidx/ui/transcript.py +148 -0
- voidx/ui/tree.py +316 -0
- voidx-1.0.0.dist-info/METADATA +59 -0
- voidx-1.0.0.dist-info/RECORD +126 -0
- voidx-1.0.0.dist-info/WHEEL +5 -0
- voidx-1.0.0.dist-info/entry_points.txt +2 -0
- 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 @@
|
|
|
1
|
+
voidx
|