newcode 0.2.6__tar.gz → 0.2.9__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 (272) hide show
  1. {newcode-0.2.6 → newcode-0.2.9}/PKG-INFO +1 -2
  2. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/base_agent.py +44 -145
  3. {newcode-0.2.6 → newcode-0.2.9}/newcode/claude_cache_client.py +13 -3
  4. {newcode-0.2.6 → newcode-0.2.9}/newcode/cli_runner.py +0 -35
  5. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/config_commands.py +0 -10
  6. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/core_commands.py +15 -1
  7. {newcode-0.2.6 → newcode-0.2.9}/newcode/config.py +0 -21
  8. {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/executor.py +1 -1
  9. {newcode-0.2.6 → newcode-0.2.9}/newcode/models.json +4 -4
  10. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/chatgpt_oauth/oauth_flow.py +3 -2
  11. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/chatgpt_oauth/test_plugin.py +7 -1
  12. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/chatgpt_oauth/utils.py +25 -1
  13. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/utils.py +39 -3
  14. {newcode-0.2.6 → newcode-0.2.9}/newcode/summarization_agent.py +3 -3
  15. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/agent_tools.py +21 -110
  16. {newcode-0.2.6 → newcode-0.2.9}/pyproject.toml +1 -2
  17. {newcode-0.2.6 → newcode-0.2.9}/.gitignore +0 -0
  18. {newcode-0.2.6 → newcode-0.2.9}/LICENSE +0 -0
  19. {newcode-0.2.6 → newcode-0.2.9}/README.md +0 -0
  20. {newcode-0.2.6 → newcode-0.2.9}/newcode/__init__.py +0 -0
  21. {newcode-0.2.6 → newcode-0.2.9}/newcode/__main__.py +0 -0
  22. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/__init__.py +0 -0
  23. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_c_reviewer.py +0 -0
  24. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_code_agent.py +0 -0
  25. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_code_reviewer.py +0 -0
  26. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_cpp_reviewer.py +0 -0
  27. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_creator_agent.py +0 -0
  28. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_golang_reviewer.py +0 -0
  29. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_javascript_reviewer.py +0 -0
  30. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_manager.py +0 -0
  31. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_pack_leader.py +0 -0
  32. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_planning.py +0 -0
  33. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_python_programmer.py +0 -0
  34. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_python_reviewer.py +0 -0
  35. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_qa_browser.py +0 -0
  36. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_qa_expert.py +0 -0
  37. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_security_auditor.py +0 -0
  38. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_terminal_qa.py +0 -0
  39. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_typescript_reviewer.py +0 -0
  40. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/event_stream_handler.py +0 -0
  41. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/json_agent.py +0 -0
  42. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/__init__.py +0 -0
  43. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/bloodhound.py +0 -0
  44. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/husky.py +0 -0
  45. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/retriever.py +0 -0
  46. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/shepherd.py +0 -0
  47. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/terrier.py +0 -0
  48. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/watchdog.py +0 -0
  49. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/prompt_reviewer.py +0 -0
  50. {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/subagent_stream_handler.py +0 -0
  51. {newcode-0.2.6 → newcode-0.2.9}/newcode/api/__init__.py +0 -0
  52. {newcode-0.2.6 → newcode-0.2.9}/newcode/api/app.py +0 -0
  53. {newcode-0.2.6 → newcode-0.2.9}/newcode/api/main.py +0 -0
  54. {newcode-0.2.6 → newcode-0.2.9}/newcode/api/pty_manager.py +0 -0
  55. {newcode-0.2.6 → newcode-0.2.9}/newcode/api/routers/__init__.py +0 -0
  56. {newcode-0.2.6 → newcode-0.2.9}/newcode/api/routers/agents.py +0 -0
  57. {newcode-0.2.6 → newcode-0.2.9}/newcode/api/routers/commands.py +0 -0
  58. {newcode-0.2.6 → newcode-0.2.9}/newcode/api/routers/config.py +0 -0
  59. {newcode-0.2.6 → newcode-0.2.9}/newcode/api/routers/sessions.py +0 -0
  60. {newcode-0.2.6 → newcode-0.2.9}/newcode/api/templates/terminal.html +0 -0
  61. {newcode-0.2.6 → newcode-0.2.9}/newcode/api/websocket.py +0 -0
  62. {newcode-0.2.6 → newcode-0.2.9}/newcode/callbacks.py +0 -0
  63. {newcode-0.2.6 → newcode-0.2.9}/newcode/chatgpt_codex_client.py +0 -0
  64. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/__init__.py +0 -0
  65. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/add_model_menu.py +0 -0
  66. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/agent_menu.py +0 -0
  67. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/attachments.py +0 -0
  68. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/autosave_menu.py +0 -0
  69. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/clipboard.py +0 -0
  70. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/colors_menu.py +0 -0
  71. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/command_handler.py +0 -0
  72. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/command_registry.py +0 -0
  73. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/diff_menu.py +0 -0
  74. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/file_path_completion.py +0 -0
  75. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/load_context_completion.py +0 -0
  76. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/__init__.py +0 -0
  77. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/base.py +0 -0
  78. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/catalog_server_installer.py +0 -0
  79. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/custom_server_form.py +0 -0
  80. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/custom_server_installer.py +0 -0
  81. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/edit_command.py +0 -0
  82. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/handler.py +0 -0
  83. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/help_command.py +0 -0
  84. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/install_command.py +0 -0
  85. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/install_menu.py +0 -0
  86. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/list_command.py +0 -0
  87. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/logs_command.py +0 -0
  88. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/remove_command.py +0 -0
  89. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/restart_command.py +0 -0
  90. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/search_command.py +0 -0
  91. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/start_all_command.py +0 -0
  92. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/start_command.py +0 -0
  93. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/status_command.py +0 -0
  94. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/stop_all_command.py +0 -0
  95. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/stop_command.py +0 -0
  96. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/test_command.py +0 -0
  97. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/utils.py +0 -0
  98. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/wizard_utils.py +0 -0
  99. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp_completion.py +0 -0
  100. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/model_picker_completion.py +0 -0
  101. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/model_settings_menu.py +0 -0
  102. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/motd.py +0 -0
  103. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/onboarding_slides.py +0 -0
  104. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/onboarding_wizard.py +0 -0
  105. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/pin_command_completion.py +0 -0
  106. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/prompt_toolkit_completion.py +0 -0
  107. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/session_commands.py +0 -0
  108. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/skills_completion.py +0 -0
  109. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/uc_menu.py +0 -0
  110. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/utils.py +0 -0
  111. {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/wiggum_state.py +0 -0
  112. {newcode-0.2.6 → newcode-0.2.9}/newcode/error_logging.py +0 -0
  113. {newcode-0.2.6 → newcode-0.2.9}/newcode/gemini_code_assist.py +0 -0
  114. {newcode-0.2.6 → newcode-0.2.9}/newcode/gemini_model.py +0 -0
  115. {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/README.md +0 -0
  116. {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/__init__.py +0 -0
  117. {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/aliases.py +0 -0
  118. {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/engine.py +0 -0
  119. {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/matcher.py +0 -0
  120. {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/models.py +0 -0
  121. {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/registry.py +0 -0
  122. {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/validator.py +0 -0
  123. {newcode-0.2.6 → newcode-0.2.9}/newcode/http_utils.py +0 -0
  124. {newcode-0.2.6 → newcode-0.2.9}/newcode/image_utils.py +0 -0
  125. {newcode-0.2.6 → newcode-0.2.9}/newcode/keymap.py +0 -0
  126. {newcode-0.2.6 → newcode-0.2.9}/newcode/main.py +0 -0
  127. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/__init__.py +0 -0
  128. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/async_lifecycle.py +0 -0
  129. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/blocking_startup.py +0 -0
  130. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/captured_stdio_server.py +0 -0
  131. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/circuit_breaker.py +0 -0
  132. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/config_wizard.py +0 -0
  133. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/dashboard.py +0 -0
  134. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/error_isolation.py +0 -0
  135. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/examples/retry_example.py +0 -0
  136. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/health_monitor.py +0 -0
  137. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/managed_server.py +0 -0
  138. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/manager.py +0 -0
  139. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/mcp_logs.py +0 -0
  140. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/registry.py +0 -0
  141. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/retry_manager.py +0 -0
  142. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/server_registry_catalog.py +0 -0
  143. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/status_tracker.py +0 -0
  144. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/system_tools.py +0 -0
  145. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_prompts/__init__.py +0 -0
  146. {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_prompts/hook_creator.py +0 -0
  147. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/__init__.py +0 -0
  148. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/bus.py +0 -0
  149. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/commands.py +0 -0
  150. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/markdown_patches.py +0 -0
  151. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/message_queue.py +0 -0
  152. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/messages.py +0 -0
  153. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/queue_console.py +0 -0
  154. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/renderers.py +0 -0
  155. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/rich_renderer.py +0 -0
  156. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/spinner/__init__.py +0 -0
  157. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/spinner/console_spinner.py +0 -0
  158. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/spinner/spinner_base.py +0 -0
  159. {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/subagent_console.py +0 -0
  160. {newcode-0.2.6 → newcode-0.2.9}/newcode/model_factory.py +0 -0
  161. {newcode-0.2.6 → newcode-0.2.9}/newcode/model_switching.py +0 -0
  162. {newcode-0.2.6 → newcode-0.2.9}/newcode/model_utils.py +0 -0
  163. {newcode-0.2.6 → newcode-0.2.9}/newcode/models_dev_api.json +0 -0
  164. {newcode-0.2.6 → newcode-0.2.9}/newcode/models_dev_parser.py +0 -0
  165. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/__init__.py +0 -0
  166. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/__init__.py +0 -0
  167. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/config.py +0 -0
  168. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/discovery.py +0 -0
  169. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/downloader.py +0 -0
  170. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/installer.py +0 -0
  171. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/metadata.py +0 -0
  172. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/prompt_builder.py +0 -0
  173. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/register_callbacks.py +0 -0
  174. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/remote_catalog.py +0 -0
  175. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/skill_catalog.py +0 -0
  176. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/skills_install_menu.py +0 -0
  177. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/skills_menu.py +0 -0
  178. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/__init__.py +0 -0
  179. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/accounts.py +0 -0
  180. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/antigravity_model.py +0 -0
  181. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/config.py +0 -0
  182. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/constants.py +0 -0
  183. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/oauth.py +0 -0
  184. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/register_callbacks.py +0 -0
  185. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/storage.py +0 -0
  186. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/test_plugin.py +0 -0
  187. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/token.py +0 -0
  188. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/transport.py +0 -0
  189. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/utils.py +0 -0
  190. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/chatgpt_oauth/__init__.py +0 -0
  191. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/chatgpt_oauth/config.py +0 -0
  192. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/chatgpt_oauth/register_callbacks.py +0 -0
  193. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_hooks/__init__.py +0 -0
  194. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_hooks/config.py +0 -0
  195. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_hooks/register_callbacks.py +0 -0
  196. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/README.md +0 -0
  197. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/SETUP.md +0 -0
  198. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/__init__.py +0 -0
  199. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/config.py +0 -0
  200. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/register_callbacks.py +0 -0
  201. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/test_plugin.py +0 -0
  202. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/token_refresh_heartbeat.py +0 -0
  203. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/customizable_commands/__init__.py +0 -0
  204. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/customizable_commands/register_callbacks.py +0 -0
  205. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/example_custom_command/README.md +0 -0
  206. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/example_custom_command/register_callbacks.py +0 -0
  207. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/file_permission_handler/__init__.py +0 -0
  208. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/file_permission_handler/register_callbacks.py +0 -0
  209. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/frontend_emitter/__init__.py +0 -0
  210. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/frontend_emitter/emitter.py +0 -0
  211. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/frontend_emitter/register_callbacks.py +0 -0
  212. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/hook_creator/__init__.py +0 -0
  213. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/hook_creator/register_callbacks.py +0 -0
  214. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/hook_manager/__init__.py +0 -0
  215. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/hook_manager/config.py +0 -0
  216. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/hook_manager/hooks_menu.py +0 -0
  217. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/hook_manager/register_callbacks.py +0 -0
  218. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/oauth_puppy_html.py +0 -0
  219. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/shell_safety/__init__.py +0 -0
  220. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/shell_safety/agent_shell_safety.py +0 -0
  221. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/shell_safety/command_cache.py +0 -0
  222. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/shell_safety/register_callbacks.py +0 -0
  223. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/synthetic_status/__init__.py +0 -0
  224. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/synthetic_status/register_callbacks.py +0 -0
  225. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/synthetic_status/status_api.py +0 -0
  226. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/universal_constructor/__init__.py +0 -0
  227. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/universal_constructor/models.py +0 -0
  228. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/universal_constructor/register_callbacks.py +0 -0
  229. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/universal_constructor/registry.py +0 -0
  230. {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/universal_constructor/sandbox.py +0 -0
  231. {newcode-0.2.6 → newcode-0.2.9}/newcode/prompts/antigravity_system_prompt.md +0 -0
  232. {newcode-0.2.6 → newcode-0.2.9}/newcode/pydantic_patches.py +0 -0
  233. {newcode-0.2.6 → newcode-0.2.9}/newcode/reopenable_async_client.py +0 -0
  234. {newcode-0.2.6 → newcode-0.2.9}/newcode/round_robin_model.py +0 -0
  235. {newcode-0.2.6 → newcode-0.2.9}/newcode/session_storage.py +0 -0
  236. {newcode-0.2.6 → newcode-0.2.9}/newcode/status_display.py +0 -0
  237. {newcode-0.2.6 → newcode-0.2.9}/newcode/terminal_utils.py +0 -0
  238. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/__init__.py +0 -0
  239. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/__init__.py +0 -0
  240. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/constants.py +0 -0
  241. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/demo_tui.py +0 -0
  242. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/handler.py +0 -0
  243. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/models.py +0 -0
  244. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/registration.py +0 -0
  245. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/renderers.py +0 -0
  246. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/terminal_ui.py +0 -0
  247. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/theme.py +0 -0
  248. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/tui_loop.py +0 -0
  249. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/__init__.py +0 -0
  250. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_control.py +0 -0
  251. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_interactions.py +0 -0
  252. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_locators.py +0 -0
  253. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_manager.py +0 -0
  254. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_navigation.py +0 -0
  255. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_screenshot.py +0 -0
  256. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_scripts.py +0 -0
  257. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_workflows.py +0 -0
  258. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/chromium_terminal_manager.py +0 -0
  259. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/terminal_command_tools.py +0 -0
  260. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/terminal_screenshot_tools.py +0 -0
  261. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/terminal_tools.py +0 -0
  262. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/command_runner.py +0 -0
  263. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/common.py +0 -0
  264. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/display.py +0 -0
  265. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/file_modifications.py +0 -0
  266. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/file_operations.py +0 -0
  267. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/skills_tools.py +0 -0
  268. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/subagent_context.py +0 -0
  269. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/tools_content.py +0 -0
  270. {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/universal_constructor.py +0 -0
  271. {newcode-0.2.6 → newcode-0.2.9}/newcode/uvx_detection.py +0 -0
  272. {newcode-0.2.6 → newcode-0.2.9}/newcode/version_checker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: newcode
3
- Version: 0.2.6
3
+ Version: 0.2.9
4
4
  Summary: AI-powered code generation agent platform
5
5
  Project-URL: repository, https://github.com/janfeddersen-wq/new_code
6
6
  Project-URL: HomePage, https://github.com/janfeddersen-wq/new_code
@@ -17,7 +17,6 @@ Classifier: Programming Language :: Python :: 3.13
17
17
  Classifier: Topic :: Software Development :: Code Generators
18
18
  Requires-Python: <3.14,>=3.11
19
19
  Requires-Dist: anthropic==0.79.0
20
- Requires-Dist: dbos>=2.11.0
21
20
  Requires-Dist: fastapi>=0.109.0
22
21
  Requires-Dist: httpx[http2]>=0.24.1
23
22
  Requires-Dist: json-repair>=0.46.2
@@ -27,7 +27,6 @@ from typing import (
27
27
  import mcp
28
28
  import pydantic
29
29
  import pydantic_ai.models
30
- from dbos import DBOS, SetWorkflowID
31
30
  from pydantic_ai import Agent as PydanticAgent
32
31
  from pydantic_ai import (
33
32
  BinaryContent,
@@ -37,7 +36,6 @@ from pydantic_ai import (
37
36
  UsageLimitExceeded,
38
37
  UsageLimits,
39
38
  )
40
- from pydantic_ai.durable_exec.dbos import DBOSAgent
41
39
  from pydantic_ai.messages import (
42
40
  ModelMessage,
43
41
  ModelRequest,
@@ -67,7 +65,6 @@ from newcode.config import (
67
65
  get_global_model_name,
68
66
  get_message_limit,
69
67
  get_protected_token_count,
70
- get_use_dbos,
71
68
  get_value,
72
69
  )
73
70
  from newcode.error_logging import log_error
@@ -1319,6 +1316,12 @@ class BaseAgent(ABC):
1319
1316
  """Force-reload the pydantic-ai Agent based on current config and model."""
1320
1317
  from newcode.tools import register_tools_for_agent
1321
1318
 
1319
+ # Invalidate the project-local rules cache so a fresh read from the
1320
+ # current working directory is performed on the next load_agent_rules()
1321
+ # call. This is critical for /cd: the user may have switched to a
1322
+ # different project that has its own AGENT.md (or none at all).
1323
+ self._agent_rules = None
1324
+
1322
1325
  if message_group is None:
1323
1326
  message_group = str(uuid.uuid4())
1324
1327
 
@@ -1417,64 +1420,25 @@ class BaseAgent(ABC):
1417
1420
  )
1418
1421
 
1419
1422
  self._last_model_name = resolved_model_name
1420
- # expose for run_with_mcp
1421
- # Wrap it with DBOS, but handle MCP servers separately to avoid serialization issues
1422
1423
  global _reload_count
1423
1424
  _reload_count += 1
1424
- if get_use_dbos():
1425
- # Don't pass MCP servers to the agent constructor when using DBOS
1426
- # This prevents the "cannot pickle async_generator object" error
1427
- # MCP servers will be handled separately in run_with_mcp
1428
- agent_without_mcp = PydanticAgent(
1429
- model=model,
1430
- instructions=instructions,
1431
- output_type=str,
1432
- retries=10,
1433
- toolsets=[], # Don't include MCP servers here
1434
- history_processors=[self.message_history_accumulator],
1435
- model_settings=model_settings,
1436
- )
1437
-
1438
- # Register regular tools (non-MCP) on the new agent
1439
- agent_tools = self.get_available_tools()
1440
- register_tools_for_agent(
1441
- agent_without_mcp, agent_tools, model_name=resolved_model_name
1442
- )
1443
-
1444
- # Wrap with DBOS - pass event_stream_handler at construction time
1445
- # so DBOSModel gets the handler for streaming output
1446
- dbos_agent = DBOSAgent(
1447
- agent_without_mcp,
1448
- name=f"{self.name}-{_reload_count}",
1449
- event_stream_handler=event_stream_handler,
1450
- )
1451
- self.pydantic_agent = dbos_agent
1452
- self._code_generation_agent = dbos_agent
1453
1425
 
1454
- # Store filtered MCP servers separately for runtime use
1455
- self._mcp_servers = filtered_mcp_servers
1456
- else:
1457
- # Normal path without DBOS - include filtered MCP servers in the agent
1458
- # Re-create agent with filtered MCP servers
1459
- p_agent = PydanticAgent(
1460
- model=model,
1461
- instructions=instructions,
1462
- output_type=str,
1463
- retries=10,
1464
- toolsets=filtered_mcp_servers,
1465
- history_processors=[self.message_history_accumulator],
1466
- model_settings=model_settings,
1467
- )
1468
- # Register regular tools on the agent
1469
- agent_tools = self.get_available_tools()
1470
- register_tools_for_agent(
1471
- p_agent, agent_tools, model_name=resolved_model_name
1472
- )
1426
+ p_agent = PydanticAgent(
1427
+ model=model,
1428
+ instructions=instructions,
1429
+ output_type=str,
1430
+ retries=10,
1431
+ toolsets=filtered_mcp_servers,
1432
+ history_processors=[self.message_history_accumulator],
1433
+ model_settings=model_settings,
1434
+ )
1435
+ # Register regular tools on the agent
1436
+ agent_tools = self.get_available_tools()
1437
+ register_tools_for_agent(p_agent, agent_tools, model_name=resolved_model_name)
1473
1438
 
1474
- self.pydantic_agent = p_agent
1475
- self._code_generation_agent = p_agent
1476
- self._mcp_servers = filtered_mcp_servers
1477
- self._mcp_servers = mcp_servers
1439
+ self.pydantic_agent = p_agent
1440
+ self._code_generation_agent = p_agent
1441
+ self._mcp_servers = filtered_mcp_servers
1478
1442
  return self._code_generation_agent
1479
1443
 
1480
1444
  def _create_agent_with_output_type(self, output_type: Type[Any]) -> PydanticAgent:
@@ -1488,7 +1452,7 @@ class BaseAgent(ABC):
1488
1452
  output_type: The Pydantic model or type for structured output.
1489
1453
 
1490
1454
  Returns:
1491
- A configured PydanticAgent (or DBOSAgent wrapper) with the custom output_type.
1455
+ A configured PydanticAgent with the custom output_type.
1492
1456
  """
1493
1457
  from newcode.model_utils import prepare_prompt_for_model
1494
1458
  from newcode.tools import register_tools_for_agent
@@ -1515,45 +1479,21 @@ class BaseAgent(ABC):
1515
1479
  global _reload_count
1516
1480
  _reload_count += 1
1517
1481
 
1518
- if get_use_dbos():
1519
- temp_agent = PydanticAgent(
1520
- model=model,
1521
- instructions=instructions,
1522
- output_type=output_type,
1523
- retries=10,
1524
- toolsets=[],
1525
- history_processors=[self.message_history_accumulator],
1526
- model_settings=model_settings,
1527
- )
1528
- agent_tools = self.get_available_tools()
1529
- register_tools_for_agent(
1530
- temp_agent, agent_tools, model_name=resolved_model_name
1531
- )
1532
- # Pass event_stream_handler at construction time for streaming output
1533
- dbos_agent = DBOSAgent(
1534
- temp_agent,
1535
- name=f"{self.name}-structured-{_reload_count}",
1536
- event_stream_handler=event_stream_handler,
1537
- )
1538
- return dbos_agent
1539
- else:
1540
- temp_agent = PydanticAgent(
1541
- model=model,
1542
- instructions=instructions,
1543
- output_type=output_type,
1544
- retries=10,
1545
- toolsets=mcp_servers,
1546
- history_processors=[self.message_history_accumulator],
1547
- model_settings=model_settings,
1548
- )
1549
- agent_tools = self.get_available_tools()
1550
- register_tools_for_agent(
1551
- temp_agent, agent_tools, model_name=resolved_model_name
1552
- )
1553
- return temp_agent
1482
+ temp_agent = PydanticAgent(
1483
+ model=model,
1484
+ instructions=instructions,
1485
+ output_type=output_type,
1486
+ retries=10,
1487
+ toolsets=mcp_servers,
1488
+ history_processors=[self.message_history_accumulator],
1489
+ model_settings=model_settings,
1490
+ )
1491
+ agent_tools = self.get_available_tools()
1492
+ register_tools_for_agent(
1493
+ temp_agent, agent_tools, model_name=resolved_model_name
1494
+ )
1495
+ return temp_agent
1554
1496
 
1555
- # It's okay to decorate it with DBOS.step even if not using DBOS; the decorator is a no-op in that case.
1556
- @DBOS.step()
1557
1497
  def message_history_accumulator(self, ctx: RunContext, messages: List[Any]):
1558
1498
  _message_history = self.get_message_history()
1559
1499
 
@@ -1908,51 +1848,14 @@ class BaseAgent(ABC):
1908
1848
 
1909
1849
  usage_limits = UsageLimits(request_limit=get_message_limit())
1910
1850
 
1911
- # Handle MCP servers - add them temporarily when using DBOS
1912
- if (
1913
- get_use_dbos()
1914
- and hasattr(self, "_mcp_servers")
1915
- and self._mcp_servers
1916
- ):
1917
- # Temporarily add MCP servers to the DBOS agent using internal _toolsets
1918
- original_toolsets = pydantic_agent._toolsets
1919
- pydantic_agent._toolsets = original_toolsets + self._mcp_servers
1920
- pydantic_agent._toolsets = original_toolsets + self._mcp_servers
1921
-
1922
- try:
1923
- # Set the workflow ID for DBOS context so DBOS and the agent ID match
1924
- with SetWorkflowID(group_id):
1925
- result_ = await pydantic_agent.run(
1926
- prompt_payload,
1927
- message_history=self.get_message_history(),
1928
- usage_limits=usage_limits,
1929
- event_stream_handler=event_stream_handler,
1930
- **kwargs,
1931
- )
1932
- return result_
1933
- finally:
1934
- # Always restore original toolsets
1935
- pydantic_agent._toolsets = original_toolsets
1936
- elif get_use_dbos():
1937
- with SetWorkflowID(group_id):
1938
- result_ = await pydantic_agent.run(
1939
- prompt_payload,
1940
- message_history=self.get_message_history(),
1941
- usage_limits=usage_limits,
1942
- event_stream_handler=event_stream_handler,
1943
- **kwargs,
1944
- )
1945
- return result_
1946
- else:
1947
- # Non-DBOS path (MCP servers are already included)
1948
- result_ = await pydantic_agent.run(
1949
- prompt_payload,
1950
- message_history=self.get_message_history(),
1951
- usage_limits=usage_limits,
1952
- event_stream_handler=event_stream_handler,
1953
- **kwargs,
1954
- )
1955
- return result_
1851
+ result_ = await pydantic_agent.run(
1852
+ prompt_payload,
1853
+ message_history=self.get_message_history(),
1854
+ usage_limits=usage_limits,
1855
+ event_stream_handler=event_stream_handler,
1856
+ **kwargs,
1857
+ )
1858
+ return result_
1956
1859
  except* UsageLimitExceeded as ule:
1957
1860
  emit_info(f"Usage limit exceeded: {str(ule)}", group_id=group_id)
1958
1861
  emit_info(
@@ -1968,12 +1871,8 @@ class BaseAgent(ABC):
1968
1871
  )
1969
1872
  except* asyncio.exceptions.CancelledError:
1970
1873
  emit_info("Cancelled")
1971
- if get_use_dbos():
1972
- await DBOS.cancel_workflow_async(group_id)
1973
1874
  except* InterruptedError as ie:
1974
1875
  emit_info(f"Interrupted: {str(ie)}")
1975
- if get_use_dbos():
1976
- await DBOS.cancel_workflow_async(group_id)
1977
1876
  except* Exception as other_error:
1978
1877
 
1979
1878
  def contains_cloudflare_auth_error(exc: Exception) -> bool:
@@ -371,7 +371,7 @@ class ClaudeCacheAsyncClient(httpx.AsyncClient):
371
371
  is_auth_error = response.status_code in (401, 403)
372
372
 
373
373
  if response.status_code == 400:
374
- is_auth_error = self._is_cloudflare_html_error(response)
374
+ is_auth_error = await self._is_cloudflare_html_error(response)
375
375
  if is_auth_error:
376
376
  logger.info(
377
377
  "Detected Cloudflare 400 error (expired token), attempting token refresh"
@@ -531,7 +531,7 @@ class ClaudeCacheAsyncClient(httpx.AsyncClient):
531
531
  headers["Authorization"] = bearer_value
532
532
 
533
533
  @staticmethod
534
- def _is_cloudflare_html_error(response: httpx.Response) -> bool:
534
+ async def _is_cloudflare_html_error(response: httpx.Response) -> bool:
535
535
  """Check if this is a Cloudflare HTML error response.
536
536
 
537
537
  Cloudflare often returns HTML error pages with status 400 when
@@ -546,10 +546,20 @@ class ClaudeCacheAsyncClient(httpx.AsyncClient):
546
546
  """
547
547
  try:
548
548
  body = None
549
- # Try reading the body from _content first (already consumed)
549
+
550
+ # For async httpx, read the body if content is not available yet.
551
+ if not hasattr(response, "_content") or not response._content:
552
+ try:
553
+ await response.aread()
554
+ except Exception as read_exc:
555
+ logger.debug("Failed to read response body: %s", read_exc)
556
+ return False
557
+
558
+ # Prefer raw _content if present (already consumed responses).
550
559
  if hasattr(response, "_content") and response._content:
551
560
  body = response._content.decode("utf-8", errors="ignore")
552
561
  else:
562
+ # Fallback to text property.
553
563
  try:
554
564
  body = response.text
555
565
  except Exception:
@@ -12,10 +12,8 @@ import argparse
12
12
  import asyncio
13
13
  import os
14
14
  import sys
15
- import time
16
15
  from pathlib import Path
17
16
 
18
- from dbos import DBOS, DBOSConfig
19
17
  from rich.console import Console
20
18
 
21
19
  from newcode import __version__, callbacks, plugins
@@ -25,10 +23,8 @@ from newcode.command_line.clipboard import get_clipboard_manager
25
23
  from newcode.config import (
26
24
  AUTOSAVE_DIR,
27
25
  COMMAND_HISTORY_FILE,
28
- DBOS_DATABASE_URL,
29
26
  ensure_config_exists,
30
27
  finalize_autosave_session,
31
- get_use_dbos,
32
28
  initialize_command_history_file,
33
29
  save_command_to_history,
34
30
  )
@@ -271,33 +267,6 @@ async def main():
271
267
 
272
268
  await callbacks.on_startup()
273
269
 
274
- # Initialize DBOS if not disabled
275
- if get_use_dbos():
276
- # Append a Unix timestamp in ms to the version for uniqueness
277
- dbos_app_version = os.environ.get(
278
- "DBOS_APP_VERSION", f"{current_version}-{int(time.time() * 1000)}"
279
- )
280
- dbos_config: DBOSConfig = {
281
- "name": "dbos-code-agent",
282
- "system_database_url": DBOS_DATABASE_URL,
283
- "run_admin_server": False,
284
- "conductor_key": os.environ.get(
285
- "DBOS_CONDUCTOR_KEY"
286
- ), # Optional, if set in env, connect to conductor
287
- "log_level": os.environ.get(
288
- "DBOS_LOG_LEVEL", "ERROR"
289
- ), # Default to ERROR level to suppress verbose logs
290
- "application_version": dbos_app_version, # Match DBOS app version
291
- }
292
- try:
293
- DBOS(config=dbos_config)
294
- DBOS.launch()
295
- except Exception as e:
296
- emit_error(f"Error initializing DBOS: {e}")
297
- sys.exit(1)
298
- else:
299
- pass
300
-
301
270
  global shutdown_flag
302
271
  shutdown_flag = False
303
272
  try:
@@ -322,8 +291,6 @@ async def main():
322
291
  if bus_renderer:
323
292
  bus_renderer.stop()
324
293
  await callbacks.on_shutdown()
325
- if get_use_dbos():
326
- DBOS.destroy()
327
294
 
328
295
 
329
296
  async def interactive_mode(message_renderer, initial_command: str = None) -> None:
@@ -981,8 +948,6 @@ def main_entry():
981
948
  asyncio.run(main())
982
949
  except KeyboardInterrupt:
983
950
  # Normal exit via Ctrl+C – not a crash, so just clean up quietly
984
- if get_use_dbos():
985
- DBOS.destroy()
986
951
  return 0
987
952
  finally:
988
953
  # Reset terminal on Unix-like systems (not Windows)
@@ -42,7 +42,6 @@ def handle_show_command(command: str) -> bool:
42
42
  get_protected_token_count,
43
43
  get_resume_message_count,
44
44
  get_temperature,
45
- get_use_dbos,
46
45
  get_yolo_mode,
47
46
  )
48
47
  from newcode.keymap import (
@@ -69,7 +68,6 @@ def handle_show_command(command: str) -> bool:
69
68
  [bold]default_agent:[/bold] [cyan]{default_agent}[/cyan]
70
69
  [bold]model:[/bold] [green]{model}[/green]
71
70
  [bold]YOLO_MODE:[/bold] {"[red]ON[/red]" if yolo_mode else "[yellow]off[/yellow]"}
72
- [bold]DBOS:[/bold] {"[green]enabled[/green]" if get_use_dbos() else "[yellow]disabled[/yellow]"} (toggle: /set enable_dbos true|false)
73
71
  [bold]auto_save_session:[/bold] {"[green]enabled[/green]" if auto_save else "[yellow]disabled[/yellow]"}
74
72
  [bold]protected_tokens:[/bold] [cyan]{protected_tokens:,}[/cyan] recent tokens preserved
75
73
  [bold]compaction_threshold:[/bold] [cyan]{compaction_threshold:.1%}[/cyan] context usage triggers compaction
@@ -211,14 +209,6 @@ def handle_set_command(command: str) -> bool:
211
209
  )
212
210
  return True
213
211
  if key:
214
- # Check if we're toggling DBOS enablement
215
- if key == "enable_dbos":
216
- emit_info(
217
- Text.from_markup(
218
- "[yellow]⚠️ DBOS configuration changed. Please restart the application for this change to take effect.[/yellow]"
219
- )
220
- )
221
-
222
212
  # Validate cancel_agent_key before setting
223
213
  if key == "cancel_agent_key":
224
214
  from newcode.keymap import VALID_CANCEL_KEYS
@@ -55,7 +55,7 @@ def handle_cd_command(command: str) -> bool:
55
55
  # Use shlex.split to handle quoted paths properly
56
56
  import shlex
57
57
 
58
- from newcode.messaging import emit_error, emit_info, emit_success
58
+ from newcode.messaging import emit_error, emit_info, emit_success, emit_warning
59
59
 
60
60
  try:
61
61
  tokens = shlex.split(command)
@@ -77,6 +77,20 @@ def handle_cd_command(command: str) -> bool:
77
77
  if os.path.isdir(target):
78
78
  os.chdir(target)
79
79
  emit_success(f"Changed directory to: {target}")
80
+ # Reload the agent so the system prompt and project-local
81
+ # AGENT.md rules reflect the new working directory. Without
82
+ # this, the LLM keeps receiving stale path information for the
83
+ # remainder of the session (the PydanticAgent instructions are
84
+ # baked in at construction time and never refreshed otherwise).
85
+ try:
86
+ from newcode.agents import get_current_agent
87
+
88
+ get_current_agent().reload_code_generation_agent()
89
+ except Exception as e:
90
+ emit_warning(
91
+ f"Directory changed, but agent reload failed: {e}. "
92
+ "You may need to run /agent or /model to force a refresh."
93
+ )
80
94
  else:
81
95
  emit_error(f"Not a directory: {dirname}")
82
96
  return True
@@ -49,7 +49,6 @@ EXTRA_MODELS_FILE = os.path.join(DATA_DIR, "extra_models.json")
49
49
  AGENTS_DIR = os.path.join(DATA_DIR, "agents")
50
50
  SKILLS_DIR = os.path.join(DATA_DIR, "skills")
51
51
  CONTEXTS_DIR = os.path.join(DATA_DIR, "contexts")
52
- _DEFAULT_SQLITE_FILE = os.path.join(DATA_DIR, "dbos_store.sqlite")
53
52
 
54
53
  # OAuth plugin model files (XDG_DATA_HOME)
55
54
  GEMINI_MODELS_FILE = os.path.join(DATA_DIR, "gemini_models.json")
@@ -62,19 +61,6 @@ AUTOSAVE_DIR = os.path.join(CACHE_DIR, "autosaves")
62
61
 
63
62
  # State files (XDG_STATE_HOME)
64
63
  COMMAND_HISTORY_FILE = os.path.join(STATE_DIR, "command_history.txt")
65
- DBOS_DATABASE_URL = os.environ.get(
66
- "DBOS_SYSTEM_DATABASE_URL", f"sqlite:///{_DEFAULT_SQLITE_FILE}"
67
- )
68
- # DBOS enable switch is controlled solely via puppy.cfg using key 'enable_dbos'.
69
- # Default: True (DBOS enabled) unless explicitly disabled.
70
-
71
-
72
- def get_use_dbos() -> bool:
73
- """Return True if DBOS should be used based on 'enable_dbos' (default True)."""
74
- cfg_val = get_value("enable_dbos")
75
- if cfg_val is None:
76
- return True
77
- return str(cfg_val).strip().lower() in {"1", "true", "yes", "on"}
78
64
 
79
65
 
80
66
  def get_subagent_verbose() -> bool:
@@ -288,8 +274,6 @@ def get_config_keys():
288
274
  "frontend_emitter_max_recent_events",
289
275
  "frontend_emitter_queue_size",
290
276
  ]
291
- # Add DBOS control key
292
- default_keys.append("enable_dbos")
293
277
  # Add pack agents control key
294
278
  default_keys.append("enable_pack_agents")
295
279
  # Add universal constructor control key
@@ -1193,11 +1177,6 @@ def set_http2(enabled: bool) -> None:
1193
1177
  set_config_value("http2", "true" if enabled else "false")
1194
1178
 
1195
1179
 
1196
- def set_enable_dbos(enabled: bool) -> None:
1197
- """Enable DBOS via config (true enables, default false)."""
1198
- set_config_value("enable_dbos", "true" if enabled else "false")
1199
-
1200
-
1201
1180
  def get_message_limit(default: int = 1000) -> int:
1202
1181
  """
1203
1182
  Returns the user-configured message/request limit for the agent.
@@ -193,7 +193,7 @@ def _substitute_variables(
193
193
  result = command
194
194
  for var, value in substitutions.items():
195
195
  result = result.replace(f"${{{var}}}", str(value))
196
- result = re.sub(rf"\${re.escape(var)}(?=\W|$)", str(value), result)
196
+ result = re.sub(rf"\${re.escape(var)}(?=\W|$)", lambda m: str(value), result)
197
197
  return result
198
198
 
199
199
 
@@ -9,9 +9,9 @@
9
9
  "context_length": 200000,
10
10
  "supported_settings": ["temperature", "seed", "top_p"]
11
11
  },
12
- "synthetic-MiniMax-M2.1": {
12
+ "synthetic-MiniMax-M2.5": {
13
13
  "type": "custom_openai",
14
- "name": "hf:MiniMaxAI/MiniMax-M2.1",
14
+ "name": "hf:MiniMaxAI/MiniMax-M2.5",
15
15
  "custom_endpoint": {
16
16
  "url": "https://api.synthetic.new/openai/v1/",
17
17
  "api_key": "$SYN_API_KEY"
@@ -19,9 +19,9 @@
19
19
  "context_length": 195000,
20
20
  "supported_settings": ["temperature", "seed", "top_p"]
21
21
  },
22
- "synthetic-Kimi-K2-Thinking": {
22
+ "synthetic-qwen3.5-397b": {
23
23
  "type": "custom_openai",
24
- "name": "hf:moonshotai/Kimi-K2-Thinking",
24
+ "name": "hf:Qwen/Qwen3.5-397B-A17B",
25
25
  "custom_endpoint": {
26
26
  "url": "https://api.synthetic.new/openai/v1/",
27
27
  "api_key": "$SYN_API_KEY"
@@ -318,9 +318,10 @@ def run_oauth_flow() -> None:
318
318
 
319
319
  if api_key:
320
320
  emit_info("Registering ChatGPT Codex models…")
321
- from .utils import DEFAULT_CODEX_MODELS
321
+ from .utils import fetch_chatgpt_models
322
322
 
323
- models = DEFAULT_CODEX_MODELS
323
+ account_id = tokens.get("account_id", "")
324
+ models = fetch_chatgpt_models(api_key, account_id)
324
325
  if models:
325
326
  if add_models_to_extra_config(models):
326
327
  emit_success(
@@ -251,6 +251,10 @@ def test_fetch_chatgpt_models(mock_get):
251
251
 
252
252
  models = utils.fetch_chatgpt_models("test_access_token", "test_account_id")
253
253
  assert models is not None
254
+ # Required models always injected
255
+ assert "gpt-5.4" in models
256
+ assert "gpt-5.3-instant" in models
257
+ # API-returned models present too
254
258
  assert "gpt-4o" in models
255
259
  assert "gpt-3.5-turbo" in models
256
260
  assert "o1-preview" in models
@@ -267,7 +271,9 @@ def test_fetch_chatgpt_models_fallback(mock_get):
267
271
 
268
272
  models = utils.fetch_chatgpt_models("test_access_token", "test_account_id")
269
273
  assert models is not None
270
- # Should return default models
274
+ # Should return default models (including new required ones)
275
+ assert "gpt-5.4" in models
276
+ assert "gpt-5.3-instant" in models
271
277
  assert "gpt-5.3-codex-spark" in models
272
278
  assert "gpt-5.3-codex" in models
273
279
  assert "gpt-5.2-codex" in models
@@ -344,19 +344,43 @@ def exchange_code_for_tokens(
344
344
  # These are the known models that work with ChatGPT OAuth tokens
345
345
  # Based on codex-rs CLI and shell-scripts/codex-call.sh
346
346
  DEFAULT_CODEX_MODELS = [
347
+ "gpt-5.4",
348
+ "gpt-5.3-instant",
347
349
  "gpt-5.3-codex-spark",
348
350
  "gpt-5.3-codex",
349
351
  "gpt-5.2-codex",
350
352
  "gpt-5.2",
351
353
  ]
352
354
 
355
+ # Models that MUST always be registered, even if the /models endpoint
356
+ # doesn't return them (e.g. newly launched, not yet in the API catalogue).
357
+ # These are merged into whatever the endpoint returns.
358
+ REQUIRED_CODEX_MODELS = [
359
+ "gpt-5.4",
360
+ "gpt-5.3-instant",
361
+ "gpt-5.3-codex",
362
+ ]
363
+
353
364
  # Per-model context length overrides (tokens).
354
365
  # Models not listed here use CHATGPT_OAUTH_CONFIG["default_context_length"] (272,000).
355
366
  CODEX_MODEL_CONTEXT_LENGTHS = {
356
367
  "gpt-5.3-codex-spark": 131000,
368
+ "gpt-5.3-instant": 192000,
357
369
  }
358
370
 
359
371
 
372
+ def _ensure_required_models(models: List[str]) -> List[str]:
373
+ """Merge REQUIRED_CODEX_MODELS into the given list, preserving order.
374
+
375
+ Any required model not already present is prepended so it appears first.
376
+ """
377
+ existing = set(models)
378
+ missing = [m for m in REQUIRED_CODEX_MODELS if m not in existing]
379
+ if missing:
380
+ logger.info("Injecting required models not returned by API: %s", missing)
381
+ return missing + models
382
+
383
+
360
384
  def fetch_chatgpt_models(access_token: str, account_id: str) -> Optional[List[str]]:
361
385
  """Fetch available models from ChatGPT Codex API.
362
386
 
@@ -419,7 +443,7 @@ def fetch_chatgpt_models(access_token: str, account_id: str) -> Optional[List[st
419
443
  if model_id:
420
444
  models.append(model_id)
421
445
  if models:
422
- return models
446
+ return _ensure_required_models(models)
423
447
  except (json.JSONDecodeError, ValueError) as exc:
424
448
  logger.warning("Failed to parse models response: %s", exc)
425
449