deepagents-code 0.1.12__tar.gz → 0.1.13__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 (277) hide show
  1. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/AGENTS.md +9 -1
  2. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/CHANGELOG.md +23 -0
  3. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/PKG-INFO +1 -1
  4. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/THREAT_MODEL.md +7 -0
  5. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/_debug.py +29 -9
  6. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/_env_vars.py +37 -7
  7. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/_server_config.py +3 -1
  8. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/_textual_patches.py +134 -1
  9. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/_version.py +1 -1
  10. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/agent.py +92 -22
  11. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/app.py +477 -51
  12. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/config.py +298 -111
  13. deepagents_code-0.1.13/deepagents_code/config_commands.py +487 -0
  14. deepagents_code-0.1.13/deepagents_code/config_manifest.py +1055 -0
  15. deepagents_code-0.1.13/deepagents_code/integrations/sandbox_config.py +198 -0
  16. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/integrations/sandbox_factory.py +74 -71
  17. deepagents_code-0.1.13/deepagents_code/integrations/sandbox_provider.py +137 -0
  18. deepagents_code-0.1.13/deepagents_code/integrations/sandbox_registry.py +341 -0
  19. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/local_context.py +85 -1
  20. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/main.py +240 -21
  21. deepagents_code-0.1.13/deepagents_code/managed_tools.py +470 -0
  22. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/model_config.py +34 -0
  23. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/server.py +25 -1
  24. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/ui.py +60 -1
  25. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/ask_user.py +5 -2
  26. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/chat_input.py +141 -5
  27. deepagents_code-0.1.13/deepagents_code/widgets/install_confirm.py +120 -0
  28. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/status.py +110 -1
  29. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/theme_selector.py +60 -6
  30. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/welcome.py +24 -175
  31. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/pyproject.toml +1 -1
  32. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_agent.py +223 -9
  33. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_app.py +1082 -59
  34. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_args.py +73 -1
  35. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_charset.py +17 -0
  36. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_chat_input.py +210 -0
  37. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_config.py +428 -0
  38. deepagents_code-0.1.13/tests/unit_tests/test_config_manifest.py +999 -0
  39. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_debug.py +72 -1
  40. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_install_command.py +127 -4
  41. deepagents_code-0.1.13/tests/unit_tests/test_install_confirm.py +88 -0
  42. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_local_context.py +179 -0
  43. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_main.py +117 -0
  44. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_main_args.py +347 -0
  45. deepagents_code-0.1.13/tests/unit_tests/test_managed_tools.py +690 -0
  46. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_model_config.py +23 -0
  47. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_reload.py +11 -1
  48. deepagents_code-0.1.13/tests/unit_tests/test_sandbox_config.py +140 -0
  49. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_sandbox_factory.py +86 -1
  50. deepagents_code-0.1.13/tests/unit_tests/test_sandbox_provider.py +50 -0
  51. deepagents_code-0.1.13/tests/unit_tests/test_sandbox_registry.py +305 -0
  52. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_server_helpers.py +67 -9
  53. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_startup_fast_paths.py +2 -0
  54. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_status.py +207 -5
  55. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_textual_patches.py +115 -0
  56. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_theme.py +455 -0
  57. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_ui.py +34 -1
  58. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_welcome.py +47 -143
  59. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/uv.lock +1 -1
  60. deepagents_code-0.1.12/deepagents_code/integrations/sandbox_provider.py +0 -71
  61. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/.gitignore +0 -0
  62. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/COMMANDS.md +0 -0
  63. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/DEV.md +0 -0
  64. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/Makefile +0 -0
  65. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/README.md +0 -0
  66. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/__init__.py +0 -0
  67. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/__main__.py +0 -0
  68. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/_ask_user_types.py +0 -0
  69. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/_cli_context.py +0 -0
  70. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/_constants.py +0 -0
  71. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/_git.py +0 -0
  72. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/_session_stats.py +0 -0
  73. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/_startup_error.py +0 -0
  74. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/_testing_models.py +0 -0
  75. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/app.tcss +0 -0
  76. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/ask_user.py +0 -0
  77. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/auth_display.py +0 -0
  78. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/auth_store.py +0 -0
  79. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/built_in_skills/__init__.py +0 -0
  80. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/built_in_skills/remember/SKILL.md +0 -0
  81. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/built_in_skills/skill-creator/SKILL.md +0 -0
  82. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
  83. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
  84. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/clipboard.py +0 -0
  85. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/command_registry.py +0 -0
  86. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/configurable_model.py +0 -0
  87. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/default_agent_prompt.md +0 -0
  88. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/editor.py +0 -0
  89. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/event_bus.py +0 -0
  90. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/extras_info.py +0 -0
  91. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/file_ops.py +0 -0
  92. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/filesystem_empty_result.py +0 -0
  93. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/formatting.py +0 -0
  94. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/hooks.py +0 -0
  95. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/input.py +0 -0
  96. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/integrations/__init__.py +0 -0
  97. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/iterm_cursor_guide.py +0 -0
  98. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/mcp_auth.py +0 -0
  99. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/mcp_commands.py +0 -0
  100. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/mcp_disabled.py +0 -0
  101. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/mcp_login_service.py +0 -0
  102. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/mcp_oauth_ui.py +0 -0
  103. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/mcp_providers/__init__.py +0 -0
  104. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/mcp_providers/_registry.py +0 -0
  105. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/mcp_providers/base.py +0 -0
  106. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/mcp_providers/github.py +0 -0
  107. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/mcp_providers/slack.py +0 -0
  108. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/mcp_tools.py +0 -0
  109. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/mcp_trust.py +0 -0
  110. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/media_utils.py +0 -0
  111. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/memory_guard.py +0 -0
  112. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/non_interactive.py +0 -0
  113. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/notifications.py +0 -0
  114. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/offload.py +0 -0
  115. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/onboarding.py +0 -0
  116. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/output.py +0 -0
  117. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/project_utils.py +0 -0
  118. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/py.typed +0 -0
  119. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/remote_client.py +0 -0
  120. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/resume_state.py +0 -0
  121. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/server_graph.py +0 -0
  122. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/server_manager.py +0 -0
  123. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/sessions.py +0 -0
  124. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/skills/__init__.py +0 -0
  125. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/skills/commands.py +0 -0
  126. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/skills/invocation.py +0 -0
  127. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/skills/load.py +0 -0
  128. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/state_migration.py +0 -0
  129. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/subagents.py +0 -0
  130. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/system_prompt.md +0 -0
  131. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/terminal_capabilities.py +0 -0
  132. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/terminal_escape.py +0 -0
  133. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/textual_adapter.py +0 -0
  134. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/theme.py +0 -0
  135. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/tool_display.py +0 -0
  136. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/tools.py +0 -0
  137. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/unicode_security.py +0 -0
  138. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/update_check.py +0 -0
  139. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/__init__.py +0 -0
  140. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/_links.py +0 -0
  141. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/agent_selector.py +0 -0
  142. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/approval.py +0 -0
  143. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/auth.py +0 -0
  144. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/autocomplete.py +0 -0
  145. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/cwd_switch.py +0 -0
  146. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/diff.py +0 -0
  147. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/history.py +0 -0
  148. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/launch_init.py +0 -0
  149. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/loading.py +0 -0
  150. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/mcp_login.py +0 -0
  151. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/mcp_reconnect.py +0 -0
  152. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/mcp_viewer.py +0 -0
  153. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/message_store.py +0 -0
  154. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/messages.py +0 -0
  155. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/model_selector.py +0 -0
  156. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/notification_center.py +0 -0
  157. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/notification_detail.py +0 -0
  158. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/notification_settings.py +0 -0
  159. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/restart_prompt.py +0 -0
  160. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/thread_selector.py +0 -0
  161. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/tool_renderers.py +0 -0
  162. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/tool_widgets.py +0 -0
  163. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/update_available.py +0 -0
  164. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/deepagents_code/widgets/update_progress.py +0 -0
  165. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/examples/skills/arxiv-search/SKILL.md +0 -0
  166. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/examples/skills/arxiv-search/arxiv_search.py +0 -0
  167. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/examples/skills/langgraph-docs/SKILL.md +0 -0
  168. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/examples/skills/skill-creator/SKILL.md +0 -0
  169. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
  170. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
  171. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/examples/skills/web-research/SKILL.md +0 -0
  172. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/images/tui.png +0 -0
  173. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/scripts/check_imports.py +0 -0
  174. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/scripts/debug_server.sh +0 -0
  175. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/scripts/generate_commands_catalog.py +0 -0
  176. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/scripts/install.sh +0 -0
  177. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/README.md +0 -0
  178. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/integration_tests/__init__.py +0 -0
  179. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/integration_tests/benchmarks/__init__.py +0 -0
  180. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
  181. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
  182. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/integration_tests/conftest.py +0 -0
  183. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/integration_tests/test_acp_mode.py +0 -0
  184. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/integration_tests/test_compact_resume.py +0 -0
  185. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/integration_tests/test_sandbox_factory.py +0 -0
  186. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/integration_tests/test_sandbox_operations.py +0 -0
  187. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/__init__.py +0 -0
  188. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/conftest.py +0 -0
  189. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/skills/__init__.py +0 -0
  190. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/skills/test_commands.py +0 -0
  191. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/skills/test_load.py +0 -0
  192. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/skills/test_skills_json.py +0 -0
  193. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_agent_friendly.py +0 -0
  194. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_agent_selector.py +0 -0
  195. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_approval.py +0 -0
  196. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_ask_user.py +0 -0
  197. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_ask_user_middleware.py +0 -0
  198. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_auth_display.py +0 -0
  199. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_auth_store.py +0 -0
  200. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_auth_widgets.py +0 -0
  201. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_autocomplete.py +0 -0
  202. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_clipboard.py +0 -0
  203. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_command_registry.py +0 -0
  204. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_compact_tool.py +0 -0
  205. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_configurable_model.py +0 -0
  206. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_cursor_blink.py +0 -0
  207. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_cwd_switch.py +0 -0
  208. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_editor.py +0 -0
  209. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_end_to_end.py +0 -0
  210. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_env_vars.py +0 -0
  211. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_event_bus.py +0 -0
  212. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_exception_handling.py +0 -0
  213. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_extras_info.py +0 -0
  214. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_file_ops.py +0 -0
  215. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_filesystem_empty_result.py +0 -0
  216. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_formatting.py +0 -0
  217. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_git.py +0 -0
  218. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_history.py +0 -0
  219. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_hooks.py +0 -0
  220. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_imports.py +0 -0
  221. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_input_parsing.py +0 -0
  222. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_iterm_cursor_guide.py +0 -0
  223. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_launch_init.py +0 -0
  224. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_links.py +0 -0
  225. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_loading.py +0 -0
  226. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_main_acp_mode.py +0 -0
  227. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_mcp_auth.py +0 -0
  228. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_mcp_commands.py +0 -0
  229. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_mcp_disabled.py +0 -0
  230. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_mcp_login_modal.py +0 -0
  231. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_mcp_login_service.py +0 -0
  232. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_mcp_oauth_ui.py +0 -0
  233. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_mcp_reconnect.py +0 -0
  234. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_mcp_tools.py +0 -0
  235. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_mcp_trust.py +0 -0
  236. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_mcp_viewer.py +0 -0
  237. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_media_utils.py +0 -0
  238. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_memory_guard.py +0 -0
  239. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_message_store.py +0 -0
  240. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_messages.py +0 -0
  241. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_model_selector.py +0 -0
  242. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_model_switch.py +0 -0
  243. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_non_interactive.py +0 -0
  244. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_notification_center.py +0 -0
  245. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_notification_detail.py +0 -0
  246. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_notifications.py +0 -0
  247. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_offload.py +0 -0
  248. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_offload_dict_messages.py +0 -0
  249. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_onboarding.py +0 -0
  250. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_output.py +0 -0
  251. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_remote_client.py +0 -0
  252. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_restart_prompt.py +0 -0
  253. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_resume_state.py +0 -0
  254. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_server.py +0 -0
  255. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_server_config.py +0 -0
  256. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_server_graph.py +0 -0
  257. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_server_manager.py +0 -0
  258. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_session_stats.py +0 -0
  259. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_sessions.py +0 -0
  260. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_shell_allow_list.py +0 -0
  261. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_skill_invocation.py +0 -0
  262. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_state_migration.py +0 -0
  263. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_subagents.py +0 -0
  264. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_terminal_capabilities.py +0 -0
  265. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_terminal_escape.py +0 -0
  266. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_terminal_progress_preference.py +0 -0
  267. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_textual_adapter.py +0 -0
  268. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_thread_selector.py +0 -0
  269. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_tool_display.py +0 -0
  270. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_unicode_security.py +0 -0
  271. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_update_available.py +0 -0
  272. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_update_check.py +0 -0
  273. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_update_progress.py +0 -0
  274. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/test_version.py +0 -0
  275. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/tools/__init__.py +0 -0
  276. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/tools/test_current_thread.py +0 -0
  277. {deepagents_code-0.1.12 → deepagents_code-0.1.13}/tests/unit_tests/tools/test_fetch_url.py +0 -0
@@ -38,6 +38,13 @@ Textual's `App.notify(message)` parses the message string as Rich markup by defa
38
38
 
39
39
  `console.print()` defaults to `highlight=True`, which runs `ReprHighlighter` and auto-applies bold + cyan to any detected numbers. This visually overrides subtle styles like `dim` (bold cancels dim in most terminals). Pass `highlight=False` on any `console.print()` call where the content contains numbers and consistent dim/subtle styling matters.
40
40
 
41
+ ### Glyphs and spinners — reuse, don't redefine
42
+
43
+ Charset-dependent characters and animations have **single sources of truth**. Reuse them instead of hand-rolling new ones — copies drift, and (more subtly) a hardcoded Unicode literal won't degrade to ASCII on terminals that need it.
44
+
45
+ - **Glyphs** (checkmarks, arrows, ellipsis, cursor, box-drawing, branch icon, etc.): pull from `get_glyphs()` (`config.Glyphs`). Each glyph has a Unicode and an ASCII variant; `get_glyphs()` returns the right set for the active terminal. Never inline `"✓"`, `"…"`, `"›"`, and friends.
46
+ - **Animated spinners**: reuse the `Spinner` class in `widgets/loading.py`, which wraps `get_glyphs().spinner_frames` (braille on Unicode, `(-) (\) (|) (/)` on ASCII) and exposes `next_frame()`/`current_frame()`. Do **not** define your own frame tuples or interval constants for a spinner — drive a `Spinner` on a `set_interval`. The status-bar reconnect indicator (`widgets/status.py`) is the reference example; it ticks at the same 0.1s cadence as `LoadingWidget`. All connection/queue progress lives in the status bar — the welcome banner deliberately stays out of it, so there are currently no bespoke spinners to carve an exception for.
47
+
41
48
  ### Textual patterns used in this codebase
42
49
 
43
50
  - **Workers** (`@work` decorator) for async operations - see [Workers guide](https://textual.textualize.io/guide/workers/)
@@ -140,7 +147,8 @@ To add a new slash command: (1) add a `SlashCommand` entry to `COMMANDS`, (2) se
140
147
  1. `deepagents_code/model_config.py` — add `"provider_name": "ENV_VAR_NAME"` to `PROVIDER_API_KEY_ENV`
141
148
  2. `deepagents_code/model_config.py` — if the provider reads a *dedicated* endpoint env var, add `"provider_name": ("CANONICAL_BASE_URL", "ALTERNATE", ...)` to `PROVIDER_BASE_URL_ENV` (see guidelines below); omit the provider entirely when it has no provider-specific endpoint variable
142
149
  3. `pyproject.toml` — add `provider = ["langchain-provider>=X.Y.Z,<N.0.0"]` to `[project.optional-dependencies]` and include it in the `all-providers` composite extra
143
- 4. `tests/unit_tests/test_model_config.py` — add `assert PROVIDER_API_KEY_ENV["provider_name"] == "ENV_VAR_NAME"` to `TestProviderApiKeyEnv.test_contains_major_providers`, and pin any `PROVIDER_BASE_URL_ENV` entry with a matching assertion
150
+ 4. `deepagents_code/model_config.py` — add `"provider_name"` to `RETRY_PARAM_BY_PROVIDER` if the provider's chat model accepts `max_retries`
151
+ 5. `tests/unit_tests/test_model_config.py` — add `assert PROVIDER_API_KEY_ENV["provider_name"] == "ENV_VAR_NAME"` to `TestProviderApiKeyEnv.test_contains_major_providers`, and pin any `PROVIDER_BASE_URL_ENV` entry with a matching assertion
144
152
 
145
153
  ### `PROVIDER_BASE_URL_ENV` guidelines
146
154
 
@@ -2,6 +2,29 @@
2
2
 
3
3
  # Deep Agents Code Changelog
4
4
 
5
+ ## [0.1.13](https://github.com/langchain-ai/deepagents/compare/deepagents-code==0.1.12...deepagents-code==0.1.13) (2026-06-11)
6
+
7
+ ### Features
8
+
9
+ * Pluggable third-party sandbox backends ([#3842](https://github.com/langchain-ai/deepagents/issues/3842)) ([2b635a7](https://github.com/langchain-ai/deepagents/commit/2b635a7e6e6b50ca8ce783c2ac96ed8643ae0224))
10
+ * Auto-install ripgrep on first run ([#3348](https://github.com/langchain-ai/deepagents/issues/3348)) ([fecf22b](https://github.com/langchain-ai/deepagents/commit/fecf22b0909e79ff7bdf180baf20abf5fdf1f390))
11
+ * `config` command and canonical config manifest ([#3763](https://github.com/langchain-ai/deepagents/issues/3763)) ([79899a3](https://github.com/langchain-ai/deepagents/commit/79899a306d01de6217a1dfcc013ae92c808a47a0))
12
+ * Confirm modal for `/install --package` ([#3840](https://github.com/langchain-ai/deepagents/issues/3840)) ([3d75026](https://github.com/langchain-ai/deepagents/commit/3d75026e2f241648fae78d9e1de2cbb4985f58ff))
13
+ * Copy focused input selection on `Ctrl+C` ([#3841](https://github.com/langchain-ai/deepagents/issues/3841)) ([99f782c](https://github.com/langchain-ai/deepagents/commit/99f782cf08336c200d02a24ae4edaa650af67ed2))
14
+ * `[retries]` config ([#3772](https://github.com/langchain-ai/deepagents/issues/3772)) ([9334d91](https://github.com/langchain-ai/deepagents/commit/9334d91ef94997e46d5373daca9c146fa9498763))
15
+ * Show connection state in the status bar ([#3710](https://github.com/langchain-ai/deepagents/issues/3710)) ([3e3e8fe](https://github.com/langchain-ai/deepagents/commit/3e3e8feb0e6e1b77be75a7756fbf32e5c9497c28))
16
+ * Surface LangSmith tracing projects in `LocalContextMiddleware` ([#3836](https://github.com/langchain-ai/deepagents/issues/3836)) ([676abec](https://github.com/langchain-ai/deepagents/commit/676abecf892ff537fcb1425ba5929cace3c5d503))
17
+
18
+ ### Bug Fixes
19
+
20
+ * Add debug-log guidance for truncated startup errors ([#3849](https://github.com/langchain-ai/deepagents/issues/3849)) ([cd1ef30](https://github.com/langchain-ai/deepagents/commit/cd1ef303cf5d0e9d746c787eb09a4a89437e965a))
21
+ * Drop lock-key events so Caps Lock in iTerm2 doesn't type ([#3855](https://github.com/langchain-ai/deepagents/issues/3855)) ([110f1a7](https://github.com/langchain-ai/deepagents/commit/110f1a7a975743efda12e181cb3afc8404202254))
22
+ * Hand pointer over splash tracing project link ([#3858](https://github.com/langchain-ai/deepagents/issues/3858)) ([ea7dae5](https://github.com/langchain-ai/deepagents/commit/ea7dae58a37cfb1d2b96544eb7c941aad331b280))
23
+ * Keep terminal-default theme on Esc in `/theme` selector ([#3854](https://github.com/langchain-ai/deepagents/issues/3854)) ([c3bc67b](https://github.com/langchain-ai/deepagents/commit/c3bc67b0cdeda6f4dbcc6360ddd72b455aec4fe7))
24
+ * Preserve inherited `PYTHONPATH` for server subprocess ([#3833](https://github.com/langchain-ai/deepagents/issues/3833)) ([4689569](https://github.com/langchain-ai/deepagents/commit/4689569f94138987319cd9cbb45ce66a1f496934))
25
+ * Resolve interpreter PTC allowlist against the runtime tool registry ([#3845](https://github.com/langchain-ai/deepagents/issues/3845)) ([c59a27e](https://github.com/langchain-ai/deepagents/commit/c59a27ef2405b8e04c4351ce7ffa53d8d16d519c))
26
+ * Treat multi-line key-event pastes as one input ([#3856](https://github.com/langchain-ai/deepagents/issues/3856)) ([6bb15d4](https://github.com/langchain-ai/deepagents/commit/6bb15d4bd97bd16f47504f937c8458d1b53d9cc4))
27
+
5
28
  ## [0.1.12](https://github.com/langchain-ai/deepagents/compare/deepagents-code==0.1.11...deepagents-code==0.1.12) (2026-06-10)
6
29
 
7
30
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepagents-code
3
- Version: 0.1.12
3
+ Version: 0.1.13
4
4
  Summary: Terminal interface for Deep Agents - interactive AI agent with file operations, shell access, and sub-agent capabilities.
5
5
  Project-URL: Homepage, https://docs.langchain.com/oss/python/deepagents/overview
6
6
  Project-URL: Documentation, https://reference.langchain.com/python/deepagents/
@@ -409,6 +409,13 @@
409
409
  - **Description**: The `"env"` field in stdio MCP server definitions (`.mcp.json`) accepts an arbitrary key-value dict. `mcp_tools._validate_server_config` only checks that the field is a dict — it does not filter key names or values. The dict is forwarded directly to `StdioConnection(env=...)` which passes it to the subprocess. An attacker who can modify a project-level `.mcp.json` could set `PATH` to redirect command resolution, `LD_PRELOAD` to inject shared libraries, or `PYTHONPATH` to hijack Python imports in the MCP subprocess.
410
410
  - **Preconditions**: (1) Attacker has write access to a project-level `.mcp.json`; (2) The project MCP config must be trusted by the user (fingerprint approval gate via `mcp_trust`). For user-level `~/.deepagents/.mcp.json`, the attacker already has home directory write access. Note: the `env` dict from MCP config is passed to `StdioConnection` — whether it replaces or merges with `os.environ` depends on the `langchain_mcp_adapters` library implementation.
411
411
 
412
+ #### T11: Auto-Installed ripgrep Binary from Upstream Release
413
+
414
+ - **Flow**: First-run download performed by `managed_tools.ensure_ripgrep` when `rg` is not on `PATH`.
415
+ - **Description**: On first invocation without a system `rg`, Deep Agents Code fetches the pinned ripgrep release tarball from `github.com/BurntSushi/ripgrep/releases/...`, verifies it against an in-tree SHA-256 (`RIPGREP_ASSETS`), extracts it under a `TemporaryDirectory`, and atomically moves the binary into `~/.deepagents/bin/rg`. The binary then runs unsandboxed, inheriting the same trust as a user-installed `rg` (the SDK invokes it via `subprocess.run(["rg", ...])`).
416
+ - **Mitigations**: (1) SHA-256 verified against the pinned hash table before move — a mismatch aborts the install and leaves `BIN_DIR` clean. (2) Network egress is limited to `github.com`. (3) Opt-out via `DEEPAGENTS_CODE_OFFLINE` for air-gapped environments. (4) Pinned version + checksums are bumped in-tree, so a compromised upstream release is detected on the next Deep Agents Code release rather than silently propagating. (5) Atomic move-into-place avoids partial installs when concurrent CLI invocations race.
417
+ - **Preconditions**: User has not installed `rg` via their package manager, `DEEPAGENTS_CODE_OFFLINE` is unset, and the host can reach `github.com`. The pinned SHA-256 in `RIPGREP_ASSETS` would need to be incorrect (a supply-chain compromise of the deepagents-code release) for a tampered binary to be installed.
418
+
412
419
  ---
413
420
 
414
421
  ## Input Source Coverage
@@ -13,7 +13,12 @@ import os
13
13
  import sys
14
14
  from pathlib import Path
15
15
 
16
- from deepagents_code._env_vars import DEBUG, DEBUG_FILE, is_env_truthy
16
+ from deepagents_code._env_vars import (
17
+ DEBUG,
18
+ DEBUG_FILE,
19
+ DEFAULT_DEBUG_FILE,
20
+ is_env_truthy,
21
+ )
17
22
 
18
23
  _DEBUG_HANDLER_ATTR = "_deepagents_code_debug_handler"
19
24
 
@@ -25,8 +30,8 @@ def configure_debug_logging(target: logging.Logger) -> None:
25
30
  module loggers reach the same file via propagation, so individual modules do
26
31
  not configure logging themselves.
27
32
 
28
- The log file defaults to `'/tmp/deepagents_debug.log'` but can be overridden
29
- with `DEEPAGENTS_CODE_DEBUG_FILE`. The handler appends (`mode='a'`) so logs
33
+ The log file defaults to `DEFAULT_DEBUG_FILE` but can be overridden with
34
+ `DEEPAGENTS_CODE_DEBUG_FILE`. The handler appends (`mode='a'`) so logs
30
35
  are preserved across separate process runs. Calling this again with the same
31
36
  resolved path is a no-op: the existing tagged handler is reused rather than
32
37
  stacking duplicates. If the resolved path changes, the stale handler is
@@ -40,12 +45,7 @@ def configure_debug_logging(target: logging.Logger) -> None:
40
45
  if not is_env_truthy(DEBUG):
41
46
  return
42
47
 
43
- debug_path = Path(
44
- os.environ.get(
45
- DEBUG_FILE,
46
- "/tmp/deepagents_debug.log", # noqa: S108
47
- )
48
- )
48
+ debug_path = Path(os.environ.get(DEBUG_FILE, DEFAULT_DEBUG_FILE))
49
49
  for existing in list(target.handlers):
50
50
  if not (
51
51
  isinstance(existing, logging.FileHandler)
@@ -74,3 +74,23 @@ def configure_debug_logging(target: logging.Logger) -> None:
74
74
  handler.setFormatter(logging.Formatter("%(asctime)s %(name)s %(message)s"))
75
75
  target.addHandler(handler)
76
76
  target.setLevel(logging.DEBUG)
77
+
78
+
79
+ def installed_debug_log_path() -> Path | None:
80
+ """Return the path of the active debug log file, or `None` if not logging.
81
+
82
+ Reflects the file handler actually attached by `configure_debug_logging`,
83
+ not the current `DEEPAGENTS_CODE_DEBUG` env value. The two diverge when the
84
+ variable is set after import — e.g. via a project/global `.env` loaded during
85
+ settings bootstrap — in which case the variable reads truthy but no handler
86
+ was installed and no log file exists. Callers that surface "full error in
87
+ <path>" hints must use this rather than the env var to avoid pointing users
88
+ at a file that was never created.
89
+ """
90
+ package_logger = logging.getLogger(__package__ or "deepagents_code")
91
+ for handler in package_logger.handlers:
92
+ if isinstance(handler, logging.FileHandler) and getattr(
93
+ handler, _DEBUG_HANDLER_ATTR, False
94
+ ):
95
+ return Path(handler.baseFilename)
96
+ return None
@@ -46,7 +46,10 @@ as enabled, and `0`, `false`, `no`, `off`, empty string, or unset as disabled.
46
46
  """
47
47
 
48
48
  DEBUG_FILE = "DEEPAGENTS_CODE_DEBUG_FILE"
49
- """Path for the debug log file (default: `/tmp/deepagents_debug.log`)."""
49
+ """Path for the debug log file (default: `DEFAULT_DEBUG_FILE`)."""
50
+
51
+ DEFAULT_DEBUG_FILE = "/tmp/deepagents_debug.log" # noqa: S108 # opt-in debug log
52
+ """Default path for the debug log when `DEBUG_FILE` is unset."""
50
53
 
51
54
  DEBUG_MCP_PROJECT_TRUST = "DEEPAGENTS_CODE_DEBUG_MCP_PROJECT_TRUST"
52
55
  """Force the project MCP approval prompt for manual UI testing.
@@ -124,6 +127,14 @@ NO_TERMINAL_ESCAPE = "DEEPAGENTS_CODE_NO_TERMINAL_ESCAPE"
124
127
  NO_UPDATE_CHECK = "DEEPAGENTS_CODE_NO_UPDATE_CHECK"
125
128
  """Disable automatic update checking when set."""
126
129
 
130
+ OFFLINE = "DEEPAGENTS_CODE_OFFLINE"
131
+ """Disable network downloads of managed binaries (e.g. ripgrep).
132
+
133
+ Parsed by `is_env_truthy`: accepts `1`, `true`, `yes`, `on` as enabled. When
134
+ truthy, `managed_tools.ensure_ripgrep` will not attempt to download a binary
135
+ and falls back to the existing missing-tool notification + slow Python regex
136
+ path."""
137
+
127
138
  OLLAMA_DISCOVERY = "DEEPAGENTS_CODE_OLLAMA_DISCOVERY"
128
139
  """Toggle Ollama model and profile discovery probes.
129
140
 
@@ -164,6 +175,29 @@ _TRUTHY_VALUES = frozenset({"1", "true", "yes", "on"})
164
175
  _FALSY_VALUES = frozenset({"0", "false", "no", "off", ""})
165
176
 
166
177
 
178
+ def classify_env_bool(raw: str) -> bool | None:
179
+ """Classify a raw env-var string as a truthy, falsy, or unrecognized token.
180
+
181
+ The single source of truth for which strings count as boolean on/off
182
+ values; `is_env_truthy` and the config resolver both build on it so they
183
+ agree on what "recognizably boolean" means.
184
+
185
+ Args:
186
+ raw: The raw (unstripped) environment-variable value.
187
+
188
+ Returns:
189
+ `True` for `1`/`true`/`yes`/`on`, `False` for `0`/`false`/`no`/`off`/
190
+ empty string (case-insensitive), or `None` when the value
191
+ is neither.
192
+ """
193
+ lowered = raw.strip().lower()
194
+ if lowered in _TRUTHY_VALUES:
195
+ return True
196
+ if lowered in _FALSY_VALUES:
197
+ return False
198
+ return None
199
+
200
+
167
201
  def is_env_truthy(name: str, *, default: bool = False) -> bool:
168
202
  """Return whether env var *name* is set to a recognizably truthy value.
169
203
 
@@ -184,9 +218,5 @@ def is_env_truthy(name: str, *, default: bool = False) -> bool:
184
218
  raw = os.environ.get(name)
185
219
  if raw is None:
186
220
  return default
187
- lowered = raw.strip().lower()
188
- if lowered in _TRUTHY_VALUES:
189
- return True
190
- if lowered in _FALSY_VALUES:
191
- return False
192
- return default
221
+ classified = classify_env_bool(raw)
222
+ return default if classified is None else classified
@@ -164,7 +164,9 @@ class ServerConfig:
164
164
 
165
165
  `None` means "fall through to whatever `settings.interpreter_ptc` resolves
166
166
  to from `~/.deepagents/config.toml`". A string is one of `"safe"`/`"all"`;
167
- a list is an explicit allowlist of tool names.
167
+ a list is an explicit allowlist of tool names that may also include the
168
+ `"safe"` preset (expanded at agent-build time); `"all"` is rejected inside
169
+ a list.
168
170
  """
169
171
 
170
172
  interpreter_ptc_acknowledge_unsafe: bool = False
@@ -13,7 +13,30 @@ upstream.
13
13
  `alt+enter`. Tracked in Textualize/textual#6378. Remove this patch and
14
14
  the Textual pin comment in `pyproject.toml` when that lands.
15
15
 
16
- 2. Double-click word selection. Stock Textual selects the entire widget on
16
+ 2. Kitty lock-key and sub-field handling. Two related problems with the
17
+ pinned Textual parser:
18
+
19
+ a. Lock keys (Caps Lock / Num Lock / Scroll Lock) must never produce
20
+ text, but terminals encode them inconsistently. kitty/Ghostty/VS Code
21
+ send the functional key code (`CSI 57358 ... u`) with associated text
22
+ set to the letter the *next* key would have produced. iTerm2 instead
23
+ reports the Caps Lock toggle as a bare upper-case ASCII letter (`CSI
24
+ 65 u` → 'A') with no modifier or associated-text field — not a valid
25
+ encoding for a real key press per the kitty spec. Either way the chat
26
+ input would type a stray capital. The patch collapses both forms to a
27
+ single character-less `caps_lock` event, regardless of the modifier,
28
+ associated-text, or event-type sub-fields the terminal includes.
29
+
30
+ b. `_re_extended_key` only accepts `;`-separated numeric fields, so any
31
+ *non-lock* kitty sequence carrying `:`-separated sub-fields — alternate
32
+ keys (`unicode:shifted:base`) or an event-type (`modifiers:event`) —
33
+ fails to match and is re-emitted one byte at a time as literal text.
34
+ The patch strips the `:` sub-fields before Textual parses the sequence
35
+ so it resolves to a single key event.
36
+
37
+ Remove when the pinned Textual neutralizes lock keys and widens its parser.
38
+
39
+ 3. Double-click word selection. Stock Textual selects the entire widget on
17
40
  a click chain; these patches narrow a double-click (and double-click
18
41
  drag) to word boundaries. No upstream issue tracks this yet, so it has
19
42
  no removal criterion — it stays until Textual grows native word select.
@@ -24,6 +47,7 @@ Imported for side effect from `app.py` before any `App()` is created.
24
47
  from __future__ import annotations
25
48
 
26
49
  import logging
50
+ import re
27
51
  from inspect import isawaitable
28
52
  from typing import TYPE_CHECKING
29
53
 
@@ -60,6 +84,99 @@ try:
60
84
  except (ImportError, AttributeError) as exc: # pragma: no cover - defensive
61
85
  logger.warning("Textual keyboard parser patch skipped: %s", exc)
62
86
  else:
87
+ # Kitty functional key codes for the lock keys (Caps Lock, Scroll Lock,
88
+ # Num Lock). The kitty protocol assigns these Private Use Area codepoints;
89
+ # they appear as the leading key-code field of a `CSI ... u` sequence.
90
+ _KITTY_LOCK_KEY_CODES = frozenset({"57358", "57359", "57360"})
91
+ _KITTY_LOCK_KEY_NAMES = {
92
+ "57358": "caps_lock",
93
+ "57359": "scroll_lock",
94
+ "57360": "num_lock",
95
+ }
96
+
97
+ # Any `CSI <code>[:...][;...] u` sequence. Group 1 is the leading key-code
98
+ # field (before any `:` alternate-key sub-field); `_lock_key_event` checks
99
+ # it against the lock-key set. The match is deliberately broad so the code
100
+ # is extracted regardless of the modifier / associated-text / event-type
101
+ # sub-fields that follow, which iTerm2 and other terminals encode in
102
+ # varying shapes.
103
+ _KITTY_KEY_SEQUENCE = re.compile(r"\x1b\[(\d+)[\d;:]*u")
104
+
105
+ # Kitty extended-key sequence carrying `:` sub-fields (alternate keys or an
106
+ # event-type sub-field). The pinned Textual's `_re_extended_key` rejects the
107
+ # colons, so non-lock keys with these sub-fields would otherwise leak as
108
+ # literal text — strip the sub-fields so they parse to a single key event.
109
+ _KITTY_SUBFIELD_KEY = re.compile(r"\x1b\[[\d;:]*:[\d;:]*[u~ABCDEFHPQRS]")
110
+
111
+ # iTerm2 reports the Caps Lock toggle as a `CSI u` sequence whose primary
112
+ # key code is the *uppercase* ASCII letter that would be produced next
113
+ # (e.g. `CSI 65 u` → 'A'), with no real modifier bits and no associated
114
+ # text. The kitty spec requires the primary code to be the unshifted
115
+ # (lower-case) code point, so a bare upper-case letter here is iTerm2's
116
+ # Caps Lock artifact rather than a real key press. Group 1 is the code
117
+ # point; group 2 the optional modifier field; group 3 the optional text.
118
+ _KITTY_CSI_U = re.compile(
119
+ r"\x1b\[(\d+)(?::\d+)*(?:;(\d+)[\d:]*)?(?:;(\d+)[\d:]*)?u"
120
+ )
121
+ _ASCII_UPPER_A = 65
122
+ _ASCII_UPPER_Z = 90
123
+ # Modifier mask for the "real" modifiers (shift|alt|ctrl|super|hyper|meta);
124
+ # excludes the caps_lock (64) and num_lock (128) lock bits.
125
+ _REAL_MODIFIER_MASK = 0b111111
126
+
127
+ def _spurious_caps_lock(sequence: str) -> bool:
128
+ """Whether `sequence` is iTerm2's bare Caps Lock toggle report.
129
+
130
+ Matches a `CSI u` key whose primary code point is an upper-case ASCII
131
+ letter with no real modifiers and no associated-text field — which the
132
+ kitty spec never produces for a genuine key press.
133
+
134
+ Returns:
135
+ `True` if `sequence` is the spurious Caps Lock toggle report.
136
+ """
137
+ match = _KITTY_CSI_U.fullmatch(sequence)
138
+ if match is None:
139
+ return False
140
+ code = int(match.group(1))
141
+ if not _ASCII_UPPER_A <= code <= _ASCII_UPPER_Z:
142
+ return False
143
+ modifier_bits = (int(match.group(2)) - 1) if match.group(2) else 0
144
+ has_text = match.group(3) is not None
145
+ return modifier_bits & _REAL_MODIFIER_MASK == 0 and not has_text
146
+
147
+ def _strip_kitty_subfields(sequence: str) -> str:
148
+ """Drop `:` sub-fields from a kitty extended-key sequence.
149
+
150
+ Keeps the primary value of each `;`-separated field (the unicode key
151
+ code, modifier mask, and associated text), which is all Textual reads.
152
+
153
+ Returns:
154
+ The sequence with every `:` sub-field removed.
155
+ """
156
+ body, terminator = sequence[2:-1], sequence[-1]
157
+ primary = ";".join(field.split(":", 1)[0] for field in body.split(";"))
158
+ return f"\x1b[{primary}{terminator}"
159
+
160
+ def _lock_key_event(sequence: str) -> events.Key | None:
161
+ """Return a text-free lock-key event for a kitty lock-key sequence.
162
+
163
+ Lock keys must never produce text. Under the kitty protocol with
164
+ associated-text reporting, terminals (notably iTerm2) encode Caps
165
+ Lock as a `CSI 57358 ... u` sequence whose associated-text field is
166
+ the letter the *next* key would have produced — Textual then either
167
+ types that letter or, when `:` sub-fields are present, leaks the raw
168
+ sequence byte by byte. Collapsing any lock-key sequence to a single
169
+ character-less event stops both failure modes at the source, for
170
+ every widget.
171
+
172
+ Returns:
173
+ A `Key` event for the lock key, or `None` if `sequence` is not a
174
+ kitty lock-key sequence.
175
+ """
176
+ match = _KITTY_KEY_SEQUENCE.fullmatch(sequence)
177
+ if match is None or match.group(1) not in _KITTY_LOCK_KEY_CODES:
178
+ return None
179
+ return events.Key(_KITTY_LOCK_KEY_NAMES[match.group(1)], None)
63
180
 
64
181
  def _emit_alt(keys: tuple, character: str | None) -> Iterable[events.Key]:
65
182
  for key in keys:
@@ -68,6 +185,22 @@ else:
68
185
  def _sequence_to_key_events_with_alt(
69
186
  self: XTermParser, sequence: str, alt: bool = False
70
187
  ) -> Iterable[events.Key]:
188
+ # Lock keys (Caps Lock / Num Lock / Scroll Lock) must never type. Emit
189
+ # a single character-less event regardless of how the terminal encoded
190
+ # the modifiers, associated text, or event-type sub-fields.
191
+ if (lock_event := _lock_key_event(sequence)) is not None:
192
+ yield lock_event
193
+ return
194
+ # iTerm2 reports the Caps Lock toggle as a bare upper-case letter (e.g.
195
+ # `CSI 65 u` → 'A') rather than the kitty `57358` functional code. Drop
196
+ # it so the toggle never types a stray capital into the input.
197
+ if _spurious_caps_lock(sequence):
198
+ yield events.Key("caps_lock", None)
199
+ return
200
+ # Normalize any other kitty sequence with `:` sub-fields so it resolves
201
+ # to a single key event instead of leaking raw bytes.
202
+ if _KITTY_SUBFIELD_KEY.fullmatch(sequence):
203
+ sequence = _strip_kitty_subfields(sequence)
71
204
  # Fast path: \x1b<byte> on first pass. Short-circuits the ~100 ms
72
205
  # escape-delay wait when both bytes arrive together. Semantic side
73
206
  # effect: \x1b\x1b dispatches as `alt+escape` with no delay, matching
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Keep the `x-release-please-version` annotation — release-please uses it to
4
4
  # bump `__version__` in sync with `pyproject.toml` on every release PR.
5
- __version__ = "0.1.12" # x-release-please-version
5
+ __version__ = "0.1.13" # x-release-please-version
6
6
 
7
7
  DOCS_URL = "https://docs.langchain.com/oss/python/deepagents/code"
8
8
  """URL for `deepagents-code` documentation."""
@@ -54,11 +54,13 @@ from langchain.agents.middleware.types import AgentMiddleware
54
54
  from deepagents_code import theme
55
55
  from deepagents_code._constants import DEFAULT_AGENT_NAME
56
56
  from deepagents_code.config import (
57
+ _INHERITED_PYTHONPATH_ENV,
57
58
  _ShellAllowAll,
58
59
  config,
59
60
  console,
60
61
  get_default_coding_instructions,
61
62
  get_glyphs,
63
+ get_langsmith_project_name,
62
64
  settings,
63
65
  )
64
66
  from deepagents_code.configurable_model import ConfigurableModelMiddleware
@@ -219,12 +221,23 @@ def _resolve_ptc_option(
219
221
  ) -> list[str] | None:
220
222
  """Resolve the configured PTC allowlist to a concrete list of tool names.
221
223
 
224
+ Names are *not* validated against `tools`. The Deep Agents SDK injects the
225
+ filesystem, `task`, `write_todos`, and `execute` tools via middleware in
226
+ `create_deep_agent` — *after* this point — so they are absent from `tools`
227
+ here, and the SDK exposes no importable list of them. `CodeInterpreterMiddleware`
228
+ matches the resolved names against the live runtime registry and silently
229
+ ignores any that are absent, so resolution passes names through and lets
230
+ runtime decide. (Names that match nothing at runtime are dropped, so a typo
231
+ silently exposes no tool rather than raising.)
232
+
222
233
  Args:
223
234
  ptc: Raw `interpreter_ptc` value from settings or CLI. Accepts
224
- `False`/`[]`, `"safe"`, `"all"`, or a list of names.
225
- tools: Live tool list given to `create_cli_agent`. Used to validate
226
- explicit names, intersect the `"safe"` preset, and enumerate
227
- `"all"`.
235
+ `False`/`[]`, `"safe"`, `"all"`, or a list of names. A list may
236
+ include `"safe"`, which expands to `INTERPRETER_PTC_SAFE_PRESET`;
237
+ `"all"` is rejected inside a list.
238
+ tools: Tools passed to `create_cli_agent`. Used only to enumerate
239
+ `"all"`, which is therefore limited to these explicitly-passed
240
+ tools (the SDK runtime built-ins cannot be enumerated here).
228
241
  acknowledge_unsafe: Mirrors `settings.interpreter_ptc_acknowledge_unsafe`;
229
242
  required when `ptc="all"` and `auto_approve` is `False`.
230
243
  auto_approve: Whether HITL approval is globally disabled. When `True`,
@@ -236,8 +249,9 @@ def _resolve_ptc_option(
236
249
  suitable for `CodeInterpreterMiddleware(ptc=...)`.
237
250
 
238
251
  Raises:
239
- ValueError: For unknown names in an explicit list, or for `"all"`
240
- without `acknowledge_unsafe` outside of `auto_approve`.
252
+ ValueError: For `"all"` inside a list, for `"all"` without
253
+ `acknowledge_unsafe` outside of `auto_approve`, or for an invalid
254
+ `ptc` type or string.
241
255
  """
242
256
  from langchain.tools import BaseTool as _BaseTool
243
257
 
@@ -265,14 +279,10 @@ def _resolve_ptc_option(
265
279
  if normalized == "safe":
266
280
  from deepagents_code.config import INTERPRETER_PTC_SAFE_PRESET
267
281
 
268
- selected = sorted(INTERPRETER_PTC_SAFE_PRESET & live_set)
269
- dropped = sorted(INTERPRETER_PTC_SAFE_PRESET - live_set)
270
- if dropped:
271
- logger.debug(
272
- "interpreter_ptc='safe' preset members not present in toolset: %s",
273
- dropped,
274
- )
275
- return selected
282
+ # Return the preset as-is; the middleware exposes whichever members
283
+ # exist in the live registry at runtime (they are SDK built-ins not
284
+ # present in `tools` here).
285
+ return sorted(INTERPRETER_PTC_SAFE_PRESET)
276
286
  if normalized == "all":
277
287
  if not auto_approve and not acknowledge_unsafe:
278
288
  msg = (
@@ -282,6 +292,11 @@ def _resolve_ptc_option(
282
292
  "auto_approve=True) to opt in."
283
293
  )
284
294
  raise ValueError(msg)
295
+ # `all` can only enumerate the tools passed to `create_cli_agent`;
296
+ # SDK runtime built-ins (filesystem, `task`, …) are injected later
297
+ # and are not enumerable here. Exposing them under `all` needs an
298
+ # "expose everything" sentinel in `CodeInterpreterMiddleware`
299
+ # (tracked in langchain-ai/deepagents#3847).
285
300
  included = sorted(live_set)
286
301
  write_included = sorted(_INTERPRETER_WRITE_TOOLS & live_set)
287
302
  if write_included:
@@ -297,15 +312,42 @@ def _resolve_ptc_option(
297
312
  raise ValueError(msg)
298
313
 
299
314
  if isinstance(ptc, list):
300
- unknown = [name for name in ptc if name not in live_set]
301
- if unknown:
302
- available = ", ".join(sorted(live_set)) or "<none>"
315
+ from deepagents_code.config import INTERPRETER_PTC_SAFE_PRESET
316
+
317
+ if any(name.strip().lower() == "all" for name in ptc):
303
318
  msg = (
304
- "Unknown tool names in interpreter_ptc: "
305
- f"{sorted(set(unknown))}. Available tools: {available}."
319
+ "interpreter_ptc list entries cannot include 'all'; use 'all' "
320
+ "as a standalone value or list explicit tool names (optionally "
321
+ "with the 'safe' preset)."
306
322
  )
307
323
  raise ValueError(msg)
308
- return list(ptc)
324
+
325
+ resolved: list[str] = []
326
+ seen: set[str] = set()
327
+
328
+ def _add(name: str) -> None:
329
+ if name not in seen:
330
+ seen.add(name)
331
+ resolved.append(name)
332
+
333
+ for name in ptc:
334
+ if name.strip().lower() == "safe":
335
+ for member in sorted(INTERPRETER_PTC_SAFE_PRESET):
336
+ _add(member)
337
+ continue
338
+ _add(name)
339
+
340
+ # Explicit names are passed through unvalidated: the middleware resolves
341
+ # them against the live runtime registry (which includes the SDK
342
+ # built-ins absent from `tools`) and drops any that match nothing.
343
+ absent = sorted(n for n in resolved if n not in live_set)
344
+ if absent:
345
+ logger.debug(
346
+ "interpreter_ptc names not in the build-time toolset (resolved "
347
+ "at runtime if present): %s",
348
+ absent,
349
+ )
350
+ return resolved
309
351
 
310
352
  msg = (
311
353
  "interpreter_ptc must be False, 'safe', 'all', or a list of tool names; "
@@ -1024,6 +1066,23 @@ def _add_interrupt_on() -> dict[str, InterruptOnConfig]:
1024
1066
  return interrupt_map
1025
1067
 
1026
1068
 
1069
+ def _apply_inherited_pythonpath(env: dict[str, str]) -> None:
1070
+ """Re-apply a relayed launch-time `PYTHONPATH` to a shell-command env.
1071
+
1072
+ `server._build_server_env` strips `PYTHONPATH` from the server interpreter
1073
+ and relays the launch value via `config._INHERITED_PYTHONPATH_ENV`. This
1074
+ restores it as `PYTHONPATH` for the approval-gated `execute` subprocesses,
1075
+ which run in the user's working directory and need the import path. Mutates
1076
+ `env` in place; a no-op when no value was relayed.
1077
+
1078
+ Args:
1079
+ env: Environment mapping for the shell backend, modified in place.
1080
+ """
1081
+ inherited = env.pop(_INHERITED_PYTHONPATH_ENV, None)
1082
+ if inherited is not None:
1083
+ env["PYTHONPATH"] = inherited
1084
+
1085
+
1027
1086
  def create_cli_agent(
1028
1087
  model: str | BaseChatModel,
1029
1088
  assistant_id: str,
@@ -1367,13 +1426,19 @@ def create_cli_agent(
1367
1426
  shell_env = os.environ.copy()
1368
1427
  if settings.user_langchain_project:
1369
1428
  shell_env["LANGSMITH_PROJECT"] = settings.user_langchain_project
1429
+ # Re-apply a launch-time PYTHONPATH that was stripped from the server
1430
+ # interpreter but relayed for approval-gated `execute` commands.
1431
+ _apply_inherited_pythonpath(shell_env)
1370
1432
 
1371
1433
  # Use LocalShellBackend for filesystem + shell execution.
1372
1434
  # The SDK's FilesystemMiddleware exposes per-command timeout
1373
1435
  # on the execute tool natively.
1436
+ # `inherit_env=False`: `shell_env` is already a complete, curated
1437
+ # copy of `os.environ`. Inheriting again would re-copy `os.environ`
1438
+ # and resurrect the popped carrier var, leaking it into `execute`.
1374
1439
  backend = LocalShellBackend(
1375
1440
  root_dir=root_dir,
1376
- inherit_env=True,
1441
+ inherit_env=False,
1377
1442
  env=shell_env,
1378
1443
  )
1379
1444
  else:
@@ -1419,7 +1484,12 @@ def create_cli_agent(
1419
1484
  # Local context middleware (git info, directory tree, etc.).
1420
1485
  if isinstance(backend, (_ExecutableBackend, _AsyncExecutableBackend)):
1421
1486
  agent_middleware.append(
1422
- LocalContextMiddleware(backend=backend, mcp_server_info=mcp_server_info)
1487
+ LocalContextMiddleware(
1488
+ backend=backend,
1489
+ mcp_server_info=mcp_server_info,
1490
+ tracing_project=get_langsmith_project_name(),
1491
+ user_tracing_project=settings.user_langchain_project,
1492
+ )
1423
1493
  )
1424
1494
 
1425
1495
  # Add shell allow-list middleware when interrupt_shell_only is active.