gemcode 0.3.36__tar.gz → 0.3.38__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.
Files changed (120) hide show
  1. {gemcode-0.3.36/src/gemcode.egg-info → gemcode-0.3.38}/PKG-INFO +1 -1
  2. {gemcode-0.3.36 → gemcode-0.3.38}/pyproject.toml +1 -1
  3. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/cli.py +1 -1
  4. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/invoke.py +2 -2
  5. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/live_audio_engine.py +1 -1
  6. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tui/input_handler.py +18 -9
  7. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tui/scrollback.py +20 -2
  8. {gemcode-0.3.36 → gemcode-0.3.38/src/gemcode.egg-info}/PKG-INFO +1 -1
  9. {gemcode-0.3.36 → gemcode-0.3.38}/LICENSE +0 -0
  10. {gemcode-0.3.36 → gemcode-0.3.38}/MANIFEST.in +0 -0
  11. {gemcode-0.3.36 → gemcode-0.3.38}/README.md +0 -0
  12. {gemcode-0.3.36 → gemcode-0.3.38}/setup.cfg +0 -0
  13. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/__init__.py +0 -0
  14. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/__main__.py +0 -0
  15. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/agent.py +0 -0
  16. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/audit.py +0 -0
  17. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/autocompact.py +0 -0
  18. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/callbacks.py +0 -0
  19. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/capability_routing.py +0 -0
  20. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/compaction.py +0 -0
  21. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/computer_use/__init__.py +0 -0
  22. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/computer_use/browser_computer.py +0 -0
  23. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/config.py +0 -0
  24. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/context_budget.py +0 -0
  25. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/context_warning.py +0 -0
  26. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/credentials.py +0 -0
  27. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/hitl_session.py +0 -0
  28. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/hooks.py +0 -0
  29. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/interactions.py +0 -0
  30. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/kairos_daemon.py +0 -0
  31. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/limits.py +0 -0
  32. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/logging_config.py +0 -0
  33. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/mcp_loader.py +0 -0
  34. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/memory/__init__.py +0 -0
  35. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/memory/embedding_memory_service.py +0 -0
  36. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/memory/file_memory_service.py +0 -0
  37. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/modality_tools.py +0 -0
  38. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/model_errors.py +0 -0
  39. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/model_routing.py +0 -0
  40. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/openapi_loader.py +0 -0
  41. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/paths.py +0 -0
  42. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/permissions.py +0 -0
  43. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/plugins/__init__.py +0 -0
  44. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
  45. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
  46. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/pricing.py +0 -0
  47. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/prompt_suggestions.py +0 -0
  48. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/query/__init__.py +0 -0
  49. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/query/config.py +0 -0
  50. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/query/deps.py +0 -0
  51. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/query/engine.py +0 -0
  52. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/query/stop_hooks.py +0 -0
  53. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/query/token_budget.py +0 -0
  54. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/query/transitions.py +0 -0
  55. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/refine.py +0 -0
  56. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/repl_commands.py +0 -0
  57. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/repl_slash.py +0 -0
  58. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/review_agent.py +0 -0
  59. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/session_runtime.py +0 -0
  60. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/session_store.py +0 -0
  61. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/slash_commands.py +0 -0
  62. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/thinking.py +0 -0
  63. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tool_prompt_manifest.py +0 -0
  64. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tool_registry.py +0 -0
  65. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/__init__.py +0 -0
  66. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/bash.py +0 -0
  67. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/browser.py +0 -0
  68. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/edit.py +0 -0
  69. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/filesystem.py +0 -0
  70. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/notes.py +0 -0
  71. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/search.py +0 -0
  72. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/shell.py +0 -0
  73. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/shell_gate.py +0 -0
  74. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/subtask.py +0 -0
  75. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/think.py +0 -0
  76. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/todo.py +0 -0
  77. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools/web.py +0 -0
  78. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tools_inspector.py +0 -0
  79. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/trust.py +0 -0
  80. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tui/spinner.py +0 -0
  81. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tui/welcome_banner.py +0 -0
  82. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/tui/welcome_rich.py +0 -0
  83. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/version.py +0 -0
  84. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/vertex.py +0 -0
  85. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/web/__init__.py +0 -0
  86. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/web/claude_sse_adapter.py +0 -0
  87. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/web/terminal_repl.py +0 -0
  88. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode/workspace_hints.py +0 -0
  89. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode.egg-info/SOURCES.txt +0 -0
  90. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode.egg-info/dependency_links.txt +0 -0
  91. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode.egg-info/entry_points.txt +0 -0
  92. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode.egg-info/requires.txt +0 -0
  93. {gemcode-0.3.36 → gemcode-0.3.38}/src/gemcode.egg-info/top_level.txt +0 -0
  94. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_agent_instruction.py +0 -0
  95. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_autocompact.py +0 -0
  96. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_capability_routing.py +0 -0
  97. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_claude_web_adapter_sse.py +0 -0
  98. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_cli_init.py +0 -0
  99. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_computer_use_permissions.py +0 -0
  100. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_context_budget.py +0 -0
  101. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_context_warning.py +0 -0
  102. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_credentials.py +0 -0
  103. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_interactive_permission_ask.py +0 -0
  104. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_kairos_scheduler.py +0 -0
  105. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_modality_tools.py +0 -0
  106. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_model_error_retry.py +0 -0
  107. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_model_errors.py +0 -0
  108. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_model_routing.py +0 -0
  109. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_paths.py +0 -0
  110. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_permissions.py +0 -0
  111. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_prompt_suggestions.py +0 -0
  112. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_repl_commands.py +0 -0
  113. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_repl_slash.py +0 -0
  114. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_slash_commands.py +0 -0
  115. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_thinking_config.py +0 -0
  116. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_token_budget.py +0 -0
  117. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_tool_context_circulation.py +0 -0
  118. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_tools.py +0 -0
  119. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_tools_inspector.py +0 -0
  120. {gemcode-0.3.36 → gemcode-0.3.38}/tests/test_workspace_hints.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemcode
3
- Version: 0.3.36
3
+ Version: 0.3.38
4
4
  Summary: Local-first coding agent on Google Gemini + ADK
5
5
  Author: GemCode Contributors
6
6
  License: Apache License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gemcode"
7
- version = "0.3.36"
7
+ version = "0.3.38"
8
8
  description = "Local-first coding agent on Google Gemini + ADK"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -27,7 +27,7 @@ def _events_to_text(events) -> str:
27
27
  if not event.content or not event.content.parts:
28
28
  continue
29
29
  for part in event.content.parts:
30
- if part.text and event.author and event.author != "user":
30
+ if part.text and getattr(event, "author", None) != "user":
31
31
  parts.append(part.text)
32
32
  return "".join(parts)
33
33
 
@@ -27,8 +27,8 @@ def _events_to_text(events: list[Any]) -> str:
27
27
  content = getattr(event, "content", None)
28
28
  if not content or not getattr(content, "parts", None):
29
29
  continue
30
- author = getattr(event, "author", None)
31
- if not author or author == "user":
30
+ # Omit only user-authored events; model events may have author=None.
31
+ if getattr(event, "author", None) == "user":
32
32
  continue
33
33
  for part in getattr(content, "parts", []) or []:
34
34
  t = getattr(part, "text", None)
@@ -89,7 +89,7 @@ async def run_live_audio(
89
89
  for part in event.content.parts:
90
90
  part_text = getattr(part, "text", None)
91
91
  # We only print model-authored text to avoid echoing user input.
92
- if part_text and getattr(event, "author", None) and event.author != "user":
92
+ if part_text and getattr(event, "author", None) != "user":
93
93
  sys.stdout.write(part_text)
94
94
  sys.stdout.flush()
95
95
  printed_any = True
@@ -15,6 +15,7 @@ stdout is not a TTY (e.g. piped input, CI).
15
15
 
16
16
  from __future__ import annotations
17
17
 
18
+ import os
18
19
  import sys
19
20
  from typing import Callable
20
21
 
@@ -143,8 +144,8 @@ class GemCodeInputHandler:
143
144
  "completion-menu.meta.completion": "bg:#0d2035 fg:#5a7a9a",
144
145
  "completion-menu.meta.completion.current": "bg:#0065a0 fg:#cce8ff",
145
146
  "completion-menu.border": "#0087d7",
146
- # Bottom toolbar
147
- "bottom-toolbar": "bg:#0d1f2d fg:#4a7a9a",
147
+ # Bottom status line — muted (not multi-colour); detail in HTML
148
+ "bottom-toolbar": "bg:#0a0e12 fg:#5a6570",
148
149
  }
149
150
  )
150
151
 
@@ -170,9 +171,9 @@ class GemCodeInputHandler:
170
171
  flags.append("BROWSER")
171
172
  if flags:
172
173
  extras = " · " + " ".join(f"[{f}]" for f in flags)
174
+ # Single muted tone (no bright cyan) — reads as a quiet status strip
173
175
  return HTML(
174
- f'<style bg="#0d1f2d" fg="#5fafd7"><b> ◆ {model}</b></style>'
175
- f'<style bg="#0d1f2d" fg="#3d6080"> · session {sid_short}'
176
+ f'<style bg="#0a0e12" fg="#5f6b78"> ◆ {model} · session {sid_short}'
176
177
  f'{extras} · / for commands</style>'
177
178
  )
178
179
 
@@ -183,6 +184,14 @@ class GemCodeInputHandler:
183
184
  """Ctrl+C clears current line (like a real shell)."""
184
185
  event.app.current_buffer.reset()
185
186
 
187
+ # Rows reserved for the / command popup. Too high (e.g. 20) leaves a huge
188
+ # empty band above the prompt; 10–12 is enough for most slash lists.
189
+ try:
190
+ _menu_rows = int(os.environ.get("GEMCODE_TUI_RESERVE_MENU_LINES", "12"))
191
+ except ValueError:
192
+ _menu_rows = 12
193
+ _menu_rows = max(6, min(24, _menu_rows))
194
+
186
195
  self._session = PromptSession(
187
196
  history=InMemoryHistory(),
188
197
  completer=_SlashCommandCompleter(),
@@ -190,11 +199,11 @@ class GemCodeInputHandler:
190
199
  style=style,
191
200
  bottom_toolbar=bottom_toolbar,
192
201
  key_bindings=kb,
193
- mouse_support=False,
194
- complete_in_thread=True,
195
- reserve_space_for_menu=20,
196
- # Single-column popup with description column (like VS Code)
197
- complete_style="COLUMN",
202
+ mouse_support=False,
203
+ complete_in_thread=True,
204
+ reserve_space_for_menu=_menu_rows,
205
+ # Single-column popup with description column (like VS Code)
206
+ complete_style="COLUMN",
198
207
  )
199
208
 
200
209
  def is_interactive(self) -> bool:
@@ -577,7 +577,9 @@ async def run_gemcode_scrollback_tui(
577
577
  try:
578
578
  if not ev.content or not ev.content.parts:
579
579
  continue
580
- if not getattr(ev, "author", None) or ev.author == "user":
580
+ # Only skip user turns. ADK often omits `author` on model events — do NOT
581
+ # skip those or the assistant text never renders (blank reply, ↓0 tokens).
582
+ if getattr(ev, "author", None) == "user":
581
583
  continue
582
584
  for part in ev.content.parts:
583
585
  delta = getattr(part, "text", None)
@@ -616,6 +618,11 @@ async def run_gemcode_scrollback_tui(
616
618
  if not confirmation_fcs:
617
619
  thought_text = "".join(buffered_thought).strip()
618
620
  final_text = "".join(buffered_final).strip()
621
+ # Gemini with thinking enabled may emit visible text only in "thought" parts;
622
+ # usage can show thoughts_token_count > 0 and candidates_token_count == 0.
623
+ if not final_text and thought_text:
624
+ final_text = thought_text
625
+ thought_text = ""
619
626
 
620
627
  # ── Thinking display (collapsed by default, verbose with /thinking verbose)
621
628
  if thought_text and not (
@@ -763,7 +770,18 @@ async def run_gemcode_scrollback_tui(
763
770
  token_part = " · " + " · ".join(parts_t)
764
771
  except Exception:
765
772
  pass
766
- print(f"{ansi.dim} · {model} · session {sid}{token_part}{ansi.reset}")
773
+ # Bottom input bar already shows model + session; avoid duplicating them here
774
+ # (reduces visual noise and “gappy” repeats). Optional full line via env.
775
+ _dup = os.environ.get("GEMCODE_TUI_FOOTER_DUP_STATUS", "").lower() in (
776
+ "1", "true", "yes", "on",
777
+ )
778
+ if token_part:
779
+ if _dup:
780
+ print(f"{ansi.dim} · {model} · session {sid}{token_part}{ansi.reset}")
781
+ else:
782
+ print(f"{ansi.dim}{token_part}{ansi.reset}")
783
+ elif _dup:
784
+ print(f"{ansi.dim} · {model} · session {sid}{ansi.reset}")
767
785
  if os.environ.get("GEMCODE_TUI_TURN_RULE", "1").lower() in (
768
786
  "1",
769
787
  "true",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemcode
3
- Version: 0.3.36
3
+ Version: 0.3.38
4
4
  Summary: Local-first coding agent on Google Gemini + ADK
5
5
  Author: GemCode Contributors
6
6
  License: Apache License
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