gemcode 0.3.24__tar.gz → 0.3.26__tar.gz
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.
- {gemcode-0.3.24/src/gemcode.egg-info → gemcode-0.3.26}/PKG-INFO +1 -1
- {gemcode-0.3.24 → gemcode-0.3.26}/pyproject.toml +1 -1
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tui/scrollback.py +83 -11
- {gemcode-0.3.24 → gemcode-0.3.26/src/gemcode.egg-info}/PKG-INFO +1 -1
- {gemcode-0.3.24 → gemcode-0.3.26}/LICENSE +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/MANIFEST.in +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/README.md +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/setup.cfg +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/__init__.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/__main__.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/agent.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/audit.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/autocompact.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/callbacks.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/capability_routing.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/cli.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/compaction.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/computer_use/__init__.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/computer_use/browser_computer.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/config.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/context_budget.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/context_warning.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/credentials.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/hitl_session.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/interactions.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/invoke.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/kairos_daemon.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/limits.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/live_audio_engine.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/logging_config.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/mcp_loader.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/memory/__init__.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/memory/embedding_memory_service.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/memory/file_memory_service.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/modality_tools.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/model_errors.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/model_routing.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/paths.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/permissions.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/plugins/__init__.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/prompt_suggestions.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/query/__init__.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/query/config.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/query/deps.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/query/engine.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/query/stop_hooks.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/query/token_budget.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/query/transitions.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/repl_commands.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/repl_slash.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/session_runtime.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/slash_commands.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/thinking.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tool_prompt_manifest.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tool_registry.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools/__init__.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools/bash.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools/browser.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools/edit.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools/filesystem.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools/search.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools/shell.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools/shell_gate.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools/subtask.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools/think.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools/todo.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools/web.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tools_inspector.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/trust.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tui/input_handler.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tui/spinner.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tui/welcome_banner.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/tui/welcome_rich.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/version.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/vertex.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/web/__init__.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/web/claude_sse_adapter.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/web/terminal_repl.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode/workspace_hints.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode.egg-info/SOURCES.txt +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode.egg-info/dependency_links.txt +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode.egg-info/entry_points.txt +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode.egg-info/requires.txt +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/src/gemcode.egg-info/top_level.txt +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_agent_instruction.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_autocompact.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_capability_routing.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_claude_web_adapter_sse.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_cli_init.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_computer_use_permissions.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_context_budget.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_context_warning.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_credentials.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_interactive_permission_ask.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_kairos_scheduler.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_modality_tools.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_model_error_retry.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_model_errors.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_model_routing.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_paths.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_permissions.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_prompt_suggestions.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_repl_commands.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_repl_slash.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_slash_commands.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_thinking_config.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_token_budget.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_tool_context_circulation.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_tools.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_tools_inspector.py +0 -0
- {gemcode-0.3.24 → gemcode-0.3.26}/tests/test_workspace_hints.py +0 -0
|
@@ -140,6 +140,43 @@ class _Ansi:
|
|
|
140
140
|
return self.esc("38;5;69")
|
|
141
141
|
|
|
142
142
|
|
|
143
|
+
async def _read_permission_char(loop) -> bool:
|
|
144
|
+
"""
|
|
145
|
+
Read a single character from stdin without requiring Enter.
|
|
146
|
+
|
|
147
|
+
Uses cbreak mode (Unix) so the user just presses 'y' — no Enter needed.
|
|
148
|
+
This sidesteps the prompt_toolkit raw-mode conflict entirely: after
|
|
149
|
+
prompt_async() returns, the terminal may still behave as if Enter sends
|
|
150
|
+
\\r instead of \\n, causing input()/readline() to block forever.
|
|
151
|
+
cbreak mode + read(1) works regardless of the terminal's current line-
|
|
152
|
+
discipline state.
|
|
153
|
+
|
|
154
|
+
Falls back to readline() on Windows or non-TTY (CI, piped input).
|
|
155
|
+
"""
|
|
156
|
+
# ── Unix / macOS: cbreak + read(1) ───────────────────────────────────────
|
|
157
|
+
try:
|
|
158
|
+
import termios
|
|
159
|
+
import tty
|
|
160
|
+
|
|
161
|
+
fd = sys.stdin.fileno()
|
|
162
|
+
old_settings = termios.tcgetattr(fd)
|
|
163
|
+
try:
|
|
164
|
+
tty.setcbreak(fd) # single-char, no echo, signals still work
|
|
165
|
+
ch = await loop.run_in_executor(None, lambda: sys.stdin.read(1))
|
|
166
|
+
finally:
|
|
167
|
+
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
168
|
+
return ch.lower() == "y"
|
|
169
|
+
except Exception:
|
|
170
|
+
pass
|
|
171
|
+
|
|
172
|
+
# ── Fallback: readline in thread (Windows, non-TTY, termios error) ───────
|
|
173
|
+
try:
|
|
174
|
+
raw = await loop.run_in_executor(None, sys.stdin.readline)
|
|
175
|
+
return (raw or "").replace("\r", "").replace("\n", "").strip().lower() in ("y", "yes")
|
|
176
|
+
except EOFError:
|
|
177
|
+
return False
|
|
178
|
+
|
|
179
|
+
|
|
143
180
|
def _term_width(default: int = 100) -> int:
|
|
144
181
|
try:
|
|
145
182
|
import shutil
|
|
@@ -563,27 +600,59 @@ async def run_gemcode_scrollback_tui(
|
|
|
563
600
|
if not interactive_enabled:
|
|
564
601
|
print("")
|
|
565
602
|
print(
|
|
566
|
-
f" ⎿ {ansi.blue_warn}{ansi.bold}Permission needed{ansi.reset} for
|
|
567
|
-
f"
|
|
603
|
+
f" ⎿ {ansi.blue_warn}{ansi.bold}Permission needed{ansi.reset} for "
|
|
604
|
+
f"{ansi.bold}{tool_name}{ansi.reset} — auto-denying "
|
|
605
|
+
f"(run with --yes or /computer on to allow)."
|
|
568
606
|
)
|
|
569
607
|
ok = False
|
|
570
608
|
else:
|
|
571
609
|
print("")
|
|
572
610
|
if hint:
|
|
573
611
|
print(
|
|
574
|
-
f" ⎿ {ansi.blue}{ansi.bold}Permission needed{ansi.reset}
|
|
612
|
+
f" ⎿ {ansi.blue}{ansi.bold}Permission needed{ansi.reset} "
|
|
613
|
+
f"for {ansi.bold}{tool_name}{ansi.reset}: {hint}"
|
|
575
614
|
)
|
|
576
615
|
else:
|
|
577
616
|
print(
|
|
578
|
-
f" ⎿ {ansi.blue}{ansi.bold}Permission needed{ansi.reset}
|
|
617
|
+
f" ⎿ {ansi.blue}{ansi.bold}Permission needed{ansi.reset} "
|
|
618
|
+
f"for {ansi.bold}{tool_name}{ansi.reset}."
|
|
579
619
|
)
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
620
|
+
sys.stdout.flush()
|
|
621
|
+
# The core issue: prompt_toolkit puts the terminal in raw mode
|
|
622
|
+
# while reading user input. After prompt_async() returns, the
|
|
623
|
+
# terminal may still be in (or close to) raw mode. In raw mode
|
|
624
|
+
# pressing Enter sends \r instead of \n. Both input() and
|
|
625
|
+
# readline() wait for \n — so they block forever.
|
|
626
|
+
#
|
|
627
|
+
# Fix: read a SINGLE CHARACTER using cbreak mode (no Enter needed).
|
|
628
|
+
# - tty.setcbreak() disables line-buffering + echo but keeps
|
|
629
|
+
# signal keys (Ctrl+C etc.) working.
|
|
630
|
+
# - read(1) returns immediately after any key is pressed.
|
|
631
|
+
# - The user only needs to press "y" — no Enter required.
|
|
632
|
+
# - On Windows (no termios) we fall back to readline().
|
|
633
|
+
prompt_str = (
|
|
634
|
+
f" ⎿ Allow? "
|
|
635
|
+
f"[{ansi.blue_ok}y{ansi.reset} = yes "
|
|
636
|
+
f"{ansi.dim}any other key = no{ansi.reset}] "
|
|
637
|
+
)
|
|
638
|
+
sys.stdout.write(prompt_str)
|
|
639
|
+
sys.stdout.flush()
|
|
640
|
+
ok = await _read_permission_char(asyncio.get_running_loop())
|
|
641
|
+
# Echo the answer and move to next line
|
|
642
|
+
sys.stdout.write(("y" if ok else "n") + "\n")
|
|
643
|
+
sys.stdout.flush()
|
|
644
|
+
|
|
645
|
+
# Explicit visual feedback — user knows their answer was received.
|
|
646
|
+
if ok:
|
|
647
|
+
print(
|
|
648
|
+
f" ⎿ {ansi.blue_ok}{ansi.bold}Approved{ansi.reset} — "
|
|
649
|
+
f"continuing…"
|
|
650
|
+
)
|
|
651
|
+
else:
|
|
652
|
+
print(
|
|
653
|
+
f" ⎿ {ansi.dim}Denied — skipping {tool_name}.{ansi.reset}"
|
|
654
|
+
)
|
|
655
|
+
sys.stdout.flush()
|
|
587
656
|
|
|
588
657
|
parts.append(
|
|
589
658
|
types.Part(
|
|
@@ -596,6 +665,9 @@ async def run_gemcode_scrollback_tui(
|
|
|
596
665
|
)
|
|
597
666
|
current_message = types.Content(role="user", parts=parts)
|
|
598
667
|
do_reset = False
|
|
668
|
+
# Restart the spinner so the user knows the agent is working again
|
|
669
|
+
# after they answered the permission prompt.
|
|
670
|
+
_start_anim("Working\u2026")
|
|
599
671
|
|
|
600
672
|
print("")
|
|
601
673
|
if os.environ.get("GEMCODE_TUI_TURN_FOOTER", "1").lower() in (
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|