deepy-cli 0.2.1__tar.gz → 0.2.2__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 (84) hide show
  1. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/PKG-INFO +1 -1
  2. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/pyproject.toml +1 -1
  3. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/__init__.py +1 -1
  4. deepy_cli-0.2.2/src/deepy/data/tools/modify.md +26 -0
  5. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/prompts/system.py +1 -1
  6. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/tools/agents.py +2 -1
  7. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/tools/builtin.py +19 -1
  8. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/tools/file_state.py +16 -0
  9. deepy_cli-0.2.1/src/deepy/data/tools/modify.md +0 -22
  10. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/README.md +0 -0
  11. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/__main__.py +0 -0
  12. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/cli.py +0 -0
  13. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/config/__init__.py +0 -0
  14. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/config/settings.py +0 -0
  15. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/data/__init__.py +0 -0
  16. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/data/skills/skill-creator/SKILL.md +0 -0
  17. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/data/skills/skill-installer/SKILL.md +0 -0
  18. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/data/tools/AskUserQuestion.md +0 -0
  19. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/data/tools/WebFetch.md +0 -0
  20. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/data/tools/WebSearch.md +0 -0
  21. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/data/tools/__init__.py +0 -0
  22. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/data/tools/edit.md +0 -0
  23. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/data/tools/read.md +0 -0
  24. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/data/tools/shell.md +0 -0
  25. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/data/tools/write.md +0 -0
  26. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/errors.py +0 -0
  27. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/llm/__init__.py +0 -0
  28. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/llm/agent.py +0 -0
  29. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/llm/compaction.py +0 -0
  30. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/llm/context.py +0 -0
  31. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/llm/events.py +0 -0
  32. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/llm/model_capabilities.py +0 -0
  33. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/llm/provider.py +0 -0
  34. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/llm/replay.py +0 -0
  35. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/llm/runner.py +0 -0
  36. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/llm/thinking.py +0 -0
  37. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/mcp.py +0 -0
  38. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/prompts/__init__.py +0 -0
  39. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/prompts/compact.py +0 -0
  40. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/prompts/init_agents.py +0 -0
  41. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/prompts/rules.py +0 -0
  42. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/prompts/runtime_context.py +0 -0
  43. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/prompts/tool_docs.py +0 -0
  44. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/sessions/__init__.py +0 -0
  45. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/sessions/jsonl.py +0 -0
  46. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/sessions/manager.py +0 -0
  47. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/skill_market.py +0 -0
  48. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/skills.py +0 -0
  49. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/status.py +0 -0
  50. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/tools/__init__.py +0 -0
  51. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/tools/result.py +0 -0
  52. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/tools/shell_output.py +0 -0
  53. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/tools/shell_utils.py +0 -0
  54. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/types/__init__.py +0 -0
  55. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/types/sdk.py +0 -0
  56. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/types/tool_payloads.py +0 -0
  57. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/__init__.py +0 -0
  58. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/app.py +0 -0
  59. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/ask_user_question.py +0 -0
  60. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/exit_summary.py +0 -0
  61. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/file_mentions.py +0 -0
  62. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/loading_text.py +0 -0
  63. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/local_command.py +0 -0
  64. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/markdown.py +0 -0
  65. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/message_view.py +0 -0
  66. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/model_picker.py +0 -0
  67. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/prompt_buffer.py +0 -0
  68. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/prompt_input.py +0 -0
  69. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/session_list.py +0 -0
  70. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/session_picker.py +0 -0
  71. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/skill_picker.py +0 -0
  72. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/slash_commands.py +0 -0
  73. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/styles.py +0 -0
  74. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/terminal.py +0 -0
  75. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/theme_picker.py +0 -0
  76. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/thinking_state.py +0 -0
  77. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/ui/welcome.py +0 -0
  78. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/update_check.py +0 -0
  79. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/usage.py +0 -0
  80. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/utils/__init__.py +0 -0
  81. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/utils/debug_logger.py +0 -0
  82. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/utils/error_logger.py +0 -0
  83. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/src/deepy/utils/json.py +0 -0
  84. {deepy_cli-0.2.1 → deepy_cli-0.2.2}/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.1
3
+ Version: 0.2.2
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "deepy-cli"
3
- version = "0.2.1"
3
+ version = "0.2.2"
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.1"
3
+ __version__ = "0.2.2"
4
4
 
5
5
 
6
6
  def main() -> None:
@@ -0,0 +1,26 @@
1
+ ## modify
2
+
3
+ Create new files or edit existing files.
4
+
5
+ Use `content` only when the target file does not exist. For existing files, use
6
+ `old_string` and `new_string` for the smallest reliable replacement. You may
7
+ attempt an exact replacement directly when you already know the current text;
8
+ Deepy records the required file snapshot internally when no prior snapshot
9
+ exists. Read first when you need to inspect context. Do not rewrite an existing
10
+ scaffolded file with full content; replace the specific generated block instead.
11
+
12
+ Args for new files: `file_path`, `content`.
13
+
14
+ Args for existing files: `file_path`, `old_string`, `new_string`, optional
15
+ `replace_all`, optional `snippet_id`.
16
+
17
+ Existing-file edits must have a managed snapshot before Deepy commits changes;
18
+ `modify` can create that snapshot internally for direct exact replacements. Stale
19
+ edits are rejected. Repeated matches are rejected unless `replace_all` is true;
20
+ candidate snippets can be reused with `snippet_id`. Success includes diff
21
+ metadata.
22
+
23
+ If several `old_string` attempts fail and you know the complete desired file content,
24
+ re-read the file and use the managed whole-file replacement path. Do not delete the file
25
+ and recreate it with shell commands or here-strings; that bypasses Deepy's encoding,
26
+ newline, and stale-write protections, especially on Windows.
@@ -45,7 +45,7 @@ def build_system_prompt(
45
45
  Core rules:
46
46
  - Work in the repo with tools: inspect, modify, test, verify.
47
47
  - Preserve user changes. Prefer small, verifiable edits.
48
- - Read before changing existing files.
48
+ - Read existing files when you need context; exact `modify` edits can establish the managed snapshot internally.
49
49
  - Use `modify` for file changes: `content` only creates new files; existing files use `old_string`/`new_string`.
50
50
  - After project generators create scaffold files, read and edit the generated block instead of replacing the file.
51
51
  - Run shell commands using the Runtime context's command dialect and path style: `powershell` -> PowerShell with Windows paths; `cmd` -> cmd; `posix` -> POSIX shell.
@@ -107,7 +107,8 @@ def build_function_tools(
107
107
  name="modify",
108
108
  description=(
109
109
  "Create new files or edit existing files. Use content only for files that do not "
110
- "exist. For existing files, read first and use old_string/new_string."
110
+ "exist. For existing files, use old_string/new_string; read first when you need "
111
+ "to inspect context."
111
112
  ),
112
113
  params_json_schema=MODIFY_SCHEMA,
113
114
  on_invoke_tool=invoke_modify,
@@ -1302,7 +1302,14 @@ class ToolRuntime:
1302
1302
  "modify",
1303
1303
  "Provide content for a new file, or both old_string and new_string for an existing file.",
1304
1304
  ).to_json()
1305
- return self.edit(path, old, new, replace_all=replace_all, snippet_id=snippet_id)
1305
+ return self.edit(
1306
+ path,
1307
+ old,
1308
+ new,
1309
+ replace_all=replace_all,
1310
+ snippet_id=snippet_id,
1311
+ auto_read_if_missing_snapshot=True,
1312
+ )
1306
1313
 
1307
1314
  def write(self, path: str, content: object) -> str:
1308
1315
  name = "write"
@@ -1351,6 +1358,7 @@ class ToolRuntime:
1351
1358
  new: str,
1352
1359
  replace_all: bool = False,
1353
1360
  snippet_id: str | None = None,
1361
+ auto_read_if_missing_snapshot: bool = False,
1354
1362
  ) -> str:
1355
1363
  name = "edit"
1356
1364
  if not old:
@@ -1377,6 +1385,14 @@ class ToolRuntime:
1377
1385
  target = _resolve_in_cwd(self.cwd, path)
1378
1386
  if not target.exists():
1379
1387
  return ToolResult.error_result(name, f"File does not exist: {target}").to_json()
1388
+ auto_read_before_modify = False
1389
+ if (
1390
+ auto_read_if_missing_snapshot
1391
+ and snippet is None
1392
+ and self.file_state.snapshot_status(target) == "missing"
1393
+ ):
1394
+ self.file_state.mark_read(target)
1395
+ auto_read_before_modify = True
1380
1396
  ok, error = self.file_state.check_writable(
1381
1397
  target,
1382
1398
  require_read=True,
@@ -1465,6 +1481,8 @@ class ToolRuntime:
1465
1481
  "diff": diff,
1466
1482
  "diff_preview": diff,
1467
1483
  }
1484
+ if auto_read_before_modify:
1485
+ metadata["autoReadBeforeModify"] = True
1468
1486
  if snippet is not None:
1469
1487
  metadata["scope"] = _format_scope_metadata(target, snippet, scope, text)
1470
1488
  return ToolResult.ok_result(name, f"Edited {target}", metadata=metadata).to_json()
@@ -2,6 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass, field
4
4
  from pathlib import Path
5
+ from typing import Literal
6
+
7
+
8
+ SnapshotStatus = Literal["missing", "full", "partial", "deleted", "stale"]
5
9
 
6
10
 
7
11
  @dataclass
@@ -58,6 +62,18 @@ class FileState:
58
62
  return False, "File changed since it was read; read it again before editing."
59
63
  return True, None
60
64
 
65
+ def snapshot_status(self, path: Path) -> SnapshotStatus:
66
+ resolved = path.resolve()
67
+ snapshot = self._snapshots.get(resolved)
68
+ if snapshot is None:
69
+ return "missing"
70
+ if not resolved.exists():
71
+ return "deleted"
72
+ stat = resolved.stat()
73
+ if stat.st_mtime_ns != snapshot.mtime_ns or stat.st_size != snapshot.size:
74
+ return "stale"
75
+ return "full" if snapshot.full_read else "partial"
76
+
61
77
  def mark_written(self, path: Path) -> None:
62
78
  if path.exists():
63
79
  self.mark_read(path)
@@ -1,22 +0,0 @@
1
- ## modify
2
-
3
- Create new files or edit existing files.
4
-
5
- Use `content` only when the target file does not exist. For existing files, read the
6
- file first, then use `old_string` and `new_string` for the smallest reliable
7
- replacement. Do not rewrite an existing scaffolded file with full content; replace the
8
- specific generated block instead.
9
-
10
- Args for new files: `file_path`, `content`.
11
-
12
- Args for existing files: `file_path`, `old_string`, `new_string`, optional
13
- `replace_all`, optional `snippet_id`.
14
-
15
- Existing files must be read before editing. Stale edits are rejected. Repeated matches
16
- are rejected unless `replace_all` is true; candidate snippets can be reused with
17
- `snippet_id`. Success includes diff metadata.
18
-
19
- If several `old_string` attempts fail and you know the complete desired file content,
20
- re-read the file and use the managed whole-file replacement path. Do not delete the file
21
- and recreate it with shell commands or here-strings; that bypasses Deepy's encoding,
22
- newline, and stale-write protections, especially on Windows.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes