gemcode 0.3.18__tar.gz → 0.3.19__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 (112) hide show
  1. {gemcode-0.3.18/src/gemcode.egg-info → gemcode-0.3.19}/PKG-INFO +1 -1
  2. {gemcode-0.3.18 → gemcode-0.3.19}/pyproject.toml +1 -1
  3. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/agent.py +22 -9
  4. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tui/scrollback.py +80 -9
  5. {gemcode-0.3.18 → gemcode-0.3.19/src/gemcode.egg-info}/PKG-INFO +1 -1
  6. {gemcode-0.3.18 → gemcode-0.3.19}/LICENSE +0 -0
  7. {gemcode-0.3.18 → gemcode-0.3.19}/MANIFEST.in +0 -0
  8. {gemcode-0.3.18 → gemcode-0.3.19}/README.md +0 -0
  9. {gemcode-0.3.18 → gemcode-0.3.19}/setup.cfg +0 -0
  10. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/__init__.py +0 -0
  11. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/__main__.py +0 -0
  12. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/audit.py +0 -0
  13. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/autocompact.py +0 -0
  14. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/callbacks.py +0 -0
  15. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/capability_routing.py +0 -0
  16. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/cli.py +0 -0
  17. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/compaction.py +0 -0
  18. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/computer_use/__init__.py +0 -0
  19. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/computer_use/browser_computer.py +0 -0
  20. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/config.py +0 -0
  21. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/context_budget.py +0 -0
  22. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/context_warning.py +0 -0
  23. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/credentials.py +0 -0
  24. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/hitl_session.py +0 -0
  25. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/interactions.py +0 -0
  26. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/invoke.py +0 -0
  27. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/kairos_daemon.py +0 -0
  28. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/limits.py +0 -0
  29. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/live_audio_engine.py +0 -0
  30. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/logging_config.py +0 -0
  31. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/mcp_loader.py +0 -0
  32. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/memory/__init__.py +0 -0
  33. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/memory/embedding_memory_service.py +0 -0
  34. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/memory/file_memory_service.py +0 -0
  35. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/modality_tools.py +0 -0
  36. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/model_errors.py +0 -0
  37. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/model_routing.py +0 -0
  38. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/paths.py +0 -0
  39. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/permissions.py +0 -0
  40. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/plugins/__init__.py +0 -0
  41. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
  42. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
  43. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/prompt_suggestions.py +0 -0
  44. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/query/__init__.py +0 -0
  45. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/query/config.py +0 -0
  46. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/query/deps.py +0 -0
  47. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/query/engine.py +0 -0
  48. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/query/stop_hooks.py +0 -0
  49. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/query/token_budget.py +0 -0
  50. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/query/transitions.py +0 -0
  51. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/repl_commands.py +0 -0
  52. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/repl_slash.py +0 -0
  53. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/session_runtime.py +0 -0
  54. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/slash_commands.py +0 -0
  55. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/thinking.py +0 -0
  56. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tool_prompt_manifest.py +0 -0
  57. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tool_registry.py +0 -0
  58. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tools/__init__.py +0 -0
  59. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tools/bash.py +0 -0
  60. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tools/edit.py +0 -0
  61. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tools/filesystem.py +0 -0
  62. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tools/search.py +0 -0
  63. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tools/shell.py +0 -0
  64. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tools/shell_gate.py +0 -0
  65. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tools/subtask.py +0 -0
  66. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tools/think.py +0 -0
  67. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tools/todo.py +0 -0
  68. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tools/web.py +0 -0
  69. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tools_inspector.py +0 -0
  70. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/trust.py +0 -0
  71. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tui/input_handler.py +0 -0
  72. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tui/spinner.py +0 -0
  73. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tui/welcome_banner.py +0 -0
  74. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/tui/welcome_rich.py +0 -0
  75. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/version.py +0 -0
  76. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/vertex.py +0 -0
  77. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/web/__init__.py +0 -0
  78. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/web/claude_sse_adapter.py +0 -0
  79. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/web/terminal_repl.py +0 -0
  80. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode/workspace_hints.py +0 -0
  81. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode.egg-info/SOURCES.txt +0 -0
  82. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode.egg-info/dependency_links.txt +0 -0
  83. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode.egg-info/entry_points.txt +0 -0
  84. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode.egg-info/requires.txt +0 -0
  85. {gemcode-0.3.18 → gemcode-0.3.19}/src/gemcode.egg-info/top_level.txt +0 -0
  86. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_agent_instruction.py +0 -0
  87. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_autocompact.py +0 -0
  88. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_capability_routing.py +0 -0
  89. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_claude_web_adapter_sse.py +0 -0
  90. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_cli_init.py +0 -0
  91. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_computer_use_permissions.py +0 -0
  92. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_context_budget.py +0 -0
  93. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_context_warning.py +0 -0
  94. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_credentials.py +0 -0
  95. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_interactive_permission_ask.py +0 -0
  96. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_kairos_scheduler.py +0 -0
  97. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_modality_tools.py +0 -0
  98. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_model_error_retry.py +0 -0
  99. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_model_errors.py +0 -0
  100. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_model_routing.py +0 -0
  101. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_paths.py +0 -0
  102. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_permissions.py +0 -0
  103. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_prompt_suggestions.py +0 -0
  104. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_repl_commands.py +0 -0
  105. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_repl_slash.py +0 -0
  106. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_slash_commands.py +0 -0
  107. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_thinking_config.py +0 -0
  108. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_token_budget.py +0 -0
  109. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_tool_context_circulation.py +0 -0
  110. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_tools.py +0 -0
  111. {gemcode-0.3.18 → gemcode-0.3.19}/tests/test_tools_inspector.py +0 -0
  112. {gemcode-0.3.18 → gemcode-0.3.19}/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.18
3
+ Version: 0.3.19
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.18"
7
+ version = "0.3.19"
8
8
  description = "Local-first coding agent on Google Gemini + ADK"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -79,13 +79,26 @@ You run locally via the GemCode CLI. You are the same agent the user launched
79
79
 
80
80
  ## Core identity and approach
81
81
  You are a senior engineer who *acts*, not just advises. When given a task:
82
- 1. **Orient** — understand the repo structure, find the relevant files.
82
+ 1. **Orient** — use `list_directory`, `glob_files`, `grep_content`, `read_file` to understand structure. These tools need **no permission** and are instant. Start here.
83
83
  2. **Plan** — for complex tasks, call `todo_write` upfront to map out the work.
84
84
  3. **Execute** — make the changes, run the checks, iterate.
85
85
  4. **Verify** — confirm the result is correct before reporting done.
86
86
 
87
87
  Never stop mid-task just because the first tool call succeeded. Keep going until the full task is complete or you hit a genuine blocker.
88
88
 
89
+ ## CRITICAL: Read-only tools first — never bash for exploration
90
+ `bash` and `run_command` require permission confirmation by default. Always start with the **zero-permission** read-only tools:
91
+
92
+ | Instead of… | Use… |
93
+ |---|---|
94
+ | `bash("ls -la src/")` | `list_directory("src")` |
95
+ | `bash("find . -name '*.py'")` | `glob_files("**/*.py")` |
96
+ | `bash("cat file.py")` | `read_file("file.py")` |
97
+ | `bash("grep -r pattern .")` | `grep_content("pattern", "**/*")` |
98
+ | `bash("find . -type f \| head -50")` | `list_directory(".")` + `glob_files("**/*")` |
99
+
100
+ Only reach for `bash` or `run_command` when you actually need to **execute** something: run tests, build, git ops, start a server, install packages. **NEVER** use bash to list or read files.
101
+
89
102
  ## Thinking through hard problems
90
103
  You have native deep thinking capability — use it actively:
91
104
  - **Before** starting a complex refactor or architectural change, think: what are the dependencies? what could break? what is the minimal safe change?
@@ -94,11 +107,12 @@ You have native deep thinking capability — use it actively:
94
107
  - **For trade-off decisions** (which library, which pattern, which approach): reason through the pros/cons given this specific codebase.
95
108
 
96
109
  ## Interpreting requests
97
- - Treat every message as a software engineering task unless clearly otherwise.
110
+ - Treat every message as a software engineering task start working immediately. Do NOT respond with just a greeting or introduction.
98
111
  - If vague ("fix it", "the config", "rename that"), **infer from the repo**: search, read, then act. Do not give abstract advice when concrete files exist.
99
- - If the user refers to symbols or behaviors, **find them** with glob/grep/list — never ask them to paste paths you can discover yourself.
112
+ - If the user refers to symbols or behaviors, **find them** with `glob_files`/`grep_content`/`list_directory` — never ask them to paste paths you can discover yourself.
100
113
  - **Never propose edits to files you haven't read.** Read first, then edit.
101
114
  - When something fails, diagnose (re-read the error, check assumptions) before switching strategy. Do not repeat the same failed call.
115
+ - For analysis tasks ("analyse X", "explain X", "what does X do"): immediately start reading files with `list_directory` + `read_file` + `grep_content`. Produce concrete findings, not hypotheses.
102
116
 
103
117
  ## Tool selection guide
104
118
 
@@ -174,12 +188,11 @@ One user message = many model↔tool rounds (up to 256 LLM calls by default). Th
174
188
 
175
189
  **Standard workflow for complex tasks:**
176
190
  1. `todo_write` — plan the work items
177
- 2. Explore — `bash("find . ...")` or `list_directory` or `glob_files` to understand structure
178
- 3. Read — `read_file` with line ranges on large files; `grep_content` for symbol search
179
- 4. Edit — `write_file` / `search_replace` for changes
180
- 5. Verify`bash("pytest ...")` or `bash("npm run build ...")` or `bash("git diff")`
181
- 6. Fixiterate on failures, re-verify
182
- 7. Update todos — mark done as you go
191
+ 2. **Explore (read-only, no permission needed)** `list_directory` + `glob_files` to map structure; `grep_content` to find symbols; `read_file` to understand code. Do NOT use `bash` for this step.
192
+ 3. **Edit** — `write_file` / `search_replace` for changes
193
+ 4. **Verify (shell needed)** — `bash("pytest ...")` or `bash("npm run build ...")` or `bash("git diff")`
194
+ 5. Fixiterate on failures, re-verify
195
+ 6. Update todos mark done as you go
183
196
 
184
197
  **Do not stop after step 2 or 3** — complete the full task.
185
198
 
@@ -236,7 +236,76 @@ async def run_gemcode_scrollback_tui(
236
236
  pass
237
237
  return tool_name, hint
238
238
 
239
+ # ── Live status indicator ─────────────────────────────────────────────────
240
+ # spinner_active[0] = True while "⟳ Working..." is on the current line.
241
+ # _clear_spinner() uses \r + ANSI erase to overwrite it before real output.
242
+ spinner_active = [False]
243
+
244
+ def _clear_spinner() -> None:
245
+ if spinner_active[0]:
246
+ sys.stdout.write("\r\033[K")
247
+ sys.stdout.flush()
248
+ spinner_active[0] = False
249
+
250
+ def _fmt_tool_result(resp: object) -> str:
251
+ """One-line summary of a tool execution result."""
252
+ try:
253
+ d = resp if isinstance(resp, dict) else {}
254
+ # ADK may wrap the return value; try both the raw dict and a nested "result" key.
255
+ inner = d.get("result", d)
256
+ if not isinstance(inner, dict):
257
+ inner = d
258
+ err = inner.get("error") or d.get("error")
259
+ if err:
260
+ return f"\u2717 {str(err)[:80]}"
261
+ exit_code = inner.get("exit_code")
262
+ if exit_code is not None:
263
+ icon = "\u2713" if exit_code == 0 else f"\u2717 exit {exit_code}"
264
+ out = str(inner.get("stdout", "") or "").strip()
265
+ first = out.split("\n")[0][:80] if out else ""
266
+ if not first:
267
+ first = str(inner.get("stderr", "") or "").strip().split("\n")[0][:80]
268
+ return f"{icon} {first}" if first else icon
269
+ if inner.get("content") is not None:
270
+ lines = str(inner["content"]).count("\n") + 1
271
+ return f"\u2713 {lines} lines"
272
+ if inner.get("files") is not None:
273
+ return f"\u2713 {len(inner['files'])} files"
274
+ if inner.get("matches") is not None:
275
+ return f"\u2713 {len(inner['matches'])} matches"
276
+ if inner.get("ok") or d.get("ok"):
277
+ return "\u2713"
278
+ return ""
279
+ except Exception:
280
+ return ""
281
+
282
+ def _render_tool_results(ev) -> None:
283
+ """Print a brief one-line summary when a tool finishes executing."""
284
+ try:
285
+ frs: list = []
286
+ try:
287
+ frs = ev.get_function_responses() or []
288
+ except Exception:
289
+ pass
290
+ if not frs and ev.content and ev.content.parts:
291
+ for part in ev.content.parts:
292
+ fr = getattr(part, "function_response", None)
293
+ if fr is not None:
294
+ frs.append(fr)
295
+ for fr in frs:
296
+ name = getattr(fr, "name", "") or ""
297
+ if name == _ADK_REQUEST_CONFIRMATION:
298
+ continue
299
+ _clear_spinner()
300
+ resp = getattr(fr, "response", {}) or {}
301
+ summary = _fmt_tool_result(resp)
302
+ if summary:
303
+ print(f" ⎿ {ansi.dim}\u21b3 {summary}{ansi.reset}")
304
+ except Exception:
305
+ pass
306
+
239
307
  def _render_tool_calls(ev) -> None:
308
+ _clear_spinner()
240
309
  try:
241
310
  fcs = ev.get_function_calls() or []
242
311
  except Exception:
@@ -331,9 +400,18 @@ async def run_gemcode_scrollback_tui(
331
400
  kwargs["run_config"] = run_config
332
401
  # (We don't handle token budget reset here; full-screen TUI does.)
333
402
 
403
+ # Show a live "Working…" indicator so the user never wonders if the
404
+ # agent froze. _clear_spinner() overwrites it with \r+ANSI-erase
405
+ # before the first real output (tool call, tool result, or response).
406
+ if ansi.enabled:
407
+ spinner_active[0] = True
408
+ sys.stdout.write(f" {ansi.dim}\u27f3 Working\u2026{ansi.reset}")
409
+ sys.stdout.flush()
410
+
334
411
  async for ev in runner.run_async(**kwargs):
335
412
  events.append(ev)
336
413
  _render_tool_calls(ev)
414
+ _render_tool_results(ev)
337
415
  try:
338
416
  if not ev.content or not ev.content.parts:
339
417
  continue
@@ -351,6 +429,8 @@ async def run_gemcode_scrollback_tui(
351
429
  except Exception:
352
430
  continue
353
431
 
432
+ _clear_spinner() # ensure "Working…" is gone before any response line
433
+
354
434
  if not assistant_wrote_text and _events_had_non_confirmation_tools(events):
355
435
  await typewrite(
356
436
  f"{ansi.dim}(Tools ran without a text reply in this step; "
@@ -377,15 +457,6 @@ async def run_gemcode_scrollback_tui(
377
457
  await typewrite(thought_text)
378
458
  sys.stdout.write("\n")
379
459
  sys.stdout.flush()
380
- else:
381
- # Keep thinking visible even if the model produced no separate
382
- # "thought" channel output.
383
- print(
384
- f" ⎿ {ansi.dim}{ansi.bold}\u2234 Thinking{ansi.reset}: "
385
- "(no thinking output)"
386
- )
387
- print("")
388
-
389
460
  if buffered_final:
390
461
  sys.stdout.write(f" ⎿ {ansi.bold}GemCode{ansi.reset}: ")
391
462
  sys.stdout.flush()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemcode
3
- Version: 0.3.18
3
+ Version: 0.3.19
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