gemcode 0.3.109__tar.gz → 0.3.110__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 (164) hide show
  1. {gemcode-0.3.109/src/gemcode.egg-info → gemcode-0.3.110}/PKG-INFO +1 -1
  2. {gemcode-0.3.109 → gemcode-0.3.110}/pyproject.toml +1 -1
  3. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/kaira_daemon.py +55 -5
  4. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/session_runtime.py +3 -0
  5. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tui/scrollback.py +56 -0
  6. {gemcode-0.3.109 → gemcode-0.3.110/src/gemcode.egg-info}/PKG-INFO +1 -1
  7. {gemcode-0.3.109 → gemcode-0.3.110}/LICENSE +0 -0
  8. {gemcode-0.3.109 → gemcode-0.3.110}/MANIFEST.in +0 -0
  9. {gemcode-0.3.109 → gemcode-0.3.110}/README.md +0 -0
  10. {gemcode-0.3.109 → gemcode-0.3.110}/setup.cfg +0 -0
  11. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/__init__.py +0 -0
  12. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/__main__.py +0 -0
  13. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/agent.py +0 -0
  14. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/audit.py +0 -0
  15. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/autocompact.py +0 -0
  16. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/autotune.py +0 -0
  17. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/callbacks.py +0 -0
  18. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/capability_routing.py +0 -0
  19. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/checkpoints.py +0 -0
  20. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/cli.py +0 -0
  21. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/compaction.py +0 -0
  22. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/computer_use/__init__.py +0 -0
  23. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/computer_use/browser_computer.py +0 -0
  24. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/config.py +0 -0
  25. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/context_budget.py +0 -0
  26. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/context_warning.py +0 -0
  27. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/credentials.py +0 -0
  28. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/curated_memory.py +0 -0
  29. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/dynamic_policy.py +0 -0
  30. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/evals/harness.py +0 -0
  31. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/hitl_session.py +0 -0
  32. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/hooks.py +0 -0
  33. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/ide_protocol.py +0 -0
  34. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/ide_stdio.py +0 -0
  35. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/intent_classifier.py +0 -0
  36. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/interactions.py +0 -0
  37. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/invoke.py +0 -0
  38. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/kaira_client.py +0 -0
  39. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/kaira_ipc.py +0 -0
  40. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/kaira_job_store.py +0 -0
  41. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/learning.py +0 -0
  42. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/limits.py +0 -0
  43. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/live_audio_engine.py +0 -0
  44. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/logging_config.py +0 -0
  45. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/mcp_loader.py +0 -0
  46. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/memory/__init__.py +0 -0
  47. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/memory/embedding_memory_service.py +0 -0
  48. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/memory/file_memory_service.py +0 -0
  49. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/modality_tools.py +0 -0
  50. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/model_errors.py +0 -0
  51. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/model_routing.py +0 -0
  52. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/multimodal_input.py +0 -0
  53. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/openapi_loader.py +0 -0
  54. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/org.py +0 -0
  55. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/output_styles.py +0 -0
  56. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/paths.py +0 -0
  57. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/permissions.py +0 -0
  58. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/plugins/__init__.py +0 -0
  59. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
  60. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
  61. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/policy_profile.py +0 -0
  62. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/pricing.py +0 -0
  63. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/prompt_suggestions.py +0 -0
  64. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/__init__.py +0 -0
  65. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/config.py +0 -0
  66. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/deps.py +0 -0
  67. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/engine.py +0 -0
  68. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/stop_hooks.py +0 -0
  69. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/token_budget.py +0 -0
  70. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/transitions.py +0 -0
  71. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query_sanitizer.py +0 -0
  72. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/refine.py +0 -0
  73. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/repl_commands.py +0 -0
  74. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/repl_slash.py +0 -0
  75. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/review_agent.py +0 -0
  76. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/rules.py +0 -0
  77. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/session_store.py +0 -0
  78. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/session_summariser.py +0 -0
  79. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/skills.py +0 -0
  80. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/slash_commands.py +0 -0
  81. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/thinking.py +0 -0
  82. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tool_prompt_manifest.py +0 -0
  83. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tool_registry.py +0 -0
  84. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tool_result_store.py +0 -0
  85. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/__init__.py +0 -0
  86. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/bash.py +0 -0
  87. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/browser.py +0 -0
  88. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/compress_memory.py +0 -0
  89. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/curated_memory.py +0 -0
  90. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/edit.py +0 -0
  91. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/filesystem.py +0 -0
  92. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/notebook.py +0 -0
  93. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/notes.py +0 -0
  94. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/org_tools.py +0 -0
  95. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/repo_map.py +0 -0
  96. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/search.py +0 -0
  97. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/shell.py +0 -0
  98. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/shell_gate.py +0 -0
  99. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/skills.py +0 -0
  100. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/subtask.py +0 -0
  101. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/tasks.py +0 -0
  102. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/think.py +0 -0
  103. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/todo.py +0 -0
  104. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/user_choice.py +0 -0
  105. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/veomem_tools.py +0 -0
  106. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/web.py +0 -0
  107. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/web_search.py +0 -0
  108. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools_inspector.py +0 -0
  109. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/trust.py +0 -0
  110. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tui/input_handler.py +0 -0
  111. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tui/spinner.py +0 -0
  112. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tui/welcome_banner.py +0 -0
  113. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tui/welcome_rich.py +0 -0
  114. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/veomem_bridge.py +0 -0
  115. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/version.py +0 -0
  116. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/vertex.py +0 -0
  117. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/wal.py +0 -0
  118. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/web/__init__.py +0 -0
  119. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/web/sse_adapter.py +0 -0
  120. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/web/terminal_repl.py +0 -0
  121. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/web/web_sse_compat.py +0 -0
  122. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/workspace_hints.py +0 -0
  123. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode.egg-info/SOURCES.txt +0 -0
  124. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode.egg-info/dependency_links.txt +0 -0
  125. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode.egg-info/entry_points.txt +0 -0
  126. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode.egg-info/requires.txt +0 -0
  127. {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode.egg-info/top_level.txt +0 -0
  128. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_add_dir.py +0 -0
  129. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_agent_instruction.py +0 -0
  130. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_autocompact.py +0 -0
  131. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_capability_routing.py +0 -0
  132. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_checkpoint_diff_command.py +0 -0
  133. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_cli_init.py +0 -0
  134. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_compress_memory_tool.py +0 -0
  135. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_computer_use_permissions.py +0 -0
  136. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_context_budget.py +0 -0
  137. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_context_warning.py +0 -0
  138. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_credentials.py +0 -0
  139. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_eval_harness_layout.py +0 -0
  140. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_ide_stdio_attachments.py +0 -0
  141. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_interactive_permission_ask.py +0 -0
  142. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_kaira_scheduler.py +0 -0
  143. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_modality_tools.py +0 -0
  144. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_model_error_retry.py +0 -0
  145. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_model_errors.py +0 -0
  146. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_model_routing.py +0 -0
  147. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_multimodal_input.py +0 -0
  148. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_output_styles_and_rules.py +0 -0
  149. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_paths.py +0 -0
  150. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_permissions.py +0 -0
  151. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_prompt_suggestions.py +0 -0
  152. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_repl_commands.py +0 -0
  153. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_repl_slash.py +0 -0
  154. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_session_runtime_cache.py +0 -0
  155. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_skills.py +0 -0
  156. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_slash_commands.py +0 -0
  157. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_slash_completion_registry.py +0 -0
  158. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_thinking_config.py +0 -0
  159. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_token_budget.py +0 -0
  160. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_tool_context_circulation.py +0 -0
  161. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_tools.py +0 -0
  162. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_tools_inspector.py +0 -0
  163. {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_web_sse_adapter.py +0 -0
  164. {gemcode-0.3.109 → gemcode-0.3.110}/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.109
3
+ Version: 0.3.110
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.109"
7
+ version = "0.3.110"
8
8
  description = "Local-first coding agent on Google Gemini + ADK"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -94,6 +94,22 @@ def _fmt_tool_result(resp: object) -> str:
94
94
  return ""
95
95
 
96
96
 
97
+ def _should_stream_to_terminal() -> bool:
98
+ """Stream live job output to the local terminal when interactive."""
99
+ try:
100
+ return bool(hasattr(sys.stdin, "isatty") and sys.stdin.isatty())
101
+ except Exception:
102
+ return False
103
+
104
+
105
+ def _stream_print(s: str) -> None:
106
+ try:
107
+ sys.stdout.write(s)
108
+ sys.stdout.flush()
109
+ except Exception:
110
+ pass
111
+
112
+
97
113
  async def _broadcast_text_delta(
98
114
  *,
99
115
  ipc: KairaIpcServer,
@@ -402,6 +418,9 @@ class KairaDaemon:
402
418
  async def _stream_one_message(*, current_message: types.Content) -> tuple[list, str]:
403
419
  emitted_text = ""
404
420
  events: list = []
421
+ stream_live = _should_stream_to_terminal()
422
+ if stream_live:
423
+ _stream_print(f"\n[kaira {job.job_id}] started\n")
405
424
  async for ev in runner.run_async(
406
425
  user_id=self.user_id,
407
426
  session_id=job.session_id,
@@ -409,6 +428,28 @@ class KairaDaemon:
409
428
  **({"run_config": run_config} if run_config is not None else {}),
410
429
  ):
411
430
  events.append(ev)
431
+ # Live terminal streaming (independent of IPC).
432
+ if stream_live:
433
+ try:
434
+ from gemcode.web.sse_adapter import extract_text_from_event
435
+
436
+ txt_live = extract_text_from_event(ev)
437
+ if txt_live:
438
+ if txt_live.startswith(emitted_text):
439
+ delta_live = txt_live[len(emitted_text) :]
440
+ else:
441
+ # Fallback: find common prefix.
442
+ common = 0
443
+ max_common = min(len(txt_live), len(emitted_text))
444
+ while common < max_common and txt_live[common] == emitted_text[common]:
445
+ common += 1
446
+ delta_live = txt_live[common:]
447
+ if delta_live:
448
+ _stream_print(delta_live)
449
+ emitted_text = txt_live
450
+ except Exception:
451
+ pass
452
+
412
453
  if self._ipc is None:
413
454
  continue
414
455
 
@@ -460,7 +501,7 @@ class KairaDaemon:
460
501
  except Exception:
461
502
  pass
462
503
 
463
- # Text deltas
504
+ # Text deltas (IPC subscribers)
464
505
  try:
465
506
  from gemcode.web.sse_adapter import extract_text_from_event
466
507
 
@@ -602,8 +643,12 @@ class KairaDaemon:
602
643
  session_id=session_id,
603
644
  )
604
645
 
605
- async def run_forever(self, *, session_id: str) -> None:
606
- """Start the scheduler and keep running until stdin EOF/quit."""
646
+ async def run_forever(self, *, session_id: str, enable_stdin: bool = True) -> None:
647
+ """Start the scheduler and keep running until stopped.
648
+
649
+ When enable_stdin=False, Kaira runs headless (IPC-only) and does not read
650
+ from stdin. This mode is used when embedding Kaira inside the GemCode TUI.
651
+ """
607
652
 
608
653
  # Start IPC server for two-way control + event streaming.
609
654
  try:
@@ -623,11 +668,16 @@ class KairaDaemon:
623
668
  print(f"[kaira] ipc disabled: {e}", file=sys.stderr, flush=True)
624
669
 
625
670
  scheduler_task = asyncio.create_task(self._scheduler_loop())
626
- stdin_task = asyncio.create_task(self._stdin_loop(session_id=session_id))
671
+ stdin_task = None
672
+ if enable_stdin:
673
+ stdin_task = asyncio.create_task(self._stdin_loop(session_id=session_id))
627
674
 
628
675
  # Wait for either scheduler to stop (shouldn't happen) or stdin loop to end.
676
+ wait_set = {scheduler_task}
677
+ if stdin_task is not None:
678
+ wait_set.add(stdin_task)
629
679
  done, pending = await asyncio.wait(
630
- {scheduler_task, stdin_task},
680
+ wait_set,
631
681
  return_when=asyncio.FIRST_COMPLETED,
632
682
  )
633
683
  for p in pending:
@@ -474,9 +474,12 @@ def create_runner(cfg: GemCodeConfig, extra_tools: list | None = None) -> Runner
474
474
  import sys
475
475
 
476
476
  prompt_afc = os.environ.get("GEMCODE_AFC_PROMPT", "1").strip().lower() in ("1", "true", "yes", "on")
477
+ afc_default = (os.environ.get("GEMCODE_AFC_DEFAULT") or "").strip().lower()
477
478
  if prompt_afc and hasattr(sys.stdin, "isatty") and sys.stdin.isatty():
478
479
  tools_list = list(merged_extra_tools or [])
479
480
  noncallable = [t for t in tools_list if not callable(t)]
481
+ if noncallable and getattr(cfg, "_afc_choice", None) not in ("all", "callables") and afc_default in ("all", "callables"):
482
+ object.__setattr__(cfg, "_afc_choice", afc_default)
480
483
  if noncallable and getattr(cfg, "_afc_choice", None) not in ("all", "callables"):
481
484
  print(
482
485
  "\n[gemcode] AFC compatibility\n"
@@ -279,6 +279,50 @@ async def run_gemcode_scrollback_tui(
279
279
  get_cfg=lambda: cfg,
280
280
  )
281
281
 
282
+ # ── Optional: embed Kaira daemon in this TUI ─────────────────────────────
283
+ # This enables continuous background automation without requiring a second
284
+ # terminal. The TUI will also auto-subscribe to IPC events (below) so job
285
+ # output appears inline.
286
+ _embedded_kaira_task: list = [None] # asyncio.Task | None
287
+
288
+ def _embed_kaira_enabled() -> bool:
289
+ return os.environ.get("GEMCODE_TUI_WITH_KAIRA", "0").strip().lower() in (
290
+ "1",
291
+ "true",
292
+ "yes",
293
+ "on",
294
+ )
295
+
296
+ async def _start_embedded_kaira() -> None:
297
+ if not _embed_kaira_enabled():
298
+ return
299
+ # Avoid starting if a socket already exists (external daemon running).
300
+ sock = os.environ.get("GEMCODE_KAIRA_SOCKET") or str(cfg.project_root / _KAIRA_SOCKET_DEFAULT)
301
+ try:
302
+ from pathlib import Path as _Path
303
+
304
+ if _Path(sock).exists():
305
+ return
306
+ except Exception:
307
+ pass
308
+ try:
309
+ from gemcode.kaira_daemon import KairaDaemon
310
+
311
+ # Use this TUI's session id as the default session for stdin-less jobs.
312
+ daemon = KairaDaemon(cfg=cfg, concurrency=2, default_priority=0)
313
+ # Run headless: IPC-only. Jobs are enqueued via IPC (monitor scripts, org tools, etc.).
314
+ await daemon.run_forever(session_id=session_id, enable_stdin=False)
315
+ except asyncio.CancelledError:
316
+ return
317
+ except Exception:
318
+ return
319
+
320
+ try:
321
+ if _embed_kaira_enabled():
322
+ _embedded_kaira_task[0] = asyncio.create_task(_start_embedded_kaira())
323
+ except Exception:
324
+ _embedded_kaira_task[0] = None
325
+
282
326
  # ── Kaira auto-connect (IPC subscribe) ───────────────────────────────────
283
327
  # If a Kaira daemon is running for this project, subscribe to its updates and
284
328
  # surface them in the same terminal UI. Also handle permission requests by
@@ -765,6 +809,12 @@ async def run_gemcode_scrollback_tui(
765
809
  t.cancel()
766
810
  except Exception:
767
811
  pass
812
+ try:
813
+ t2 = _embedded_kaira_task[0]
814
+ if t2 is not None:
815
+ t2.cancel()
816
+ except Exception:
817
+ pass
768
818
  try:
769
819
  from gemcode.hooks import run_session_stop_hook
770
820
  run_session_stop_hook(cfg.project_root, model=getattr(cfg, "model", "") or "")
@@ -781,6 +831,12 @@ async def run_gemcode_scrollback_tui(
781
831
  t.cancel()
782
832
  except Exception:
783
833
  pass
834
+ try:
835
+ t2 = _embedded_kaira_task[0]
836
+ if t2 is not None:
837
+ t2.cancel()
838
+ except Exception:
839
+ pass
784
840
  from gemcode.hooks import run_session_stop_hook
785
841
  run_session_stop_hook(cfg.project_root, model=getattr(cfg, "model", "") or "")
786
842
  except Exception:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemcode
3
- Version: 0.3.109
3
+ Version: 0.3.110
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