tunacode-cli 0.1.37__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 (368) hide show
  1. tunacode_cli-0.1.37/.claude/JOURNAL.md +359 -0
  2. tunacode_cli-0.1.37/.claude/debug_history/2026-01-12_missing-cached-tokens.md +45 -0
  3. tunacode_cli-0.1.37/.claude/debug_history/list-dir-tool-execution-error.md +55 -0
  4. tunacode_cli-0.1.37/.claude/delta/2026-01-17-dangling-tool-calls.md +171 -0
  5. tunacode_cli-0.1.37/.claude/delta/remove-global-cache-user-config.md +54 -0
  6. tunacode_cli-0.1.37/.claude/qa/no-cargo-cult-fixes.md +52 -0
  7. tunacode_cli-0.1.37/.claude/qa/raw.md +2 -0
  8. tunacode_cli-0.1.37/.claude/qa/semantically-dead-code.md +85 -0
  9. tunacode_cli-0.1.37/.github/pull_request_template.md +51 -0
  10. tunacode_cli-0.1.37/.github/workflows/lint.yml +20 -0
  11. tunacode_cli-0.1.37/.github/workflows/publish-release.yml +73 -0
  12. tunacode_cli-0.1.37/.gitignore +86 -0
  13. tunacode_cli-0.1.37/.pre-commit-config.yaml +148 -0
  14. tunacode_cli-0.1.37/AGENTS.md +304 -0
  15. tunacode_cli-0.1.37/CHANGELOG.md +205 -0
  16. tunacode_cli-0.1.37/CLAUDE.md +441 -0
  17. tunacode_cli-0.1.37/CONTRIBUTING.md +148 -0
  18. tunacode_cli-0.1.37/LICENSE +21 -0
  19. tunacode_cli-0.1.37/MANIFEST.in +20 -0
  20. tunacode_cli-0.1.37/PKG-INFO +176 -0
  21. tunacode_cli-0.1.37/README.md +124 -0
  22. tunacode_cli-0.1.37/assets/tunacode.png +0 -0
  23. tunacode_cli-0.1.37/assets/tunacode_example.png +0 -0
  24. tunacode_cli-0.1.37/docs/codebase-map/MAP.md +465 -0
  25. tunacode_cli-0.1.37/docs/codebase-map/architecture/architecture.md +809 -0
  26. tunacode_cli-0.1.37/docs/codebase-map/architecture/conversation-turns.md +403 -0
  27. tunacode_cli-0.1.37/docs/codebase-map/modules/00-overview.md +57 -0
  28. tunacode_cli-0.1.37/docs/codebase-map/modules/INDEX.md +123 -0
  29. tunacode_cli-0.1.37/docs/codebase-map/modules/configuration.md +98 -0
  30. tunacode_cli-0.1.37/docs/codebase-map/modules/constants.md +170 -0
  31. tunacode_cli-0.1.37/docs/codebase-map/modules/core-agents.md +225 -0
  32. tunacode_cli-0.1.37/docs/codebase-map/modules/core-compaction.md +163 -0
  33. tunacode_cli-0.1.37/docs/codebase-map/modules/core-limits.md +171 -0
  34. tunacode_cli-0.1.37/docs/codebase-map/modules/core-logging.md +100 -0
  35. tunacode_cli-0.1.37/docs/codebase-map/modules/core-prompting.md +119 -0
  36. tunacode_cli-0.1.37/docs/codebase-map/modules/core-state.md +57 -0
  37. tunacode_cli-0.1.37/docs/codebase-map/modules/exceptions.md +187 -0
  38. tunacode_cli-0.1.37/docs/codebase-map/modules/indexing.md +96 -0
  39. tunacode_cli-0.1.37/docs/codebase-map/modules/lsp.md +112 -0
  40. tunacode_cli-0.1.37/docs/codebase-map/modules/prompts.md +151 -0
  41. tunacode_cli-0.1.37/docs/codebase-map/modules/templates.md +113 -0
  42. tunacode_cli-0.1.37/docs/codebase-map/modules/tools-overview.md +232 -0
  43. tunacode_cli-0.1.37/docs/codebase-map/modules/types.md +95 -0
  44. tunacode_cli-0.1.37/docs/codebase-map/modules/ui-overview.md +202 -0
  45. tunacode_cli-0.1.37/docs/codebase-map/modules/utils.md +134 -0
  46. tunacode_cli-0.1.37/docs/codebase-map/state/state.md +324 -0
  47. tunacode_cli-0.1.37/docs/codebase-map/structure/00-root-overview.md +82 -0
  48. tunacode_cli-0.1.37/docs/codebase-map/structure/01-ui-directory.md +131 -0
  49. tunacode_cli-0.1.37/docs/codebase-map/structure/02-core-directory.md +135 -0
  50. tunacode_cli-0.1.37/docs/codebase-map/structure/03-tools-directory.md +171 -0
  51. tunacode_cli-0.1.37/docs/codebase-map/structure/04-configuration-directory.md +171 -0
  52. tunacode_cli-0.1.37/docs/codebase-map/structure/05-cli-directory.md +122 -0
  53. tunacode_cli-0.1.37/docs/codebase-map/structure/06-supporting-modules.md +214 -0
  54. tunacode_cli-0.1.37/docs/codebase-map/structure/ANALYSIS_SUMMARY.md +266 -0
  55. tunacode_cli-0.1.37/docs/codebase-map/structure/README.md +231 -0
  56. tunacode_cli-0.1.37/docs/codebase-map/structure/tree-structure.txt +261 -0
  57. tunacode_cli-0.1.37/docs/configuration/README.md +90 -0
  58. tunacode_cli-0.1.37/docs/configuration/tunacode.json.example +36 -0
  59. tunacode_cli-0.1.37/docs/configuration/tunacode.local.json.example +34 -0
  60. tunacode_cli-0.1.37/docs/images/logo.jpeg +0 -0
  61. tunacode_cli-0.1.37/docs/images/logo_clear.png +0 -0
  62. tunacode_cli-0.1.37/docs/images/theme.png +0 -0
  63. tunacode_cli-0.1.37/docs/images/tui-model-setup.png +0 -0
  64. tunacode_cli-0.1.37/docs/images/tui.png +0 -0
  65. tunacode_cli-0.1.37/docs/media/agent-response.png +0 -0
  66. tunacode_cli-0.1.37/docs/media/plan-approval.png +0 -0
  67. tunacode_cli-0.1.37/docs/media/read-file-tool.png +0 -0
  68. tunacode_cli-0.1.37/docs/media/tc-logo.jpg +0 -0
  69. tunacode_cli-0.1.37/docs/tools/architecture.md +221 -0
  70. tunacode_cli-0.1.37/docs/ui/agent_response_panel.md +91 -0
  71. tunacode_cli-0.1.37/docs/ui/design_philosophy.md +26 -0
  72. tunacode_cli-0.1.37/docs/ui/layout.md +61 -0
  73. tunacode_cli-0.1.37/docs/ui/nextstep_panels.md +108 -0
  74. tunacode_cli-0.1.37/docs/ui/shell_runner.md +113 -0
  75. tunacode_cli-0.1.37/docs/ui/tool_renderers.md +266 -0
  76. tunacode_cli-0.1.37/memory-bank/execute/2026-01-07_23-25-00_glob-grep-modelretry.md +121 -0
  77. tunacode_cli-0.1.37/memory-bank/execute/2026-01-08_22-30-00_agent-response-panel.md +55 -0
  78. tunacode_cli-0.1.37/memory-bank/execute/2026-01-09_19-05-00_register-present-plan-tool-222.md +95 -0
  79. tunacode_cli-0.1.37/memory-bank/execute/2026-01-10_14-45-00_dead-code-m1.md +78 -0
  80. tunacode_cli-0.1.37/memory-bank/execute/2026-01-19_15-30-00_timeout_cleanup_gap.md +153 -0
  81. tunacode_cli-0.1.37/memory-bank/plan/2026-01-07_16-30-00_renderer-unification.md +156 -0
  82. tunacode_cli-0.1.37/memory-bank/plan/2026-01-07_23-12-56_glob-grep-modelretry.md +165 -0
  83. tunacode_cli-0.1.37/memory-bank/plan/2026-01-08_agent-response-panel.md +211 -0
  84. tunacode_cli-0.1.37/memory-bank/plan/2026-01-09_19-00-00_register-present-plan-tool-222.md +139 -0
  85. tunacode_cli-0.1.37/memory-bank/plan/2026-01-10_09-40-00_shell_panel_nextstep_standardization.md +280 -0
  86. tunacode_cli-0.1.37/memory-bank/plan/2026-01-10_14-10-34_dead-code-dry-cleanup.md +160 -0
  87. tunacode_cli-0.1.37/memory-bank/plan/2026-01-11_app-py-decomposition.md +200 -0
  88. tunacode_cli-0.1.37/memory-bank/plan/2026-01-12_15-45-00_node_processor_cleanup.md +215 -0
  89. tunacode_cli-0.1.37/memory-bank/plan/2026-01-14_13-15-00_centralized-ignore-patterns.md +152 -0
  90. tunacode_cli-0.1.37/memory-bank/plan/2026-01-15_slim-panels-ui-update.md +252 -0
  91. tunacode_cli-0.1.37/memory-bank/plan/2026-01-19_15-00-00_timeout_cleanup_gap.md +147 -0
  92. tunacode_cli-0.1.37/memory-bank/plan/assets/dream-mockup-slim-panels.webp +0 -0
  93. tunacode_cli-0.1.37/memory-bank/plan/subplan-renderer-ui.md +139 -0
  94. tunacode_cli-0.1.37/memory-bank/research/2026-01-07_23-10-22_glob-grep-error-strings.md +207 -0
  95. tunacode_cli-0.1.37/memory-bank/research/2026-01-07_panel-architecture-map.md +229 -0
  96. tunacode_cli-0.1.37/memory-bank/research/2026-01-07_pydantic-v2-analysis.md +142 -0
  97. tunacode_cli-0.1.37/memory-bank/research/2026-01-08_14-14-39_local-mode-docs.md +147 -0
  98. tunacode_cli-0.1.37/memory-bank/research/2026-01-08_14-20-00_messages-and-pruning-local-vs-api.md +229 -0
  99. tunacode_cli-0.1.37/memory-bank/research/2026-01-08_23-46-19_plan-permission-keeps-asking.md +150 -0
  100. tunacode_cli-0.1.37/memory-bank/research/2026-01-08_agent-reply-rendering-analysis.md +178 -0
  101. tunacode_cli-0.1.37/memory-bank/research/2026-01-08_raw-code-rendering-gaps.md +255 -0
  102. tunacode_cli-0.1.37/memory-bank/research/2026-01-08_ui-model-selector-logic.md +257 -0
  103. tunacode_cli-0.1.37/memory-bank/research/2026-01-09_11-33-26_grep-read-performance.md +203 -0
  104. tunacode_cli-0.1.37/memory-bank/research/2026-01-09_18-41-11_register-present-plan-tool-222.md +131 -0
  105. tunacode_cli-0.1.37/memory-bank/research/2026-01-09_simple-prompt-evals.md +153 -0
  106. tunacode_cli-0.1.37/memory-bank/research/2026-01-10_09-33-00_shell_panel_nextstep_standardization.md +264 -0
  107. tunacode_cli-0.1.37/memory-bank/research/2026-01-10_agent_config_map.md +279 -0
  108. tunacode_cli-0.1.37/memory-bank/research/2026-01-11_16-57-40_plan-tool-and-workflow.md +265 -0
  109. tunacode_cli-0.1.37/memory-bank/research/2026-01-12-000000_parallel_tool_call_execution.md +188 -0
  110. tunacode_cli-0.1.37/memory-bank/research/2026-01-12-22-30-59_agent_components_codebase_mapping.md +459 -0
  111. tunacode_cli-0.1.37/memory-bank/research/2026-01-12_12-42-33_parallel-tool-calling-not-working.md +109 -0
  112. tunacode_cli-0.1.37/memory-bank/research/2026-01-12_15-30-07_node_processor_mapping.md +220 -0
  113. tunacode_cli-0.1.37/memory-bank/research/2026-01-14_12-27-29_glob-tool-bottlenecks.md +298 -0
  114. tunacode_cli-0.1.37/memory-bank/research/2026-01-14_12-50-37_centralized-ignore-patterns.md +193 -0
  115. tunacode_cli-0.1.37/memory-bank/research/2026-01-14_streaming-architecture.md +254 -0
  116. tunacode_cli-0.1.37/memory-bank/research/2026-01-15_option-c-grouped-sections.md +257 -0
  117. tunacode_cli-0.1.37/memory-bank/research/2026-01-15_tool-panel-redesign-options.md +290 -0
  118. tunacode_cli-0.1.37/memory-bank/research/2026-01-15_tool-panel-scrolling-readability.md +175 -0
  119. tunacode_cli-0.1.37/memory-bank/research/2026-01-16_10-59-35_tool-panel-architecture.md +161 -0
  120. tunacode_cli-0.1.37/memory-bank/research/2026-01-16_11-04-37_streaming-architecture.md +272 -0
  121. tunacode_cli-0.1.37/memory-bank/research/2026-01-16_13-57-44_hook-arrow-file-indicator.md +130 -0
  122. tunacode_cli-0.1.37/memory-bank/research/2026-01-16_tool-panel-resize-truncation.md +140 -0
  123. tunacode_cli-0.1.37/memory-bank/research/2026-01-19_12-03-10_pydantic_ai_tool_call_wire_format.md +230 -0
  124. tunacode_cli-0.1.37/memory-bank/research/2026-01-19_12-43-23_utils_code_smells_analysis.md +232 -0
  125. tunacode_cli-0.1.37/memory-bank/research/2026-01-19_14-30-00_dangling_tool_calls_timeout_gap.md +207 -0
  126. tunacode_cli-0.1.37/memory-bank/research/2026-01-19_14-38-26_ui_code_smells_analysis.md +441 -0
  127. tunacode_cli-0.1.37/memory-bank/research/bash.md +260 -0
  128. tunacode_cli-0.1.37/pyproject.toml +192 -0
  129. tunacode_cli-0.1.37/pytest.ini +36 -0
  130. tunacode_cli-0.1.37/scripts/check-file-length.sh +101 -0
  131. tunacode_cli-0.1.37/scripts/check-unused-constants.py +142 -0
  132. tunacode_cli-0.1.37/scripts/download_ripgrep.py +176 -0
  133. tunacode_cli-0.1.37/scripts/install_linux.sh +551 -0
  134. tunacode_cli-0.1.37/scripts/playwright_cache.py +141 -0
  135. tunacode_cli-0.1.37/scripts/preview_tool_panels.py +489 -0
  136. tunacode_cli-0.1.37/scripts/run-dead-imports.sh +82 -0
  137. tunacode_cli-0.1.37/scripts/startup_timer.py +272 -0
  138. tunacode_cli-0.1.37/scripts/ui_import_timer.py +194 -0
  139. tunacode_cli-0.1.37/scripts/uninstall.sh +481 -0
  140. tunacode_cli-0.1.37/scripts/update_models_registry.sh +4 -0
  141. tunacode_cli-0.1.37/scripts/utils/vulture_whitelist.py +10 -0
  142. tunacode_cli-0.1.37/src/tunacode/__init__.py +0 -0
  143. tunacode_cli-0.1.37/src/tunacode/configuration/__init__.py +1 -0
  144. tunacode_cli-0.1.37/src/tunacode/configuration/defaults.py +45 -0
  145. tunacode_cli-0.1.37/src/tunacode/configuration/models.py +163 -0
  146. tunacode_cli-0.1.37/src/tunacode/configuration/models_registry.json +1 -0
  147. tunacode_cli-0.1.37/src/tunacode/configuration/pricing.py +74 -0
  148. tunacode_cli-0.1.37/src/tunacode/configuration/settings.py +36 -0
  149. tunacode_cli-0.1.37/src/tunacode/constants.py +224 -0
  150. tunacode_cli-0.1.37/src/tunacode/core/__init__.py +6 -0
  151. tunacode_cli-0.1.37/src/tunacode/core/agents/__init__.py +35 -0
  152. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/__init__.py +37 -0
  153. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/agent_config.py +453 -0
  154. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/agent_helpers.py +221 -0
  155. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/message_handler.py +31 -0
  156. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/orchestrator/__init__.py +5 -0
  157. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/orchestrator/message_recorder.py +8 -0
  158. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/orchestrator/orchestrator.py +167 -0
  159. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/orchestrator/tool_dispatcher.py +348 -0
  160. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/orchestrator/usage_tracker.py +48 -0
  161. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/response_state.py +129 -0
  162. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/result_wrapper.py +51 -0
  163. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/state_transition.py +117 -0
  164. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/streaming.py +291 -0
  165. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/tool_buffer.py +44 -0
  166. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/tool_executor.py +116 -0
  167. tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/truncation_checker.py +37 -0
  168. tunacode_cli-0.1.37/src/tunacode/core/agents/delegation_tools.py +109 -0
  169. tunacode_cli-0.1.37/src/tunacode/core/agents/main.py +566 -0
  170. tunacode_cli-0.1.37/src/tunacode/core/agents/research_agent.py +242 -0
  171. tunacode_cli-0.1.37/src/tunacode/core/compaction.py +237 -0
  172. tunacode_cli-0.1.37/src/tunacode/core/limits.py +96 -0
  173. tunacode_cli-0.1.37/src/tunacode/core/logging/__init__.py +24 -0
  174. tunacode_cli-0.1.37/src/tunacode/core/logging/handlers.py +170 -0
  175. tunacode_cli-0.1.37/src/tunacode/core/logging/levels.py +17 -0
  176. tunacode_cli-0.1.37/src/tunacode/core/logging/manager.py +160 -0
  177. tunacode_cli-0.1.37/src/tunacode/core/logging/records.py +22 -0
  178. tunacode_cli-0.1.37/src/tunacode/core/prompting/__init__.py +29 -0
  179. tunacode_cli-0.1.37/src/tunacode/core/prompting/loader.py +66 -0
  180. tunacode_cli-0.1.37/src/tunacode/core/prompting/local_prompt.md +72 -0
  181. tunacode_cli-0.1.37/src/tunacode/core/prompting/prompting_engine.py +98 -0
  182. tunacode_cli-0.1.37/src/tunacode/core/prompting/sections.py +50 -0
  183. tunacode_cli-0.1.37/src/tunacode/core/prompting/templates.py +85 -0
  184. tunacode_cli-0.1.37/src/tunacode/core/state.py +434 -0
  185. tunacode_cli-0.1.37/src/tunacode/exceptions.py +313 -0
  186. tunacode_cli-0.1.37/src/tunacode/indexing/__init__.py +5 -0
  187. tunacode_cli-0.1.37/src/tunacode/indexing/code_index.py +432 -0
  188. tunacode_cli-0.1.37/src/tunacode/indexing/constants.py +53 -0
  189. tunacode_cli-0.1.37/src/tunacode/lsp/__init__.py +110 -0
  190. tunacode_cli-0.1.37/src/tunacode/lsp/client.py +352 -0
  191. tunacode_cli-0.1.37/src/tunacode/lsp/diagnostics.py +19 -0
  192. tunacode_cli-0.1.37/src/tunacode/lsp/servers.py +101 -0
  193. tunacode_cli-0.1.37/src/tunacode/prompts/default_prompt.md +955 -0
  194. tunacode_cli-0.1.37/src/tunacode/prompts/research/sections/agent_role.xml +5 -0
  195. tunacode_cli-0.1.37/src/tunacode/prompts/research/sections/constraints.xml +14 -0
  196. tunacode_cli-0.1.37/src/tunacode/prompts/research/sections/output_format.xml +57 -0
  197. tunacode_cli-0.1.37/src/tunacode/prompts/research/sections/tool_use.xml +23 -0
  198. tunacode_cli-0.1.37/src/tunacode/prompts/sections/advanced_patterns.xml +255 -0
  199. tunacode_cli-0.1.37/src/tunacode/prompts/sections/agent_role.xml +8 -0
  200. tunacode_cli-0.1.37/src/tunacode/prompts/sections/completion.xml +9 -0
  201. tunacode_cli-0.1.37/src/tunacode/prompts/sections/critical_rules.xml +37 -0
  202. tunacode_cli-0.1.37/src/tunacode/prompts/sections/examples.xml +220 -0
  203. tunacode_cli-0.1.37/src/tunacode/prompts/sections/output_style.xml +94 -0
  204. tunacode_cli-0.1.37/src/tunacode/prompts/sections/parallel_exec.xml +109 -0
  205. tunacode_cli-0.1.37/src/tunacode/prompts/sections/search_pattern.xml +100 -0
  206. tunacode_cli-0.1.37/src/tunacode/prompts/sections/system_info.xml +6 -0
  207. tunacode_cli-0.1.37/src/tunacode/prompts/sections/tool_use.xml +90 -0
  208. tunacode_cli-0.1.37/src/tunacode/prompts/sections/user_instructions.xml +3 -0
  209. tunacode_cli-0.1.37/src/tunacode/py.typed +0 -0
  210. tunacode_cli-0.1.37/src/tunacode/templates/__init__.py +5 -0
  211. tunacode_cli-0.1.37/src/tunacode/templates/loader.py +15 -0
  212. tunacode_cli-0.1.37/src/tunacode/tools/__init__.py +10 -0
  213. tunacode_cli-0.1.37/src/tunacode/tools/authorization/__init__.py +29 -0
  214. tunacode_cli-0.1.37/src/tunacode/tools/authorization/context.py +33 -0
  215. tunacode_cli-0.1.37/src/tunacode/tools/authorization/factory.py +22 -0
  216. tunacode_cli-0.1.37/src/tunacode/tools/authorization/handler.py +65 -0
  217. tunacode_cli-0.1.37/src/tunacode/tools/authorization/notifier.py +40 -0
  218. tunacode_cli-0.1.37/src/tunacode/tools/authorization/policy.py +40 -0
  219. tunacode_cli-0.1.37/src/tunacode/tools/authorization/requests.py +120 -0
  220. tunacode_cli-0.1.37/src/tunacode/tools/authorization/rules.py +91 -0
  221. tunacode_cli-0.1.37/src/tunacode/tools/authorization/types.py +18 -0
  222. tunacode_cli-0.1.37/src/tunacode/tools/bash.py +223 -0
  223. tunacode_cli-0.1.37/src/tunacode/tools/decorators.py +218 -0
  224. tunacode_cli-0.1.37/src/tunacode/tools/glob.py +357 -0
  225. tunacode_cli-0.1.37/src/tunacode/tools/grep.py +469 -0
  226. tunacode_cli-0.1.37/src/tunacode/tools/grep_components/__init__.py +9 -0
  227. tunacode_cli-0.1.37/src/tunacode/tools/grep_components/file_filter.py +91 -0
  228. tunacode_cli-0.1.37/src/tunacode/tools/grep_components/pattern_matcher.py +158 -0
  229. tunacode_cli-0.1.37/src/tunacode/tools/grep_components/result_formatter.py +87 -0
  230. tunacode_cli-0.1.37/src/tunacode/tools/grep_components/search_result.py +34 -0
  231. tunacode_cli-0.1.37/src/tunacode/tools/ignore.py +177 -0
  232. tunacode_cli-0.1.37/src/tunacode/tools/list_dir.py +173 -0
  233. tunacode_cli-0.1.37/src/tunacode/tools/present_plan.py +102 -0
  234. tunacode_cli-0.1.37/src/tunacode/tools/prompts/bash_prompt.xml +10 -0
  235. tunacode_cli-0.1.37/src/tunacode/tools/prompts/glob_prompt.xml +7 -0
  236. tunacode_cli-0.1.37/src/tunacode/tools/prompts/grep_prompt.xml +10 -0
  237. tunacode_cli-0.1.37/src/tunacode/tools/prompts/list_dir_prompt.xml +7 -0
  238. tunacode_cli-0.1.37/src/tunacode/tools/prompts/present_plan_prompt.xml +42 -0
  239. tunacode_cli-0.1.37/src/tunacode/tools/prompts/read_file_prompt.xml +9 -0
  240. tunacode_cli-0.1.37/src/tunacode/tools/prompts/submit_prompt.xml +8 -0
  241. tunacode_cli-0.1.37/src/tunacode/tools/prompts/todoclear_prompt.xml +12 -0
  242. tunacode_cli-0.1.37/src/tunacode/tools/prompts/todoread_prompt.xml +16 -0
  243. tunacode_cli-0.1.37/src/tunacode/tools/prompts/todowrite_prompt.xml +28 -0
  244. tunacode_cli-0.1.37/src/tunacode/tools/prompts/update_file_prompt.xml +9 -0
  245. tunacode_cli-0.1.37/src/tunacode/tools/prompts/web_fetch_prompt.xml +11 -0
  246. tunacode_cli-0.1.37/src/tunacode/tools/prompts/write_file_prompt.xml +7 -0
  247. tunacode_cli-0.1.37/src/tunacode/tools/react.py +111 -0
  248. tunacode_cli-0.1.37/src/tunacode/tools/read_file.py +96 -0
  249. tunacode_cli-0.1.37/src/tunacode/tools/submit.py +45 -0
  250. tunacode_cli-0.1.37/src/tunacode/tools/todo.py +222 -0
  251. tunacode_cli-0.1.37/src/tunacode/tools/update_file.py +62 -0
  252. tunacode_cli-0.1.37/src/tunacode/tools/utils/__init__.py +1 -0
  253. tunacode_cli-0.1.37/src/tunacode/tools/utils/ripgrep.py +340 -0
  254. tunacode_cli-0.1.37/src/tunacode/tools/utils/text_match.py +352 -0
  255. tunacode_cli-0.1.37/src/tunacode/tools/web_fetch.py +245 -0
  256. tunacode_cli-0.1.37/src/tunacode/tools/write_file.py +34 -0
  257. tunacode_cli-0.1.37/src/tunacode/tools/xml_helper.py +34 -0
  258. tunacode_cli-0.1.37/src/tunacode/types/__init__.py +170 -0
  259. tunacode_cli-0.1.37/src/tunacode/types/base.py +94 -0
  260. tunacode_cli-0.1.37/src/tunacode/types/callbacks.py +55 -0
  261. tunacode_cli-0.1.37/src/tunacode/types/dataclasses.py +121 -0
  262. tunacode_cli-0.1.37/src/tunacode/types/pydantic_ai.py +66 -0
  263. tunacode_cli-0.1.37/src/tunacode/types/state.py +138 -0
  264. tunacode_cli-0.1.37/src/tunacode/ui/__init__.py +6 -0
  265. tunacode_cli-0.1.37/src/tunacode/ui/app.py +557 -0
  266. tunacode_cli-0.1.37/src/tunacode/ui/assets/logo.ansi +9 -0
  267. tunacode_cli-0.1.37/src/tunacode/ui/commands/__init__.py +534 -0
  268. tunacode_cli-0.1.37/src/tunacode/ui/headless/__init__.py +5 -0
  269. tunacode_cli-0.1.37/src/tunacode/ui/headless/output.py +72 -0
  270. tunacode_cli-0.1.37/src/tunacode/ui/logo_assets.py +20 -0
  271. tunacode_cli-0.1.37/src/tunacode/ui/main.py +252 -0
  272. tunacode_cli-0.1.37/src/tunacode/ui/plan_approval.py +144 -0
  273. tunacode_cli-0.1.37/src/tunacode/ui/renderers/__init__.py +41 -0
  274. tunacode_cli-0.1.37/src/tunacode/ui/renderers/agent_response.py +221 -0
  275. tunacode_cli-0.1.37/src/tunacode/ui/renderers/errors.py +197 -0
  276. tunacode_cli-0.1.37/src/tunacode/ui/renderers/panel_widths.py +14 -0
  277. tunacode_cli-0.1.37/src/tunacode/ui/renderers/panels.py +554 -0
  278. tunacode_cli-0.1.37/src/tunacode/ui/renderers/search.py +313 -0
  279. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/__init__.py +73 -0
  280. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/base.py +480 -0
  281. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/bash.py +254 -0
  282. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/diagnostics.py +186 -0
  283. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/glob.py +230 -0
  284. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/grep.py +232 -0
  285. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/list_dir.py +226 -0
  286. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/read_file.py +230 -0
  287. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/research.py +294 -0
  288. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/syntax_utils.py +227 -0
  289. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/update_file.py +272 -0
  290. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/web_fetch.py +191 -0
  291. tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/write_file.py +168 -0
  292. tunacode_cli-0.1.37/src/tunacode/ui/repl_support.py +234 -0
  293. tunacode_cli-0.1.37/src/tunacode/ui/screens/__init__.py +16 -0
  294. tunacode_cli-0.1.37/src/tunacode/ui/screens/model_picker.py +303 -0
  295. tunacode_cli-0.1.37/src/tunacode/ui/screens/session_picker.py +181 -0
  296. tunacode_cli-0.1.37/src/tunacode/ui/screens/setup.py +218 -0
  297. tunacode_cli-0.1.37/src/tunacode/ui/screens/theme_picker.py +90 -0
  298. tunacode_cli-0.1.37/src/tunacode/ui/screens/update_confirm.py +69 -0
  299. tunacode_cli-0.1.37/src/tunacode/ui/shell_runner.py +267 -0
  300. tunacode_cli-0.1.37/src/tunacode/ui/startup.py +57 -0
  301. tunacode_cli-0.1.37/src/tunacode/ui/styles/layout.tcss +99 -0
  302. tunacode_cli-0.1.37/src/tunacode/ui/styles/modals.tcss +38 -0
  303. tunacode_cli-0.1.37/src/tunacode/ui/styles/panels.tcss +81 -0
  304. tunacode_cli-0.1.37/src/tunacode/ui/styles/theme-nextstep.tcss +320 -0
  305. tunacode_cli-0.1.37/src/tunacode/ui/styles/widgets.tcss +39 -0
  306. tunacode_cli-0.1.37/src/tunacode/ui/styles.py +18 -0
  307. tunacode_cli-0.1.37/src/tunacode/ui/welcome.py +69 -0
  308. tunacode_cli-0.1.37/src/tunacode/ui/widgets/__init__.py +23 -0
  309. tunacode_cli-0.1.37/src/tunacode/ui/widgets/command_autocomplete.py +62 -0
  310. tunacode_cli-0.1.37/src/tunacode/ui/widgets/editor.py +402 -0
  311. tunacode_cli-0.1.37/src/tunacode/ui/widgets/file_autocomplete.py +47 -0
  312. tunacode_cli-0.1.37/src/tunacode/ui/widgets/messages.py +46 -0
  313. tunacode_cli-0.1.37/src/tunacode/ui/widgets/resource_bar.py +179 -0
  314. tunacode_cli-0.1.37/src/tunacode/ui/widgets/status_bar.py +98 -0
  315. tunacode_cli-0.1.37/src/tunacode/utils/__init__.py +0 -0
  316. tunacode_cli-0.1.37/src/tunacode/utils/config/__init__.py +13 -0
  317. tunacode_cli-0.1.37/src/tunacode/utils/config/user_configuration.py +62 -0
  318. tunacode_cli-0.1.37/src/tunacode/utils/messaging/__init__.py +9 -0
  319. tunacode_cli-0.1.37/src/tunacode/utils/messaging/message_utils.py +34 -0
  320. tunacode_cli-0.1.37/src/tunacode/utils/messaging/token_counter.py +20 -0
  321. tunacode_cli-0.1.37/src/tunacode/utils/parsing/__init__.py +13 -0
  322. tunacode_cli-0.1.37/src/tunacode/utils/parsing/command_parser.py +56 -0
  323. tunacode_cli-0.1.37/src/tunacode/utils/parsing/json_utils.py +158 -0
  324. tunacode_cli-0.1.37/src/tunacode/utils/parsing/retry.py +153 -0
  325. tunacode_cli-0.1.37/src/tunacode/utils/parsing/tool_parser.py +350 -0
  326. tunacode_cli-0.1.37/src/tunacode/utils/system/__init__.py +25 -0
  327. tunacode_cli-0.1.37/src/tunacode/utils/system/gitignore.py +80 -0
  328. tunacode_cli-0.1.37/src/tunacode/utils/system/ignore_patterns.py +130 -0
  329. tunacode_cli-0.1.37/src/tunacode/utils/system/paths.py +190 -0
  330. tunacode_cli-0.1.37/src/tunacode/utils/ui/__init__.py +9 -0
  331. tunacode_cli-0.1.37/src/tunacode/utils/ui/file_filter.py +116 -0
  332. tunacode_cli-0.1.37/src/tunacode/utils/ui/helpers.py +24 -0
  333. tunacode_cli-0.1.37/tests/__init__.py +1 -0
  334. tunacode_cli-0.1.37/tests/conftest.py +19 -0
  335. tunacode_cli-0.1.37/tests/test_base_renderer.py +88 -0
  336. tunacode_cli-0.1.37/tests/test_base_tool_renderer.py +193 -0
  337. tunacode_cli-0.1.37/tests/test_cli_default_command.py +29 -0
  338. tunacode_cli-0.1.37/tests/test_compaction.py +349 -0
  339. tunacode_cli-0.1.37/tests/test_confirmation_preview.py +46 -0
  340. tunacode_cli-0.1.37/tests/test_diagnostics_renderer.py +175 -0
  341. tunacode_cli-0.1.37/tests/test_exceptions.py +94 -0
  342. tunacode_cli-0.1.37/tests/test_glob_grep_path_validation.py +70 -0
  343. tunacode_cli-0.1.37/tests/test_headless_cli.py +37 -0
  344. tunacode_cli-0.1.37/tests/test_limits.py +245 -0
  345. tunacode_cli-0.1.37/tests/test_logging.py +295 -0
  346. tunacode_cli-0.1.37/tests/test_message_utils.py +92 -0
  347. tunacode_cli-0.1.37/tests/test_present_plan.py +118 -0
  348. tunacode_cli-0.1.37/tests/test_prompting_engine.py +90 -0
  349. tunacode_cli-0.1.37/tests/test_repl_support.py +26 -0
  350. tunacode_cli-0.1.37/tests/test_shell_command_escape.py +97 -0
  351. tunacode_cli-0.1.37/tests/test_shell_runner.py +103 -0
  352. tunacode_cli-0.1.37/tests/test_text_match.py +132 -0
  353. tunacode_cli-0.1.37/tests/test_todo_tools.py +48 -0
  354. tunacode_cli-0.1.37/tests/test_token_counter.py +79 -0
  355. tunacode_cli-0.1.37/tests/test_tool_call_lifecycle.py +895 -0
  356. tunacode_cli-0.1.37/tests/test_tool_conformance.py +143 -0
  357. tunacode_cli-0.1.37/tests/test_tool_decorators.py +219 -0
  358. tunacode_cli-0.1.37/tests/test_tool_dispatcher_coverage.py +376 -0
  359. tunacode_cli-0.1.37/tests/test_tool_parser.py +437 -0
  360. tunacode_cli-0.1.37/tests/test_tool_performance.py +281 -0
  361. tunacode_cli-0.1.37/tests/test_tool_retry.py +284 -0
  362. tunacode_cli-0.1.37/tests/test_update_file_renderer.py +20 -0
  363. tunacode_cli-0.1.37/tests/test_usage_tracker.py +35 -0
  364. tunacode_cli-0.1.37/tests/test_web_fetch.py +141 -0
  365. tunacode_cli-0.1.37/tests/tools/test_ignore.py +80 -0
  366. tunacode_cli-0.1.37/tests/unit/tools/test_submit.py +65 -0
  367. tunacode_cli-0.1.37/tests/unit/ui/test_agent_response.py +144 -0
  368. tunacode_cli-0.1.37/uv.lock +3560 -0
@@ -0,0 +1,359 @@
1
+ # Claude Journal
2
+
3
+ ## 2026-01-07: Renderer Unification
4
+
5
+ Unifying the 8 tool renderers in `src/tunacode/ui/renderers/tools/` to eliminate duplication via a shared base class and registry pattern.
6
+
7
+ ### Completed:
8
+ - Created `base.py` with `BaseToolRenderer[T]` ABC and `ToolRendererProtocol`
9
+ - Extracted shared helpers: `truncate_line`, `truncate_content`, `pad_lines`
10
+ - Added registry pattern: `@tool_renderer`, `get_renderer`, `list_renderers`
11
+ - Migrated `list_dir.py` to use `BaseToolRenderer` (199 -> 149 lines)
12
+ - Created documentation at `docs/ui/tool_renderers.md`
13
+
14
+ ### Architecture Decisions:
15
+ - Module-level singleton renderer instances (not created per-call)
16
+ - Render functions remain the public API (backward compatible)
17
+ - `@tool_renderer` decorator for self-registration
18
+ - Helpers are standalone functions, not methods
19
+
20
+ ---
21
+
22
+ ## 2026-01-07: Local Mode Context Optimization
23
+
24
+ ### Problem:
25
+ - System prompt + tool schemas used ~3.5k tokens before any conversation
26
+ - Each file read could use 2000 lines (~20k tokens)
27
+ - With 10k context, only ~6.5k left for conversation
28
+ - LLM APIs are stateless - system prompt sent every turn
29
+
30
+ ### Solution:
31
+
32
+ **1. Minimal System Prompt**
33
+ - `LOCAL_TEMPLATE` in `templates.py` - only 3 sections: AGENT_ROLE, TOOL_USE, USER_INSTRUCTIONS
34
+ - `local_mode: true` setting triggers minimal template
35
+
36
+ **2. Minimal Tool Schemas**
37
+ - Reduced from 11 tools to 6 (bash, read_file, update_file, write_file, glob, list_dir)
38
+ - 1-word descriptions ("Shell", "Read", "Edit", etc.) - saves ~1k tokens
39
+
40
+ **3. Aggressive Pruning**
41
+ - LOCAL_PRUNE_PROTECT_TOKENS: 2,000 (vs 40,000)
42
+ - LOCAL_PRUNE_MINIMUM_THRESHOLD: 500 (vs 20,000)
43
+
44
+ **4. Tool Output Limits**
45
+ - LOCAL_DEFAULT_READ_LIMIT: 200 lines (vs 2,000)
46
+ - LOCAL_MAX_LINE_LENGTH: 500 chars (vs 2,000)
47
+ - LOCAL_MAX_COMMAND_OUTPUT: 1,500 chars (vs 5,000)
48
+
49
+ **5. Response Limit**
50
+ - local_max_tokens: 1000 - caps model output per turn
51
+
52
+ ### Token Budget (Local Mode):
53
+ | Component | Tokens |
54
+ |-----------|--------|
55
+ | System prompt | ~1,100 |
56
+ | Guide file | ~500 |
57
+ | 6 tools (minimal) | ~575 |
58
+ | **Total base** | **~2,200** |
59
+
60
+ With 10k context: ~7.8k available for conversation.
61
+
62
+ ### Key Insight:
63
+ LLM APIs are stateless. Every request sends: system prompt + tool schemas + full conversation history. Model has no memory - re-reads everything each turn.
64
+
65
+ ### Key Files:
66
+ - `src/tunacode/core/limits.py` - Centralized limit configuration
67
+ - `src/tunacode/core/prompting/templates.py` - LOCAL_TEMPLATE
68
+ - `src/tunacode/core/prompting/local_prompt.md` - Condensed prompt
69
+ - `src/tunacode/core/compaction.py` - Dynamic prune thresholds
70
+ - `src/tunacode/constants.py` - Local mode limit constants
71
+
72
+ ---
73
+
74
+ ## 2026-01-06: Local Model Support
75
+
76
+ ### Task: Add local model support to tunacode
77
+
78
+ ### Completed:
79
+ - Created condensed system prompt at `src/tunacode/prompts/local_model_prompt.txt` (~500 bytes vs 34KB full prompt)
80
+ - Added `local_model: true/false` setting in config defaults
81
+ - Modified `load_system_prompt()` to use condensed prompt when `local_model=true`
82
+ - Added cache invalidation for `local_model` setting in `_compute_agent_version()`
83
+ - Skip AGENTS.md loading for local models to save tokens
84
+ - Created `fallback_executor.py` for models that output tool calls in text (e.g., `<tool_call>` tags)
85
+ - Updated `node_processor.py` to detect and execute fallback tool calls
86
+ - Passed `agent_ctx` through the call chain for result injection
87
+ - Tested with multiple local models via LM Studio/vLLM
88
+
89
+ ### Notes:
90
+ - Qwen2.5-Coder-14B supports native OpenAI tool calling format
91
+ - Smaller models (0.6B-1.7B) output `<tool_call>` tags in content - fallback parser handles this
92
+ - llama.cpp uses KV cache efficiently (LCP similarity) so repeated prompt not re-computed
93
+
94
+ ---
95
+
96
+ ## 2026-01-08: Config Restoration & Local Mode Docs
97
+
98
+ ### Task: Restore pre-local-mode config and document local mode setup
99
+
100
+ ### Completed:
101
+
102
+ **1. Config Backup Discovery**
103
+ Found three config variants in `~/.config/`:
104
+ - `tunacode.json` - was set to local mode (grok-code-fast-1, 10k context)
105
+ - `tunacode.json.bak` - MiniMax-M2.1, 200k context, no local mode
106
+ - `@tunacode.json` - Gemini 3 Pro via OpenRouter
107
+
108
+ **2. Restored Config**
109
+ - Restored `~/.config/tunacode.json` from `.bak` (MiniMax config)
110
+ - Settings: `minimax:MiniMax-M2.1`, 200k context, `guide_file: AGENTS.md`
111
+
112
+ **3. Created Local Mode Example**
113
+ - Created `docs/configuration/tunacode.local.json.example`
114
+ - Documents all local mode settings:
115
+ - `local_mode: true`
116
+ - `local_max_tokens: 1000`
117
+ - `context_window_size: 10000`
118
+ - `OPENAI_BASE_URL: http://127.0.0.1:8080/v1`
119
+ - `guide_file: CLAUDE_LOCAL.md`
120
+
121
+ ### Key Files:
122
+ - `~/.config/tunacode.json` - user config (restored to MiniMax)
123
+ - `docs/configuration/tunacode.json.example` - standard example
124
+ - `docs/configuration/tunacode.local.json.example` - NEW: local mode example
125
+
126
+ ### Notes:
127
+ - Local mode uses condensed prompts and minimal tool schemas for small context windows
128
+ - The `.bak` file preserved the pre-experimentation state - good backup hygiene!
129
+ - User was testing local models, now back to cloud (MiniMax)
130
+
131
+ ---
132
+
133
+ ## 2026-01-08: Syntax Highlighting for Tool Renderers (Branch: ui-model-work)
134
+
135
+ ### The Mission:
136
+ Make tool outputs pretty! All those ugly plain text viewports were a crime against NeXTSTEP aesthetics. Time to add syntax highlighting everywhere.
137
+
138
+ ### Completed (Commit 9db8e92):
139
+
140
+ **1. Created `syntax_utils.py` - The Shared Foundation**
141
+ - `EXTENSION_LEXERS` - 60+ file extension → lexer mappings
142
+ - `get_lexer(filepath)` - Get pygments lexer from file path
143
+ - `syntax_or_text(content, filepath)` - Render highlighted or plain
144
+ - `detect_code_lexer(content)` - Heuristic code detection (shebangs, JSON, Python/JS patterns)
145
+ - `SYNTAX_THEME = "monokai"` - Consistent theme everywhere
146
+
147
+ **2. Created `write_file.py` - New Renderer!**
148
+ - Was missing entirely - now shows syntax-highlighted preview of written content
149
+ - Green "NEW" badge in header, file stats
150
+
151
+ **3. Updated 8 Existing Renderers:**
152
+
153
+ | Renderer | What Changed |
154
+ |----------|-------------|
155
+ | `read_file` | Syntax highlighting by file extension, built-in line numbers from Syntax component |
156
+ | `grep` | Cyan file paths, yellow `reverse` highlighted matches, styled line numbers with `│` |
157
+ | `glob` | Files colored by type: Python=bright_blue, JS=yellow, JSON=green, etc. Dir path dim, filename bold |
158
+ | `list_dir` | Tree chars dim, directories bold cyan, files colored by lexer type |
159
+ | `bash` | Smart detection: `git diff`→diff lexer, JSON commands→json lexer, labeled stdout/stderr |
160
+ | `web_fetch` | URL-based detection (raw.githubusercontent.com, .json, /api/), content heuristics |
161
+ | `research` | New "Code" section with syntax-highlighted examples from `code_examples` field |
162
+ | `update_file` | Already had Syntax("diff") - unchanged, the OG |
163
+
164
+ **4. Updated `__init__.py`:**
165
+ - Added `write_file` renderer to exports
166
+ - Added syntax utility functions to `__all__`
167
+ - Better docstring explaining the 4-zone pattern
168
+
169
+ ### Key Design Decisions:
170
+ - `syntax_or_text()` returns `RenderableType` - graceful fallback to `Text()` for unknown extensions
171
+ - File-type coloring consistent across `glob`, `list_dir`, `grep` (same color = same type)
172
+ - Bash output detection is conservative - only highlights when confident
173
+ - Research viewport prioritizes findings over code (code is supplementary)
174
+
175
+ ### Files Modified:
176
+ ```
177
+ src/tunacode/ui/renderers/tools/
178
+ ├── __init__.py (exports + docstring)
179
+ ├── syntax_utils.py (NEW - shared utilities)
180
+ ├── write_file.py (NEW - renderer)
181
+ ├── read_file.py (syntax highlighting)
182
+ ├── grep.py (styled matches)
183
+ ├── glob.py (colored paths)
184
+ ├── list_dir.py (styled tree)
185
+ ├── bash.py (smart detection)
186
+ ├── web_fetch.py (URL/content detection)
187
+ └── research.py (code examples)
188
+ ```
189
+
190
+ ### What's Left on This Branch:
191
+ - Other UI model work (the branch name suggests more to do)
192
+ - Unstaged: `.claude/JOURNAL.md`, `CLAUDE.md`, research docs, config example
193
+
194
+ ### Commands:
195
+ ```bash
196
+ uv run ruff check src/tunacode/ui/renderers/tools/ # All checks pass
197
+ uv run python -c "from tunacode.ui.renderers.tools import list_renderers; print(list_renderers())"
198
+ # ['bash', 'glob', 'grep', 'list_dir', 'read_file', 'research_codebase', 'update_file', 'web_fetch', 'write_file']
199
+ ```
200
+
201
+ ### Fun Fact:
202
+ We went from 0 syntax-highlighted viewports to 8 in one session. The `update_file` renderer was the lonely pioneer - now it has friends!
203
+
204
+ ---
205
+
206
+ ## 2026-01-08: The Great Panel Width Debugging Adventure (Branch: master)
207
+
208
+ ### The Problem:
209
+ Tool panels were narrower than agent panels. User showed screenshot - `read_file` panel was ~50 chars wide while `agent` panel was full width. Classic NeXTSTEP violation!
210
+
211
+ ### The Red Herring (What We Thought):
212
+ Initially believed the issue was `width=TOOL_PANEL_WIDTH` (50 chars) on `Panel()` calls. Spent time:
213
+ - Removing `width=TOOL_PANEL_WIDTH` from 7 Panel() calls in `panels.py`
214
+ - Removing it from `search.py`, `update_file.py`, `app.py`
215
+ - Cleaning up unused imports
216
+
217
+ But panels were STILL narrow after restart. User called me out: "stop being lazy, dig deeper"
218
+
219
+ ### The Actual Root Cause (The AHA Moment):
220
+
221
+ **Textual's `RichLog.write()` has its OWN `expand` parameter that defaults to `False`!**
222
+
223
+ From `.venv/lib/python3.13/site-packages/textual/widgets/_rich_log.py`:
224
+ ```python
225
+ def write(
226
+ self,
227
+ content: RenderableType | object,
228
+ width: int | None = None,
229
+ expand: bool = False, # <-- THIS IS THE VILLAIN
230
+ shrink: bool = True,
231
+ ...
232
+ )
233
+ ```
234
+
235
+ When `expand=False` (default), RichLog measures the content's minimum width and renders at that width, **completely ignoring** the Panel's own `expand=True` property!
236
+
237
+ The Panel's expand tells Rich "expand to console width", but RichLog overrides the console width to be just the measured content width. Two different expand flags, two different systems!
238
+
239
+ ### The Real Fix:
240
+ Pass `expand=True` to `rich_log.write()`:
241
+
242
+ ```python
243
+ # Before
244
+ self.rich_log.write(panel)
245
+
246
+ # After
247
+ self.rich_log.write(panel, expand=True)
248
+ ```
249
+
250
+ ### Files Modified:
251
+ | File | Change |
252
+ |------|--------|
253
+ | `src/tunacode/ui/app.py` | 3 panel writes → `expand=True` (lines 325, 377, 558) |
254
+ | `src/tunacode/ui/plan_approval.py` | 1 panel write → `expand=True` (line 132) |
255
+ | `src/tunacode/ui/renderers/panels.py` | Removed `width=TOOL_PANEL_WIDTH` (harmless cleanup) |
256
+ | `src/tunacode/ui/renderers/search.py` | Removed unused import |
257
+ | `src/tunacode/ui/renderers/tools/update_file.py` | Removed unused import |
258
+
259
+ ### The Lesson:
260
+ When Rich Panel has `expand=True` but isn't expanding in Textual:
261
+ 1. The Panel's expand is **not** the issue
262
+ 2. Check how the panel is being **written** to the widget
263
+ 3. RichLog.write() has its own expand parameter!
264
+
265
+ ### Status:
266
+ - Changes made, ruff passes
267
+ - NOT COMMITTED YET - user needs to test
268
+ - Previous width removal changes are technically unnecessary but harmless
269
+
270
+ ### Commands:
271
+ ```bash
272
+ git diff --stat # See all changes
273
+ uv run ruff check src/tunacode/ui/ # Verify
274
+ # Restart tunacode and make NEW request to test
275
+ ```
276
+
277
+ ### Philosophical Note:
278
+ This bug was a perfect example of "the abstraction leaked". Panel.expand and RichLog.write(expand=) look like they should be the same thing, but they operate at different levels. Panel tells Rich what to do. RichLog tells Rich what size canvas to give it. The canvas size wins.
279
+
280
+ ---
281
+
282
+ ## 2026-01-14: Glob Tool Dead Code Cleanup (Branch: glob-improvements)
283
+
284
+ ### The Mission:
285
+ Clean up glob tool based on research doc findings. Remove dead code, fix deprecations.
286
+
287
+ ### The Discovery: Semantically Dead Code
288
+
289
+ Static analysis (Vulture) reported "no dead code" in glob.py. But manual review found:
290
+
291
+ ```python
292
+ # Line 29: Global declared
293
+ _gitignore_patterns: set[str] | None = None
294
+
295
+ # Line 73-74: Function called
296
+ if use_gitignore:
297
+ await _load_gitignore_patterns(root_path)
298
+
299
+ # Lines 155-174: Function populates global
300
+ async def _load_gitignore_patterns(root: Path) -> None:
301
+ global _gitignore_patterns
302
+ # ... reads .gitignore files, populates set
303
+ ```
304
+
305
+ **The Problem:** `_gitignore_patterns` was NEVER READ. All 7 references were writes. The actual filtering used `DEFAULT_EXCLUDE_DIRS`. The `use_gitignore` parameter was a lie.
306
+
307
+ ### Why Vulture Missed It
308
+
309
+ Vulture checks: "Is this symbol referenced?"
310
+ It does NOT check: "Is the result consumed?"
311
+
312
+ The function WAS called. The variable WAS assigned. But the data went nowhere.
313
+
314
+ ### Completed:
315
+
316
+ **Commit 61384fe - Dead Code Removal:**
317
+ - Removed `_gitignore_patterns` global
318
+ - Removed `_load_gitignore_patterns()` function (21 lines)
319
+ - Removed `use_gitignore` parameter from signature
320
+ - Replaced 2x `asyncio.get_event_loop().run_in_executor()` with `asyncio.to_thread()`
321
+ - Created QA card: `.claude/qa/semantically-dead-code.md`
322
+ - Added lesson to CLAUDE.md Continuous Learning
323
+
324
+ **Commit 745a56b - Asyncio Deprecation Fixes:**
325
+ Fixed all remaining `get_event_loop()` calls in codebase:
326
+
327
+ | File | Calls | Fix |
328
+ |------|-------|-----|
329
+ | `grep.py` | 2 | `get_running_loop().run_in_executor()` (custom executor) |
330
+ | `startup.py` | 2 | `asyncio.to_thread()` |
331
+ | `app.py` | 2 | `asyncio.to_thread()` |
332
+ | `lsp/client.py` | 3 | `get_running_loop()` for create_future/time |
333
+
334
+ ### Key Insight: asyncio.to_thread() vs get_running_loop()
335
+
336
+ - `asyncio.to_thread(func)` - For default executor (None), simpler API
337
+ - `asyncio.get_running_loop().run_in_executor(exec, func)` - For custom executors
338
+
339
+ ### Prevention Rule
340
+
341
+ When adding `load_X()` function:
342
+ 1. Grep for READS of X, not just references
343
+ 2. If a parameter "controls behavior", trace data flow to prove it changes output
344
+ 3. Question unused returns - if nothing reads it, why compute it?
345
+
346
+ ### Status:
347
+ - Branch: `glob-improvements`
348
+ - Tests: 304 passed
349
+ - Ruff: clean
350
+ - Zero `get_event_loop()` calls remain in src/
351
+ - Ready to push
352
+
353
+ ### Next:
354
+ Push branch, optionally create PR
355
+
356
+ ### References:
357
+ - Research: `memory-bank/research/2026-01-14_12-27-29_glob-tool-bottlenecks.md`
358
+ - QA Card: `.claude/qa/semantically-dead-code.md`
359
+ - Skill used: `.claude/skills/dead-code-detector/` (Vulture - catches syntactic, not semantic)
@@ -0,0 +1,45 @@
1
+ ---
2
+ title: Missing cached_tokens in RequestUsage crashes usage tracking
3
+ link: missing-cached-tokens-request-usage
4
+ type: delta
5
+ path: src/tunacode/core/agents/agent_components/orchestrator/usage_tracker.py
6
+ depth: 0
7
+ seams: [D] data
8
+ ontological_relations:
9
+ - relates_to: [[agent-orchestrator]]
10
+ - affects: [[usage-tracking]]
11
+ - fixes: [[requestusage-missing-cached-tokens]]
12
+ tags:
13
+ - usage
14
+ - crash
15
+ - tracking
16
+ created_at: 2026-01-12T22:19:08Z
17
+ updated_at: 2026-01-12T22:19:08Z
18
+ uuid: 00080ff4-9b7e-418b-b7dc-ca671160aee7
19
+ ---
20
+
21
+ ## Summary
22
+
23
+ The new usage tracker accessed `cached_tokens` directly on provider usage objects, which caused an AttributeError for providers that omit that field. We now normalize usage objects at the boundary and default missing fields to 0, matching the old behavior.
24
+
25
+ ## Context
26
+
27
+ This surfaced after the node processor refactor when the usage tracking logic moved into `usage_tracker.py` and lost the defensive `getattr` fallback. We missed it because the refactor did not include a regression test for usage objects without cached token data.
28
+
29
+ ## Root Cause
30
+
31
+ Provider usage payloads are not uniform: some only include request/response tokens. The new code assumed the presence of `cached_tokens`, violating the implicit contract that missing fields should be treated as zero. Prevention: normalize usage objects at the type boundary and add a test for missing cached tokens.
32
+
33
+ ## Changes
34
+
35
+ - Added a normalization helper for usage objects with defaults for missing fields.
36
+ - Updated usage tracking to use the normalized shape.
37
+ - Added a regression test covering missing `cached_tokens`.
38
+
39
+ ## Behavioral Impact
40
+
41
+ Usage tracking no longer crashes when a provider omits cached token data; costs and totals still accumulate correctly with cached tokens treated as zero.
42
+
43
+ ## Related Cards
44
+
45
+ None
@@ -0,0 +1,55 @@
1
+ ---
2
+ title: list_dir halts agent on bad paths
3
+ link: list-dir-tool-execution-error
4
+ type: delta
5
+ path: src/tunacode/tools/list_dir.py
6
+ depth: 0
7
+ seams: [M] module
8
+ ontological_relations:
9
+ - relates_to: [[tools]]
10
+ - affects: [[tool-executor]]
11
+ - fixes: [[agent-halt-on-tool-error]]
12
+ tags:
13
+ - tools
14
+ - error-handling
15
+ - list_dir
16
+ - ModelRetry
17
+ created_at: 2026-01-07T22:54:00-08:00
18
+ updated_at: 2026-01-07T23:15:00-08:00
19
+ uuid: a1b2c3d4-e5f6-7890-abcd-ef1234567890
20
+ ---
21
+
22
+ ## Summary
23
+
24
+ `list_dir` raised `FileNotFoundError` on non-existent directories, which `@base_tool` wrapped as `ToolExecutionError`. Since `ToolExecutionError` is in `NON_RETRYABLE_ERRORS`, the agent halted instead of letting the LLM self-correct with a valid path.
25
+
26
+ ## Context
27
+
28
+ Surfaced when agent called `list_dir("/home/tuna/tunacode/apps")` - a directory that doesn't exist. Agent crashed with `ToolExecutionError` instead of retrying.
29
+
30
+ ## Root Cause
31
+
32
+ Error propagation chain:
33
+ 1. `list_dir` raises `FileNotFoundError`
34
+ 2. `@base_tool` decorator wraps it as `ToolExecutionError`
35
+ 3. `tool_executor.py` has `ToolExecutionError` in `NON_RETRYABLE_ERRORS`
36
+ 4. Non-retryable errors propagate immediately, halting the agent
37
+
38
+ First attempted fix: switch to `@file_tool` decorator. Failed because `@file_tool` expects required `filepath` positional arg, but `list_dir` has optional `directory="."`.
39
+
40
+ ## Changes
41
+
42
+ - Import `ModelRetry` from `pydantic_ai.exceptions`
43
+ - Replace `raise FileNotFoundError(...)` with `raise ModelRetry(...)`
44
+ - Replace `raise NotADirectoryError(...)` with `raise ModelRetry(...)`
45
+ - Keep `@base_tool` decorator (not `@file_tool`)
46
+
47
+ ## Behavioral Impact
48
+
49
+ - Agent no longer halts on bad directory paths
50
+ - LLM receives retry signal with error message, can self-correct
51
+ - No change to valid path behavior
52
+
53
+ ## Related Cards
54
+
55
+ - [[glob-grep-error-strings]] - similar smell: return error strings instead of raising
@@ -0,0 +1,171 @@
1
+ ---
2
+ title: Dangling Tool Calls on User Abort
3
+ link: dangling-tool-calls-abort
4
+ type: delta
5
+ path: src/tunacode/core/agents/main.py
6
+ depth: 0
7
+ seams: [M, S]
8
+ ontological_relations:
9
+ - relates_to: [[conversation-turns]]
10
+ - affects: [[message-history]]
11
+ - fixes: [[api-error-on-next-request]]
12
+ tags:
13
+ - bug
14
+ - abort-handling
15
+ - message-invariants
16
+ - tool-calls
17
+ created_at: 2026-01-17T06:00:00Z
18
+ updated_at: 2026-01-17T06:00:00Z
19
+ uuid: d7c8e9f0-1a2b-3c4d-5e6f-7a8b9c0d1e2f
20
+ ---
21
+
22
+ # Dangling Tool Calls on User Abort
23
+
24
+ ## Summary
25
+
26
+ When a user aborted mid-tool-call (Ctrl+C or tool denial), the conversation history was left with a `ModelResponse` containing tool calls but no corresponding `ToolReturn` messages. The next API request failed because the provider expected tool returns for pending calls.
27
+
28
+ ## Context
29
+
30
+ - File: `src/tunacode/core/agents/main.py`
31
+ - PR: #246
32
+ - Surfaces: On any abort during tool execution, next request fails
33
+
34
+ ## Root Cause
35
+
36
+ **Missing invariant enforcement on exception path.**
37
+
38
+ The message flow has an implicit invariant:
39
+
40
+ ```
41
+ INVARIANT: Every ModelResponse with tool_calls MUST be followed by
42
+ matching ToolReturn(s) before the next ModelRequest
43
+ ```
44
+
45
+ The happy path naturally maintains this - tool executes, result recorded. But `UserAbortError` breaks out of the loop BEFORE recording tool returns, violating the invariant.
46
+
47
+ ```
48
+ ┌─────────────────────────────────────────────────────────────┐
49
+ │ Happy Path: │
50
+ │ ModelResponse(tool_calls=[A, B]) │
51
+ │ → execute tools │
52
+ │ → ToolReturn(A), ToolReturn(B) │
53
+ │ → ModelRequest (next turn) ✓ │
54
+ └─────────────────────────────────────────────────────────────┘
55
+
56
+ ┌─────────────────────────────────────────────────────────────┐
57
+ │ Abort Path (BEFORE fix): │
58
+ │ ModelResponse(tool_calls=[A, B]) │
59
+ │ → execute tool A │
60
+ │ → UserAbortError raised │
61
+ │ → messages still has ModelResponse with [A, B] │
62
+ │ → NO ToolReturn recorded │
63
+ │ → ModelRequest (next turn) ✗ API ERROR │
64
+ └─────────────────────────────────────────────────────────────┘
65
+ ```
66
+
67
+ ## Changes
68
+
69
+ Added `_remove_dangling_tool_calls()` in the `except UserAbortError` handler:
70
+
71
+ ```python
72
+ except UserAbortError:
73
+ cleanup_applied = _remove_dangling_tool_calls(
74
+ self.state_manager.session.messages,
75
+ self.state_manager.session.tool_call_args_by_id,
76
+ )
77
+ if cleanup_applied:
78
+ self.state_manager.session.update_token_count()
79
+ raise
80
+ ```
81
+
82
+ The function walks backward through messages, removing any trailing `ModelResponse` that has unanswered tool calls, and clears cached args.
83
+
84
+ ## Behavioral Impact
85
+
86
+ - User aborts mid-tool → dangling messages cleaned up
87
+ - Next request works normally
88
+ - Token count recalculated after cleanup
89
+
90
+ ## Prevention: What We Should Have Done
91
+
92
+ ### 1. Document Message Invariants
93
+
94
+ The conversation turns doc now exists, but we missed documenting this invariant:
95
+
96
+ ```markdown
97
+ ## Message Invariants
98
+
99
+ 1. **Tool Call Pairing**: Every `ModelResponse` with tool_calls MUST
100
+ be followed by matching `ToolReturn(s)` before any new `ModelRequest`.
101
+
102
+ 2. **Exception Safety**: Any exception path that exits the agent loop
103
+ must restore message history to a valid state.
104
+ ```
105
+
106
+ Add this to `docs/codebase-map/architecture/conversation-turns.md`.
107
+
108
+ ### 2. Add Exception Path Tests
109
+
110
+ No test existed for abort scenarios:
111
+
112
+ ```python
113
+ async def test_abort_mid_tool_call_cleans_up_messages():
114
+ """Verify abort during tool execution doesn't corrupt message history."""
115
+ # Arrange: Start a request that will trigger a tool call
116
+ # Act: Raise UserAbortError during tool execution
117
+ # Assert: messages ends with a valid state (no dangling tool calls)
118
+ # Assert: Next request succeeds
119
+ ```
120
+
121
+ ### 3. State Machine Should Track Message Validity
122
+
123
+ The `ResponseState` tracks iteration progress but not message-level invariants. Consider:
124
+
125
+ ```python
126
+ def validate_message_invariants(messages: list[Any]) -> bool:
127
+ """Return False if messages violate tool-call pairing invariant."""
128
+ # Walk through messages
129
+ # Track pending tool calls
130
+ # Verify each is answered before next ModelRequest
131
+ ```
132
+
133
+ This could be called:
134
+ - After each agent iteration (debug mode)
135
+ - Before persisting session
136
+ - On session load
137
+
138
+ ### 4. Design Pattern: Exception-Safe State Updates
139
+
140
+ The broader lesson: **state mutations during a loop must be exception-safe**.
141
+
142
+ Options:
143
+ 1. **Rollback on exception** (what we did) - detect and fix invalid state
144
+ 2. **Transactional updates** - only commit state after successful completion
145
+ 3. **Copy-on-write** - work on a copy, swap on success
146
+
147
+ For message history, option 2 would be:
148
+ ```python
149
+ # Don't append to session.messages during the loop
150
+ # Collect in a local buffer
151
+ # Merge to session.messages only on successful completion
152
+ ```
153
+
154
+ This is partially what `agent_run.all_messages()` does - but the exception path didn't use it.
155
+
156
+ ## Related Cards
157
+
158
+ - [[conversation-turns]] - Full turn flow documentation
159
+ - [[message-history-persistence]] - How messages are persisted
160
+ - [[response-state]] - State machine for agent progress
161
+
162
+ ## Lesson
163
+
164
+ **Exception paths are first-class citizens.** When designing a stateful loop:
165
+
166
+ 1. List every exception that can exit the loop
167
+ 2. For each: what state is left behind?
168
+ 3. For each: is that state valid for the next operation?
169
+ 4. Add tests for exception scenarios
170
+
171
+ The bug was obvious in hindsight - we just never traced what happens when `UserAbortError` interrupts the tool execution flow.
@@ -0,0 +1,54 @@
1
+ ---
2
+ title: Remove global cache state from user_configuration
3
+ link: delta/remove-global-cache-user-config
4
+ type: delta
5
+ path: src/tunacode/utils/config/user_configuration.py
6
+ depth: 3
7
+ seams: [M] module
8
+ ontological_relations:
9
+ - relates_to: [[utils]]
10
+ - affects: [[user_configuration.py]]
11
+ tags:
12
+ - utils
13
+ - config
14
+ - state-management
15
+ - cleanup
16
+ created_at: 2026-01-12T00:00:00Z
17
+ updated_at: 2026-01-12T00:00:00Z
18
+ uuid: 3383a720-0203-4a5b-9c1c-7b2f8c4d5e6f
19
+ ---
20
+
21
+ ## Summary
22
+
23
+ Removed global mutable cache state from the user configuration module. The previous implementation used module-level `_config_fingerprint` and `_config_cache` variables for a fast-path optimization that was likely premature for configuration file handling.
24
+
25
+ ## Context
26
+
27
+ The original `load_config()` function stored parsed config and its SHA-1 fingerprint in module globals to avoid re-parsing unchanged files. This added complexity and hidden state that could cause cache staleness issues.
28
+
29
+ ## Root Cause
30
+
31
+ The fast-path optimization was unnecessary overhead for configuration files that:
32
+ - Are small (typically < 1KB)
33
+ - Are read infrequently (once per session or on demand)
34
+ - May change externally between calls
35
+
36
+ The cost of hashing and comparing fingerprints likely exceeded the cost of simply parsing the JSON.
37
+
38
+ ## Changes
39
+
40
+ - Removed `_config_fingerprint` and `_config_cache` module-level globals
41
+ - Simplified `load_config()` to read and parse file directly
42
+ - Changed `save_config()` return type from `bool` to `None` (always returned `True`)
43
+ - Changed `set_default_model()` return type from `bool` to `None`
44
+ - Removed dead `except ConfigurationError: raise` code in `set_default_model()`
45
+
46
+ ## Behavioral Impact
47
+
48
+ - Config loading is now simpler and more predictable
49
+ - No functional change in behavior - callers already handled `None` returns and exceptions
50
+ - Slightly more straightforward debugging with no hidden cache state
51
+
52
+ ## Related Cards
53
+
54
+ - [[utils]] - Parent system