spruce-grove 1.0.1__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 (292) hide show
  1. spruce_grove-1.0.1/.gitignore +70 -0
  2. spruce_grove-1.0.1/LICENSE +21 -0
  3. spruce_grove-1.0.1/PKG-INFO +194 -0
  4. spruce_grove-1.0.1/README.md +139 -0
  5. spruce_grove-1.0.1/pyproject.toml +121 -0
  6. spruce_grove-1.0.1/spruce_grove/__init__.py +42 -0
  7. spruce_grove-1.0.1/spruce_grove/__main__.py +10 -0
  8. spruce_grove-1.0.1/spruce_grove/_code_puppy_compat.py +103 -0
  9. spruce_grove-1.0.1/spruce_grove/_pydantic_tool_helpers.py +103 -0
  10. spruce_grove-1.0.1/spruce_grove/agent_execution_context.py +40 -0
  11. spruce_grove-1.0.1/spruce_grove/agents/__init__.py +34 -0
  12. spruce_grove-1.0.1/spruce_grove/agents/_builder.py +796 -0
  13. spruce_grove-1.0.1/spruce_grove/agents/_compaction.py +403 -0
  14. spruce_grove-1.0.1/spruce_grove/agents/_diagnostics.py +173 -0
  15. spruce_grove-1.0.1/spruce_grove/agents/_history.py +650 -0
  16. spruce_grove-1.0.1/spruce_grove/agents/_key_listeners.py +1013 -0
  17. spruce_grove-1.0.1/spruce_grove/agents/_model_message_transform.py +28 -0
  18. spruce_grove-1.0.1/spruce_grove/agents/_non_streaming_render.py +149 -0
  19. spruce_grove-1.0.1/spruce_grove/agents/_output_limits.py +78 -0
  20. spruce_grove-1.0.1/spruce_grove/agents/_run_signals.py +310 -0
  21. spruce_grove-1.0.1/spruce_grove/agents/_runtime.py +1224 -0
  22. spruce_grove-1.0.1/spruce_grove/agents/_steer_processor.py +94 -0
  23. spruce_grove-1.0.1/spruce_grove/agents/_subagent_recursion.py +114 -0
  24. spruce_grove-1.0.1/spruce_grove/agents/agent_code_puppy.py +14 -0
  25. spruce_grove-1.0.1/spruce_grove/agents/agent_creator_agent.py +711 -0
  26. spruce_grove-1.0.1/spruce_grove/agents/agent_helios.py +123 -0
  27. spruce_grove-1.0.1/spruce_grove/agents/agent_manager.py +847 -0
  28. spruce_grove-1.0.1/spruce_grove/agents/agent_model_judge.py +197 -0
  29. spruce_grove-1.0.1/spruce_grove/agents/agent_planning.py +163 -0
  30. spruce_grove-1.0.1/spruce_grove/agents/agent_qa_kitten.py +248 -0
  31. spruce_grove-1.0.1/spruce_grove/agents/agent_spruce_grove.py +163 -0
  32. spruce_grove-1.0.1/spruce_grove/agents/agent_web_retriever.py +258 -0
  33. spruce_grove-1.0.1/spruce_grove/agents/base_agent.py +371 -0
  34. spruce_grove-1.0.1/spruce_grove/agents/event_stream_handler.py +572 -0
  35. spruce_grove-1.0.1/spruce_grove/agents/json_agent.py +398 -0
  36. spruce_grove-1.0.1/spruce_grove/agents/retry_checkpoint.py +62 -0
  37. spruce_grove-1.0.1/spruce_grove/agents/retry_profiles.py +281 -0
  38. spruce_grove-1.0.1/spruce_grove/agents/run_stats.py +684 -0
  39. spruce_grove-1.0.1/spruce_grove/agents/smooth_stream.py +130 -0
  40. spruce_grove-1.0.1/spruce_grove/agents/subagent_stream_handler.py +277 -0
  41. spruce_grove-1.0.1/spruce_grove/asyncio_cleanup.py +71 -0
  42. spruce_grove-1.0.1/spruce_grove/atomic_io.py +269 -0
  43. spruce_grove-1.0.1/spruce_grove/atomic_json.py +129 -0
  44. spruce_grove-1.0.1/spruce_grove/callbacks.py +1740 -0
  45. spruce_grove-1.0.1/spruce_grove/chatgpt_codex_client.py +437 -0
  46. spruce_grove-1.0.1/spruce_grove/claude_cache_client.py +498 -0
  47. spruce_grove-1.0.1/spruce_grove/claude_oauth_transport.py +285 -0
  48. spruce_grove-1.0.1/spruce_grove/cli_runner.py +1627 -0
  49. spruce_grove-1.0.1/spruce_grove/command_line/__init__.py +1 -0
  50. spruce_grove-1.0.1/spruce_grove/command_line/add_model_details.py +144 -0
  51. spruce_grove-1.0.1/spruce_grove/command_line/add_model_menu.py +602 -0
  52. spruce_grove-1.0.1/spruce_grove/command_line/agent_menu.py +471 -0
  53. spruce_grove-1.0.1/spruce_grove/command_line/attachments.py +491 -0
  54. spruce_grove-1.0.1/spruce_grove/command_line/autosave_menu.py +112 -0
  55. spruce_grove-1.0.1/spruce_grove/command_line/autosave_search.py +178 -0
  56. spruce_grove-1.0.1/spruce_grove/command_line/clipboard.py +472 -0
  57. spruce_grove-1.0.1/spruce_grove/command_line/colors_menu.py +102 -0
  58. spruce_grove-1.0.1/spruce_grove/command_line/command_handler.py +304 -0
  59. spruce_grove-1.0.1/spruce_grove/command_line/command_registry.py +186 -0
  60. spruce_grove-1.0.1/spruce_grove/command_line/completers.py +436 -0
  61. spruce_grove-1.0.1/spruce_grove/command_line/completion_cache.py +37 -0
  62. spruce_grove-1.0.1/spruce_grove/command_line/config_apply.py +154 -0
  63. spruce_grove-1.0.1/spruce_grove/command_line/config_commands.py +477 -0
  64. spruce_grove-1.0.1/spruce_grove/command_line/core_commands.py +745 -0
  65. spruce_grove-1.0.1/spruce_grove/command_line/file_index.py +157 -0
  66. spruce_grove-1.0.1/spruce_grove/command_line/file_path_completion.py +184 -0
  67. spruce_grove-1.0.1/spruce_grove/command_line/help_catalog.py +266 -0
  68. spruce_grove-1.0.1/spruce_grove/command_line/help_overlay.py +100 -0
  69. spruce_grove-1.0.1/spruce_grove/command_line/image_utils.py +198 -0
  70. spruce_grove-1.0.1/spruce_grove/command_line/load_context_completion.py +52 -0
  71. spruce_grove-1.0.1/spruce_grove/command_line/mcp/__init__.py +10 -0
  72. spruce_grove-1.0.1/spruce_grove/command_line/mcp/base.py +32 -0
  73. spruce_grove-1.0.1/spruce_grove/command_line/mcp/catalog_server_installer.py +175 -0
  74. spruce_grove-1.0.1/spruce_grove/command_line/mcp/custom_server_form.py +544 -0
  75. spruce_grove-1.0.1/spruce_grove/command_line/mcp/custom_server_installer.py +192 -0
  76. spruce_grove-1.0.1/spruce_grove/command_line/mcp/edit_command.py +148 -0
  77. spruce_grove-1.0.1/spruce_grove/command_line/mcp/handler.py +141 -0
  78. spruce_grove-1.0.1/spruce_grove/command_line/mcp/help_command.py +153 -0
  79. spruce_grove-1.0.1/spruce_grove/command_line/mcp/install_command.py +214 -0
  80. spruce_grove-1.0.1/spruce_grove/command_line/mcp/install_menu.py +320 -0
  81. spruce_grove-1.0.1/spruce_grove/command_line/mcp/list_command.py +94 -0
  82. spruce_grove-1.0.1/spruce_grove/command_line/mcp/logs_command.py +235 -0
  83. spruce_grove-1.0.1/spruce_grove/command_line/mcp/mcp_servers_store.py +74 -0
  84. spruce_grove-1.0.1/spruce_grove/command_line/mcp/remove_command.py +86 -0
  85. spruce_grove-1.0.1/spruce_grove/command_line/mcp/restart_command.py +100 -0
  86. spruce_grove-1.0.1/spruce_grove/command_line/mcp/search_command.py +123 -0
  87. spruce_grove-1.0.1/spruce_grove/command_line/mcp/silence_warning_command.py +91 -0
  88. spruce_grove-1.0.1/spruce_grove/command_line/mcp/start_all_command.py +135 -0
  89. spruce_grove-1.0.1/spruce_grove/command_line/mcp/start_command.py +151 -0
  90. spruce_grove-1.0.1/spruce_grove/command_line/mcp/status_command.py +184 -0
  91. spruce_grove-1.0.1/spruce_grove/command_line/mcp/stop_all_command.py +112 -0
  92. spruce_grove-1.0.1/spruce_grove/command_line/mcp/stop_command.py +80 -0
  93. spruce_grove-1.0.1/spruce_grove/command_line/mcp/trust_command.py +216 -0
  94. spruce_grove-1.0.1/spruce_grove/command_line/mcp/utils.py +129 -0
  95. spruce_grove-1.0.1/spruce_grove/command_line/mcp/wizard_utils.py +328 -0
  96. spruce_grove-1.0.1/spruce_grove/command_line/mcp_binding_menu.py +249 -0
  97. spruce_grove-1.0.1/spruce_grove/command_line/mcp_completion.py +173 -0
  98. spruce_grove-1.0.1/spruce_grove/command_line/menu_session.py +72 -0
  99. spruce_grove-1.0.1/spruce_grove/command_line/model_picker_completion.py +411 -0
  100. spruce_grove-1.0.1/spruce_grove/command_line/model_settings_defs.py +420 -0
  101. spruce_grove-1.0.1/spruce_grove/command_line/model_settings_menu.py +497 -0
  102. spruce_grove-1.0.1/spruce_grove/command_line/onboarding_slides.py +192 -0
  103. spruce_grove-1.0.1/spruce_grove/command_line/onboarding_wizard.py +413 -0
  104. spruce_grove-1.0.1/spruce_grove/command_line/pagination.py +43 -0
  105. spruce_grove-1.0.1/spruce_grove/command_line/pin_command_completion.py +361 -0
  106. spruce_grove-1.0.1/spruce_grove/command_line/refresh_models.py +140 -0
  107. spruce_grove-1.0.1/spruce_grove/command_line/session_browser.py +604 -0
  108. spruce_grove-1.0.1/spruce_grove/command_line/session_browser_data.py +418 -0
  109. spruce_grove-1.0.1/spruce_grove/command_line/session_commands.py +513 -0
  110. spruce_grove-1.0.1/spruce_grove/command_line/set_menu.py +440 -0
  111. spruce_grove-1.0.1/spruce_grove/command_line/set_menu_catalog.py +662 -0
  112. spruce_grove-1.0.1/spruce_grove/command_line/set_menu_schema.py +33 -0
  113. spruce_grove-1.0.1/spruce_grove/command_line/set_menu_settings.py +26 -0
  114. spruce_grove-1.0.1/spruce_grove/command_line/set_menu_shims.py +46 -0
  115. spruce_grove-1.0.1/spruce_grove/command_line/set_menu_values.py +126 -0
  116. spruce_grove-1.0.1/spruce_grove/command_line/shell_passthrough.py +150 -0
  117. spruce_grove-1.0.1/spruce_grove/command_line/skills_completion.py +160 -0
  118. spruce_grove-1.0.1/spruce_grove/command_line/tui_style.py +44 -0
  119. spruce_grove-1.0.1/spruce_grove/command_line/uc_menu.py +376 -0
  120. spruce_grove-1.0.1/spruce_grove/command_line/utils.py +104 -0
  121. spruce_grove-1.0.1/spruce_grove/config.py +3251 -0
  122. spruce_grove-1.0.1/spruce_grove/config_file.py +158 -0
  123. spruce_grove-1.0.1/spruce_grove/diagnostics.py +124 -0
  124. spruce_grove-1.0.1/spruce_grove/error_logging.py +134 -0
  125. spruce_grove-1.0.1/spruce_grove/file_completion_io.py +59 -0
  126. spruce_grove-1.0.1/spruce_grove/file_completion_tokens.py +42 -0
  127. spruce_grove-1.0.1/spruce_grove/gemini_code_assist.py +396 -0
  128. spruce_grove-1.0.1/spruce_grove/gemini_model.py +968 -0
  129. spruce_grove-1.0.1/spruce_grove/hook_engine/README.md +105 -0
  130. spruce_grove-1.0.1/spruce_grove/hook_engine/__init__.py +21 -0
  131. spruce_grove-1.0.1/spruce_grove/hook_engine/aliases.py +156 -0
  132. spruce_grove-1.0.1/spruce_grove/hook_engine/engine.py +221 -0
  133. spruce_grove-1.0.1/spruce_grove/hook_engine/executor.py +544 -0
  134. spruce_grove-1.0.1/spruce_grove/hook_engine/matcher.py +156 -0
  135. spruce_grove-1.0.1/spruce_grove/hook_engine/models.py +240 -0
  136. spruce_grove-1.0.1/spruce_grove/hook_engine/registry.py +106 -0
  137. spruce_grove-1.0.1/spruce_grove/hook_engine/validator.py +144 -0
  138. spruce_grove-1.0.1/spruce_grove/http_retry.py +138 -0
  139. spruce_grove-1.0.1/spruce_grove/http_utils.py +277 -0
  140. spruce_grove-1.0.1/spruce_grove/httpx2_utils.py +67 -0
  141. spruce_grove-1.0.1/spruce_grove/i18n/__init__.py +79 -0
  142. spruce_grove-1.0.1/spruce_grove/i18n/audit.py +336 -0
  143. spruce_grove-1.0.1/spruce_grove/i18n/catalog.py +213 -0
  144. spruce_grove-1.0.1/spruce_grove/i18n/formats.py +90 -0
  145. spruce_grove-1.0.1/spruce_grove/i18n/locale.py +147 -0
  146. spruce_grove-1.0.1/spruce_grove/i18n/locales/en-US.json +390 -0
  147. spruce_grove-1.0.1/spruce_grove/i18n/locales/es.json +257 -0
  148. spruce_grove-1.0.1/spruce_grove/i18n/locales/fr-CA.json +257 -0
  149. spruce_grove-1.0.1/spruce_grove/i18n/plurals.py +71 -0
  150. spruce_grove-1.0.1/spruce_grove/i18n/pseudo.py +108 -0
  151. spruce_grove-1.0.1/spruce_grove/i18n/translate.py +199 -0
  152. spruce_grove-1.0.1/spruce_grove/kennel_provider.py +39 -0
  153. spruce_grove-1.0.1/spruce_grove/keymap.py +154 -0
  154. spruce_grove-1.0.1/spruce_grove/list_filtering.py +26 -0
  155. spruce_grove-1.0.1/spruce_grove/main.py +23 -0
  156. spruce_grove-1.0.1/spruce_grove/mcp_/__init__.py +66 -0
  157. spruce_grove-1.0.1/spruce_grove/mcp_/agent_bindings.py +289 -0
  158. spruce_grove-1.0.1/spruce_grove/mcp_/async_lifecycle.py +306 -0
  159. spruce_grove-1.0.1/spruce_grove/mcp_/blocking_startup.py +381 -0
  160. spruce_grove-1.0.1/spruce_grove/mcp_/circuit_breaker.py +287 -0
  161. spruce_grove-1.0.1/spruce_grove/mcp_/config_wizard.py +536 -0
  162. spruce_grove-1.0.1/spruce_grove/mcp_/dashboard.py +308 -0
  163. spruce_grove-1.0.1/spruce_grove/mcp_/error_isolation.py +407 -0
  164. spruce_grove-1.0.1/spruce_grove/mcp_/examples/retry_example.py +226 -0
  165. spruce_grove-1.0.1/spruce_grove/mcp_/health_monitor.py +582 -0
  166. spruce_grove-1.0.1/spruce_grove/mcp_/managed_server.py +541 -0
  167. spruce_grove-1.0.1/spruce_grove/mcp_/manager.py +976 -0
  168. spruce_grove-1.0.1/spruce_grove/mcp_/mcp_logs.py +224 -0
  169. spruce_grove-1.0.1/spruce_grove/mcp_/project_config.py +288 -0
  170. spruce_grove-1.0.1/spruce_grove/mcp_/registry.py +451 -0
  171. spruce_grove-1.0.1/spruce_grove/mcp_/retry_manager.py +337 -0
  172. spruce_grove-1.0.1/spruce_grove/mcp_/server_registry_catalog.py +1122 -0
  173. spruce_grove-1.0.1/spruce_grove/mcp_/status_tracker.py +355 -0
  174. spruce_grove-1.0.1/spruce_grove/mcp_/system_tools.py +209 -0
  175. spruce_grove-1.0.1/spruce_grove/mcp_/tool_arg_coercion.py +180 -0
  176. spruce_grove-1.0.1/spruce_grove/mcp_/toolset_utils.py +77 -0
  177. spruce_grove-1.0.1/spruce_grove/mcp_prompts/__init__.py +1 -0
  178. spruce_grove-1.0.1/spruce_grove/mcp_prompts/hook_creator.py +103 -0
  179. spruce_grove-1.0.1/spruce_grove/messaging/__init__.py +299 -0
  180. spruce_grove-1.0.1/spruce_grove/messaging/bar_painters.py +352 -0
  181. spruce_grove-1.0.1/spruce_grove/messaging/bar_rendering.py +326 -0
  182. spruce_grove-1.0.1/spruce_grove/messaging/bottom_bar.py +803 -0
  183. spruce_grove-1.0.1/spruce_grove/messaging/bus.py +655 -0
  184. spruce_grove-1.0.1/spruce_grove/messaging/chords.py +151 -0
  185. spruce_grove-1.0.1/spruce_grove/messaging/commands.py +216 -0
  186. spruce_grove-1.0.1/spruce_grove/messaging/editor_actions.py +100 -0
  187. spruce_grove-1.0.1/spruce_grove/messaging/editor_completion.py +313 -0
  188. spruce_grove-1.0.1/spruce_grove/messaging/editor_display.py +132 -0
  189. spruce_grove-1.0.1/spruce_grove/messaging/editor_history.py +279 -0
  190. spruce_grove-1.0.1/spruce_grove/messaging/editor_keys.py +171 -0
  191. spruce_grove-1.0.1/spruce_grove/messaging/editor_paste.py +175 -0
  192. spruce_grove-1.0.1/spruce_grove/messaging/external_editor.py +137 -0
  193. spruce_grove-1.0.1/spruce_grove/messaging/inline_bar.py +386 -0
  194. spruce_grove-1.0.1/spruce_grove/messaging/line_editor.py +706 -0
  195. spruce_grove-1.0.1/spruce_grove/messaging/markdown_patches.py +88 -0
  196. spruce_grove-1.0.1/spruce_grove/messaging/message_queue.py +416 -0
  197. spruce_grove-1.0.1/spruce_grove/messaging/messages.py +581 -0
  198. spruce_grove-1.0.1/spruce_grove/messaging/pause_controller.py +494 -0
  199. spruce_grove-1.0.1/spruce_grove/messaging/prompt_prefix_style.py +103 -0
  200. spruce_grove-1.0.1/spruce_grove/messaging/queue_console.py +285 -0
  201. spruce_grove-1.0.1/spruce_grove/messaging/renderers.py +554 -0
  202. spruce_grove-1.0.1/spruce_grove/messaging/rich_renderer.py +1361 -0
  203. spruce_grove-1.0.1/spruce_grove/messaging/run_ui.py +754 -0
  204. spruce_grove-1.0.1/spruce_grove/messaging/run_ui_wiring.py +131 -0
  205. spruce_grove-1.0.1/spruce_grove/messaging/spinner/__init__.py +162 -0
  206. spruce_grove-1.0.1/spruce_grove/messaging/subagent_console.py +468 -0
  207. spruce_grove-1.0.1/spruce_grove/messaging/transcript_guard.py +466 -0
  208. spruce_grove-1.0.1/spruce_grove/model_descriptions.py +62 -0
  209. spruce_grove-1.0.1/spruce_grove/model_factory.py +1194 -0
  210. spruce_grove-1.0.1/spruce_grove/model_switching.py +143 -0
  211. spruce_grove-1.0.1/spruce_grove/model_utils.py +535 -0
  212. spruce_grove-1.0.1/spruce_grove/models.json +2 -0
  213. spruce_grove-1.0.1/spruce_grove/models_dev_api.json +1 -0
  214. spruce_grove-1.0.1/spruce_grove/models_dev_parser.py +461 -0
  215. spruce_grove-1.0.1/spruce_grove/observability.py +112 -0
  216. spruce_grove-1.0.1/spruce_grove/platform_utils.py +42 -0
  217. spruce_grove-1.0.1/spruce_grove/plugins/__init__.py +831 -0
  218. spruce_grove-1.0.1/spruce_grove/plugins/config.py +114 -0
  219. spruce_grove-1.0.1/spruce_grove/plugins/oauth_grove_html.py +194 -0
  220. spruce_grove-1.0.1/spruce_grove/plugins/oauth_pasteback.py +110 -0
  221. spruce_grove-1.0.1/spruce_grove/plugins/trust.py +146 -0
  222. spruce_grove-1.0.1/spruce_grove/plugins/trust_notice.py +69 -0
  223. spruce_grove-1.0.1/spruce_grove/private_inference.py +114 -0
  224. spruce_grove-1.0.1/spruce_grove/provider_credentials.py +328 -0
  225. spruce_grove-1.0.1/spruce_grove/provider_identity.py +110 -0
  226. spruce_grove-1.0.1/spruce_grove/pydantic_patches.py +650 -0
  227. spruce_grove-1.0.1/spruce_grove/reopenable_async_client.py +232 -0
  228. spruce_grove-1.0.1/spruce_grove/round_robin_model.py +155 -0
  229. spruce_grove-1.0.1/spruce_grove/secret_store.py +796 -0
  230. spruce_grove-1.0.1/spruce_grove/secret_store_backends.py +193 -0
  231. spruce_grove-1.0.1/spruce_grove/session_format_migration.py +302 -0
  232. spruce_grove-1.0.1/spruce_grove/session_lifecycle.py +317 -0
  233. spruce_grove-1.0.1/spruce_grove/session_migration.py +220 -0
  234. spruce_grove-1.0.1/spruce_grove/session_storage.py +340 -0
  235. spruce_grove-1.0.1/spruce_grove/session_surrogate_unpickler.py +418 -0
  236. spruce_grove-1.0.1/spruce_grove/shared_credentials.py +118 -0
  237. spruce_grove-1.0.1/spruce_grove/skill_provider.py +45 -0
  238. spruce_grove-1.0.1/spruce_grove/splash.py +385 -0
  239. spruce_grove-1.0.1/spruce_grove/status_display.py +315 -0
  240. spruce_grove-1.0.1/spruce_grove/steer_metadata.py +33 -0
  241. spruce_grove-1.0.1/spruce_grove/terminal_utils.py +634 -0
  242. spruce_grove-1.0.1/spruce_grove/token_usage.py +415 -0
  243. spruce_grove-1.0.1/spruce_grove/tolerant_openai.py +73 -0
  244. spruce_grove-1.0.1/spruce_grove/tools/__init__.py +473 -0
  245. spruce_grove-1.0.1/spruce_grove/tools/_browser_registry.py +142 -0
  246. spruce_grove-1.0.1/spruce_grove/tools/_lazy.py +12 -0
  247. spruce_grove-1.0.1/spruce_grove/tools/agent_tools.py +340 -0
  248. spruce_grove-1.0.1/spruce_grove/tools/apply_patch.py +478 -0
  249. spruce_grove-1.0.1/spruce_grove/tools/ask_user_question/__init__.py +26 -0
  250. spruce_grove-1.0.1/spruce_grove/tools/ask_user_question/constants.py +75 -0
  251. spruce_grove-1.0.1/spruce_grove/tools/ask_user_question/demo_tui.py +55 -0
  252. spruce_grove-1.0.1/spruce_grove/tools/ask_user_question/handler.py +232 -0
  253. spruce_grove-1.0.1/spruce_grove/tools/ask_user_question/models.py +304 -0
  254. spruce_grove-1.0.1/spruce_grove/tools/ask_user_question/registration.py +153 -0
  255. spruce_grove-1.0.1/spruce_grove/tools/ask_user_question/renderers.py +394 -0
  256. spruce_grove-1.0.1/spruce_grove/tools/ask_user_question/terminal_ui.py +336 -0
  257. spruce_grove-1.0.1/spruce_grove/tools/ask_user_question/theme.py +155 -0
  258. spruce_grove-1.0.1/spruce_grove/tools/ask_user_question/tui_loop.py +262 -0
  259. spruce_grove-1.0.1/spruce_grove/tools/browser/__init__.py +37 -0
  260. spruce_grove-1.0.1/spruce_grove/tools/browser/browser_control.py +289 -0
  261. spruce_grove-1.0.1/spruce_grove/tools/browser/browser_interactions.py +545 -0
  262. spruce_grove-1.0.1/spruce_grove/tools/browser/browser_locator_resolver.py +70 -0
  263. spruce_grove-1.0.1/spruce_grove/tools/browser/browser_locators.py +640 -0
  264. spruce_grove-1.0.1/spruce_grove/tools/browser/browser_manager.py +519 -0
  265. spruce_grove-1.0.1/spruce_grove/tools/browser/browser_navigation.py +251 -0
  266. spruce_grove-1.0.1/spruce_grove/tools/browser/browser_page_snapshot.py +147 -0
  267. spruce_grove-1.0.1/spruce_grove/tools/browser/browser_screenshot.py +179 -0
  268. spruce_grove-1.0.1/spruce_grove/tools/browser/browser_scripts.py +462 -0
  269. spruce_grove-1.0.1/spruce_grove/tools/browser/browser_semantic_interactions.py +189 -0
  270. spruce_grove-1.0.1/spruce_grove/tools/browser/browser_workflows.py +220 -0
  271. spruce_grove-1.0.1/spruce_grove/tools/browser/tool_registry.py +5 -0
  272. spruce_grove-1.0.1/spruce_grove/tools/command_runner.py +1590 -0
  273. spruce_grove-1.0.1/spruce_grove/tools/common.py +1332 -0
  274. spruce_grove-1.0.1/spruce_grove/tools/display.py +103 -0
  275. spruce_grove-1.0.1/spruce_grove/tools/file_modifications.py +1471 -0
  276. spruce_grove-1.0.1/spruce_grove/tools/file_operations.py +1534 -0
  277. spruce_grove-1.0.1/spruce_grove/tools/file_permission_state.py +137 -0
  278. spruce_grove-1.0.1/spruce_grove/tools/fs_access.py +228 -0
  279. spruce_grove-1.0.1/spruce_grove/tools/image_tools.py +192 -0
  280. spruce_grove-1.0.1/spruce_grove/tools/io_backends.py +186 -0
  281. spruce_grove-1.0.1/spruce_grove/tools/model_tools.py +105 -0
  282. spruce_grove-1.0.1/spruce_grove/tools/shell_backgrounding.py +94 -0
  283. spruce_grove-1.0.1/spruce_grove/tools/skills_tools.py +205 -0
  284. spruce_grove-1.0.1/spruce_grove/tools/subagent_context.py +247 -0
  285. spruce_grove-1.0.1/spruce_grove/tools/subagent_invocation.py +840 -0
  286. spruce_grove-1.0.1/spruce_grove/tools/subagent_usage_metrics.py +221 -0
  287. spruce_grove-1.0.1/spruce_grove/tools/tools_content.py +52 -0
  288. spruce_grove-1.0.1/spruce_grove/tools/universal_constructor.py +923 -0
  289. spruce_grove-1.0.1/spruce_grove/undo_manager.py +67 -0
  290. spruce_grove-1.0.1/spruce_grove/universal_constructor_provider.py +97 -0
  291. spruce_grove-1.0.1/spruce_grove/version_checker.py +106 -0
  292. spruce_grove-1.0.1/spruce_grove/zai_model.py +16 -0
@@ -0,0 +1,70 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ .coverage
13
+ coverage.json
14
+
15
+ # Session memory
16
+ .puppy_session_memory.json
17
+
18
+ # Pytest cache
19
+ .pytest_cache/
20
+
21
+ dummy_path
22
+
23
+ .idea/
24
+
25
+ .DS_Store
26
+ .env
27
+ .serena/
28
+ .beads/
29
+ main.dist/
30
+ nuitka-crash-report.xml
31
+ *.backup
32
+ main.bin
33
+
34
+ # Session log dumps (auto-committed by updater; not source)
35
+ NEWLog*.txt
36
+
37
+ # Bundled skills removed — skills are now fetched from remote catalog
38
+ code_puppy/bundled_skills/
39
+
40
+ # Hook engine runtime artifacts (logs, compiled outputs)
41
+ .claude/activity.jsonl
42
+ .claude/hooks/audit.log
43
+
44
+ # Compiled hook binaries (built from .go sources in .claude/hooks/go-hooks/)
45
+ .claude/hooks/go-hooks/audit-bash
46
+ .claude/hooks/go-hooks/file-policy
47
+
48
+ # Compiled TypeScript hook output (built from .ts sources)
49
+ .claude/hooks/ts-hooks/dist/
50
+
51
+ .json
52
+
53
+ .state/
54
+
55
+ # Local git worktrees
56
+ .worktrees/
57
+
58
+ # Cancel-wedge repro harness output (scripts/repro_cancel_wedge.py)
59
+ wedge_artifacts/
60
+ wedge_soak.log
61
+
62
+ # Personal voice memo + local transcript (never publish — repo is public)
63
+ MASTER-MASTER-PROMPT.m4a
64
+ MASTER-MASTER-PROMPT.txt
65
+ MASTER-MASTER-PROMPT.srt
66
+
67
+ # Beads / Dolt files (added by bd init)
68
+ .dolt/
69
+ *.db
70
+ .beads-credential-key
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mike Pfaffenberger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,194 @@
1
+ Metadata-Version: 2.5
2
+ Name: spruce-grove
3
+ Version: 1.0.1
4
+ Summary: Spruce Grove OS - an agentic coding CLI distribution inspired by Code Puppy. Together we are better. Always.
5
+ Project-URL: repository, https://github.com/t-granlund/SPRUCE-GROVE-OS
6
+ Project-URL: HomePage, https://tylergranlund.com
7
+ Author: Michael Pfaffenberger
8
+ Author-email: Tyler Granlund <hello@tylergranlund.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Code Generators
18
+ Requires-Python: <3.15,>=3.11
19
+ Requires-Dist: agent-client-protocol<0.12,>=0.11.0
20
+ Requires-Dist: anthropic<2,>=1.0.0
21
+ Requires-Dist: anyio>=4.7.0
22
+ Requires-Dist: azure-identity>=1.15.0
23
+ Requires-Dist: boto3>=1.43.9
24
+ Requires-Dist: code-puppy-core-plugins>=0.0.45
25
+ Requires-Dist: httpx2>=2.7
26
+ Requires-Dist: httpx[http2]>=0.24.1
27
+ Requires-Dist: json-repair>=0.46.2
28
+ Requires-Dist: keyring>=24.0.0
29
+ Requires-Dist: logfire>=4.0
30
+ Requires-Dist: mcp>=1.9.4
31
+ Requires-Dist: openai>=2.45.0
32
+ Requires-Dist: packaging>=24.0
33
+ Requires-Dist: pillow>=10.0.0
34
+ Requires-Dist: playwright>=1.40.0; sys_platform != 'android'
35
+ Requires-Dist: pydantic-ai-harness==0.23.0
36
+ Requires-Dist: pydantic-ai-slim[anthropic,mcp,openai]==2.35.0
37
+ Requires-Dist: pydantic>=2.4.0
38
+ Requires-Dist: pyfiglet>=0.8.post1
39
+ Requires-Dist: python-dotenv>=1.0.0
40
+ Requires-Dist: rapidfuzz>=3.13.0
41
+ Requires-Dist: requests>=2.28.0
42
+ Requires-Dist: rich>=13.4.2
43
+ Requires-Dist: ripgrep==14.1.0; sys_platform != 'android'
44
+ Requires-Dist: termflow-md>=0.9.1
45
+ Requires-Dist: typer>=0.12.0
46
+ Provides-Extra: bedrock
47
+ Requires-Dist: boto3>=1.35.0; extra == 'bedrock'
48
+ Provides-Extra: computer-use
49
+ Requires-Dist: pyobjc-framework-applicationservices>=10.3; (sys_platform == 'darwin') and extra == 'computer-use'
50
+ Requires-Dist: pyobjc-framework-cocoa>=10.3; (sys_platform == 'darwin') and extra == 'computer-use'
51
+ Requires-Dist: pyobjc-framework-quartz>=10.3; (sys_platform == 'darwin') and extra == 'computer-use'
52
+ Provides-Extra: durable
53
+ Requires-Dist: dbos>=2.11.0; extra == 'durable'
54
+ Description-Content-Type: text/markdown
55
+
56
+ # SPRUCE GROVE OS
57
+
58
+ <p align="center">
59
+ <img src="logos/spruce_grove_logo_withback.jpeg" alt="The Spruce Grove mark - three geometric spruces in brand greens on charcoal" width="260">
60
+ </p>
61
+
62
+ **gran · lund · sv. · spruce grove** — an agentic coding CLI grown in the grove.
63
+
64
+ > Together we are better. Always.
65
+
66
+ ![License: MIT](https://img.shields.io/badge/license-MIT-2D4F3A)
67
+ ![Python 3.11–3.14](https://img.shields.io/badge/python-3.11--3.14-588F5E)
68
+ ![Tests: 7700 passing](https://img.shields.io/badge/tests-7700%20passing-D2A069)
69
+ ![Inspired by Code Puppy](https://img.shields.io/badge/inspired%20by-Code%20Puppy-F0E1C8)
70
+
71
+ Spruce Grove OS is a full custom instance of an agentic coding assistant:
72
+ the same engine, frameworks, plugins, agents, tools, skills, MCP plumbing,
73
+ and TUI as the project it is inspired by — replanted around one grove's
74
+ vision, mission, and values.
75
+
76
+ ## Inspired by Code Puppy
77
+
78
+ Every trail in this grove started as a Code Puppy trail. Spruce Grove OS is
79
+ built directly from — and stays import-compatible with — **Code Puppy** by
80
+ [Michael Pfaffenberger](https://github.com/mpfaffenberger/code_puppy)
81
+ (MIT licensed). Huge respect to the original project and its contributors;
82
+ this grove exists because the puppy shared everything. Exact lineage, sync
83
+ points, and the full rename/contract map: [PROVENANCE.md](PROVENANCE.md).
84
+
85
+ ## The ethos of the grove
86
+
87
+ Three sources, one creed — [ETHOS.md](ETHOS.md):
88
+
89
+ 1. **Ozark Bagels — how to carry yourself.** Be first to say hello. Be kinder
90
+ than necessary. Be tough minded, but tender hearted. Leave everything
91
+ better than you found it. Spread joy, love, and cream cheese.
92
+ 2. **The Junto (1727) — how to think with others.** Love truth for truth's
93
+ sake. No invented facts — ever; cite or flag "NOT VERIFIED". Provisional
94
+ phrasing over contradiction combat. Pragmatism over metaphysics.
95
+ 3. **gran·lund — who is doing the carrying.** Help people solve problems.
96
+ Remove technology obstacles. Meet people where they are, as humans.
97
+
98
+ ## Meet Cedar
99
+
100
+ The default agent persona is **Cedar**, the grove guide — same competent
101
+ agent core, new disposition: candid about code, gentle with people, allergic
102
+ to invented facts. Rename it anytime in `grove.cfg`.
103
+
104
+ ---
105
+
106
+ ## Design system
107
+
108
+ Nordic forest, dark-first. Charcoal base, deep spruce, warm cedar accents,
109
+ mist typography. Tokens shared with
110
+ [tylergranlund.com](https://tylergranlund.com) — the same palette that colors
111
+ the terminal splash.
112
+
113
+ ### Color tokens
114
+
115
+ | Token | OKLCH | Role | Chip |
116
+ |---|---|---|---|
117
+ | charcoal | `oklch(0.18 0.012 150)` | base background | ![#1d211e](https://img.shields.io/badge/-%23001D21-1d211e) |
118
+ | spruce-deep | `oklch(0.22 0.03 158)` | deep brand layer | ![#20392b](https://img.shields.io/badge/-%2320392B-20392b) |
119
+ | spruce | `oklch(0.32 0.045 158)` | primary brand | ![#2d4f3a](https://img.shields.io/badge/-%232D4F3A-2d4f3a) |
120
+ | moss | `oklch(0.45 0.06 155)` | accent green | ![#588f5e](https://img.shields.io/badge/-%23588F5E-588f5e) |
121
+ | cedar | `oklch(0.78 0.12 55)` | warm accent, persona | ![#d2a069](https://img.shields.io/badge/-%23D2A069-d2a069) |
122
+ | bark | `oklch(0.32 0.025 60)` | earthy neutral | ![#4d4136](https://img.shields.io/badge/-%234D4136-4d4136) |
123
+ | stone | `oklch(0.85 0.012 90)` | soft UI text | ![#d6d2c8](https://img.shields.io/badge/-%23D6D2C8-d6d2c8) |
124
+ | mist | `oklch(0.94 0.008 100)` | foreground/typography | ![#f0e1c8](https://img.shields.io/badge/-%23F0E1C8-f0e1c8) |
125
+
126
+ ### Typography
127
+
128
+ - **Fraunces** (variable serif) — wordmarks and display
129
+ - **Inter** — body copy
130
+ - **JetBrains Mono** — code, CLI output
131
+
132
+ ### Terminal theming
133
+
134
+ The boot splash renders a shimmering pyramid + figlet lockup
135
+ ("SPRUCE GROVE", compact "GROVE" on narrow terminals) in a truecolor
136
+ canopy-to-cedar gradient: halo `#2D4F3A` → glow `#588F5E` → core `#D2A069`,
137
+ with a mist-white crest (`#F0E1C8`) where the sheen passes. ANSI fallbacks
138
+ step down through green → bright green → yellow.
139
+
140
+ ### Voice
141
+
142
+ Plain-spoken, warm, a little playful. First to say hello. Candid, never
143
+ roasty. Zero invented facts — "NOT VERIFIED" beats a confident guess.
144
+
145
+ Full tokens and voice guide: [BRAND.md](BRAND.md).
146
+
147
+ ---
148
+
149
+ ## What's inside (same bones as Code Puppy)
150
+
151
+ ```
152
+ ┌──────────────────────────────────────────────────┐
153
+ │ TUI / CLI (command_line/) │
154
+ ├──────────────────────────────────────────────────┤
155
+ │ Agent Layer (agents/) — Cedar default + JSON │
156
+ ├──────────────────────────────────────────────────┤
157
+ │ Tool Layer (tools/) — TOOL_REGISTRY │
158
+ ├──────────────────────────────────────────────────┤
159
+ │ Plugin Layer (plugins/, callbacks.py) │
160
+ ├──────────────────────────────────────────────────┤
161
+ │ Model Layer (model_factory.py) │
162
+ ├──────────────────────────────────────────────────┤
163
+ │ pydantic-ai + MCP (external) │
164
+ └──────────────────────────────────────────────────┘
165
+ ```
166
+
167
+ Python 3.11–3.14 · pydantic-ai · pluggable models (OpenAI, Anthropic,
168
+ Gemini, Bedrock, Z.AI, custom endpoints) · MCP servers · skills with
169
+ namespaces · session history + compaction · i18n.
170
+
171
+ ## Install & run
172
+
173
+ ```bash
174
+ git clone https://github.com/t-granlund/SPRUCE-GROVE-OS
175
+ cd SPRUCE-GROVE-OS
176
+ uv sync
177
+ uv run spruce-grove # or: uv run grove
178
+ ```
179
+
180
+ Config: `~/.spruce_grove/grove.cfg` · Env vars: `SPRUCE_GROVE_*`.
181
+
182
+ ## Code Puppy compatibility
183
+
184
+ - `code_puppy.*` imports (e.g. from `code-puppy-core-plugins`) resolve to
185
+ `spruce_grove.*` via an import shim with true module identity.
186
+ - The plugin entry-point group `code_puppy.plugins` is intentionally retained.
187
+ - Legacy aliases kept: `agent_code_puppy`, `CodePuppyAgent`,
188
+ `get_puppy_name()`, persisted `puppy_name` fallback.
189
+ - Full contract ledger: [PROVENANCE.md](PROVENANCE.md).
190
+
191
+ ## License
192
+
193
+ MIT — inherited from Code Puppy. See [LICENSE](LICENSE) and attribution in
194
+ [PROVENANCE.md](PROVENANCE.md).
@@ -0,0 +1,139 @@
1
+ # SPRUCE GROVE OS
2
+
3
+ <p align="center">
4
+ <img src="logos/spruce_grove_logo_withback.jpeg" alt="The Spruce Grove mark - three geometric spruces in brand greens on charcoal" width="260">
5
+ </p>
6
+
7
+ **gran · lund · sv. · spruce grove** — an agentic coding CLI grown in the grove.
8
+
9
+ > Together we are better. Always.
10
+
11
+ ![License: MIT](https://img.shields.io/badge/license-MIT-2D4F3A)
12
+ ![Python 3.11–3.14](https://img.shields.io/badge/python-3.11--3.14-588F5E)
13
+ ![Tests: 7700 passing](https://img.shields.io/badge/tests-7700%20passing-D2A069)
14
+ ![Inspired by Code Puppy](https://img.shields.io/badge/inspired%20by-Code%20Puppy-F0E1C8)
15
+
16
+ Spruce Grove OS is a full custom instance of an agentic coding assistant:
17
+ the same engine, frameworks, plugins, agents, tools, skills, MCP plumbing,
18
+ and TUI as the project it is inspired by — replanted around one grove's
19
+ vision, mission, and values.
20
+
21
+ ## Inspired by Code Puppy
22
+
23
+ Every trail in this grove started as a Code Puppy trail. Spruce Grove OS is
24
+ built directly from — and stays import-compatible with — **Code Puppy** by
25
+ [Michael Pfaffenberger](https://github.com/mpfaffenberger/code_puppy)
26
+ (MIT licensed). Huge respect to the original project and its contributors;
27
+ this grove exists because the puppy shared everything. Exact lineage, sync
28
+ points, and the full rename/contract map: [PROVENANCE.md](PROVENANCE.md).
29
+
30
+ ## The ethos of the grove
31
+
32
+ Three sources, one creed — [ETHOS.md](ETHOS.md):
33
+
34
+ 1. **Ozark Bagels — how to carry yourself.** Be first to say hello. Be kinder
35
+ than necessary. Be tough minded, but tender hearted. Leave everything
36
+ better than you found it. Spread joy, love, and cream cheese.
37
+ 2. **The Junto (1727) — how to think with others.** Love truth for truth's
38
+ sake. No invented facts — ever; cite or flag "NOT VERIFIED". Provisional
39
+ phrasing over contradiction combat. Pragmatism over metaphysics.
40
+ 3. **gran·lund — who is doing the carrying.** Help people solve problems.
41
+ Remove technology obstacles. Meet people where they are, as humans.
42
+
43
+ ## Meet Cedar
44
+
45
+ The default agent persona is **Cedar**, the grove guide — same competent
46
+ agent core, new disposition: candid about code, gentle with people, allergic
47
+ to invented facts. Rename it anytime in `grove.cfg`.
48
+
49
+ ---
50
+
51
+ ## Design system
52
+
53
+ Nordic forest, dark-first. Charcoal base, deep spruce, warm cedar accents,
54
+ mist typography. Tokens shared with
55
+ [tylergranlund.com](https://tylergranlund.com) — the same palette that colors
56
+ the terminal splash.
57
+
58
+ ### Color tokens
59
+
60
+ | Token | OKLCH | Role | Chip |
61
+ |---|---|---|---|
62
+ | charcoal | `oklch(0.18 0.012 150)` | base background | ![#1d211e](https://img.shields.io/badge/-%23001D21-1d211e) |
63
+ | spruce-deep | `oklch(0.22 0.03 158)` | deep brand layer | ![#20392b](https://img.shields.io/badge/-%2320392B-20392b) |
64
+ | spruce | `oklch(0.32 0.045 158)` | primary brand | ![#2d4f3a](https://img.shields.io/badge/-%232D4F3A-2d4f3a) |
65
+ | moss | `oklch(0.45 0.06 155)` | accent green | ![#588f5e](https://img.shields.io/badge/-%23588F5E-588f5e) |
66
+ | cedar | `oklch(0.78 0.12 55)` | warm accent, persona | ![#d2a069](https://img.shields.io/badge/-%23D2A069-d2a069) |
67
+ | bark | `oklch(0.32 0.025 60)` | earthy neutral | ![#4d4136](https://img.shields.io/badge/-%234D4136-4d4136) |
68
+ | stone | `oklch(0.85 0.012 90)` | soft UI text | ![#d6d2c8](https://img.shields.io/badge/-%23D6D2C8-d6d2c8) |
69
+ | mist | `oklch(0.94 0.008 100)` | foreground/typography | ![#f0e1c8](https://img.shields.io/badge/-%23F0E1C8-f0e1c8) |
70
+
71
+ ### Typography
72
+
73
+ - **Fraunces** (variable serif) — wordmarks and display
74
+ - **Inter** — body copy
75
+ - **JetBrains Mono** — code, CLI output
76
+
77
+ ### Terminal theming
78
+
79
+ The boot splash renders a shimmering pyramid + figlet lockup
80
+ ("SPRUCE GROVE", compact "GROVE" on narrow terminals) in a truecolor
81
+ canopy-to-cedar gradient: halo `#2D4F3A` → glow `#588F5E` → core `#D2A069`,
82
+ with a mist-white crest (`#F0E1C8`) where the sheen passes. ANSI fallbacks
83
+ step down through green → bright green → yellow.
84
+
85
+ ### Voice
86
+
87
+ Plain-spoken, warm, a little playful. First to say hello. Candid, never
88
+ roasty. Zero invented facts — "NOT VERIFIED" beats a confident guess.
89
+
90
+ Full tokens and voice guide: [BRAND.md](BRAND.md).
91
+
92
+ ---
93
+
94
+ ## What's inside (same bones as Code Puppy)
95
+
96
+ ```
97
+ ┌──────────────────────────────────────────────────┐
98
+ │ TUI / CLI (command_line/) │
99
+ ├──────────────────────────────────────────────────┤
100
+ │ Agent Layer (agents/) — Cedar default + JSON │
101
+ ├──────────────────────────────────────────────────┤
102
+ │ Tool Layer (tools/) — TOOL_REGISTRY │
103
+ ├──────────────────────────────────────────────────┤
104
+ │ Plugin Layer (plugins/, callbacks.py) │
105
+ ├──────────────────────────────────────────────────┤
106
+ │ Model Layer (model_factory.py) │
107
+ ├──────────────────────────────────────────────────┤
108
+ │ pydantic-ai + MCP (external) │
109
+ └──────────────────────────────────────────────────┘
110
+ ```
111
+
112
+ Python 3.11–3.14 · pydantic-ai · pluggable models (OpenAI, Anthropic,
113
+ Gemini, Bedrock, Z.AI, custom endpoints) · MCP servers · skills with
114
+ namespaces · session history + compaction · i18n.
115
+
116
+ ## Install & run
117
+
118
+ ```bash
119
+ git clone https://github.com/t-granlund/SPRUCE-GROVE-OS
120
+ cd SPRUCE-GROVE-OS
121
+ uv sync
122
+ uv run spruce-grove # or: uv run grove
123
+ ```
124
+
125
+ Config: `~/.spruce_grove/grove.cfg` · Env vars: `SPRUCE_GROVE_*`.
126
+
127
+ ## Code Puppy compatibility
128
+
129
+ - `code_puppy.*` imports (e.g. from `code-puppy-core-plugins`) resolve to
130
+ `spruce_grove.*` via an import shim with true module identity.
131
+ - The plugin entry-point group `code_puppy.plugins` is intentionally retained.
132
+ - Legacy aliases kept: `agent_code_puppy`, `CodePuppyAgent`,
133
+ `get_puppy_name()`, persisted `puppy_name` fallback.
134
+ - Full contract ledger: [PROVENANCE.md](PROVENANCE.md).
135
+
136
+ ## License
137
+
138
+ MIT — inherited from Code Puppy. See [LICENSE](LICENSE) and attribution in
139
+ [PROVENANCE.md](PROVENANCE.md).
@@ -0,0 +1,121 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "spruce-grove"
7
+ version = "1.0.1"
8
+ description = "Spruce Grove OS - an agentic coding CLI distribution inspired by Code Puppy. Together we are better. Always."
9
+ readme = "README.md"
10
+ requires-python = ">=3.11,<3.15"
11
+ dependencies = [
12
+ "code-puppy-core-plugins>=0.0.45",
13
+ "logfire>=4.0",
14
+ "pydantic-ai-slim[openai,anthropic,mcp]==2.35.0",
15
+ "pydantic-ai-harness==0.23.0",
16
+ "anyio>=4.7.0",
17
+ "typer>=0.12.0",
18
+ "mcp>=1.9.4",
19
+ "httpx[http2]>=0.24.1",
20
+ "httpx2>=2.7",
21
+ "requests>=2.28.0",
22
+ "packaging>=24.0",
23
+ "rich>=13.4.2",
24
+ "pydantic>=2.4.0",
25
+ "python-dotenv>=1.0.0",
26
+ "json-repair>=0.46.2",
27
+ "pyfiglet>=0.8.post1",
28
+ "rapidfuzz>=3.13.0",
29
+ "openai>=2.45.0",
30
+ "ripgrep==14.1.0; sys_platform != 'android'",
31
+ "playwright>=1.40.0; sys_platform != 'android'",
32
+ "termflow-md>=0.9.1",
33
+ "Pillow>=10.0.0",
34
+ "azure-identity>=1.15.0",
35
+ "anthropic>=1.0.0,<2",
36
+ "boto3>=1.43.9",
37
+ "keyring>=24.0.0",
38
+ "agent-client-protocol>=0.11.0,<0.12",
39
+ ]
40
+ dev-dependencies = [
41
+ "pytest>=8.3.4",
42
+ "pytest-cov>=6.1.1",
43
+ "pytest-asyncio>=0.23.1",
44
+ "ruff>=0.15,<0.16",
45
+ "pexpect>=4.9.0",
46
+ ]
47
+ authors = [
48
+ {name = "Tyler Granlund", email = "hello@tylergranlund.com"},
49
+ {name = "Michael Pfaffenberger"} # original author of Code Puppy, the project this is inspired by and built from
50
+ ]
51
+ license = {text = "MIT"}
52
+ classifiers = [
53
+ "Programming Language :: Python :: 3",
54
+ "Programming Language :: Python :: 3.11",
55
+ "Programming Language :: Python :: 3.12",
56
+ "Programming Language :: Python :: 3.13",
57
+ "License :: OSI Approved :: MIT License",
58
+ "Operating System :: OS Independent",
59
+ "Topic :: Software Development :: Code Generators",
60
+ ]
61
+
62
+ [project.optional-dependencies]
63
+ bedrock = ["boto3>=1.35.0"]
64
+ durable = ["dbos>=2.11.0"]
65
+ computer-use = [
66
+ "pyobjc-framework-ApplicationServices>=10.3; sys_platform == 'darwin'",
67
+ "pyobjc-framework-Cocoa>=10.3; sys_platform == 'darwin'",
68
+ "pyobjc-framework-Quartz>=10.3; sys_platform == 'darwin'",
69
+ ]
70
+
71
+ [project.urls]
72
+ repository = "https://github.com/t-granlund/SPRUCE-GROVE-OS"
73
+ HomePage = "https://tylergranlund.com"
74
+
75
+
76
+ [project.scripts]
77
+ spruce-grove = "spruce_grove.main:main_entry"
78
+ grove = "spruce_grove.main:main_entry"
79
+
80
+ [tool.logfire]
81
+ ignore_no_config = true
82
+
83
+ [tool.hatch.build]
84
+ packages = ["spruce_grove"]
85
+
86
+ [tool.hatch.build.targets.wheel.shared-data]
87
+ "spruce_grove/models.json" = "spruce_grove/models.json"
88
+ "spruce_grove/models_dev_api.json" = "spruce_grove/models_dev_api.json"
89
+
90
+ [[tool.hatch.build.targets.sdist.include]]
91
+ path = "spruce_grove/models.json"
92
+
93
+ [[tool.hatch.build.targets.sdist.include]]
94
+ path = "spruce_grove/models_dev_api.json"
95
+
96
+ [tool.ruff.lint.per-file-ignores]
97
+ "spruce_grove/__init__.py" = ["E402"]
98
+ "spruce_grove/main.py" = ["E402"]
99
+ "spruce_grove/cli_runner.py" = ["E402"]
100
+ "spruce_grove/messaging/__init__.py" = ["E402"]
101
+
102
+ [tool.pytest.ini_options]
103
+ addopts = "--cov=spruce_grove --cov-report=term-missing"
104
+ testpaths = ["tests"]
105
+ asyncio_mode = "auto"
106
+
107
+ [tool.coverage.run]
108
+ omit = ["spruce_grove/main.py"]
109
+
110
+ [tool.uv]
111
+ python-preference = "only-managed"
112
+
113
+ [dependency-groups]
114
+ dev = [
115
+ "pytest>=8.3.4",
116
+ "pytest-cov>=6.1.1",
117
+ "pytest-asyncio>=0.23.1",
118
+ "ruff>=0.15,<0.16",
119
+ "pexpect>=4.9.0",
120
+ "pyte>=0.8.2",
121
+ ]
@@ -0,0 +1,42 @@
1
+ """Installed distribution metadata for Spruce Grove."""
2
+
3
+ import importlib.metadata
4
+
5
+ from packaging.version import Version
6
+
7
+
8
+ def _get_distribution_version(
9
+ distribution_name: str, fallback: str | None = None
10
+ ) -> str | None:
11
+ """Return an installed distribution version or a stable fallback."""
12
+ try:
13
+ detected_version = importlib.metadata.version(distribution_name)
14
+ return detected_version if detected_version else fallback
15
+ except Exception:
16
+ return fallback
17
+
18
+
19
+ def get_core_plugins_version() -> str | None:
20
+ """Return the valid installed official core-plugin bundle version."""
21
+ detected_version = _get_distribution_version("code-puppy-core-plugins")
22
+ if not isinstance(detected_version, str):
23
+ return None
24
+
25
+ try:
26
+ normalized_version = detected_version.strip()
27
+ if not normalized_version:
28
+ return None
29
+ Version(normalized_version)
30
+ except Exception:
31
+ return None
32
+
33
+ return normalized_version
34
+
35
+
36
+ # Planted in the grove. -Cedar
37
+ __version__ = _get_distribution_version("spruce-grove", "0.0.0-dev")
38
+
39
+ from spruce_grove._code_puppy_compat import install as _install_legacy_shim
40
+
41
+ _install_legacy_shim()
42
+ del _install_legacy_shim
@@ -0,0 +1,10 @@
1
+ """
2
+ Entry point for running spruce-grove as a module.
3
+
4
+ This allows the package to be run with: python -m spruce_grove
5
+ """
6
+
7
+ from spruce_grove.main import main_entry
8
+
9
+ if __name__ == "__main__":
10
+ main_entry()