tunacode-cli 0.1.21__py3-none-any.whl

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.

Potentially problematic release.


This version of tunacode-cli might be problematic. Click here for more details.

Files changed (174) hide show
  1. tunacode/__init__.py +0 -0
  2. tunacode/cli/textual_repl.tcss +283 -0
  3. tunacode/configuration/__init__.py +1 -0
  4. tunacode/configuration/defaults.py +45 -0
  5. tunacode/configuration/models.py +147 -0
  6. tunacode/configuration/models_registry.json +1 -0
  7. tunacode/configuration/pricing.py +74 -0
  8. tunacode/configuration/settings.py +35 -0
  9. tunacode/constants.py +227 -0
  10. tunacode/core/__init__.py +6 -0
  11. tunacode/core/agents/__init__.py +39 -0
  12. tunacode/core/agents/agent_components/__init__.py +48 -0
  13. tunacode/core/agents/agent_components/agent_config.py +441 -0
  14. tunacode/core/agents/agent_components/agent_helpers.py +290 -0
  15. tunacode/core/agents/agent_components/message_handler.py +99 -0
  16. tunacode/core/agents/agent_components/node_processor.py +477 -0
  17. tunacode/core/agents/agent_components/response_state.py +129 -0
  18. tunacode/core/agents/agent_components/result_wrapper.py +51 -0
  19. tunacode/core/agents/agent_components/state_transition.py +112 -0
  20. tunacode/core/agents/agent_components/streaming.py +271 -0
  21. tunacode/core/agents/agent_components/task_completion.py +40 -0
  22. tunacode/core/agents/agent_components/tool_buffer.py +44 -0
  23. tunacode/core/agents/agent_components/tool_executor.py +101 -0
  24. tunacode/core/agents/agent_components/truncation_checker.py +37 -0
  25. tunacode/core/agents/delegation_tools.py +109 -0
  26. tunacode/core/agents/main.py +545 -0
  27. tunacode/core/agents/prompts.py +66 -0
  28. tunacode/core/agents/research_agent.py +231 -0
  29. tunacode/core/compaction.py +218 -0
  30. tunacode/core/prompting/__init__.py +27 -0
  31. tunacode/core/prompting/loader.py +66 -0
  32. tunacode/core/prompting/prompting_engine.py +98 -0
  33. tunacode/core/prompting/sections.py +50 -0
  34. tunacode/core/prompting/templates.py +69 -0
  35. tunacode/core/state.py +409 -0
  36. tunacode/exceptions.py +313 -0
  37. tunacode/indexing/__init__.py +5 -0
  38. tunacode/indexing/code_index.py +432 -0
  39. tunacode/indexing/constants.py +86 -0
  40. tunacode/lsp/__init__.py +112 -0
  41. tunacode/lsp/client.py +351 -0
  42. tunacode/lsp/diagnostics.py +19 -0
  43. tunacode/lsp/servers.py +101 -0
  44. tunacode/prompts/default_prompt.md +952 -0
  45. tunacode/prompts/research/sections/agent_role.xml +5 -0
  46. tunacode/prompts/research/sections/constraints.xml +14 -0
  47. tunacode/prompts/research/sections/output_format.xml +57 -0
  48. tunacode/prompts/research/sections/tool_use.xml +23 -0
  49. tunacode/prompts/sections/advanced_patterns.xml +255 -0
  50. tunacode/prompts/sections/agent_role.xml +8 -0
  51. tunacode/prompts/sections/completion.xml +10 -0
  52. tunacode/prompts/sections/critical_rules.xml +37 -0
  53. tunacode/prompts/sections/examples.xml +220 -0
  54. tunacode/prompts/sections/output_style.xml +94 -0
  55. tunacode/prompts/sections/parallel_exec.xml +105 -0
  56. tunacode/prompts/sections/search_pattern.xml +100 -0
  57. tunacode/prompts/sections/system_info.xml +6 -0
  58. tunacode/prompts/sections/tool_use.xml +84 -0
  59. tunacode/prompts/sections/user_instructions.xml +3 -0
  60. tunacode/py.typed +0 -0
  61. tunacode/templates/__init__.py +5 -0
  62. tunacode/templates/loader.py +15 -0
  63. tunacode/tools/__init__.py +10 -0
  64. tunacode/tools/authorization/__init__.py +29 -0
  65. tunacode/tools/authorization/context.py +32 -0
  66. tunacode/tools/authorization/factory.py +20 -0
  67. tunacode/tools/authorization/handler.py +58 -0
  68. tunacode/tools/authorization/notifier.py +35 -0
  69. tunacode/tools/authorization/policy.py +19 -0
  70. tunacode/tools/authorization/requests.py +119 -0
  71. tunacode/tools/authorization/rules.py +72 -0
  72. tunacode/tools/bash.py +222 -0
  73. tunacode/tools/decorators.py +213 -0
  74. tunacode/tools/glob.py +353 -0
  75. tunacode/tools/grep.py +468 -0
  76. tunacode/tools/grep_components/__init__.py +9 -0
  77. tunacode/tools/grep_components/file_filter.py +93 -0
  78. tunacode/tools/grep_components/pattern_matcher.py +158 -0
  79. tunacode/tools/grep_components/result_formatter.py +87 -0
  80. tunacode/tools/grep_components/search_result.py +34 -0
  81. tunacode/tools/list_dir.py +205 -0
  82. tunacode/tools/prompts/bash_prompt.xml +10 -0
  83. tunacode/tools/prompts/glob_prompt.xml +7 -0
  84. tunacode/tools/prompts/grep_prompt.xml +10 -0
  85. tunacode/tools/prompts/list_dir_prompt.xml +7 -0
  86. tunacode/tools/prompts/read_file_prompt.xml +9 -0
  87. tunacode/tools/prompts/todoclear_prompt.xml +12 -0
  88. tunacode/tools/prompts/todoread_prompt.xml +16 -0
  89. tunacode/tools/prompts/todowrite_prompt.xml +28 -0
  90. tunacode/tools/prompts/update_file_prompt.xml +9 -0
  91. tunacode/tools/prompts/web_fetch_prompt.xml +11 -0
  92. tunacode/tools/prompts/write_file_prompt.xml +7 -0
  93. tunacode/tools/react.py +111 -0
  94. tunacode/tools/read_file.py +68 -0
  95. tunacode/tools/todo.py +222 -0
  96. tunacode/tools/update_file.py +62 -0
  97. tunacode/tools/utils/__init__.py +1 -0
  98. tunacode/tools/utils/ripgrep.py +311 -0
  99. tunacode/tools/utils/text_match.py +352 -0
  100. tunacode/tools/web_fetch.py +245 -0
  101. tunacode/tools/write_file.py +34 -0
  102. tunacode/tools/xml_helper.py +34 -0
  103. tunacode/types/__init__.py +166 -0
  104. tunacode/types/base.py +94 -0
  105. tunacode/types/callbacks.py +53 -0
  106. tunacode/types/dataclasses.py +121 -0
  107. tunacode/types/pydantic_ai.py +31 -0
  108. tunacode/types/state.py +122 -0
  109. tunacode/ui/__init__.py +6 -0
  110. tunacode/ui/app.py +542 -0
  111. tunacode/ui/commands/__init__.py +430 -0
  112. tunacode/ui/components/__init__.py +1 -0
  113. tunacode/ui/headless/__init__.py +5 -0
  114. tunacode/ui/headless/output.py +72 -0
  115. tunacode/ui/main.py +252 -0
  116. tunacode/ui/renderers/__init__.py +41 -0
  117. tunacode/ui/renderers/errors.py +197 -0
  118. tunacode/ui/renderers/panels.py +550 -0
  119. tunacode/ui/renderers/search.py +314 -0
  120. tunacode/ui/renderers/tools/__init__.py +21 -0
  121. tunacode/ui/renderers/tools/bash.py +247 -0
  122. tunacode/ui/renderers/tools/diagnostics.py +186 -0
  123. tunacode/ui/renderers/tools/glob.py +226 -0
  124. tunacode/ui/renderers/tools/grep.py +228 -0
  125. tunacode/ui/renderers/tools/list_dir.py +198 -0
  126. tunacode/ui/renderers/tools/read_file.py +226 -0
  127. tunacode/ui/renderers/tools/research.py +294 -0
  128. tunacode/ui/renderers/tools/update_file.py +237 -0
  129. tunacode/ui/renderers/tools/web_fetch.py +182 -0
  130. tunacode/ui/repl_support.py +226 -0
  131. tunacode/ui/screens/__init__.py +16 -0
  132. tunacode/ui/screens/model_picker.py +303 -0
  133. tunacode/ui/screens/session_picker.py +181 -0
  134. tunacode/ui/screens/setup.py +218 -0
  135. tunacode/ui/screens/theme_picker.py +90 -0
  136. tunacode/ui/screens/update_confirm.py +69 -0
  137. tunacode/ui/shell_runner.py +129 -0
  138. tunacode/ui/styles/layout.tcss +98 -0
  139. tunacode/ui/styles/modals.tcss +38 -0
  140. tunacode/ui/styles/panels.tcss +81 -0
  141. tunacode/ui/styles/theme-nextstep.tcss +303 -0
  142. tunacode/ui/styles/widgets.tcss +33 -0
  143. tunacode/ui/styles.py +18 -0
  144. tunacode/ui/widgets/__init__.py +23 -0
  145. tunacode/ui/widgets/command_autocomplete.py +62 -0
  146. tunacode/ui/widgets/editor.py +402 -0
  147. tunacode/ui/widgets/file_autocomplete.py +47 -0
  148. tunacode/ui/widgets/messages.py +46 -0
  149. tunacode/ui/widgets/resource_bar.py +182 -0
  150. tunacode/ui/widgets/status_bar.py +98 -0
  151. tunacode/utils/__init__.py +0 -0
  152. tunacode/utils/config/__init__.py +13 -0
  153. tunacode/utils/config/user_configuration.py +91 -0
  154. tunacode/utils/messaging/__init__.py +10 -0
  155. tunacode/utils/messaging/message_utils.py +34 -0
  156. tunacode/utils/messaging/token_counter.py +77 -0
  157. tunacode/utils/parsing/__init__.py +13 -0
  158. tunacode/utils/parsing/command_parser.py +55 -0
  159. tunacode/utils/parsing/json_utils.py +188 -0
  160. tunacode/utils/parsing/retry.py +146 -0
  161. tunacode/utils/parsing/tool_parser.py +267 -0
  162. tunacode/utils/security/__init__.py +15 -0
  163. tunacode/utils/security/command.py +106 -0
  164. tunacode/utils/system/__init__.py +25 -0
  165. tunacode/utils/system/gitignore.py +155 -0
  166. tunacode/utils/system/paths.py +190 -0
  167. tunacode/utils/ui/__init__.py +9 -0
  168. tunacode/utils/ui/file_filter.py +135 -0
  169. tunacode/utils/ui/helpers.py +24 -0
  170. tunacode_cli-0.1.21.dist-info/METADATA +170 -0
  171. tunacode_cli-0.1.21.dist-info/RECORD +174 -0
  172. tunacode_cli-0.1.21.dist-info/WHEEL +4 -0
  173. tunacode_cli-0.1.21.dist-info/entry_points.txt +2 -0
  174. tunacode_cli-0.1.21.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,98 @@
1
+ /* TunaCode Textual REPL Stylesheet
2
+ * NeXTSTEP Zone-Based Layout (Modern):
3
+ * ◇ tokens: 1.2k ◇ model ◇ $0.00 ◇ tunacode
4
+ * ┌────────────────────────────────────────────────────┐
5
+ * │ │
6
+ * │ Main viewport (thin subtle border) │
7
+ * │ │
8
+ * ├──────────┬─────────────────────────────────────────┤
9
+ * │ Context │ Editor (Enter to submit) │
10
+ * └──────────┴─────────────────────────────────────────┘
11
+ */
12
+
13
+ /* ============================================
14
+ * RESOURCE BAR - Compact, no border
15
+ * NeXTSTEP: "Glanceable, rarely changes"
16
+ * ============================================ */
17
+ ResourceBar {
18
+ width: 100%;
19
+ height: 1;
20
+ background: $background;
21
+ padding: 0 1;
22
+ }
23
+
24
+ /* ============================================
25
+ * PRIMARY VIEWPORT - Unified container for RichLog + streaming
26
+ * NeXTSTEP: "Objects stay where put" - content lives in ONE zone
27
+ * ============================================ */
28
+ #viewport {
29
+ height: 1fr;
30
+ border: solid $border;
31
+ }
32
+
33
+ /* Streaming mode - accent border on viewport (not RichLog) */
34
+ #viewport.streaming {
35
+ border: solid $accent;
36
+ }
37
+
38
+ /* Pause mode - NeXTSTEP: "Modes must be visually apparent" */
39
+ #viewport.paused {
40
+ border: solid $warning;
41
+ }
42
+
43
+ /* RichLog - inside viewport, no border */
44
+ RichLog {
45
+ height: 1fr;
46
+ background: $background;
47
+ padding: 1;
48
+ scrollbar-gutter: stable;
49
+ }
50
+
51
+ /* ============================================
52
+ * LOADING INDICATOR - Hidden by default, shown during processing
53
+ * ============================================ */
54
+ LoadingIndicator {
55
+ height: 1;
56
+ display: none;
57
+ background: $background;
58
+ }
59
+
60
+ LoadingIndicator.active {
61
+ display: block;
62
+ }
63
+
64
+ /* ============================================
65
+ * STREAMING OUTPUT - Live text display during generation
66
+ * Inside viewport container; dashed separator distinguishes live content
67
+ * ============================================ */
68
+ #streaming-output {
69
+ height: auto;
70
+ max-height: 30%;
71
+ display: none;
72
+ background: $background;
73
+ padding: 0 1;
74
+ overflow-y: auto;
75
+ border-top: dashed #6272a4;
76
+ }
77
+
78
+ #streaming-output.active {
79
+ display: block;
80
+ }
81
+
82
+ /* ============================================
83
+ * EDITOR - Input bar (compact)
84
+ * ============================================ */
85
+ Editor {
86
+ width: 1fr;
87
+ height: 6;
88
+ background: $background;
89
+ border-top: solid $border;
90
+ border-right: solid $border;
91
+ border-bottom: solid $border;
92
+ border-left: solid $border;
93
+ padding: 0 1;
94
+ }
95
+
96
+ Editor.bash-mode {
97
+ border: solid $success;
98
+ }
@@ -0,0 +1,38 @@
1
+ /* ============================================
2
+ * MODAL OVERLAYS - Tool Confirmation
3
+ * NeXTSTEP: "Controls change appearance immediately"
4
+ * ============================================ */
5
+ ToolConfirmationModal {
6
+ align: center middle;
7
+ }
8
+
9
+ #modal-body {
10
+ width: 60;
11
+ height: auto;
12
+ border: solid $primary;
13
+ background: $surface;
14
+ padding: 1 2;
15
+ }
16
+
17
+ #modal-body Label {
18
+ margin-bottom: 1;
19
+ }
20
+
21
+ #modal-body Checkbox {
22
+ margin-top: 1;
23
+ }
24
+
25
+ #tool-title {
26
+ text-style: bold;
27
+ color: $primary;
28
+ margin-bottom: 1;
29
+ }
30
+
31
+ #actions {
32
+ margin-top: 1;
33
+ align: center middle;
34
+ }
35
+
36
+ #actions Button {
37
+ margin: 0 1;
38
+ }
@@ -0,0 +1,81 @@
1
+ /* ============================================
2
+ * RICH PANELS - Tool/Error/Search Display
3
+ * NeXTSTEP: "Objects that look the same should act the same"
4
+ * ============================================ */
5
+
6
+ /* Tool execution panels - cyan accent */
7
+ .tool-panel {
8
+ border: solid $primary;
9
+ background: $surface;
10
+ padding: 0 1;
11
+ margin: 0 0 1 0;
12
+ }
13
+
14
+ .tool-panel.running {
15
+ border: solid $accent;
16
+ }
17
+
18
+ .tool-panel.completed {
19
+ border: solid $success;
20
+ }
21
+
22
+ .tool-panel.failed {
23
+ border: solid $error;
24
+ }
25
+
26
+ /* Error panels - red border, recovery actions */
27
+ .error-panel {
28
+ border: solid $error;
29
+ background: $surface;
30
+ padding: 0 1;
31
+ margin: 0 0 1 0;
32
+ }
33
+
34
+ .error-panel.warning {
35
+ border: solid $warning;
36
+ }
37
+
38
+ .error-panel.info {
39
+ border: solid $secondary;
40
+ }
41
+
42
+ /* Search result panels - accent border */
43
+ .search-panel {
44
+ border: solid $accent;
45
+ background: $surface;
46
+ padding: 0 1;
47
+ margin: 0 0 1 0;
48
+ }
49
+
50
+ /* Pagination controls in search */
51
+ .pagination {
52
+ height: 1;
53
+ padding: 0 1;
54
+ color: $text-muted;
55
+ }
56
+
57
+ /* Result item highlighting */
58
+ .result-item {
59
+ padding: 0 1;
60
+ }
61
+
62
+ .result-item:hover {
63
+ background: $surface;
64
+ }
65
+
66
+ .result-item.selected {
67
+ background: $primary 20%;
68
+ border-left: solid $primary;
69
+ }
70
+
71
+ /* Recovery command styling */
72
+ .recovery-command {
73
+ color: $primary;
74
+ text-style: underline;
75
+ }
76
+
77
+ /* Context detail styling */
78
+ .context-detail {
79
+ color: $text-muted;
80
+ padding-left: 2;
81
+ }
@@ -0,0 +1,303 @@
1
+ /* ============================================
2
+ * NEXTSTEP THEME OVERRIDES
3
+ * Classic 1990s NeXTSTEP look - Authentic styling
4
+ * Only applies when .theme-nextstep CSS class is active
5
+ *
6
+ * NeXTSTEP Color Reference:
7
+ * Title bar: #3a3a3a (dark charcoal)
8
+ * Title text: #e0e0e0 (light gray)
9
+ * Window content:#d0d0d0 (light gray)
10
+ * Surface: #c8c8c8 (medium gray)
11
+ * Background: #acacac (desktop gray)
12
+ * Border: #2a2a2a (near black)
13
+ * Bevel light: #e8e8e8 (highlight)
14
+ * Bevel dark: #606060 (shadow)
15
+ * ============================================ */
16
+
17
+ /* --- Base App --- */
18
+ .theme-nextstep {
19
+ background: #acacac;
20
+ }
21
+
22
+ /* --- Resource Bar (Title Bar Style) --- */
23
+ .theme-nextstep ResourceBar {
24
+ background: #3a3a3a;
25
+ color: #e0e0e0;
26
+ border-bottom: solid #2a2a2a;
27
+ }
28
+
29
+ .theme-nextstep ResourceBar Static {
30
+ color: #e0e0e0;
31
+ }
32
+
33
+ /* --- Main Viewport (Container - Window Content) --- */
34
+ .theme-nextstep #viewport {
35
+ /* Raised 3D bevel: light top/left, dark bottom/right */
36
+ border-top: solid #e8e8e8;
37
+ border-left: solid #e8e8e8;
38
+ border-bottom: solid #606060;
39
+ border-right: solid #606060;
40
+ }
41
+
42
+ .theme-nextstep #viewport.streaming {
43
+ /* Inverted bevel = pressed/active state */
44
+ border-top: solid #606060;
45
+ border-left: solid #606060;
46
+ border-bottom: solid #e8e8e8;
47
+ border-right: solid #e8e8e8;
48
+ }
49
+
50
+ .theme-nextstep #viewport.paused {
51
+ border: double #2a2a2a;
52
+ }
53
+
54
+ .theme-nextstep RichLog {
55
+ background: #d0d0d0;
56
+ color: #000000;
57
+ }
58
+
59
+ /* --- Editor (Inset Input Field) --- */
60
+ .theme-nextstep Editor {
61
+ background: #c8c8c8;
62
+ color: #000000;
63
+ /* Inset 3D bevel: dark top/left, light bottom/right */
64
+ border-top: solid #606060;
65
+ border-left: solid #606060;
66
+ border-bottom: solid #e8e8e8;
67
+ border-right: solid #e8e8e8;
68
+ }
69
+
70
+ .theme-nextstep Editor.bash-mode {
71
+ border: double #4ec9b0;
72
+ }
73
+
74
+ /* --- Status Bar (Bottom) --- */
75
+ .theme-nextstep StatusBar {
76
+ background: #acacac;
77
+ color: #000000;
78
+ border-top: solid #606060;
79
+ }
80
+
81
+ .theme-nextstep StatusBar Static {
82
+ color: #000000;
83
+ }
84
+
85
+ .theme-nextstep #status-mid {
86
+ color: #404040;
87
+ }
88
+
89
+ .theme-nextstep #status-right {
90
+ color: #404040;
91
+ }
92
+
93
+ /* --- Loading Indicator --- */
94
+ .theme-nextstep LoadingIndicator {
95
+ background: #c8c8c8;
96
+ color: #000000;
97
+ }
98
+
99
+ /* --- Streaming Output --- */
100
+ .theme-nextstep #streaming-output {
101
+ background: #d0d0d0;
102
+ color: #000000;
103
+ }
104
+
105
+ /* --- Modal Dialogs --- */
106
+ .theme-nextstep #modal-body {
107
+ background: #c8c8c8;
108
+ color: #000000;
109
+ /* Raised 3D bevel */
110
+ border-top: solid #e8e8e8;
111
+ border-left: solid #e8e8e8;
112
+ border-bottom: solid #606060;
113
+ border-right: solid #606060;
114
+ }
115
+
116
+ .theme-nextstep #tool-title {
117
+ background: #3a3a3a;
118
+ color: #e0e0e0;
119
+ text-style: bold;
120
+ }
121
+
122
+ /* --- Buttons (NeXTSTEP 3D beveled) --- */
123
+ .theme-nextstep Button {
124
+ background: #acacac;
125
+ color: #000000;
126
+ text-style: bold;
127
+ /* Raised 3D bevel */
128
+ border-top: solid #e8e8e8;
129
+ border-left: solid #e8e8e8;
130
+ border-bottom: solid #606060;
131
+ border-right: solid #606060;
132
+ }
133
+
134
+ .theme-nextstep Button:hover {
135
+ background: #c8c8c8;
136
+ }
137
+
138
+ .theme-nextstep Button:focus {
139
+ /* Pressed = inverted bevel */
140
+ background: #acacac;
141
+ border-top: solid #606060;
142
+ border-left: solid #606060;
143
+ border-bottom: solid #e8e8e8;
144
+ border-right: solid #e8e8e8;
145
+ }
146
+
147
+ .theme-nextstep Button.-primary {
148
+ background: #acacac;
149
+ color: #000000;
150
+ }
151
+
152
+ .theme-nextstep Button.-success {
153
+ background: #acacac;
154
+ color: #000000;
155
+ }
156
+
157
+ .theme-nextstep Button.-warning {
158
+ background: #acacac;
159
+ color: #000000;
160
+ }
161
+
162
+ .theme-nextstep Button.-error {
163
+ background: #acacac;
164
+ color: #000000;
165
+ }
166
+
167
+ /* --- Tool Panels --- */
168
+ .theme-nextstep .tool-panel {
169
+ background: #c8c8c8;
170
+ color: #000000;
171
+ /* Raised 3D bevel */
172
+ border-top: solid #e8e8e8;
173
+ border-left: solid #e8e8e8;
174
+ border-bottom: solid #606060;
175
+ border-right: solid #606060;
176
+ }
177
+
178
+ .theme-nextstep .tool-panel.running {
179
+ /* Active = inverted bevel */
180
+ border-top: solid #606060;
181
+ border-left: solid #606060;
182
+ border-bottom: solid #e8e8e8;
183
+ border-right: solid #e8e8e8;
184
+ }
185
+
186
+ .theme-nextstep .tool-panel.completed {
187
+ border: solid #2a2a2a;
188
+ }
189
+
190
+ .theme-nextstep .tool-panel.failed {
191
+ border: dashed #2a2a2a;
192
+ }
193
+
194
+ /* --- Error Panels --- */
195
+ .theme-nextstep .error-panel {
196
+ background: #c8c8c8;
197
+ color: #000000;
198
+ border: dashed #2a2a2a;
199
+ }
200
+
201
+ .theme-nextstep .error-panel.warning {
202
+ border: solid #2a2a2a;
203
+ }
204
+
205
+ .theme-nextstep .error-panel.info {
206
+ border: solid #404040;
207
+ }
208
+
209
+ /* --- Search Panels --- */
210
+ .theme-nextstep .search-panel {
211
+ background: #c8c8c8;
212
+ color: #000000;
213
+ border: solid #2a2a2a;
214
+ }
215
+
216
+ /* --- Checkboxes & Switches --- */
217
+ .theme-nextstep Checkbox {
218
+ color: #000000;
219
+ }
220
+
221
+ .theme-nextstep Switch {
222
+ background: #acacac;
223
+ color: #000000;
224
+ }
225
+
226
+ /* --- Input Fields --- */
227
+ .theme-nextstep Input {
228
+ background: #c8c8c8;
229
+ color: #000000;
230
+ /* Inset 3D bevel */
231
+ border-top: solid #606060;
232
+ border-left: solid #606060;
233
+ border-bottom: solid #e8e8e8;
234
+ border-right: solid #e8e8e8;
235
+ }
236
+
237
+ .theme-nextstep Input:focus {
238
+ border: solid #2a2a2a;
239
+ }
240
+
241
+ /* --- Labels & Static Text --- */
242
+ .theme-nextstep Label {
243
+ color: #000000;
244
+ }
245
+
246
+ .theme-nextstep Static {
247
+ color: #000000;
248
+ }
249
+
250
+ /* --- OptionList (Theme Picker, etc) --- */
251
+ .theme-nextstep OptionList {
252
+ background: #c8c8c8;
253
+ color: #000000;
254
+ border: solid #2a2a2a;
255
+ }
256
+
257
+ .theme-nextstep OptionList > .option-list--option-highlighted {
258
+ background: #3a3a3a;
259
+ color: #e0e0e0;
260
+ text-style: bold;
261
+ }
262
+
263
+ .theme-nextstep OptionList > .option-list--option-hover {
264
+ background: #acacac;
265
+ }
266
+
267
+ /* --- DataTable --- */
268
+ .theme-nextstep DataTable {
269
+ background: #c8c8c8;
270
+ color: #000000;
271
+ }
272
+
273
+ .theme-nextstep DataTable > .datatable--header {
274
+ background: #3a3a3a;
275
+ color: #e0e0e0;
276
+ text-style: bold;
277
+ }
278
+
279
+ .theme-nextstep DataTable > .datatable--cursor {
280
+ background: #acacac;
281
+ color: #000000;
282
+ }
283
+
284
+ /* --- Recovery Commands --- */
285
+ .theme-nextstep .recovery-command {
286
+ color: #000000;
287
+ text-style: bold underline;
288
+ }
289
+
290
+ /* --- Result Items --- */
291
+ .theme-nextstep .result-item:hover {
292
+ background: #acacac;
293
+ }
294
+
295
+ .theme-nextstep .result-item.selected {
296
+ background: #acacac;
297
+ border-left: solid #2a2a2a;
298
+ }
299
+
300
+ /* --- Pagination --- */
301
+ .theme-nextstep .pagination {
302
+ color: #404040;
303
+ }
@@ -0,0 +1,33 @@
1
+ /* ============================================
2
+ * STATUS BAR - 3-column bottom status (no borders)
3
+ * NeXTSTEP: "left=identity, center=metrics, right=state"
4
+ * ============================================ */
5
+ StatusBar {
6
+ height: 1;
7
+ width: 100%;
8
+ background: $background;
9
+ }
10
+
11
+ StatusBar Static {
12
+ color: $text;
13
+ }
14
+
15
+ #status-left {
16
+ width: 1fr;
17
+ text-align: left;
18
+ padding: 0 1;
19
+ }
20
+
21
+ #status-mid {
22
+ width: auto;
23
+ text-align: center;
24
+ color: $text-muted;
25
+ padding: 0 2;
26
+ }
27
+
28
+ #status-right {
29
+ width: 1fr;
30
+ text-align: right;
31
+ padding: 0 1;
32
+ color: $text-muted;
33
+ }
tunacode/ui/styles.py ADDED
@@ -0,0 +1,18 @@
1
+ """Rich-compatible style constants for TunaCode UI.
2
+
3
+ Centralizes color references to UI_COLORS for consistent theming.
4
+ """
5
+
6
+ from tunacode.constants import UI_COLORS
7
+
8
+ # Rich Text style strings (single colors)
9
+ STYLE_PRIMARY = UI_COLORS["primary"]
10
+ STYLE_ACCENT = UI_COLORS["accent"]
11
+ STYLE_SUCCESS = UI_COLORS["success"]
12
+ STYLE_WARNING = UI_COLORS["warning"]
13
+ STYLE_ERROR = UI_COLORS["error"]
14
+ STYLE_MUTED = UI_COLORS["muted"]
15
+
16
+ # Composite styles
17
+ STYLE_HEADING = f"bold {STYLE_ACCENT}"
18
+ STYLE_SUBHEADING = f"bold {STYLE_PRIMARY}"
@@ -0,0 +1,23 @@
1
+ """Textual widgets for TunaCode REPL."""
2
+
3
+ from .command_autocomplete import CommandAutoComplete
4
+ from .editor import Editor
5
+ from .file_autocomplete import FileAutoComplete
6
+ from .messages import (
7
+ EditorCompletionsAvailable,
8
+ EditorSubmitRequested,
9
+ ToolResultDisplay,
10
+ )
11
+ from .resource_bar import ResourceBar
12
+ from .status_bar import StatusBar
13
+
14
+ __all__ = [
15
+ "CommandAutoComplete",
16
+ "Editor",
17
+ "EditorCompletionsAvailable",
18
+ "EditorSubmitRequested",
19
+ "FileAutoComplete",
20
+ "ResourceBar",
21
+ "StatusBar",
22
+ "ToolResultDisplay",
23
+ ]
@@ -0,0 +1,62 @@
1
+ """Slash command autocomplete dropdown widget."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from textual.widgets import Input
6
+ from textual_autocomplete import AutoComplete, DropdownItem, TargetState
7
+
8
+ from tunacode.ui.commands import COMMANDS
9
+
10
+ # Pre-compute sorted command items at module load (8 items)
11
+ _COMMAND_ITEMS: list[tuple[str, str]] = sorted(
12
+ [(name, cmd.description) for name, cmd in COMMANDS.items()]
13
+ )
14
+
15
+
16
+ class CommandAutoComplete(AutoComplete):
17
+ """Real-time / command autocomplete dropdown."""
18
+
19
+ def __init__(self, target: Input) -> None:
20
+ super().__init__(target)
21
+
22
+ def get_search_string(self, target_state: TargetState) -> str:
23
+ """Extract text after / symbol at start of input."""
24
+ text = target_state.text
25
+ if not text.startswith("/"):
26
+ return ""
27
+
28
+ prefix = text[1 : target_state.cursor_position]
29
+ return "" if " " in prefix else prefix
30
+
31
+ def should_show_dropdown(self, search_string: str) -> bool: # noqa: ARG002
32
+ """Show dropdown only while typing command (before space)."""
33
+ del search_string
34
+ if self.option_list.option_count == 0:
35
+ return False
36
+ # Hide once user has typed a space (command complete, now typing args)
37
+ target_state = self._get_target_state()
38
+ if not target_state.text.startswith("/"):
39
+ return False
40
+ # Check if there's a space before cursor (command already entered)
41
+ prefix = target_state.text[1 : target_state.cursor_position]
42
+ return " " not in prefix
43
+
44
+ def get_candidates(self, target_state: TargetState) -> list[DropdownItem]:
45
+ """Return command candidates for current search."""
46
+ if not target_state.text.startswith("/"):
47
+ return []
48
+
49
+ search = self.get_search_string(target_state).lower()
50
+ return [
51
+ DropdownItem(main=f"/{name} - {desc}")
52
+ for name, desc in _COMMAND_ITEMS
53
+ if name.startswith(search)
54
+ ]
55
+
56
+ def apply_completion(self, value: str, state: TargetState) -> None:
57
+ """Replace /command region with completed value, always add trailing space."""
58
+ command = value.split(" - ", 1)[0] # Extracts "/model" from "/model - description"
59
+ trailing = state.text[state.cursor_position :].lstrip()
60
+ new_text = command + " " + trailing
61
+ self.target.value = new_text
62
+ self.target.cursor_position = len(command) + 1