deepy-cli 0.2.12__tar.gz → 0.2.13__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 (99) hide show
  1. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/PKG-INFO +3 -1
  2. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/pyproject.toml +3 -1
  3. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/__init__.py +1 -1
  4. deepy_cli-0.2.13/src/deepy/data/tools/Search.md +20 -0
  5. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/prompts/system.py +1 -0
  6. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/prompts/tool_docs.py +1 -0
  7. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tools/agents.py +89 -0
  8. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tools/builtin.py +41 -0
  9. deepy_cli-0.2.13/src/deepy/tools/search.py +643 -0
  10. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/message_view.py +49 -0
  11. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/README.md +0 -0
  12. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/__main__.py +0 -0
  13. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/cli.py +0 -0
  14. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/config/__init__.py +0 -0
  15. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/config/settings.py +0 -0
  16. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/__init__.py +0 -0
  17. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/skills/skill-creator/SKILL.md +0 -0
  18. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/skills/skill-installer/SKILL.md +0 -0
  19. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/tools/AskUserQuestion.md +0 -0
  20. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/tools/WebFetch.md +0 -0
  21. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/tools/WebSearch.md +0 -0
  22. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/tools/__init__.py +0 -0
  23. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/tools/apply_patch.md +0 -0
  24. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/tools/edit_text.md +0 -0
  25. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/tools/read_file.md +0 -0
  26. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/tools/shell.md +0 -0
  27. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/tools/todo_write.md +0 -0
  28. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/data/tools/write_file.md +0 -0
  29. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/errors.py +0 -0
  30. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/input_suggestions.py +0 -0
  31. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/llm/__init__.py +0 -0
  32. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/llm/agent.py +0 -0
  33. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/llm/compaction.py +0 -0
  34. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/llm/context.py +0 -0
  35. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/llm/events.py +0 -0
  36. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/llm/model_capabilities.py +0 -0
  37. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/llm/provider.py +0 -0
  38. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/llm/replay.py +0 -0
  39. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/llm/runner.py +0 -0
  40. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/llm/thinking.py +0 -0
  41. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/mcp.py +0 -0
  42. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/prompts/__init__.py +0 -0
  43. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/prompts/compact.py +0 -0
  44. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/prompts/init_agents.py +0 -0
  45. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/prompts/rules.py +0 -0
  46. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/prompts/runtime_context.py +0 -0
  47. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/session_cost.py +0 -0
  48. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/sessions/__init__.py +0 -0
  49. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/sessions/jsonl.py +0 -0
  50. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/sessions/manager.py +0 -0
  51. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/skill_market.py +0 -0
  52. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/skills.py +0 -0
  53. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/status.py +0 -0
  54. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/todos.py +0 -0
  55. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tools/__init__.py +0 -0
  56. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tools/file_state.py +0 -0
  57. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tools/result.py +0 -0
  58. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tools/shell_output.py +0 -0
  59. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tools/shell_utils.py +0 -0
  60. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tui/__init__.py +0 -0
  61. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tui/app.py +0 -0
  62. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tui/commands.py +0 -0
  63. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tui/compat.py +0 -0
  64. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tui/diff.py +0 -0
  65. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tui/runner.py +0 -0
  66. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tui/screens.py +0 -0
  67. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tui/state.py +0 -0
  68. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/tui/widgets.py +0 -0
  69. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/types/__init__.py +0 -0
  70. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/types/sdk.py +0 -0
  71. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/types/tool_payloads.py +0 -0
  72. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/__init__.py +0 -0
  73. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/app.py +0 -0
  74. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/ask_user_question.py +0 -0
  75. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/exit_summary.py +0 -0
  76. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/file_mentions.py +0 -0
  77. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/loading_text.py +0 -0
  78. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/local_command.py +0 -0
  79. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/markdown.py +0 -0
  80. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/model_picker.py +0 -0
  81. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/prompt_buffer.py +0 -0
  82. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/prompt_input.py +0 -0
  83. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/session_list.py +0 -0
  84. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/session_picker.py +0 -0
  85. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/skill_picker.py +0 -0
  86. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/slash_commands.py +0 -0
  87. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/status_footer.py +0 -0
  88. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/styles.py +0 -0
  89. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/terminal.py +0 -0
  90. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/theme_picker.py +0 -0
  91. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/thinking_state.py +0 -0
  92. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/ui/welcome.py +0 -0
  93. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/update_check.py +0 -0
  94. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/usage.py +0 -0
  95. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/utils/__init__.py +0 -0
  96. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/utils/debug_logger.py +0 -0
  97. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/utils/error_logger.py +0 -0
  98. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/src/deepy/utils/json.py +0 -0
  99. {deepy_cli-0.2.12 → deepy_cli-0.2.13}/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.12
3
+ Version: 0.2.13
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
@@ -15,8 +15,10 @@ Classifier: Topic :: Terminals
15
15
  Requires-Dist: openai-agents>=0.17.0
16
16
  Requires-Dist: openai>=2.26,<3
17
17
  Requires-Dist: orjson>=3.10,<4
18
+ Requires-Dist: pathspec>=1.1.1
18
19
  Requires-Dist: pydantic>=2.12,<3
19
20
  Requires-Dist: prompt-toolkit>=3.0,<4
21
+ Requires-Dist: regex>=2026.5.9
20
22
  Requires-Dist: pyyaml>=6.0,<7
21
23
  Requires-Dist: rich>=14.2,<15
22
24
  Requires-Dist: textual>=8.2,<9
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "deepy-cli"
3
- version = "0.2.12"
3
+ version = "0.2.13"
4
4
  description = "Deepy - Vibe coding for DeepSeek models in your terminal"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -21,8 +21,10 @@ dependencies = [
21
21
  "openai-agents>=0.17.0",
22
22
  "openai>=2.26,<3",
23
23
  "orjson>=3.10,<4",
24
+ "pathspec>=1.1.1",
24
25
  "pydantic>=2.12,<3",
25
26
  "prompt-toolkit>=3.0,<4",
27
+ "regex>=2026.5.9",
26
28
  "pyyaml>=6.0,<7",
27
29
  "rich>=14.2,<15",
28
30
  "textual>=8.2,<9",
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.2.12"
3
+ __version__ = "0.2.13"
4
4
 
5
5
 
6
6
  def main() -> None:
@@ -0,0 +1,20 @@
1
+ ## Search
2
+
3
+ Search local project files without shell `grep`, `find`, or `rg`.
4
+
5
+ Args: `query`, `path`, `glob`, `mode`, `output_mode`, `case_sensitive`,
6
+ `context`, `limit`, `offset`, `include_ignored`.
7
+
8
+ Use `Search` for repository code/text search before falling back to `shell`.
9
+ It is built into Deepy and does not require ripgrep or platform-specific shell
10
+ commands. It is read-only.
11
+
12
+ Defaults and guidance:
13
+ - Use `mode: "literal"` unless the user clearly needs a regex.
14
+ - Use `output_mode: "files"` for broad discovery, then `read_file` specific
15
+ files or rerun with `output_mode: "content"`.
16
+ - Use `output_mode: "count"` to understand match distribution.
17
+ - Use `glob` or a narrower `path` to keep results focused.
18
+ - Use `limit` and `offset` to page through large result sets.
19
+ - Leave `include_ignored` false unless ignored build artifacts or dependencies
20
+ are explicitly relevant. Sensitive files are still filtered.
@@ -45,6 +45,7 @@ def build_system_prompt(
45
45
  Core rules:
46
46
  - Work in the repo with tools: inspect, edit, test, verify.
47
47
  - Preserve user changes. Prefer small, verifiable edits.
48
+ - Use `Search` for local project code/text search instead of shell `grep`, `find`, or `rg`; narrow with `path`, `glob`, `output_mode`, `limit`, and `offset`.
48
49
  - Read existing files when you need context; exact `edit_text` edits can establish the managed snapshot internally.
49
50
  - Use `edit_text` for one small single-file exact edit. Use structured `apply_patch.operations` when a change has multiple edits in one file, touches multiple files, creates/deletes/moves files, or replaces a larger block. Use `write_file` for new files or explicit whole-file replacement.
50
51
  - After project generators create scaffold files, read and edit the generated block instead of replacing the file.
@@ -5,6 +5,7 @@ from importlib import resources
5
5
 
6
6
  TOOL_DOC_FILES = (
7
7
  "shell.md",
8
+ "Search.md",
8
9
  "read_file.md",
9
10
  "edit_text.md",
10
11
  "write_file.md",
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import asyncio
3
4
  from typing import TYPE_CHECKING, Any
4
5
 
5
6
  from deepy.utils import json as json_utils
@@ -26,6 +27,22 @@ def build_function_tools(
26
27
  questions = args.get("questions")
27
28
  return runtime.ask_user_question(questions if isinstance(questions, list) else [])
28
29
 
30
+ async def invoke_search(_context: object, raw_input: str) -> str:
31
+ args = _tool_args(raw_input)
32
+ return await asyncio.to_thread(
33
+ runtime.search,
34
+ _string_arg(args, "query"),
35
+ path=_string_arg(args, "path") or ".",
36
+ glob=_optional_string_arg(args, "glob"),
37
+ mode=_string_arg(args, "mode") or "literal",
38
+ output_mode=_string_arg(args, "output_mode") or "content",
39
+ case_sensitive=_bool_arg(args, "case_sensitive", True),
40
+ context=_int_arg(args, "context", 0),
41
+ limit=_int_arg(args, "limit", 100),
42
+ offset=_int_arg(args, "offset", 0),
43
+ include_ignored=_bool_arg(args, "include_ignored", False),
44
+ )
45
+
29
46
  async def invoke_read_file(_context: object, raw_input: str) -> str:
30
47
  args = _tool_args(raw_input)
31
48
  return runtime.read_file(
@@ -114,6 +131,17 @@ def build_function_tools(
114
131
  on_invoke_tool=invoke_ask_user_question,
115
132
  strict_json_schema=False,
116
133
  ),
134
+ FunctionTool(
135
+ name="Search",
136
+ description=(
137
+ "Search local project files without shell grep or rg. Prefer this for repository "
138
+ "code/text search. Defaults to literal content search; use regex mode only when "
139
+ "a regular expression is intentional."
140
+ ),
141
+ params_json_schema=SEARCH_SCHEMA,
142
+ on_invoke_tool=invoke_search,
143
+ strict_json_schema=True,
144
+ ),
117
145
  FunctionTool(
118
146
  name="read_file",
119
147
  description=(
@@ -303,6 +331,67 @@ ASK_USER_QUESTION_SCHEMA: dict[str, Any] = {
303
331
  "additionalProperties": False,
304
332
  }
305
333
 
334
+ SEARCH_SCHEMA: dict[str, Any] = {
335
+ "type": "object",
336
+ "properties": {
337
+ "query": {
338
+ "type": "string",
339
+ "description": "Literal string or regex pattern to search for in local project files.",
340
+ },
341
+ "path": {
342
+ "type": "string",
343
+ "description": "Project-relative file or directory path to search. Use '.' for the project.",
344
+ },
345
+ "glob": {
346
+ "type": ["string", "null"],
347
+ "description": "Optional glob filter against project-relative paths, such as '*.py'.",
348
+ },
349
+ "mode": {
350
+ "type": "string",
351
+ "enum": ["literal", "regex"],
352
+ "description": "Search mode. Use literal by default; use regex only intentionally.",
353
+ },
354
+ "output_mode": {
355
+ "type": "string",
356
+ "enum": ["content", "files", "count"],
357
+ "description": "Return matching lines, matching file paths, or per-file counts.",
358
+ },
359
+ "case_sensitive": {
360
+ "type": "boolean",
361
+ "description": "Whether matching is case-sensitive.",
362
+ },
363
+ "context": {
364
+ "type": "integer",
365
+ "description": "Number of context lines before and after content matches.",
366
+ },
367
+ "limit": {
368
+ "type": "integer",
369
+ "description": "Maximum number of result entries to return. Use 0 for unlimited sparingly.",
370
+ },
371
+ "offset": {
372
+ "type": "integer",
373
+ "description": "Number of result entries to skip for pagination.",
374
+ },
375
+ "include_ignored": {
376
+ "type": "boolean",
377
+ "description": "Whether to include gitignored files. Sensitive files are still filtered.",
378
+ },
379
+ },
380
+ "required": [
381
+ "query",
382
+ "path",
383
+ "glob",
384
+ "mode",
385
+ "output_mode",
386
+ "case_sensitive",
387
+ "context",
388
+ "limit",
389
+ "offset",
390
+ "include_ignored",
391
+ ],
392
+ "additionalProperties": False,
393
+ }
394
+
306
395
  READ_FILE_SCHEMA: dict[str, Any] = {
307
396
  "type": "object",
308
397
  "properties": {
@@ -29,6 +29,7 @@ from deepy.utils import json as json_utils
29
29
 
30
30
  from .file_state import FileSnippet, FileState
31
31
  from .result import ToolResult
32
+ from .search import SearchMode, SearchOutputMode, SearchRequest, search_project
32
33
  from .shell_output import decode_shell_output
33
34
  from .shell_utils import RuntimeEnvironment
34
35
  from .shell_utils import build_disable_extglob_command
@@ -1572,6 +1573,46 @@ class ToolRuntime:
1572
1573
  ) -> str:
1573
1574
  return self._read_file_result(path, start_line=start_line, limit=limit, pages=pages)
1574
1575
 
1576
+ def search(
1577
+ self,
1578
+ query: str,
1579
+ *,
1580
+ path: str = ".",
1581
+ glob: str | None = None,
1582
+ mode: str = "literal",
1583
+ output_mode: str = "content",
1584
+ case_sensitive: bool = True,
1585
+ context: int = 0,
1586
+ limit: int = 100,
1587
+ offset: int = 0,
1588
+ include_ignored: bool = False,
1589
+ ) -> str:
1590
+ name = "Search"
1591
+ request = SearchRequest(
1592
+ query=query,
1593
+ path=path,
1594
+ glob=glob,
1595
+ mode=cast(SearchMode, mode),
1596
+ output_mode=cast(SearchOutputMode, output_mode),
1597
+ case_sensitive=case_sensitive,
1598
+ context=context,
1599
+ limit=limit,
1600
+ offset=offset,
1601
+ include_ignored=include_ignored,
1602
+ )
1603
+ page = search_project(self.cwd, request)
1604
+ error = page.metadata.get("error")
1605
+ error_code = page.metadata.get("error_code")
1606
+ if isinstance(error, str) and error_code:
1607
+ return ToolResult.error_result(name, error, metadata=page.metadata).to_json()
1608
+ if error_code and not page.output:
1609
+ return ToolResult.error_result(
1610
+ name,
1611
+ "Search failed.",
1612
+ metadata=page.metadata,
1613
+ ).to_json()
1614
+ return ToolResult.ok_result(name, page.output, metadata=page.metadata).to_json()
1615
+
1575
1616
  def write(
1576
1617
  self,
1577
1618
  path: str,