deepy-cli 0.2.21__tar.gz → 0.2.23__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/PKG-INFO +9 -5
  2. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/README.md +8 -4
  3. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/pyproject.toml +1 -1
  4. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/__init__.py +1 -1
  5. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/cli.py +23 -3
  6. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/config/__init__.py +8 -0
  7. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/config/settings.py +28 -1
  8. deepy_cli-0.2.23/src/deepy/data/tools/Read.md +17 -0
  9. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/tools/Search.md +1 -1
  10. deepy_cli-0.2.23/src/deepy/data/tools/Update.md +19 -0
  11. deepy_cli-0.2.23/src/deepy/data/tools/Write.md +12 -0
  12. deepy_cli-0.2.23/src/deepy/llm/cache_context.py +331 -0
  13. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/llm/compaction.py +51 -36
  14. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/llm/provider.py +9 -0
  15. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/llm/runner.py +39 -6
  16. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/prompts/compact.py +2 -1
  17. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/prompts/system.py +3 -3
  18. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/prompts/tool_docs.py +3 -4
  19. deepy_cli-0.2.23/src/deepy/sessions/__init__.py +27 -0
  20. deepy_cli-0.2.23/src/deepy/sessions/index.py +101 -0
  21. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/sessions/manager.py +5 -21
  22. deepy_cli-0.2.23/src/deepy/sessions/session.py +746 -0
  23. deepy_cli-0.2.23/src/deepy/sessions/store_helpers.py +226 -0
  24. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/status.py +40 -5
  25. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/subagents.py +9 -8
  26. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tools/agents.py +74 -247
  27. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tools/builtin.py +512 -1396
  28. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tools/file_state.py +0 -15
  29. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tui/app.py +148 -35
  30. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tui/commands.py +1 -0
  31. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tui/diff.py +43 -6
  32. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tui/widgets.py +5 -0
  33. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/markdown.py +48 -7
  34. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/message_view.py +201 -102
  35. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/slash_commands.py +10 -6
  36. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/terminal.py +197 -49
  37. deepy_cli-0.2.23/src/deepy/ui/welcome.py +311 -0
  38. deepy_cli-0.2.21/src/deepy/data/tools/apply_patch.md +0 -71
  39. deepy_cli-0.2.21/src/deepy/data/tools/edit_text.md +0 -21
  40. deepy_cli-0.2.21/src/deepy/data/tools/read_file.md +0 -19
  41. deepy_cli-0.2.21/src/deepy/data/tools/write_file.md +0 -14
  42. deepy_cli-0.2.21/src/deepy/sessions/__init__.py +0 -17
  43. deepy_cli-0.2.21/src/deepy/sessions/jsonl.py +0 -650
  44. deepy_cli-0.2.21/src/deepy/ui/welcome.py +0 -216
  45. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/__main__.py +0 -0
  46. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/background_tasks.py +0 -0
  47. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/__init__.py +0 -0
  48. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/skills/skill-creator/SKILL.md +0 -0
  49. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/skills/skill-installer/SKILL.md +0 -0
  50. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/tools/AskUserQuestion.md +0 -0
  51. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/tools/WebFetch.md +0 -0
  52. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/tools/WebSearch.md +0 -0
  53. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/tools/__init__.py +0 -0
  54. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/tools/shell.md +0 -0
  55. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/tools/task_list.md +0 -0
  56. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/tools/task_output.md +0 -0
  57. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/tools/task_stop.md +0 -0
  58. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/tools/test_shell.md +0 -0
  59. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/data/tools/todo_write.md +0 -0
  60. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/errors.py +0 -0
  61. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/input_suggestions.py +0 -0
  62. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/llm/__init__.py +0 -0
  63. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/llm/agent.py +0 -0
  64. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/llm/context.py +0 -0
  65. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/llm/events.py +0 -0
  66. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/llm/model_capabilities.py +0 -0
  67. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/llm/replay.py +0 -0
  68. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/llm/thinking.py +0 -0
  69. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/mcp.py +0 -0
  70. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/prompts/__init__.py +0 -0
  71. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/prompts/init_agents.py +0 -0
  72. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/prompts/rules.py +0 -0
  73. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/prompts/runtime_context.py +0 -0
  74. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/session_cost.py +0 -0
  75. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/skill_market.py +0 -0
  76. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/skills.py +0 -0
  77. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/todos.py +0 -0
  78. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tools/__init__.py +0 -0
  79. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tools/result.py +0 -0
  80. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tools/search.py +0 -0
  81. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tools/shell_output.py +0 -0
  82. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tools/shell_utils.py +0 -0
  83. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tools/test_shell.py +0 -0
  84. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tui/__init__.py +0 -0
  85. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tui/compat.py +0 -0
  86. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tui/runner.py +0 -0
  87. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tui/screens.py +0 -0
  88. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/tui/state.py +0 -0
  89. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/types/__init__.py +0 -0
  90. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/types/sdk.py +0 -0
  91. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/types/tool_payloads.py +0 -0
  92. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/__init__.py +0 -0
  93. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/app.py +0 -0
  94. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/ask_user_question.py +0 -0
  95. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/exit_summary.py +0 -0
  96. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/file_mentions.py +0 -0
  97. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/loading_text.py +0 -0
  98. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/local_command.py +0 -0
  99. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/model_picker.py +0 -0
  100. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/prompt_buffer.py +0 -0
  101. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/prompt_input.py +0 -0
  102. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/session_list.py +0 -0
  103. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/session_picker.py +0 -0
  104. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/skill_picker.py +0 -0
  105. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/status_footer.py +0 -0
  106. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/styles.py +0 -0
  107. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/theme_picker.py +0 -0
  108. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/ui/thinking_state.py +0 -0
  109. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/update_check.py +0 -0
  110. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/usage.py +0 -0
  111. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/utils/__init__.py +0 -0
  112. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/utils/debug_logger.py +0 -0
  113. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/utils/error_logger.py +0 -0
  114. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/src/deepy/utils/json.py +0 -0
  115. {deepy_cli-0.2.21 → deepy_cli-0.2.23}/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.21
3
+ Version: 0.2.23
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
@@ -41,11 +41,11 @@ Description-Content-Type: text/markdown
41
41
  </p>
42
42
 
43
43
  <p align="center">
44
- <a href="https://deepy.kirineko.tech/"><strong>Install Website</strong></a>
44
+ <a href="https://deepy.kirineko.tech/"><strong>Install</strong></a>
45
45
  ·
46
- <a href="https://kirineko.github.io/deepy/">GitHub Pages</a>
46
+ <a href="https://kirineko.github.io/deepy/">Home</a>
47
47
  ·
48
- <a href="README.zh-CN.md">中文文档</a>
48
+ <a href="README.zh-CN.md">中文</a>
49
49
  </p>
50
50
 
51
51
  ![Deepy terminal welcome screen](asset/welcome.webp)
@@ -64,7 +64,7 @@ also supporting OpenAI-compatible providers.
64
64
  supporting OpenAI-compatible providers such as OpenRouter and Xiaomi MiMo.
65
65
  - **Transparent terminal execution**: thinking, tool calls, diffs, shell output,
66
66
  usage, and context pressure stay visible in the transcript.
67
- - **Project memory and continuity**: `AGENTS.md` rules, JSONL sessions,
67
+ - **Project memory and continuity**: `AGENTS.md` rules, local SQLite sessions,
68
68
  `/resume`, `/compact`, automatic compacting, and context-window status keep
69
69
  long project work recoverable.
70
70
  - **Extensible agent ecosystem**: Agent Skills, MCP servers, subagents, and
@@ -283,6 +283,10 @@ deepy sessions show <session-id>
283
283
  deepy run "summarize this project"
284
284
  ```
285
285
 
286
+ Deepy stores active project sessions in a local SQLite session store. Historical
287
+ JSONL session files from older Deepy versions are not imported, listed, or
288
+ resumed by current session commands.
289
+
286
290
  Inside the interactive terminal:
287
291
 
288
292
  ```text
@@ -9,11 +9,11 @@
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <a href="https://deepy.kirineko.tech/"><strong>Install Website</strong></a>
12
+ <a href="https://deepy.kirineko.tech/"><strong>Install</strong></a>
13
13
  ·
14
- <a href="https://kirineko.github.io/deepy/">GitHub Pages</a>
14
+ <a href="https://kirineko.github.io/deepy/">Home</a>
15
15
  ·
16
- <a href="README.zh-CN.md">中文文档</a>
16
+ <a href="README.zh-CN.md">中文</a>
17
17
  </p>
18
18
 
19
19
  ![Deepy terminal welcome screen](asset/welcome.webp)
@@ -32,7 +32,7 @@ also supporting OpenAI-compatible providers.
32
32
  supporting OpenAI-compatible providers such as OpenRouter and Xiaomi MiMo.
33
33
  - **Transparent terminal execution**: thinking, tool calls, diffs, shell output,
34
34
  usage, and context pressure stay visible in the transcript.
35
- - **Project memory and continuity**: `AGENTS.md` rules, JSONL sessions,
35
+ - **Project memory and continuity**: `AGENTS.md` rules, local SQLite sessions,
36
36
  `/resume`, `/compact`, automatic compacting, and context-window status keep
37
37
  long project work recoverable.
38
38
  - **Extensible agent ecosystem**: Agent Skills, MCP servers, subagents, and
@@ -251,6 +251,10 @@ deepy sessions show <session-id>
251
251
  deepy run "summarize this project"
252
252
  ```
253
253
 
254
+ Deepy stores active project sessions in a local SQLite session store. Historical
255
+ JSONL session files from older Deepy versions are not imported, listed, or
256
+ resumed by current session commands.
257
+
254
258
  Inside the interactive terminal:
255
259
 
256
260
  ```text
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "deepy-cli"
3
- version = "0.2.21"
3
+ version = "0.2.23"
4
4
  description = "Deepy - Vibe coding for DeepSeek models in your terminal"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.2.21"
3
+ __version__ = "0.2.23"
4
4
 
5
5
 
6
6
  def main() -> None:
@@ -29,9 +29,10 @@ from .config import (
29
29
  )
30
30
  from .config.settings import DEFAULT_UI_THEME, UI_THEMES
31
31
  from .errors import format_error_display
32
+ from .llm.cache_context import format_cache_usage
32
33
  from .llm.provider import build_provider_bundle
33
34
  from .llm.runner import DEFAULT_MAX_TURNS, run_prompt_once
34
- from .sessions import DeepyJsonlSession, list_session_entries
35
+ from .sessions import DeepySession, list_session_entries
35
36
  from .skills import discover_skills, find_skill, format_skills_for_terminal, read_skill_body
36
37
  from .status import build_status_report, format_status_report, status_report_to_dict
37
38
  from .usage import TokenUsage, format_usage_line, usage_from_run_result
@@ -593,11 +594,11 @@ def _cmd_sessions(args: argparse.Namespace) -> int:
593
594
  for entry in entries:
594
595
  print(
595
596
  f"{entry.id}\tupdated={entry.updated_at}\thistory_estimate={entry.active_tokens}\t"
596
- f"{format_usage_line(entry.usage)}"
597
+ f"{format_usage_line(entry.usage)}\tcache={_format_session_cache(entry)}"
597
598
  )
598
599
  return 0
599
600
  if args.sessions_command == "show":
600
- session = DeepyJsonlSession.open(Path.cwd(), args.session_id)
601
+ session = DeepySession.open(Path.cwd(), args.session_id)
601
602
  items = asyncio.run(session.get_items())
602
603
  entry = next(
603
604
  (item for item in list_session_entries(Path.cwd()) if item.id == args.session_id),
@@ -608,6 +609,11 @@ def _cmd_sessions(args: argparse.Namespace) -> int:
608
609
  {
609
610
  "session_id": args.session_id,
610
611
  "usage": entry.usage if entry is not None else None,
612
+ "cache_prefix_generation": entry.cache_prefix_generation
613
+ if entry is not None
614
+ else 0,
615
+ "cache_break_reason": entry.cache_break_reason if entry is not None else None,
616
+ "cache_usage": entry.cache_usage if entry is not None else None,
611
617
  "items": items,
612
618
  }
613
619
  )
@@ -616,6 +622,20 @@ def _cmd_sessions(args: argparse.Namespace) -> int:
616
622
  return 1
617
623
 
618
624
 
625
+ def _format_session_cache(entry: Any) -> str:
626
+ parts = []
627
+ generation = getattr(entry, "cache_prefix_generation", 0)
628
+ if generation:
629
+ parts.append(f"gen {generation}")
630
+ usage = format_cache_usage(getattr(entry, "cache_usage", None))
631
+ if usage != "unknown":
632
+ parts.append(usage)
633
+ reason = getattr(entry, "cache_break_reason", None)
634
+ if reason:
635
+ parts.append(f"break {reason}")
636
+ return " · ".join(parts) if parts else "unknown"
637
+
638
+
619
639
  def _cmd_skills(args: argparse.Namespace) -> int:
620
640
  if args.skills_command == "list":
621
641
  print(format_skills_for_terminal(discover_skills(Path.cwd())))
@@ -10,6 +10,7 @@ from .settings import (
10
10
  DEFAULT_PROVIDER,
11
11
  DEFAULT_RESERVED_CONTEXT_TOKENS,
12
12
  DEFAULT_UI_THEME,
13
+ DEFAULT_UI_VIEW_MODE,
13
14
  DEFAULT_WEB_SEARCH_SEARXNG_URL,
14
15
  DEFAULT_XIAOMI_BASE_URL,
15
16
  DeepSeekModelInfo,
@@ -26,6 +27,7 @@ from .settings import (
26
27
  TestShellToolConfig,
27
28
  UI_THEME_OPTIONS,
28
29
  UI_THEMES,
30
+ UI_VIEW_MODES,
29
31
  ToolsConfig,
30
32
  UiConfig,
31
33
  XIAOMI_MODEL_CATALOG,
@@ -43,6 +45,7 @@ from .settings import (
43
45
  is_valid_thinking_mode,
44
46
  is_valid_thinking_mode_for_provider,
45
47
  is_valid_ui_theme,
48
+ is_valid_ui_view_mode,
46
49
  is_valid_reasoning_mode,
47
50
  load_settings,
48
51
  mask_secret,
@@ -53,6 +56,7 @@ from .settings import (
53
56
  update_config_model_settings,
54
57
  update_config_input_suggestions_enabled,
55
58
  update_config_theme,
59
+ update_config_view_mode,
56
60
  ui_theme_from_selection,
57
61
  ui_theme_number,
58
62
  write_config,
@@ -68,6 +72,7 @@ __all__ = [
68
72
  "DEFAULT_PROVIDER",
69
73
  "DEFAULT_RESERVED_CONTEXT_TOKENS",
70
74
  "DEFAULT_UI_THEME",
75
+ "DEFAULT_UI_VIEW_MODE",
71
76
  "DEFAULT_WEB_SEARCH_SEARXNG_URL",
72
77
  "DEFAULT_XIAOMI_BASE_URL",
73
78
  "DeepSeekModelInfo",
@@ -84,6 +89,7 @@ __all__ = [
84
89
  "TestShellToolConfig",
85
90
  "UI_THEME_OPTIONS",
86
91
  "UI_THEMES",
92
+ "UI_VIEW_MODES",
87
93
  "ToolsConfig",
88
94
  "UiConfig",
89
95
  "XIAOMI_MODEL_CATALOG",
@@ -101,6 +107,7 @@ __all__ = [
101
107
  "is_valid_thinking_mode",
102
108
  "is_valid_thinking_mode_for_provider",
103
109
  "is_valid_ui_theme",
110
+ "is_valid_ui_view_mode",
104
111
  "is_valid_reasoning_mode",
105
112
  "load_settings",
106
113
  "mask_secret",
@@ -111,6 +118,7 @@ __all__ = [
111
118
  "update_config_model_settings",
112
119
  "update_config_input_suggestions_enabled",
113
120
  "update_config_theme",
121
+ "update_config_view_mode",
114
122
  "ui_theme_from_selection",
115
123
  "ui_theme_number",
116
124
  "write_config",
@@ -23,6 +23,7 @@ DEFAULT_MCP_CLEANUP_TIMEOUT_SECONDS = 10.0
23
23
  DEFAULT_MCP_CLIENT_SESSION_TIMEOUT_SECONDS = 30.0
24
24
  DEFAULT_MCP_CACHE_TOOLS_LIST = True
25
25
  DEFAULT_INPUT_SUGGESTIONS_ENABLED = True
26
+ DEFAULT_UI_VIEW_MODE = "concise"
26
27
  DEFAULT_PROVIDER = "deepseek"
27
28
  DEFAULT_OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"
28
29
  DEFAULT_XIAOMI_BASE_URL = "https://api.xiaomimimo.com/v1"
@@ -47,6 +48,7 @@ THINKING_MODES = set(DEEPSEEK_REASONING_MODES) | set(SWITCH_ONLY_THINKING_MODES)
47
48
  PROVIDERS = {"deepseek", "openrouter", "xiaomi"}
48
49
  UI_THEMES = {"dark", "light"}
49
50
  UI_THEME_OPTIONS = (("1", "dark"), ("2", "light"))
51
+ UI_VIEW_MODES = {"concise", "full"}
50
52
 
51
53
 
52
54
  @dataclass(frozen=True)
@@ -562,6 +564,7 @@ class UiConfig:
562
564
  theme: str = DEFAULT_UI_THEME
563
565
  theme_configured: bool = False
564
566
  input_suggestions_enabled: bool = DEFAULT_INPUT_SUGGESTIONS_ENABLED
567
+ view_mode: str = DEFAULT_UI_VIEW_MODE
565
568
 
566
569
  @classmethod
567
570
  def from_mapping(cls, raw: Mapping[str, Any]) -> Self:
@@ -570,19 +573,24 @@ class UiConfig:
570
573
  raw.get("input_suggestions_enabled"),
571
574
  DEFAULT_INPUT_SUGGESTIONS_ENABLED,
572
575
  )
576
+ view_mode = _as_str(raw.get("view_mode"), DEFAULT_UI_VIEW_MODE)
577
+ if view_mode not in UI_VIEW_MODES:
578
+ view_mode = DEFAULT_UI_VIEW_MODE
573
579
  if isinstance(theme, str) and theme.strip() == "auto":
574
580
  return cls(
575
581
  theme=DEFAULT_UI_THEME,
576
582
  theme_configured=True,
577
583
  input_suggestions_enabled=input_suggestions_enabled,
584
+ view_mode=view_mode,
578
585
  )
579
586
  if isinstance(theme, str) and theme.strip() in UI_THEMES:
580
587
  return cls(
581
588
  theme=theme.strip(),
582
589
  theme_configured=True,
583
590
  input_suggestions_enabled=input_suggestions_enabled,
591
+ view_mode=view_mode,
584
592
  )
585
- return cls(input_suggestions_enabled=input_suggestions_enabled)
593
+ return cls(input_suggestions_enabled=input_suggestions_enabled, view_mode=view_mode)
586
594
 
587
595
 
588
596
  @dataclass(frozen=True)
@@ -649,6 +657,10 @@ def is_valid_ui_theme(value: str) -> bool:
649
657
  return value in UI_THEMES
650
658
 
651
659
 
660
+ def is_valid_ui_view_mode(value: str) -> bool:
661
+ return value in UI_VIEW_MODES
662
+
663
+
652
664
  def is_supported_deepseek_model(value: str) -> bool:
653
665
  return value in SUPPORTED_DEEPSEEK_MODELS
654
666
 
@@ -758,6 +770,7 @@ def write_config(
758
770
  "ui": {
759
771
  "theme": theme,
760
772
  "input_suggestions_enabled": DEFAULT_INPUT_SUGGESTIONS_ENABLED,
773
+ "view_mode": DEFAULT_UI_VIEW_MODE,
761
774
  },
762
775
  }
763
776
  path.parent.mkdir(parents=True, exist_ok=True)
@@ -846,6 +859,20 @@ def update_config_input_suggestions_enabled(config_path: Path, enabled: bool) ->
846
859
  _write_private_toml(path, raw)
847
860
 
848
861
 
862
+ def update_config_view_mode(config_path: Path, view_mode: str) -> None:
863
+ if not is_valid_ui_view_mode(view_mode):
864
+ raise ValueError("View mode must be one of: concise, full.")
865
+ path = config_path.expanduser()
866
+ if path.suffix == ".json":
867
+ raise ValueError("Deepy only supports TOML config files; JSON config is not supported.")
868
+ raw = _read_toml_mapping(path)
869
+ ui = raw.get("ui")
870
+ ui_map = dict(ui) if isinstance(ui, Mapping) else {}
871
+ ui_map["view_mode"] = view_mode
872
+ raw["ui"] = ui_map
873
+ _write_private_toml(path, raw)
874
+
875
+
849
876
  def _read_toml_mapping(path: Path) -> dict[str, Any]:
850
877
  if not path.exists():
851
878
  return {}
@@ -0,0 +1,17 @@
1
+ ## Read
2
+
3
+ Read one or more files or directories.
4
+
5
+ Args:
6
+ - `path`: single target path.
7
+ - `files`: array of read targets for batch reads.
8
+ - Optional range controls: `range` (`"20-80"`), `head`, `tail`, `offset`, `limit`.
9
+ - Optional `pages` for PDF page ranges.
10
+
11
+ Use `Read` before replacing an existing whole file with `Write`, and whenever
12
+ you need exact context for `Update`. When several files are relevant, prefer one
13
+ batch call with `files` instead of serial single-file reads.
14
+
15
+ Text output includes line numbers and total line metadata. Successful text reads
16
+ record runtime-managed read state for later `Write` or `Update`; the model does
17
+ not need to copy snapshot ids, tokens, or content hashes.
@@ -11,7 +11,7 @@ commands. It is read-only.
11
11
 
12
12
  Defaults and guidance:
13
13
  - Use `mode: "literal"` unless the user clearly needs a regex.
14
- - Use `output_mode: "files"` for broad discovery, then `read_file` specific
14
+ - Use `output_mode: "files"` for broad discovery, then `Read` specific
15
15
  files or rerun with `output_mode: "content"`.
16
16
  - Use `output_mode: "count"` to understand match distribution.
17
17
  - Use `glob` or a narrower `path` to keep results focused.
@@ -0,0 +1,19 @@
1
+ ## Update
2
+
3
+ Apply exact text replacements to one or more files.
4
+
5
+ Args:
6
+ - Single edit: `path`, `old`, `new`.
7
+ - Multiple edits in one file: `path`, `edits: [{old, new}]`.
8
+ - Multiple files: `edits: [{path, old, new}]`.
9
+ - Optional `replace_all` and `expected_occurrences`.
10
+
11
+ Use `Update` for existing code, tests, docs, and config when the current text is
12
+ known. The `old` text is whitespace-sensitive plain text and must match exactly.
13
+ For broad replacements, use `replace_all=true` with `expected_occurrences`.
14
+
15
+ Deepy stages and validates all edits in a call before writing. If any edit is
16
+ stale, missing, ambiguous, count-mismatched, or unsupported, no file is changed
17
+ and the result identifies the failing edit. No-op edits are skipped when other
18
+ edits in the same call make real changes; an all-no-op call succeeds with no-op
19
+ metadata and does not write files.
@@ -0,0 +1,12 @@
1
+ ## Write
2
+
3
+ Create a new text file or replace a whole existing text file.
4
+
5
+ Args:
6
+ - `path`: target file path.
7
+ - `content`: complete file content.
8
+ - `overwrite`: set to `true` only for intentional existing-file replacement.
9
+
10
+ For existing files, call `Read` first so Deepy can verify the file is fresh
11
+ before replacement. Use `Update` for exact targeted edits instead of rewriting a
12
+ whole file.