speiidev 1.0.1 → 1.3.0
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.
- package/PLAN.md +292 -0
- package/bin/speiidev.js +4 -11
- package/package.json +1 -1
- package/pyproject.toml +4 -1
- package/scripts/bump_version.py +104 -0
- package/src/autodev/__init__.py +18 -8
- package/src/autodev/_version.py +14 -0
- package/src/autodev/cli.py +712 -173
- package/tests/test_cli.py +128 -1
package/tests/test_cli.py
CHANGED
|
@@ -62,7 +62,20 @@ class TestCLIHelpers(unittest.TestCase):
|
|
|
62
62
|
self.assertEqual(res.returncode, 0)
|
|
63
63
|
self.assertTrue(len(res.stdout.strip()) > 0)
|
|
64
64
|
|
|
65
|
-
def
|
|
65
|
+
def test_versions_consistent(self):
|
|
66
|
+
"""All version fields must agree (single source of truth)."""
|
|
67
|
+
res = subprocess.run(
|
|
68
|
+
[sys.executable, "scripts/bump_version.py", "--check"],
|
|
69
|
+
capture_output=True,
|
|
70
|
+
text=True,
|
|
71
|
+
cwd=str(ROOT_DIR),
|
|
72
|
+
)
|
|
73
|
+
self.assertEqual(
|
|
74
|
+
res.returncode,
|
|
75
|
+
0,
|
|
76
|
+
msg=f"Version mismatch:\n{res.stdout}\n{res.stderr}",
|
|
77
|
+
)
|
|
78
|
+
def test_block_font_runner_script(self):
|
|
66
79
|
"""Running block-font runner script should exit with 0."""
|
|
67
80
|
block_font_script = ROOT_DIR / "bin" / "block-font"
|
|
68
81
|
if not block_font_script.exists():
|
|
@@ -77,6 +90,120 @@ class TestCLIHelpers(unittest.TestCase):
|
|
|
77
90
|
self.assertEqual(res.returncode, 0)
|
|
78
91
|
self.assertIn("█", res.stdout)
|
|
79
92
|
|
|
93
|
+
def test_print_banner_responsive_widths(self):
|
|
94
|
+
"""Banner must dynamically scale and never overflow terminal width on resize."""
|
|
95
|
+
from rich.console import Console
|
|
96
|
+
import autodev.cli as cli
|
|
97
|
+
|
|
98
|
+
state = cli.AgentState()
|
|
99
|
+
for width in [120, 86, 80, 75, 60, 48, 35]:
|
|
100
|
+
c = Console(width=width, height=24, color_system=None)
|
|
101
|
+
cli.console = c
|
|
102
|
+
with c.capture() as cap:
|
|
103
|
+
cli.print_banner(state)
|
|
104
|
+
out = cap.get()
|
|
105
|
+
for line in out.splitlines():
|
|
106
|
+
self.assertLessEqual(
|
|
107
|
+
len(line),
|
|
108
|
+
width,
|
|
109
|
+
f"Banner line exceeded terminal width {width}: {repr(line)}",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Specifically verify 80-column terminal layout displays Claude 3D title art
|
|
113
|
+
c80 = Console(width=80, height=24, color_system=None)
|
|
114
|
+
cli.console = c80
|
|
115
|
+
with c80.capture() as cap:
|
|
116
|
+
cli.print_banner(state)
|
|
117
|
+
out80 = cap.get()
|
|
118
|
+
self.assertIn("▄██████╗", out80, "Expected Claude 3D font at 80 columns")
|
|
119
|
+
self.assertIn("repo", out80)
|
|
120
|
+
self.assertIn("plan", out80)
|
|
121
|
+
self.assertIn("build", out80)
|
|
122
|
+
|
|
123
|
+
def test_interactive_repl_resize_hook(self):
|
|
124
|
+
"""Interactive REPL resize hook must debounce and re-render without exception."""
|
|
125
|
+
import asyncio
|
|
126
|
+
from prompt_toolkit import PromptSession
|
|
127
|
+
from prompt_toolkit.input import create_pipe_input
|
|
128
|
+
import autodev.cli as cli
|
|
129
|
+
|
|
130
|
+
with create_pipe_input() as pipe_input:
|
|
131
|
+
session = PromptSession(input=pipe_input)
|
|
132
|
+
orig_on_resize = session.app._on_resize
|
|
133
|
+
resize_timer = [None]
|
|
134
|
+
called = [0]
|
|
135
|
+
|
|
136
|
+
def _do_redraw():
|
|
137
|
+
called[0] += 1
|
|
138
|
+
if getattr(session.app, "is_running", False):
|
|
139
|
+
try:
|
|
140
|
+
session.app.renderer.erase(leave_alternate_screen=False)
|
|
141
|
+
session.app._request_absolute_cursor_position()
|
|
142
|
+
session.app._redraw()
|
|
143
|
+
except Exception:
|
|
144
|
+
orig_on_resize()
|
|
145
|
+
|
|
146
|
+
def _handle_resize():
|
|
147
|
+
try:
|
|
148
|
+
loop = asyncio.get_running_loop()
|
|
149
|
+
if resize_timer[0] is not None:
|
|
150
|
+
resize_timer[0].cancel()
|
|
151
|
+
resize_timer[0] = loop.call_later(0.01, _do_redraw)
|
|
152
|
+
except Exception:
|
|
153
|
+
_do_redraw()
|
|
154
|
+
|
|
155
|
+
session.app._on_resize = _handle_resize
|
|
156
|
+
|
|
157
|
+
pipe_input.send_text("test_cmd\n")
|
|
158
|
+
res = session.prompt("❯ ")
|
|
159
|
+
self.assertEqual(res, "test_cmd")
|
|
160
|
+
# Verify handler can be called directly safely
|
|
161
|
+
session.app._on_resize()
|
|
162
|
+
|
|
163
|
+
def test_agent_stream_view_responsive_dimensions(self):
|
|
164
|
+
"""Live stream panel must fit within both terminal width and height on resize."""
|
|
165
|
+
from rich.console import Console
|
|
166
|
+
from collections import deque
|
|
167
|
+
import autodev.cli as cli
|
|
168
|
+
|
|
169
|
+
lines = deque(maxlen=18)
|
|
170
|
+
for i in range(25):
|
|
171
|
+
lines.append(
|
|
172
|
+
f"Step {i}: processing /long/path/to/nested/module/that/could/cause/wrapping/on/narrow/screens/code.py"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
state = cli.AgentState()
|
|
176
|
+
view = cli._AgentStreamView(
|
|
177
|
+
cmd=["agy", "--mode=accept-edits", "-p", "Execute tasks step-by-step with safety checks"],
|
|
178
|
+
title="Building Application",
|
|
179
|
+
border_color=cli.THEME["builder"],
|
|
180
|
+
badge="[BUILDER]",
|
|
181
|
+
attempt=1,
|
|
182
|
+
state=state,
|
|
183
|
+
lines=lines,
|
|
184
|
+
activity=[("Read", "lib/main.py"), ("Write", "lib/out.py")],
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
for w, h in [(120, 30), (80, 24), (70, 20), (55, 16), (40, 12)]:
|
|
188
|
+
c = Console(width=w, height=h, color_system=None)
|
|
189
|
+
cli.console = c
|
|
190
|
+
with c.capture() as cap:
|
|
191
|
+
c.print(view)
|
|
192
|
+
out = cap.get()
|
|
193
|
+
rendered = out.splitlines()
|
|
194
|
+
self.assertGreater(len(rendered), 0)
|
|
195
|
+
self.assertLessEqual(
|
|
196
|
+
len(rendered),
|
|
197
|
+
h,
|
|
198
|
+
f"Stream view panel height {len(rendered)} exceeded terminal height {h} at {w}x{h}",
|
|
199
|
+
)
|
|
200
|
+
for line in rendered:
|
|
201
|
+
self.assertLessEqual(
|
|
202
|
+
len(line),
|
|
203
|
+
w,
|
|
204
|
+
f"Stream view panel line width {len(line)} exceeded terminal width {w} at {w}x{h}",
|
|
205
|
+
)
|
|
206
|
+
|
|
80
207
|
|
|
81
208
|
if __name__ == "__main__":
|
|
82
209
|
unittest.main()
|