batrachian-toad 0.5.22__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.
- batrachian_toad-0.5.22.dist-info/METADATA +197 -0
- batrachian_toad-0.5.22.dist-info/RECORD +120 -0
- batrachian_toad-0.5.22.dist-info/WHEEL +4 -0
- batrachian_toad-0.5.22.dist-info/entry_points.txt +2 -0
- batrachian_toad-0.5.22.dist-info/licenses/LICENSE +661 -0
- toad/__init__.py +46 -0
- toad/__main__.py +4 -0
- toad/_loop.py +86 -0
- toad/about.py +90 -0
- toad/acp/agent.py +671 -0
- toad/acp/api.py +47 -0
- toad/acp/encode_tool_call_id.py +12 -0
- toad/acp/messages.py +138 -0
- toad/acp/prompt.py +54 -0
- toad/acp/protocol.py +426 -0
- toad/agent.py +62 -0
- toad/agent_schema.py +70 -0
- toad/agents.py +45 -0
- toad/ansi/__init__.py +1 -0
- toad/ansi/_ansi.py +1612 -0
- toad/ansi/_ansi_colors.py +264 -0
- toad/ansi/_control_codes.py +37 -0
- toad/ansi/_keys.py +251 -0
- toad/ansi/_sgr_styles.py +64 -0
- toad/ansi/_stream_parser.py +418 -0
- toad/answer.py +22 -0
- toad/app.py +557 -0
- toad/atomic.py +37 -0
- toad/cli.py +257 -0
- toad/code_analyze.py +28 -0
- toad/complete.py +34 -0
- toad/constants.py +58 -0
- toad/conversation_markdown.py +19 -0
- toad/danger.py +371 -0
- toad/data/agents/ampcode.com.toml +51 -0
- toad/data/agents/augmentcode.com.toml +40 -0
- toad/data/agents/claude.com.toml +41 -0
- toad/data/agents/docker.com.toml +59 -0
- toad/data/agents/geminicli.com.toml +28 -0
- toad/data/agents/goose.ai.toml +51 -0
- toad/data/agents/inference.huggingface.co.toml +33 -0
- toad/data/agents/kimi.com.toml +35 -0
- toad/data/agents/openai.com.toml +53 -0
- toad/data/agents/opencode.ai.toml +61 -0
- toad/data/agents/openhands.dev.toml +44 -0
- toad/data/agents/stakpak.dev.toml +61 -0
- toad/data/agents/vibe.mistral.ai.toml +27 -0
- toad/data/agents/vtcode.dev.toml +62 -0
- toad/data/images/frog.png +0 -0
- toad/data/sounds/turn-over.wav +0 -0
- toad/db.py +5 -0
- toad/dec.py +332 -0
- toad/directory.py +234 -0
- toad/directory_watcher.py +96 -0
- toad/fuzzy.py +140 -0
- toad/gist.py +2 -0
- toad/history.py +138 -0
- toad/jsonrpc.py +576 -0
- toad/menus.py +14 -0
- toad/messages.py +74 -0
- toad/option_content.py +51 -0
- toad/os.py +0 -0
- toad/path_complete.py +145 -0
- toad/path_filter.py +124 -0
- toad/paths.py +71 -0
- toad/pill.py +23 -0
- toad/prompt/extract.py +19 -0
- toad/prompt/resource.py +68 -0
- toad/protocol.py +28 -0
- toad/screens/action_modal.py +94 -0
- toad/screens/agent_modal.py +172 -0
- toad/screens/command_edit_modal.py +58 -0
- toad/screens/main.py +192 -0
- toad/screens/permissions.py +390 -0
- toad/screens/permissions.tcss +72 -0
- toad/screens/settings.py +254 -0
- toad/screens/settings.tcss +101 -0
- toad/screens/store.py +476 -0
- toad/screens/store.tcss +261 -0
- toad/settings.py +354 -0
- toad/settings_schema.py +318 -0
- toad/shell.py +263 -0
- toad/shell_read.py +42 -0
- toad/slash_command.py +34 -0
- toad/toad.tcss +752 -0
- toad/version.py +80 -0
- toad/visuals/columns.py +273 -0
- toad/widgets/agent_response.py +79 -0
- toad/widgets/agent_thought.py +41 -0
- toad/widgets/command_pane.py +224 -0
- toad/widgets/condensed_path.py +93 -0
- toad/widgets/conversation.py +1626 -0
- toad/widgets/danger_warning.py +65 -0
- toad/widgets/diff_view.py +709 -0
- toad/widgets/flash.py +81 -0
- toad/widgets/future_text.py +126 -0
- toad/widgets/grid_select.py +223 -0
- toad/widgets/highlighted_textarea.py +180 -0
- toad/widgets/mandelbrot.py +294 -0
- toad/widgets/markdown_note.py +13 -0
- toad/widgets/menu.py +147 -0
- toad/widgets/non_selectable_label.py +5 -0
- toad/widgets/note.py +18 -0
- toad/widgets/path_search.py +381 -0
- toad/widgets/plan.py +180 -0
- toad/widgets/project_directory_tree.py +74 -0
- toad/widgets/prompt.py +741 -0
- toad/widgets/question.py +337 -0
- toad/widgets/shell_result.py +35 -0
- toad/widgets/shell_terminal.py +18 -0
- toad/widgets/side_bar.py +74 -0
- toad/widgets/slash_complete.py +211 -0
- toad/widgets/strike_text.py +66 -0
- toad/widgets/terminal.py +526 -0
- toad/widgets/terminal_tool.py +338 -0
- toad/widgets/throbber.py +90 -0
- toad/widgets/tool_call.py +303 -0
- toad/widgets/user_input.py +23 -0
- toad/widgets/version.py +5 -0
- toad/widgets/welcome.py +31 -0
toad/__init__.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Literal, Mapping
|
|
2
|
+
import platform
|
|
3
|
+
|
|
4
|
+
NAME = "toad"
|
|
5
|
+
TITLE = "Toad"
|
|
6
|
+
|
|
7
|
+
type OS = Literal["linux", "macos", "windows", "*"]
|
|
8
|
+
|
|
9
|
+
_system = platform.system()
|
|
10
|
+
_OS_map: dict[str, OS] = {
|
|
11
|
+
"Linux": "linux",
|
|
12
|
+
"Darwin": "macos",
|
|
13
|
+
"Windows": "windows",
|
|
14
|
+
}
|
|
15
|
+
os: OS = _OS_map.get(_system, "linux")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_os_matrix(matrix: Mapping[OS, str]) -> str | None:
|
|
19
|
+
"""Get a value from a mapping where the key is an OS, falling back to a wildcard ("*").
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
matrix: A mapping where an OS literal is the key.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
The value, if one is found, or `None`.
|
|
26
|
+
"""
|
|
27
|
+
if (result := matrix.get(os)) is None:
|
|
28
|
+
result = matrix.get("*")
|
|
29
|
+
return result
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_version() -> str:
|
|
33
|
+
"""Get the current version of Toad.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
str: Version string, e.g "1.2.3"
|
|
37
|
+
"""
|
|
38
|
+
from importlib.metadata import version
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
return version("batrachian-toad")
|
|
42
|
+
except Exception:
|
|
43
|
+
try:
|
|
44
|
+
return version("toad")
|
|
45
|
+
except Exception:
|
|
46
|
+
return "0.1.0unknown"
|
toad/__main__.py
ADDED
toad/_loop.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Iterable, Literal, Sequence, TypeVar
|
|
4
|
+
|
|
5
|
+
T = TypeVar("T")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def loop_first(values: Iterable[T]) -> Iterable[tuple[bool, T]]:
|
|
9
|
+
"""Iterate and generate a tuple with a flag for first value."""
|
|
10
|
+
iter_values = iter(values)
|
|
11
|
+
try:
|
|
12
|
+
value = next(iter_values)
|
|
13
|
+
except StopIteration:
|
|
14
|
+
return
|
|
15
|
+
yield True, value
|
|
16
|
+
for value in iter_values:
|
|
17
|
+
yield False, value
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def loop_last(values: Iterable[T]) -> Iterable[tuple[bool, T]]:
|
|
21
|
+
"""Iterate and generate a tuple with a flag for last value."""
|
|
22
|
+
iter_values = iter(values)
|
|
23
|
+
try:
|
|
24
|
+
previous_value = next(iter_values)
|
|
25
|
+
except StopIteration:
|
|
26
|
+
return
|
|
27
|
+
for value in iter_values:
|
|
28
|
+
yield False, previous_value
|
|
29
|
+
previous_value = value
|
|
30
|
+
yield True, previous_value
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def loop_first_last(values: Iterable[T]) -> Iterable[tuple[bool, bool, T]]:
|
|
34
|
+
"""Iterate and generate a tuple with a flag for first and last value."""
|
|
35
|
+
iter_values = iter(values)
|
|
36
|
+
try:
|
|
37
|
+
previous_value = next(iter_values)
|
|
38
|
+
except StopIteration:
|
|
39
|
+
return
|
|
40
|
+
first = True
|
|
41
|
+
for value in iter_values:
|
|
42
|
+
yield first, False, previous_value
|
|
43
|
+
first = False
|
|
44
|
+
previous_value = value
|
|
45
|
+
yield first, True, previous_value
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def loop_from_index(
|
|
49
|
+
values: Sequence[T],
|
|
50
|
+
index: int,
|
|
51
|
+
direction: Literal[-1, +1] = +1,
|
|
52
|
+
wrap: bool = True,
|
|
53
|
+
) -> Iterable[tuple[int, T]]:
|
|
54
|
+
"""Iterate over values in a sequence from a given starting index, potentially wrapping the index
|
|
55
|
+
if it would go out of bounds.
|
|
56
|
+
|
|
57
|
+
Note that the first value to be yielded is a step from `index`, and `index` will be yielded *last*.
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
values: A sequence of values.
|
|
62
|
+
index: Starting index.
|
|
63
|
+
direction: Direction to move index (+1 for forward, -1 for backward).
|
|
64
|
+
bool: Should the index wrap when out of bounds?
|
|
65
|
+
|
|
66
|
+
Yields:
|
|
67
|
+
A tuple of index and value from the sequence.
|
|
68
|
+
"""
|
|
69
|
+
# Sanity check for devs who miss the typing errors
|
|
70
|
+
assert direction in (-1, +1), "direction must be -1 or +1"
|
|
71
|
+
count = len(values)
|
|
72
|
+
if wrap:
|
|
73
|
+
for _ in range(count):
|
|
74
|
+
index = (index + direction) % count
|
|
75
|
+
yield (index, values[index])
|
|
76
|
+
else:
|
|
77
|
+
if direction == +1:
|
|
78
|
+
for _ in range(count):
|
|
79
|
+
if (index := index + 1) >= count:
|
|
80
|
+
break
|
|
81
|
+
yield (index, values[index])
|
|
82
|
+
else:
|
|
83
|
+
for _ in range(count):
|
|
84
|
+
if (index := index - 1) < 0:
|
|
85
|
+
break
|
|
86
|
+
yield (index, values[index])
|
toad/about.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from importlib.metadata import version
|
|
3
|
+
import platform
|
|
4
|
+
from string import Template
|
|
5
|
+
|
|
6
|
+
from toad.app import ToadApp
|
|
7
|
+
from toad import paths
|
|
8
|
+
from toad import get_version
|
|
9
|
+
|
|
10
|
+
ABOUT_TEMPLATE = Template(
|
|
11
|
+
"""\
|
|
12
|
+
# About Toad v${TOAD_VERSION}
|
|
13
|
+
|
|
14
|
+
© Will McGugan.
|
|
15
|
+
|
|
16
|
+
Toad is licensed under the terms of the [GNU AFFERO GENERAL PUBLIC LICENSE](https://www.gnu.org/licenses/agpl-3.0.txt).
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## Config
|
|
20
|
+
|
|
21
|
+
config read from `$SETTINGS_PATH`
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
$CONFIG
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Paths
|
|
28
|
+
|
|
29
|
+
| Name | Path |
|
|
30
|
+
| --- | --- |
|
|
31
|
+
| App data | `$DATA_PATH` |
|
|
32
|
+
| App logs | `$LOG_PATH` |
|
|
33
|
+
|
|
34
|
+
## System
|
|
35
|
+
|
|
36
|
+
| System | Version |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| Python | $PYTHON |
|
|
39
|
+
| OS | $PLATFORM |
|
|
40
|
+
|
|
41
|
+
## Dependencies
|
|
42
|
+
|
|
43
|
+
| Library | Version |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| Toad | $TOAD_VERSION |
|
|
46
|
+
| Textual | $TEXTUAL_VERSION |
|
|
47
|
+
| Rich | $RICH_VERSION |
|
|
48
|
+
|
|
49
|
+
## Environment
|
|
50
|
+
|
|
51
|
+
| Environment variable | Value |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| `SHELL` | $SHELL |
|
|
54
|
+
| `TERM` | $TERM |
|
|
55
|
+
| `COLORTERM` | $COLORTERM |
|
|
56
|
+
| `TERM_PROGRAM` | $TERM_PROGRAM |
|
|
57
|
+
| `TERM_PROGRAM_VERSION` | $TERM_PROGRAM_VERSION |
|
|
58
|
+
"""
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def render(app: ToadApp) -> str:
|
|
63
|
+
"""Render about markdown.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Markdown string.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
config: str | None = app.settings_path.read_text()
|
|
71
|
+
except Exception:
|
|
72
|
+
config = None
|
|
73
|
+
|
|
74
|
+
template_data = {
|
|
75
|
+
"COLORTERM": os.environ.get("COLORTERM", ""),
|
|
76
|
+
"CONFIG": config,
|
|
77
|
+
"DATA_PATH": paths.get_data(),
|
|
78
|
+
"LOG_PATH": paths.get_log(),
|
|
79
|
+
"PLATFORM": platform.platform(),
|
|
80
|
+
"PYTHON": f"{platform.python_implementation()} {platform.python_version()}",
|
|
81
|
+
"RICH_VERSION": version("rich"),
|
|
82
|
+
"SETTINGS_PATH": str(app.settings_path),
|
|
83
|
+
"SHELL": os.environ.get("SHELL", ""),
|
|
84
|
+
"TERM_PROGRAM_VERSION": os.environ.get("TERM_PROGRAM_VERSION", ""),
|
|
85
|
+
"TERM_PROGRAM": os.environ.get("TERM_PROGRAM", ""),
|
|
86
|
+
"TERM": os.environ.get("TERM", ""),
|
|
87
|
+
"TEXTUAL_VERSION": version("textual"),
|
|
88
|
+
"TOAD_VERSION": get_version(),
|
|
89
|
+
}
|
|
90
|
+
return ABOUT_TEMPLATE.safe_substitute(template_data)
|