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.
Files changed (120) hide show
  1. batrachian_toad-0.5.22.dist-info/METADATA +197 -0
  2. batrachian_toad-0.5.22.dist-info/RECORD +120 -0
  3. batrachian_toad-0.5.22.dist-info/WHEEL +4 -0
  4. batrachian_toad-0.5.22.dist-info/entry_points.txt +2 -0
  5. batrachian_toad-0.5.22.dist-info/licenses/LICENSE +661 -0
  6. toad/__init__.py +46 -0
  7. toad/__main__.py +4 -0
  8. toad/_loop.py +86 -0
  9. toad/about.py +90 -0
  10. toad/acp/agent.py +671 -0
  11. toad/acp/api.py +47 -0
  12. toad/acp/encode_tool_call_id.py +12 -0
  13. toad/acp/messages.py +138 -0
  14. toad/acp/prompt.py +54 -0
  15. toad/acp/protocol.py +426 -0
  16. toad/agent.py +62 -0
  17. toad/agent_schema.py +70 -0
  18. toad/agents.py +45 -0
  19. toad/ansi/__init__.py +1 -0
  20. toad/ansi/_ansi.py +1612 -0
  21. toad/ansi/_ansi_colors.py +264 -0
  22. toad/ansi/_control_codes.py +37 -0
  23. toad/ansi/_keys.py +251 -0
  24. toad/ansi/_sgr_styles.py +64 -0
  25. toad/ansi/_stream_parser.py +418 -0
  26. toad/answer.py +22 -0
  27. toad/app.py +557 -0
  28. toad/atomic.py +37 -0
  29. toad/cli.py +257 -0
  30. toad/code_analyze.py +28 -0
  31. toad/complete.py +34 -0
  32. toad/constants.py +58 -0
  33. toad/conversation_markdown.py +19 -0
  34. toad/danger.py +371 -0
  35. toad/data/agents/ampcode.com.toml +51 -0
  36. toad/data/agents/augmentcode.com.toml +40 -0
  37. toad/data/agents/claude.com.toml +41 -0
  38. toad/data/agents/docker.com.toml +59 -0
  39. toad/data/agents/geminicli.com.toml +28 -0
  40. toad/data/agents/goose.ai.toml +51 -0
  41. toad/data/agents/inference.huggingface.co.toml +33 -0
  42. toad/data/agents/kimi.com.toml +35 -0
  43. toad/data/agents/openai.com.toml +53 -0
  44. toad/data/agents/opencode.ai.toml +61 -0
  45. toad/data/agents/openhands.dev.toml +44 -0
  46. toad/data/agents/stakpak.dev.toml +61 -0
  47. toad/data/agents/vibe.mistral.ai.toml +27 -0
  48. toad/data/agents/vtcode.dev.toml +62 -0
  49. toad/data/images/frog.png +0 -0
  50. toad/data/sounds/turn-over.wav +0 -0
  51. toad/db.py +5 -0
  52. toad/dec.py +332 -0
  53. toad/directory.py +234 -0
  54. toad/directory_watcher.py +96 -0
  55. toad/fuzzy.py +140 -0
  56. toad/gist.py +2 -0
  57. toad/history.py +138 -0
  58. toad/jsonrpc.py +576 -0
  59. toad/menus.py +14 -0
  60. toad/messages.py +74 -0
  61. toad/option_content.py +51 -0
  62. toad/os.py +0 -0
  63. toad/path_complete.py +145 -0
  64. toad/path_filter.py +124 -0
  65. toad/paths.py +71 -0
  66. toad/pill.py +23 -0
  67. toad/prompt/extract.py +19 -0
  68. toad/prompt/resource.py +68 -0
  69. toad/protocol.py +28 -0
  70. toad/screens/action_modal.py +94 -0
  71. toad/screens/agent_modal.py +172 -0
  72. toad/screens/command_edit_modal.py +58 -0
  73. toad/screens/main.py +192 -0
  74. toad/screens/permissions.py +390 -0
  75. toad/screens/permissions.tcss +72 -0
  76. toad/screens/settings.py +254 -0
  77. toad/screens/settings.tcss +101 -0
  78. toad/screens/store.py +476 -0
  79. toad/screens/store.tcss +261 -0
  80. toad/settings.py +354 -0
  81. toad/settings_schema.py +318 -0
  82. toad/shell.py +263 -0
  83. toad/shell_read.py +42 -0
  84. toad/slash_command.py +34 -0
  85. toad/toad.tcss +752 -0
  86. toad/version.py +80 -0
  87. toad/visuals/columns.py +273 -0
  88. toad/widgets/agent_response.py +79 -0
  89. toad/widgets/agent_thought.py +41 -0
  90. toad/widgets/command_pane.py +224 -0
  91. toad/widgets/condensed_path.py +93 -0
  92. toad/widgets/conversation.py +1626 -0
  93. toad/widgets/danger_warning.py +65 -0
  94. toad/widgets/diff_view.py +709 -0
  95. toad/widgets/flash.py +81 -0
  96. toad/widgets/future_text.py +126 -0
  97. toad/widgets/grid_select.py +223 -0
  98. toad/widgets/highlighted_textarea.py +180 -0
  99. toad/widgets/mandelbrot.py +294 -0
  100. toad/widgets/markdown_note.py +13 -0
  101. toad/widgets/menu.py +147 -0
  102. toad/widgets/non_selectable_label.py +5 -0
  103. toad/widgets/note.py +18 -0
  104. toad/widgets/path_search.py +381 -0
  105. toad/widgets/plan.py +180 -0
  106. toad/widgets/project_directory_tree.py +74 -0
  107. toad/widgets/prompt.py +741 -0
  108. toad/widgets/question.py +337 -0
  109. toad/widgets/shell_result.py +35 -0
  110. toad/widgets/shell_terminal.py +18 -0
  111. toad/widgets/side_bar.py +74 -0
  112. toad/widgets/slash_complete.py +211 -0
  113. toad/widgets/strike_text.py +66 -0
  114. toad/widgets/terminal.py +526 -0
  115. toad/widgets/terminal_tool.py +338 -0
  116. toad/widgets/throbber.py +90 -0
  117. toad/widgets/tool_call.py +303 -0
  118. toad/widgets/user_input.py +23 -0
  119. toad/widgets/version.py +5 -0
  120. 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
@@ -0,0 +1,4 @@
1
+ from toad.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
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)