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.
- tunacode/__init__.py +0 -0
- tunacode/cli/textual_repl.tcss +283 -0
- tunacode/configuration/__init__.py +1 -0
- tunacode/configuration/defaults.py +45 -0
- tunacode/configuration/models.py +147 -0
- tunacode/configuration/models_registry.json +1 -0
- tunacode/configuration/pricing.py +74 -0
- tunacode/configuration/settings.py +35 -0
- tunacode/constants.py +227 -0
- tunacode/core/__init__.py +6 -0
- tunacode/core/agents/__init__.py +39 -0
- tunacode/core/agents/agent_components/__init__.py +48 -0
- tunacode/core/agents/agent_components/agent_config.py +441 -0
- tunacode/core/agents/agent_components/agent_helpers.py +290 -0
- tunacode/core/agents/agent_components/message_handler.py +99 -0
- tunacode/core/agents/agent_components/node_processor.py +477 -0
- tunacode/core/agents/agent_components/response_state.py +129 -0
- tunacode/core/agents/agent_components/result_wrapper.py +51 -0
- tunacode/core/agents/agent_components/state_transition.py +112 -0
- tunacode/core/agents/agent_components/streaming.py +271 -0
- tunacode/core/agents/agent_components/task_completion.py +40 -0
- tunacode/core/agents/agent_components/tool_buffer.py +44 -0
- tunacode/core/agents/agent_components/tool_executor.py +101 -0
- tunacode/core/agents/agent_components/truncation_checker.py +37 -0
- tunacode/core/agents/delegation_tools.py +109 -0
- tunacode/core/agents/main.py +545 -0
- tunacode/core/agents/prompts.py +66 -0
- tunacode/core/agents/research_agent.py +231 -0
- tunacode/core/compaction.py +218 -0
- tunacode/core/prompting/__init__.py +27 -0
- tunacode/core/prompting/loader.py +66 -0
- tunacode/core/prompting/prompting_engine.py +98 -0
- tunacode/core/prompting/sections.py +50 -0
- tunacode/core/prompting/templates.py +69 -0
- tunacode/core/state.py +409 -0
- tunacode/exceptions.py +313 -0
- tunacode/indexing/__init__.py +5 -0
- tunacode/indexing/code_index.py +432 -0
- tunacode/indexing/constants.py +86 -0
- tunacode/lsp/__init__.py +112 -0
- tunacode/lsp/client.py +351 -0
- tunacode/lsp/diagnostics.py +19 -0
- tunacode/lsp/servers.py +101 -0
- tunacode/prompts/default_prompt.md +952 -0
- tunacode/prompts/research/sections/agent_role.xml +5 -0
- tunacode/prompts/research/sections/constraints.xml +14 -0
- tunacode/prompts/research/sections/output_format.xml +57 -0
- tunacode/prompts/research/sections/tool_use.xml +23 -0
- tunacode/prompts/sections/advanced_patterns.xml +255 -0
- tunacode/prompts/sections/agent_role.xml +8 -0
- tunacode/prompts/sections/completion.xml +10 -0
- tunacode/prompts/sections/critical_rules.xml +37 -0
- tunacode/prompts/sections/examples.xml +220 -0
- tunacode/prompts/sections/output_style.xml +94 -0
- tunacode/prompts/sections/parallel_exec.xml +105 -0
- tunacode/prompts/sections/search_pattern.xml +100 -0
- tunacode/prompts/sections/system_info.xml +6 -0
- tunacode/prompts/sections/tool_use.xml +84 -0
- tunacode/prompts/sections/user_instructions.xml +3 -0
- tunacode/py.typed +0 -0
- tunacode/templates/__init__.py +5 -0
- tunacode/templates/loader.py +15 -0
- tunacode/tools/__init__.py +10 -0
- tunacode/tools/authorization/__init__.py +29 -0
- tunacode/tools/authorization/context.py +32 -0
- tunacode/tools/authorization/factory.py +20 -0
- tunacode/tools/authorization/handler.py +58 -0
- tunacode/tools/authorization/notifier.py +35 -0
- tunacode/tools/authorization/policy.py +19 -0
- tunacode/tools/authorization/requests.py +119 -0
- tunacode/tools/authorization/rules.py +72 -0
- tunacode/tools/bash.py +222 -0
- tunacode/tools/decorators.py +213 -0
- tunacode/tools/glob.py +353 -0
- tunacode/tools/grep.py +468 -0
- tunacode/tools/grep_components/__init__.py +9 -0
- tunacode/tools/grep_components/file_filter.py +93 -0
- tunacode/tools/grep_components/pattern_matcher.py +158 -0
- tunacode/tools/grep_components/result_formatter.py +87 -0
- tunacode/tools/grep_components/search_result.py +34 -0
- tunacode/tools/list_dir.py +205 -0
- tunacode/tools/prompts/bash_prompt.xml +10 -0
- tunacode/tools/prompts/glob_prompt.xml +7 -0
- tunacode/tools/prompts/grep_prompt.xml +10 -0
- tunacode/tools/prompts/list_dir_prompt.xml +7 -0
- tunacode/tools/prompts/read_file_prompt.xml +9 -0
- tunacode/tools/prompts/todoclear_prompt.xml +12 -0
- tunacode/tools/prompts/todoread_prompt.xml +16 -0
- tunacode/tools/prompts/todowrite_prompt.xml +28 -0
- tunacode/tools/prompts/update_file_prompt.xml +9 -0
- tunacode/tools/prompts/web_fetch_prompt.xml +11 -0
- tunacode/tools/prompts/write_file_prompt.xml +7 -0
- tunacode/tools/react.py +111 -0
- tunacode/tools/read_file.py +68 -0
- tunacode/tools/todo.py +222 -0
- tunacode/tools/update_file.py +62 -0
- tunacode/tools/utils/__init__.py +1 -0
- tunacode/tools/utils/ripgrep.py +311 -0
- tunacode/tools/utils/text_match.py +352 -0
- tunacode/tools/web_fetch.py +245 -0
- tunacode/tools/write_file.py +34 -0
- tunacode/tools/xml_helper.py +34 -0
- tunacode/types/__init__.py +166 -0
- tunacode/types/base.py +94 -0
- tunacode/types/callbacks.py +53 -0
- tunacode/types/dataclasses.py +121 -0
- tunacode/types/pydantic_ai.py +31 -0
- tunacode/types/state.py +122 -0
- tunacode/ui/__init__.py +6 -0
- tunacode/ui/app.py +542 -0
- tunacode/ui/commands/__init__.py +430 -0
- tunacode/ui/components/__init__.py +1 -0
- tunacode/ui/headless/__init__.py +5 -0
- tunacode/ui/headless/output.py +72 -0
- tunacode/ui/main.py +252 -0
- tunacode/ui/renderers/__init__.py +41 -0
- tunacode/ui/renderers/errors.py +197 -0
- tunacode/ui/renderers/panels.py +550 -0
- tunacode/ui/renderers/search.py +314 -0
- tunacode/ui/renderers/tools/__init__.py +21 -0
- tunacode/ui/renderers/tools/bash.py +247 -0
- tunacode/ui/renderers/tools/diagnostics.py +186 -0
- tunacode/ui/renderers/tools/glob.py +226 -0
- tunacode/ui/renderers/tools/grep.py +228 -0
- tunacode/ui/renderers/tools/list_dir.py +198 -0
- tunacode/ui/renderers/tools/read_file.py +226 -0
- tunacode/ui/renderers/tools/research.py +294 -0
- tunacode/ui/renderers/tools/update_file.py +237 -0
- tunacode/ui/renderers/tools/web_fetch.py +182 -0
- tunacode/ui/repl_support.py +226 -0
- tunacode/ui/screens/__init__.py +16 -0
- tunacode/ui/screens/model_picker.py +303 -0
- tunacode/ui/screens/session_picker.py +181 -0
- tunacode/ui/screens/setup.py +218 -0
- tunacode/ui/screens/theme_picker.py +90 -0
- tunacode/ui/screens/update_confirm.py +69 -0
- tunacode/ui/shell_runner.py +129 -0
- tunacode/ui/styles/layout.tcss +98 -0
- tunacode/ui/styles/modals.tcss +38 -0
- tunacode/ui/styles/panels.tcss +81 -0
- tunacode/ui/styles/theme-nextstep.tcss +303 -0
- tunacode/ui/styles/widgets.tcss +33 -0
- tunacode/ui/styles.py +18 -0
- tunacode/ui/widgets/__init__.py +23 -0
- tunacode/ui/widgets/command_autocomplete.py +62 -0
- tunacode/ui/widgets/editor.py +402 -0
- tunacode/ui/widgets/file_autocomplete.py +47 -0
- tunacode/ui/widgets/messages.py +46 -0
- tunacode/ui/widgets/resource_bar.py +182 -0
- tunacode/ui/widgets/status_bar.py +98 -0
- tunacode/utils/__init__.py +0 -0
- tunacode/utils/config/__init__.py +13 -0
- tunacode/utils/config/user_configuration.py +91 -0
- tunacode/utils/messaging/__init__.py +10 -0
- tunacode/utils/messaging/message_utils.py +34 -0
- tunacode/utils/messaging/token_counter.py +77 -0
- tunacode/utils/parsing/__init__.py +13 -0
- tunacode/utils/parsing/command_parser.py +55 -0
- tunacode/utils/parsing/json_utils.py +188 -0
- tunacode/utils/parsing/retry.py +146 -0
- tunacode/utils/parsing/tool_parser.py +267 -0
- tunacode/utils/security/__init__.py +15 -0
- tunacode/utils/security/command.py +106 -0
- tunacode/utils/system/__init__.py +25 -0
- tunacode/utils/system/gitignore.py +155 -0
- tunacode/utils/system/paths.py +190 -0
- tunacode/utils/ui/__init__.py +9 -0
- tunacode/utils/ui/file_filter.py +135 -0
- tunacode/utils/ui/helpers.py +24 -0
- tunacode_cli-0.1.21.dist-info/METADATA +170 -0
- tunacode_cli-0.1.21.dist-info/RECORD +174 -0
- tunacode_cli-0.1.21.dist-info/WHEEL +4 -0
- tunacode_cli-0.1.21.dist-info/entry_points.txt +2 -0
- 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
|