deepy-cli 0.2.26__tar.gz → 0.2.27__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.
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/PKG-INFO +26 -13
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/README.md +24 -11
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/pyproject.toml +2 -2
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/__init__.py +1 -1
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/audit.py +2 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/cli.py +51 -6
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/config/__init__.py +24 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/config/settings.py +131 -1
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/llm/runner.py +52 -2
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/status.py +4 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tools/builtin.py +267 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tui/app.py +1184 -213
- deepy_cli-0.2.27/src/deepy/tui/commands.py +86 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tui/compat.py +1 -1
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tui/diff.py +53 -9
- deepy_cli-0.2.27/src/deepy/tui/interaction_surfaces.py +121 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tui/runner.py +6 -4
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tui/screens.py +193 -109
- deepy_cli-0.2.27/src/deepy/tui/theme.py +50 -0
- deepy_cli-0.2.27/src/deepy/tui/transcript.py +43 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tui/widgets.py +721 -189
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/audit_approval_panel.py +11 -63
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/local_command.py +1 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/markdown.py +15 -2
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/message_view.py +99 -29
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/slash_commands.py +78 -28
- deepy_cli-0.2.27/src/deepy/ui/syntax.py +88 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/terminal.py +175 -6
- deepy_cli-0.2.26/src/deepy/tui/commands.py +0 -105
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/__main__.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/background_tasks.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/__init__.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/skills/skill-creator/SKILL.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/skills/skill-installer/SKILL.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/AskUserQuestion.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/Read.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/Search.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/Update.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/WebFetch.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/WebSearch.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/Write.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/__init__.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/shell.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/task_list.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/task_output.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/task_stop.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/test_shell.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/data/tools/todo_write.md +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/errors.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/input_suggestions.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/llm/__init__.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/llm/agent.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/llm/cache_context.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/llm/compaction.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/llm/context.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/llm/events.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/llm/model_capabilities.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/llm/multimodal.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/llm/provider.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/llm/replay.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/llm/thinking.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/mcp.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/prompts/__init__.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/prompts/compact.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/prompts/init_agents.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/prompts/rules.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/prompts/runtime_context.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/prompts/system.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/prompts/tool_docs.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/session_cost.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/sessions/__init__.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/sessions/index.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/sessions/manager.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/sessions/session.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/sessions/store_helpers.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/skill_market.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/skills.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/subagents.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/todos.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tools/__init__.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tools/agents.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tools/file_state.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tools/result.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tools/search.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tools/shell_output.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tools/shell_utils.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tools/test_shell.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tui/__init__.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/tui/state.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/types/__init__.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/types/sdk.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/types/tool_payloads.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/__init__.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/app.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/ask_user_question.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/audit_approval_picker.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/exit_summary.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/file_mentions.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/image_input.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/loading_text.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/model_picker.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/prompt_buffer.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/prompt_input.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/session_list.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/session_picker.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/skill_picker.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/status_footer.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/styles.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/theme_picker.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/thinking_state.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/ui/welcome.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/update_check.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/usage.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/utils/__init__.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/utils/debug_logger.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/utils/error_logger.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/utils/json.py +0 -0
- {deepy_cli-0.2.26 → deepy_cli-0.2.27}/src/deepy/utils/notify.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: deepy-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.27
|
|
4
4
|
Summary: Deepy - Vibe coding for DeepSeek models in your terminal
|
|
5
5
|
Keywords: deepseek,coding-agent,terminal,cli,agents
|
|
6
6
|
Author: kirineko
|
|
@@ -21,7 +21,7 @@ Requires-Dist: prompt-toolkit>=3.0,<4
|
|
|
21
21
|
Requires-Dist: regex>=2026.5.9
|
|
22
22
|
Requires-Dist: pyyaml>=6.0,<7
|
|
23
23
|
Requires-Dist: rich>=14.2,<15
|
|
24
|
-
Requires-Dist: textual>=8.2,<9
|
|
24
|
+
Requires-Dist: textual>=8.2.7,<9
|
|
25
25
|
Requires-Dist: tiktoken>=0.9,<1
|
|
26
26
|
Requires-Dist: tomli-w>=1
|
|
27
27
|
Requires-Python: >=3.12
|
|
@@ -162,24 +162,35 @@ for direct local commands.
|
|
|
162
162
|
|
|
163
163
|

|
|
164
164
|
|
|
165
|
-
##
|
|
165
|
+
## Classic UI And Modern UI
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
Deepy has two peer terminal interfaces. Classic UI is the Rich/prompt-toolkit
|
|
168
|
+
terminal UI, and Modern UI is the Textual terminal UI. The default `deepy`
|
|
169
|
+
command starts the UI saved in `ui.interface`; missing config defaults to
|
|
170
|
+
Classic UI with the dark theme. The compatibility command below still starts
|
|
171
|
+
Modern UI directly:
|
|
169
172
|
|
|
170
173
|
```bash
|
|
171
174
|
deepy tui
|
|
172
175
|
```
|
|
173
176
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
Modern UI has a compact scrollable transcript, lightweight status line,
|
|
178
|
+
Textual-native composer, live assistant/tool activity states, compact tool
|
|
179
|
+
summary rows, slash-command and `@file` suggestions, inline audit/model/theme
|
|
180
|
+
choices, status/help screens, and a Deepy-owned diff view. Use `/ui` in either
|
|
181
|
+
interface to change the default UI for the next `deepy` startup.
|
|
179
182
|
|
|
180
183
|
`/status` shows session/project usage, context-window pressure, and DeepSeek
|
|
181
|
-
balance in one panel. Exiting
|
|
182
|
-
as
|
|
184
|
+
balance in one panel. Exiting Modern UI prints the same compact session summary
|
|
185
|
+
as Classic UI. Prompt text, image attachments, generated input
|
|
186
|
+
suggestions, slash suggestions, and file suggestions are separate composer
|
|
187
|
+
states, so UI-only attachment labels are not written into the editable prompt
|
|
188
|
+
buffer. Attached images appear in an attachment row with prompt-local keyboard
|
|
189
|
+
shortcuts: press Down to enter attachment selection, Left/Right to choose,
|
|
190
|
+
Backspace to remove, and Up to return to normal input. The shared `dark` /
|
|
191
|
+
`light` setting maps to curated
|
|
192
|
+
Textual themes in Modern UI, with `dark` defaulting to `tokyo-night`; Modern UI can
|
|
193
|
+
also save a Textual-only `ui.textual_theme` override from `/theme`.
|
|
183
194
|
|
|
184
195
|
See [docs/deepy-ui-and-tui.md](docs/deepy-ui-and-tui.md) for the full feature
|
|
185
196
|
comparison and current limitations.
|
|
@@ -263,7 +274,7 @@ MCP inheritance, and troubleshooting.
|
|
|
263
274
|
| Tutorial videos | [docs/tutorial-videos.md](docs/tutorial-videos.md) | [docs/tutorial-videos.zh-CN.md](docs/tutorial-videos.zh-CN.md) |
|
|
264
275
|
| MCP setup and troubleshooting | [docs/mcp.md](docs/mcp.md) | [docs/mcp.zh-CN.md](docs/mcp.zh-CN.md) |
|
|
265
276
|
| Subagents and custom subagents | [docs/subagents.md](docs/subagents.md) | [docs/subagents.zh-CN.md](docs/subagents.zh-CN.md) |
|
|
266
|
-
|
|
|
277
|
+
| Classic UI and Modern UI | [docs/deepy-ui-and-tui.md](docs/deepy-ui-and-tui.md) | [docs/deepy-ui-and-tui.zh-CN.md](docs/deepy-ui-and-tui.zh-CN.md) |
|
|
267
278
|
|
|
268
279
|
## Command Reference
|
|
269
280
|
|
|
@@ -301,6 +312,7 @@ Inside the interactive terminal:
|
|
|
301
312
|
/<name> [request] Invoke a Skill directly
|
|
302
313
|
/init Create or update project AGENTS.md
|
|
303
314
|
/theme Show or change terminal UI theme
|
|
315
|
+
/ui Show or change Classic/Modern UI
|
|
304
316
|
/ps Show managed background shell tasks
|
|
305
317
|
/stop Choose background shell tasks to stop
|
|
306
318
|
```
|
|
@@ -331,6 +343,7 @@ compact_preserve_recent_messages = 2
|
|
|
331
343
|
mode = "yolo" # normal, auto, or yolo
|
|
332
344
|
|
|
333
345
|
[ui]
|
|
346
|
+
interface = "classic" # classic or modern
|
|
334
347
|
theme = "dark" # dark or light
|
|
335
348
|
```
|
|
336
349
|
|
|
@@ -130,24 +130,35 @@ for direct local commands.
|
|
|
130
130
|
|
|
131
131
|

|
|
132
132
|
|
|
133
|
-
##
|
|
133
|
+
## Classic UI And Modern UI
|
|
134
134
|
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
Deepy has two peer terminal interfaces. Classic UI is the Rich/prompt-toolkit
|
|
136
|
+
terminal UI, and Modern UI is the Textual terminal UI. The default `deepy`
|
|
137
|
+
command starts the UI saved in `ui.interface`; missing config defaults to
|
|
138
|
+
Classic UI with the dark theme. The compatibility command below still starts
|
|
139
|
+
Modern UI directly:
|
|
137
140
|
|
|
138
141
|
```bash
|
|
139
142
|
deepy tui
|
|
140
143
|
```
|
|
141
144
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
Modern UI has a compact scrollable transcript, lightweight status line,
|
|
146
|
+
Textual-native composer, live assistant/tool activity states, compact tool
|
|
147
|
+
summary rows, slash-command and `@file` suggestions, inline audit/model/theme
|
|
148
|
+
choices, status/help screens, and a Deepy-owned diff view. Use `/ui` in either
|
|
149
|
+
interface to change the default UI for the next `deepy` startup.
|
|
147
150
|
|
|
148
151
|
`/status` shows session/project usage, context-window pressure, and DeepSeek
|
|
149
|
-
balance in one panel. Exiting
|
|
150
|
-
as
|
|
152
|
+
balance in one panel. Exiting Modern UI prints the same compact session summary
|
|
153
|
+
as Classic UI. Prompt text, image attachments, generated input
|
|
154
|
+
suggestions, slash suggestions, and file suggestions are separate composer
|
|
155
|
+
states, so UI-only attachment labels are not written into the editable prompt
|
|
156
|
+
buffer. Attached images appear in an attachment row with prompt-local keyboard
|
|
157
|
+
shortcuts: press Down to enter attachment selection, Left/Right to choose,
|
|
158
|
+
Backspace to remove, and Up to return to normal input. The shared `dark` /
|
|
159
|
+
`light` setting maps to curated
|
|
160
|
+
Textual themes in Modern UI, with `dark` defaulting to `tokyo-night`; Modern UI can
|
|
161
|
+
also save a Textual-only `ui.textual_theme` override from `/theme`.
|
|
151
162
|
|
|
152
163
|
See [docs/deepy-ui-and-tui.md](docs/deepy-ui-and-tui.md) for the full feature
|
|
153
164
|
comparison and current limitations.
|
|
@@ -231,7 +242,7 @@ MCP inheritance, and troubleshooting.
|
|
|
231
242
|
| Tutorial videos | [docs/tutorial-videos.md](docs/tutorial-videos.md) | [docs/tutorial-videos.zh-CN.md](docs/tutorial-videos.zh-CN.md) |
|
|
232
243
|
| MCP setup and troubleshooting | [docs/mcp.md](docs/mcp.md) | [docs/mcp.zh-CN.md](docs/mcp.zh-CN.md) |
|
|
233
244
|
| Subagents and custom subagents | [docs/subagents.md](docs/subagents.md) | [docs/subagents.zh-CN.md](docs/subagents.zh-CN.md) |
|
|
234
|
-
|
|
|
245
|
+
| Classic UI and Modern UI | [docs/deepy-ui-and-tui.md](docs/deepy-ui-and-tui.md) | [docs/deepy-ui-and-tui.zh-CN.md](docs/deepy-ui-and-tui.zh-CN.md) |
|
|
235
246
|
|
|
236
247
|
## Command Reference
|
|
237
248
|
|
|
@@ -269,6 +280,7 @@ Inside the interactive terminal:
|
|
|
269
280
|
/<name> [request] Invoke a Skill directly
|
|
270
281
|
/init Create or update project AGENTS.md
|
|
271
282
|
/theme Show or change terminal UI theme
|
|
283
|
+
/ui Show or change Classic/Modern UI
|
|
272
284
|
/ps Show managed background shell tasks
|
|
273
285
|
/stop Choose background shell tasks to stop
|
|
274
286
|
```
|
|
@@ -299,6 +311,7 @@ compact_preserve_recent_messages = 2
|
|
|
299
311
|
mode = "yolo" # normal, auto, or yolo
|
|
300
312
|
|
|
301
313
|
[ui]
|
|
314
|
+
interface = "classic" # classic or modern
|
|
302
315
|
theme = "dark" # dark or light
|
|
303
316
|
```
|
|
304
317
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "deepy-cli"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.27"
|
|
4
4
|
description = "Deepy - Vibe coding for DeepSeek models in your terminal"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -27,7 +27,7 @@ dependencies = [
|
|
|
27
27
|
"regex>=2026.5.9",
|
|
28
28
|
"pyyaml>=6.0,<7",
|
|
29
29
|
"rich>=14.2,<15",
|
|
30
|
-
"textual>=8.2,<9",
|
|
30
|
+
"textual>=8.2.7,<9",
|
|
31
31
|
"tiktoken>=0.9,<1",
|
|
32
32
|
"tomli-w>=1",
|
|
33
33
|
]
|
|
@@ -136,9 +136,11 @@ class PendingApproval:
|
|
|
136
136
|
name: str
|
|
137
137
|
tool_name: str
|
|
138
138
|
arguments: str
|
|
139
|
+
call_id: str = ""
|
|
139
140
|
agent_name: str = ""
|
|
140
141
|
action_kind: str = "tool"
|
|
141
142
|
server_name: str = ""
|
|
143
|
+
preflight: Mapping[str, Any] | None = None
|
|
142
144
|
|
|
143
145
|
|
|
144
146
|
@dataclass(frozen=True)
|
|
@@ -22,9 +22,12 @@ from .config import (
|
|
|
22
22
|
provider_info_for,
|
|
23
23
|
settings_to_toml_dict,
|
|
24
24
|
thinking_modes_for_provider,
|
|
25
|
+
ui_setup_from_selection,
|
|
26
|
+
ui_setup_number,
|
|
25
27
|
ui_theme_from_selection,
|
|
26
28
|
ui_theme_number,
|
|
27
29
|
update_config_theme,
|
|
30
|
+
update_config_ui_choice,
|
|
28
31
|
write_config,
|
|
29
32
|
)
|
|
30
33
|
from .config.settings import DEFAULT_UI_THEME, UI_THEMES
|
|
@@ -86,7 +89,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
86
89
|
run_parser.add_argument("--session", help="Resume an existing session id.")
|
|
87
90
|
run_parser.add_argument("--skill", action="append", default=[], help="Load a skill by name.")
|
|
88
91
|
|
|
89
|
-
subparsers.add_parser("tui", help="Start the
|
|
92
|
+
subparsers.add_parser("tui", help="Start the Modern UI.")
|
|
90
93
|
|
|
91
94
|
sessions_parser = subparsers.add_parser("sessions", help="Inspect project sessions.")
|
|
92
95
|
sessions_sub = sessions_parser.add_subparsers(dest="sessions_command", required=True)
|
|
@@ -131,6 +134,7 @@ def _cmd_config_init(args: argparse.Namespace) -> int:
|
|
|
131
134
|
base_url=args.base_url,
|
|
132
135
|
thinking_mode=args.thinking,
|
|
133
136
|
theme=args.theme,
|
|
137
|
+
interface="classic",
|
|
134
138
|
)
|
|
135
139
|
print(f"Wrote {config_path}")
|
|
136
140
|
return 0
|
|
@@ -170,7 +174,10 @@ def _run_config_setup(config_path: Path) -> None:
|
|
|
170
174
|
)
|
|
171
175
|
base_url = _prompt_config_value("Base URL", default=base_default)
|
|
172
176
|
thinking_mode = _prompt_thinking_mode_value(provider, default=existing.model.reasoning_mode)
|
|
173
|
-
theme =
|
|
177
|
+
interface, theme = _prompt_ui_choice_value(
|
|
178
|
+
default_interface=existing.ui.interface,
|
|
179
|
+
default_theme=existing.ui.theme,
|
|
180
|
+
)
|
|
174
181
|
_write_config(
|
|
175
182
|
config_path,
|
|
176
183
|
api_key=api_key,
|
|
@@ -179,6 +186,7 @@ def _run_config_setup(config_path: Path) -> None:
|
|
|
179
186
|
base_url=base_url,
|
|
180
187
|
thinking_mode=thinking_mode,
|
|
181
188
|
theme=theme,
|
|
189
|
+
interface=interface,
|
|
182
190
|
)
|
|
183
191
|
|
|
184
192
|
|
|
@@ -389,6 +397,27 @@ def _prompt_theme_value(*, default: str = DEFAULT_UI_THEME) -> str:
|
|
|
389
397
|
return ui_theme_from_selection(value, default=default)
|
|
390
398
|
|
|
391
399
|
|
|
400
|
+
def _prompt_ui_choice_value(
|
|
401
|
+
*,
|
|
402
|
+
default_interface: str = "classic",
|
|
403
|
+
default_theme: str = DEFAULT_UI_THEME,
|
|
404
|
+
) -> tuple[str, str]:
|
|
405
|
+
print("UI:")
|
|
406
|
+
print("1. Classic UI + dark theme Default terminal UI")
|
|
407
|
+
print("2. Classic UI + light theme")
|
|
408
|
+
print("3. Modern UI + dark theme Textual UI")
|
|
409
|
+
print("4. Modern UI + light theme Textual UI")
|
|
410
|
+
value = _prompt_config_value(
|
|
411
|
+
"UI number",
|
|
412
|
+
default=ui_setup_number(default_interface, default_theme),
|
|
413
|
+
)
|
|
414
|
+
return ui_setup_from_selection(
|
|
415
|
+
value,
|
|
416
|
+
default_interface=default_interface,
|
|
417
|
+
default_theme=default_theme,
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
|
|
392
421
|
def _write_config(
|
|
393
422
|
config_path: Path,
|
|
394
423
|
*,
|
|
@@ -397,6 +426,7 @@ def _write_config(
|
|
|
397
426
|
model: str,
|
|
398
427
|
base_url: str | None,
|
|
399
428
|
theme: str,
|
|
429
|
+
interface: str,
|
|
400
430
|
thinking_mode: str | None,
|
|
401
431
|
) -> None:
|
|
402
432
|
write_config(
|
|
@@ -406,6 +436,7 @@ def _write_config(
|
|
|
406
436
|
model=model,
|
|
407
437
|
base_url=base_url,
|
|
408
438
|
theme=theme,
|
|
439
|
+
interface=interface,
|
|
409
440
|
thinking_mode=thinking_mode,
|
|
410
441
|
)
|
|
411
442
|
|
|
@@ -670,21 +701,35 @@ def _ensure_interactive_settings(args: argparse.Namespace) -> Settings:
|
|
|
670
701
|
raise SystemExit(1)
|
|
671
702
|
settings = load_settings(args.config)
|
|
672
703
|
if settings.path is not None and not settings.ui.theme_configured:
|
|
673
|
-
theme =
|
|
674
|
-
|
|
704
|
+
interface, theme = _prompt_ui_choice_value(
|
|
705
|
+
default_interface=settings.ui.interface,
|
|
706
|
+
default_theme=settings.ui.theme,
|
|
707
|
+
)
|
|
708
|
+
update_config_ui_choice(settings.path, interface=interface, theme=theme)
|
|
675
709
|
settings = load_settings(args.config)
|
|
676
710
|
return settings
|
|
677
711
|
|
|
678
712
|
|
|
679
713
|
def _cmd_tui(args: argparse.Namespace) -> int:
|
|
680
714
|
if not sys.stdin.isatty():
|
|
681
|
-
print("
|
|
715
|
+
print("Modern UI requires a TTY; use `deepy run` for non-interactive prompts.", file=sys.stderr)
|
|
682
716
|
return 1
|
|
683
717
|
from deepy.tui import run_tui
|
|
684
718
|
|
|
685
719
|
return run_tui(_ensure_interactive_settings(args), project_root=Path.cwd())
|
|
686
720
|
|
|
687
721
|
|
|
722
|
+
def _cmd_interactive(args: argparse.Namespace) -> int:
|
|
723
|
+
settings = _ensure_interactive_settings(args)
|
|
724
|
+
if settings.ui.interface == "modern":
|
|
725
|
+
if not sys.stdin.isatty():
|
|
726
|
+
raise RuntimeError("Modern UI requires a TTY.")
|
|
727
|
+
from deepy.tui import run_tui
|
|
728
|
+
|
|
729
|
+
return run_tui(settings, project_root=Path.cwd())
|
|
730
|
+
return run_interactive(settings)
|
|
731
|
+
|
|
732
|
+
|
|
688
733
|
def main(argv: Sequence[str] | None = None) -> int:
|
|
689
734
|
parser = _build_parser()
|
|
690
735
|
args = parser.parse_args(argv)
|
|
@@ -715,7 +760,7 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
715
760
|
|
|
716
761
|
if not sys.stdin.isatty():
|
|
717
762
|
parser.error("interactive mode requires a TTY; use `deepy doctor` or `deepy config show`.")
|
|
718
|
-
return
|
|
763
|
+
return _cmd_interactive(args)
|
|
719
764
|
|
|
720
765
|
|
|
721
766
|
if __name__ == "__main__":
|
|
@@ -6,6 +6,7 @@ from .settings import (
|
|
|
6
6
|
DEFAULT_BASE_URL,
|
|
7
7
|
DEFAULT_COMPACT_PRESERVE_RECENT_MESSAGES,
|
|
8
8
|
DEFAULT_INPUT_SUGGESTIONS_ENABLED,
|
|
9
|
+
DEFAULT_UI_INTERFACE,
|
|
9
10
|
DEFAULT_OPENROUTER_BASE_URL,
|
|
10
11
|
DEFAULT_PROVIDER,
|
|
11
12
|
DEFAULT_RESERVED_CONTEXT_TOKENS,
|
|
@@ -27,6 +28,9 @@ from .settings import (
|
|
|
27
28
|
TestShellToolConfig,
|
|
28
29
|
UI_THEME_OPTIONS,
|
|
29
30
|
UI_THEMES,
|
|
31
|
+
UI_INTERFACE_OPTIONS,
|
|
32
|
+
UI_INTERFACES,
|
|
33
|
+
UI_SETUP_OPTIONS,
|
|
30
34
|
UI_VIEW_MODES,
|
|
31
35
|
ToolsConfig,
|
|
32
36
|
UiConfig,
|
|
@@ -45,6 +49,7 @@ from .settings import (
|
|
|
45
49
|
is_valid_thinking_mode,
|
|
46
50
|
is_valid_thinking_mode_for_provider,
|
|
47
51
|
is_valid_ui_theme,
|
|
52
|
+
is_valid_ui_interface,
|
|
48
53
|
is_valid_ui_view_mode,
|
|
49
54
|
is_valid_reasoning_mode,
|
|
50
55
|
is_valid_config_audit_mode,
|
|
@@ -57,8 +62,15 @@ from .settings import (
|
|
|
57
62
|
update_config_model_settings,
|
|
58
63
|
update_config_audit_mode,
|
|
59
64
|
update_config_input_suggestions_enabled,
|
|
65
|
+
update_config_textual_theme,
|
|
60
66
|
update_config_theme,
|
|
67
|
+
update_config_ui_choice,
|
|
68
|
+
update_config_ui_interface,
|
|
61
69
|
update_config_view_mode,
|
|
70
|
+
ui_interface_from_selection,
|
|
71
|
+
ui_interface_number,
|
|
72
|
+
ui_setup_from_selection,
|
|
73
|
+
ui_setup_number,
|
|
62
74
|
ui_theme_from_selection,
|
|
63
75
|
ui_theme_number,
|
|
64
76
|
write_config,
|
|
@@ -70,6 +82,7 @@ __all__ = [
|
|
|
70
82
|
"DEFAULT_BASE_URL",
|
|
71
83
|
"DEFAULT_COMPACT_PRESERVE_RECENT_MESSAGES",
|
|
72
84
|
"DEFAULT_INPUT_SUGGESTIONS_ENABLED",
|
|
85
|
+
"DEFAULT_UI_INTERFACE",
|
|
73
86
|
"DEFAULT_OPENROUTER_BASE_URL",
|
|
74
87
|
"DEFAULT_PROVIDER",
|
|
75
88
|
"DEFAULT_RESERVED_CONTEXT_TOKENS",
|
|
@@ -91,6 +104,9 @@ __all__ = [
|
|
|
91
104
|
"TestShellToolConfig",
|
|
92
105
|
"UI_THEME_OPTIONS",
|
|
93
106
|
"UI_THEMES",
|
|
107
|
+
"UI_INTERFACE_OPTIONS",
|
|
108
|
+
"UI_INTERFACES",
|
|
109
|
+
"UI_SETUP_OPTIONS",
|
|
94
110
|
"UI_VIEW_MODES",
|
|
95
111
|
"ToolsConfig",
|
|
96
112
|
"UiConfig",
|
|
@@ -109,6 +125,7 @@ __all__ = [
|
|
|
109
125
|
"is_valid_thinking_mode",
|
|
110
126
|
"is_valid_thinking_mode_for_provider",
|
|
111
127
|
"is_valid_ui_theme",
|
|
128
|
+
"is_valid_ui_interface",
|
|
112
129
|
"is_valid_ui_view_mode",
|
|
113
130
|
"is_valid_reasoning_mode",
|
|
114
131
|
"is_valid_config_audit_mode",
|
|
@@ -121,8 +138,15 @@ __all__ = [
|
|
|
121
138
|
"update_config_model_settings",
|
|
122
139
|
"update_config_audit_mode",
|
|
123
140
|
"update_config_input_suggestions_enabled",
|
|
141
|
+
"update_config_textual_theme",
|
|
124
142
|
"update_config_theme",
|
|
143
|
+
"update_config_ui_choice",
|
|
144
|
+
"update_config_ui_interface",
|
|
125
145
|
"update_config_view_mode",
|
|
146
|
+
"ui_interface_from_selection",
|
|
147
|
+
"ui_interface_number",
|
|
148
|
+
"ui_setup_from_selection",
|
|
149
|
+
"ui_setup_number",
|
|
126
150
|
"ui_theme_from_selection",
|
|
127
151
|
"ui_theme_number",
|
|
128
152
|
"write_config",
|
|
@@ -19,6 +19,7 @@ DEFAULT_RESERVED_CONTEXT_TOKENS = 50_000
|
|
|
19
19
|
DEFAULT_COMPACT_PRESERVE_RECENT_MESSAGES = 2
|
|
20
20
|
DEFAULT_WEB_SEARCH_SEARXNG_URL = "https://s.kirineko.tech/"
|
|
21
21
|
DEFAULT_UI_THEME = "dark"
|
|
22
|
+
DEFAULT_UI_INTERFACE = "classic"
|
|
22
23
|
DEFAULT_MCP_ENABLED = True
|
|
23
24
|
DEFAULT_MCP_CONNECT_TIMEOUT_SECONDS = 10.0
|
|
24
25
|
DEFAULT_MCP_CLEANUP_TIMEOUT_SECONDS = 10.0
|
|
@@ -50,6 +51,14 @@ THINKING_MODES = set(DEEPSEEK_REASONING_MODES) | set(SWITCH_ONLY_THINKING_MODES)
|
|
|
50
51
|
PROVIDERS = {"deepseek", "openrouter", "xiaomi"}
|
|
51
52
|
UI_THEMES = {"dark", "light"}
|
|
52
53
|
UI_THEME_OPTIONS = (("1", "dark"), ("2", "light"))
|
|
54
|
+
UI_INTERFACES = {"classic", "modern"}
|
|
55
|
+
UI_INTERFACE_OPTIONS = (("1", "classic"), ("2", "modern"))
|
|
56
|
+
UI_SETUP_OPTIONS = (
|
|
57
|
+
("1", "classic", "dark"),
|
|
58
|
+
("2", "classic", "light"),
|
|
59
|
+
("3", "modern", "dark"),
|
|
60
|
+
("4", "modern", "light"),
|
|
61
|
+
)
|
|
53
62
|
UI_VIEW_MODES = {"concise", "full"}
|
|
54
63
|
|
|
55
64
|
|
|
@@ -330,6 +339,10 @@ def _as_str(value: Any, default: str = "") -> str:
|
|
|
330
339
|
return value.strip() if isinstance(value, str) and value.strip() else default
|
|
331
340
|
|
|
332
341
|
|
|
342
|
+
def _as_optional_str(value: Any) -> str | None:
|
|
343
|
+
return value.strip() if isinstance(value, str) and value.strip() else None
|
|
344
|
+
|
|
345
|
+
|
|
333
346
|
def _as_string_tuple(value: Any) -> tuple[str, ...]:
|
|
334
347
|
if not isinstance(value, list):
|
|
335
348
|
return ()
|
|
@@ -567,13 +580,19 @@ class McpConfig:
|
|
|
567
580
|
@dataclass(frozen=True)
|
|
568
581
|
class UiConfig:
|
|
569
582
|
theme: str = DEFAULT_UI_THEME
|
|
583
|
+
interface: str = DEFAULT_UI_INTERFACE
|
|
570
584
|
theme_configured: bool = False
|
|
585
|
+
textual_theme: str | None = None
|
|
571
586
|
input_suggestions_enabled: bool = DEFAULT_INPUT_SUGGESTIONS_ENABLED
|
|
572
587
|
view_mode: str = DEFAULT_UI_VIEW_MODE
|
|
573
588
|
|
|
574
589
|
@classmethod
|
|
575
590
|
def from_mapping(cls, raw: Mapping[str, Any]) -> Self:
|
|
576
591
|
theme = raw.get("theme")
|
|
592
|
+
interface = _as_str(raw.get("interface"), DEFAULT_UI_INTERFACE)
|
|
593
|
+
if interface not in UI_INTERFACES:
|
|
594
|
+
interface = DEFAULT_UI_INTERFACE
|
|
595
|
+
textual_theme = _as_optional_str(raw.get("textual_theme"))
|
|
577
596
|
input_suggestions_enabled = _as_bool(
|
|
578
597
|
raw.get("input_suggestions_enabled"),
|
|
579
598
|
DEFAULT_INPUT_SUGGESTIONS_ENABLED,
|
|
@@ -584,18 +603,27 @@ class UiConfig:
|
|
|
584
603
|
if isinstance(theme, str) and theme.strip() == "auto":
|
|
585
604
|
return cls(
|
|
586
605
|
theme=DEFAULT_UI_THEME,
|
|
606
|
+
interface=interface,
|
|
587
607
|
theme_configured=True,
|
|
608
|
+
textual_theme=textual_theme,
|
|
588
609
|
input_suggestions_enabled=input_suggestions_enabled,
|
|
589
610
|
view_mode=view_mode,
|
|
590
611
|
)
|
|
591
612
|
if isinstance(theme, str) and theme.strip() in UI_THEMES:
|
|
592
613
|
return cls(
|
|
593
614
|
theme=theme.strip(),
|
|
615
|
+
interface=interface,
|
|
594
616
|
theme_configured=True,
|
|
617
|
+
textual_theme=textual_theme,
|
|
595
618
|
input_suggestions_enabled=input_suggestions_enabled,
|
|
596
619
|
view_mode=view_mode,
|
|
597
620
|
)
|
|
598
|
-
return cls(
|
|
621
|
+
return cls(
|
|
622
|
+
textual_theme=textual_theme,
|
|
623
|
+
interface=interface,
|
|
624
|
+
input_suggestions_enabled=input_suggestions_enabled,
|
|
625
|
+
view_mode=view_mode,
|
|
626
|
+
)
|
|
599
627
|
|
|
600
628
|
|
|
601
629
|
@dataclass(frozen=True)
|
|
@@ -672,6 +700,10 @@ def is_valid_ui_theme(value: str) -> bool:
|
|
|
672
700
|
return value in UI_THEMES
|
|
673
701
|
|
|
674
702
|
|
|
703
|
+
def is_valid_ui_interface(value: str) -> bool:
|
|
704
|
+
return value in UI_INTERFACES
|
|
705
|
+
|
|
706
|
+
|
|
675
707
|
def is_valid_ui_view_mode(value: str) -> bool:
|
|
676
708
|
return value in UI_VIEW_MODES
|
|
677
709
|
|
|
@@ -716,6 +748,52 @@ def ui_theme_from_selection(value: str, *, default: str = DEFAULT_UI_THEME) -> s
|
|
|
716
748
|
return default if is_valid_ui_theme(default) else DEFAULT_UI_THEME
|
|
717
749
|
|
|
718
750
|
|
|
751
|
+
def ui_interface_number(interface: str) -> str:
|
|
752
|
+
for number, value in UI_INTERFACE_OPTIONS:
|
|
753
|
+
if value == interface:
|
|
754
|
+
return number
|
|
755
|
+
return "1"
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
def ui_interface_from_selection(value: str, *, default: str = DEFAULT_UI_INTERFACE) -> str:
|
|
759
|
+
normalized = value.strip().lower()
|
|
760
|
+
if not normalized:
|
|
761
|
+
return default if is_valid_ui_interface(default) else DEFAULT_UI_INTERFACE
|
|
762
|
+
if normalized in UI_INTERFACES:
|
|
763
|
+
return normalized
|
|
764
|
+
by_number = dict(UI_INTERFACE_OPTIONS)
|
|
765
|
+
selected = by_number.get(normalized)
|
|
766
|
+
if selected is not None:
|
|
767
|
+
return selected
|
|
768
|
+
return default if is_valid_ui_interface(default) else DEFAULT_UI_INTERFACE
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
def ui_setup_number(interface: str, theme: str) -> str:
|
|
772
|
+
for number, option_interface, option_theme in UI_SETUP_OPTIONS:
|
|
773
|
+
if option_interface == interface and option_theme == theme:
|
|
774
|
+
return number
|
|
775
|
+
return "1"
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
def ui_setup_from_selection(
|
|
779
|
+
value: str,
|
|
780
|
+
*,
|
|
781
|
+
default_interface: str = DEFAULT_UI_INTERFACE,
|
|
782
|
+
default_theme: str = DEFAULT_UI_THEME,
|
|
783
|
+
) -> tuple[str, str]:
|
|
784
|
+
normalized = value.strip().lower()
|
|
785
|
+
fallback = (
|
|
786
|
+
default_interface if is_valid_ui_interface(default_interface) else DEFAULT_UI_INTERFACE,
|
|
787
|
+
default_theme if is_valid_ui_theme(default_theme) else DEFAULT_UI_THEME,
|
|
788
|
+
)
|
|
789
|
+
if not normalized:
|
|
790
|
+
return fallback
|
|
791
|
+
for number, option_interface, option_theme in UI_SETUP_OPTIONS:
|
|
792
|
+
if normalized in {number, f"{option_interface}-{option_theme}", f"{option_interface} {option_theme}"}:
|
|
793
|
+
return option_interface, option_theme
|
|
794
|
+
return fallback
|
|
795
|
+
|
|
796
|
+
|
|
719
797
|
def write_config(
|
|
720
798
|
config_path: Path,
|
|
721
799
|
*,
|
|
@@ -724,10 +802,13 @@ def write_config(
|
|
|
724
802
|
model: str,
|
|
725
803
|
base_url: str | None = None,
|
|
726
804
|
theme: str,
|
|
805
|
+
interface: str = DEFAULT_UI_INTERFACE,
|
|
727
806
|
thinking_mode: str | None = None,
|
|
728
807
|
) -> None:
|
|
729
808
|
if not is_valid_ui_theme(theme):
|
|
730
809
|
raise ValueError("UI theme must be one of: dark, light.")
|
|
810
|
+
if not is_valid_ui_interface(interface):
|
|
811
|
+
raise ValueError("UI interface must be one of: classic, modern.")
|
|
731
812
|
if not is_supported_provider(provider):
|
|
732
813
|
raise ValueError("Provider must be one of: deepseek, openrouter, xiaomi.")
|
|
733
814
|
provider_info = provider_info_for(provider)
|
|
@@ -791,6 +872,7 @@ def write_config(
|
|
|
791
872
|
},
|
|
792
873
|
},
|
|
793
874
|
"ui": {
|
|
875
|
+
"interface": interface,
|
|
794
876
|
"theme": theme,
|
|
795
877
|
"input_suggestions_enabled": DEFAULT_INPUT_SUGGESTIONS_ENABLED,
|
|
796
878
|
"view_mode": DEFAULT_UI_VIEW_MODE,
|
|
@@ -866,6 +948,54 @@ def update_config_theme(config_path: Path, theme: str) -> None:
|
|
|
866
948
|
ui = raw.get("ui")
|
|
867
949
|
ui_map = dict(ui) if isinstance(ui, Mapping) else {}
|
|
868
950
|
ui_map["theme"] = theme
|
|
951
|
+
ui_map.pop("textual_theme", None)
|
|
952
|
+
raw["ui"] = ui_map
|
|
953
|
+
_write_private_toml(path, raw)
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
def update_config_ui_interface(config_path: Path, interface: str) -> None:
|
|
957
|
+
if not is_valid_ui_interface(interface):
|
|
958
|
+
raise ValueError("UI interface must be one of: classic, modern.")
|
|
959
|
+
path = config_path.expanduser()
|
|
960
|
+
if path.suffix == ".json":
|
|
961
|
+
raise ValueError("Deepy only supports TOML config files; JSON config is not supported.")
|
|
962
|
+
raw = _read_toml_mapping(path)
|
|
963
|
+
ui = raw.get("ui")
|
|
964
|
+
ui_map = dict(ui) if isinstance(ui, Mapping) else {}
|
|
965
|
+
ui_map["interface"] = interface
|
|
966
|
+
raw["ui"] = ui_map
|
|
967
|
+
_write_private_toml(path, raw)
|
|
968
|
+
|
|
969
|
+
|
|
970
|
+
def update_config_ui_choice(config_path: Path, *, interface: str, theme: str) -> None:
|
|
971
|
+
if not is_valid_ui_interface(interface):
|
|
972
|
+
raise ValueError("UI interface must be one of: classic, modern.")
|
|
973
|
+
if not is_valid_ui_theme(theme):
|
|
974
|
+
raise ValueError("UI theme must be one of: dark, light.")
|
|
975
|
+
path = config_path.expanduser()
|
|
976
|
+
if path.suffix == ".json":
|
|
977
|
+
raise ValueError("Deepy only supports TOML config files; JSON config is not supported.")
|
|
978
|
+
raw = _read_toml_mapping(path)
|
|
979
|
+
ui = raw.get("ui")
|
|
980
|
+
ui_map = dict(ui) if isinstance(ui, Mapping) else {}
|
|
981
|
+
ui_map["interface"] = interface
|
|
982
|
+
ui_map["theme"] = theme
|
|
983
|
+
ui_map.pop("textual_theme", None)
|
|
984
|
+
raw["ui"] = ui_map
|
|
985
|
+
_write_private_toml(path, raw)
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
def update_config_textual_theme(config_path: Path, textual_theme: str) -> None:
|
|
989
|
+
theme = textual_theme.strip()
|
|
990
|
+
if not theme:
|
|
991
|
+
raise ValueError("Textual theme must not be empty.")
|
|
992
|
+
path = config_path.expanduser()
|
|
993
|
+
if path.suffix == ".json":
|
|
994
|
+
raise ValueError("Deepy only supports TOML config files; JSON config is not supported.")
|
|
995
|
+
raw = _read_toml_mapping(path)
|
|
996
|
+
ui = raw.get("ui")
|
|
997
|
+
ui_map = dict(ui) if isinstance(ui, Mapping) else {}
|
|
998
|
+
ui_map["textual_theme"] = theme
|
|
869
999
|
raw["ui"] = ui_map
|
|
870
1000
|
_write_private_toml(path, raw)
|
|
871
1001
|
|