wcgw 2.7.0__tar.gz → 2.7.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.

Potentially problematic release.


This version of wcgw might be problematic. Click here for more details.

Files changed (158) hide show
  1. {wcgw-2.7.0 → wcgw-2.7.2}/PKG-INFO +21 -3
  2. {wcgw-2.7.0 → wcgw-2.7.2}/README.md +20 -2
  3. {wcgw-2.7.0 → wcgw-2.7.2}/gpt_action_json_schema.json +43 -63
  4. {wcgw-2.7.0 → wcgw-2.7.2}/gpt_instructions.txt +5 -0
  5. {wcgw-2.7.0 → wcgw-2.7.2}/pyproject.toml +1 -1
  6. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/anthropic_client.py +12 -17
  7. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/mcp_server/server.py +44 -20
  8. wcgw-2.7.2/src/wcgw/client/memory.py +78 -0
  9. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/openai_client.py +13 -17
  10. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/tools.py +34 -26
  11. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/relay/serve.py +7 -7
  12. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/types_.py +3 -7
  13. wcgw-2.7.2/tests/client/test_memory.py +78 -0
  14. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/test_tools_basic.py +7 -14
  15. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/test_tools_extended.py +19 -9
  16. wcgw-2.7.2/tests/client/tools/test_docker_operations.py +22 -0
  17. wcgw-2.7.2/tests/client/tools/test_error_handling.py +20 -0
  18. wcgw-2.7.2/tests/client/tools/test_execute_bash.py +71 -0
  19. wcgw-2.7.2/tests/client/tools/test_is_int.py +25 -0
  20. wcgw-2.7.2/tests/client/tools/test_knowledge_transfer.py +155 -0
  21. wcgw-2.7.2/tests/client/tools/test_large_blocks.py +21 -0
  22. wcgw-2.7.2/tests/client/tools/test_render_terminal.py +25 -0
  23. wcgw-2.7.2/tests/client/tools/test_write_file.py +112 -0
  24. wcgw-2.7.2/tests/conftest.py +12 -0
  25. {wcgw-2.7.0 → wcgw-2.7.2}/uv.lock +1 -1
  26. wcgw-2.7.0/src/wcgw/client/memory.py +0 -52
  27. wcgw-2.7.0/tests/client/tools/test_knowledge_transfer.py +0 -322
  28. {wcgw-2.7.0 → wcgw-2.7.2}/.github/workflows/python-publish.yml +0 -0
  29. {wcgw-2.7.0 → wcgw-2.7.2}/.github/workflows/python-tests.yml +0 -0
  30. {wcgw-2.7.0 → wcgw-2.7.2}/.github/workflows/python-types.yml +0 -0
  31. {wcgw-2.7.0 → wcgw-2.7.2}/.gitignore +0 -0
  32. {wcgw-2.7.0 → wcgw-2.7.2}/.gitmodules +0 -0
  33. {wcgw-2.7.0 → wcgw-2.7.2}/.python-version +0 -0
  34. {wcgw-2.7.0 → wcgw-2.7.2}/.vscode/settings.json +0 -0
  35. {wcgw-2.7.0 → wcgw-2.7.2}/LICENSE +0 -0
  36. {wcgw-2.7.0 → wcgw-2.7.2}/openai.md +0 -0
  37. {wcgw-2.7.0 → wcgw-2.7.2}/src/__init__.py +0 -0
  38. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/.git +0 -0
  39. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  40. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  41. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/.github/workflows/main-checks.yml +0 -0
  42. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/.github/workflows/publish-pypi.yml +0 -0
  43. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/.github/workflows/pull-request-checks.yml +0 -0
  44. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/.github/workflows/shared.yml +0 -0
  45. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/.gitignore +0 -0
  46. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/.python-version +0 -0
  47. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/CODE_OF_CONDUCT.md +0 -0
  48. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/CONTRIBUTING.md +0 -0
  49. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/LICENSE +0 -0
  50. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/README.md +0 -0
  51. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/RELEASE.md +0 -0
  52. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/SECURITY.md +0 -0
  53. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/README.md +0 -0
  54. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-prompt/.python-version +0 -0
  55. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-prompt/README.md +0 -0
  56. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-prompt/mcp_simple_prompt/__init__.py +0 -0
  57. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-prompt/mcp_simple_prompt/__main__.py +0 -0
  58. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-prompt/mcp_simple_prompt/server.py +0 -0
  59. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-prompt/pyproject.toml +0 -0
  60. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-resource/.python-version +0 -0
  61. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-resource/README.md +0 -0
  62. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-resource/mcp_simple_resource/__init__.py +0 -0
  63. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-resource/mcp_simple_resource/__main__.py +0 -0
  64. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-resource/mcp_simple_resource/server.py +0 -0
  65. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-resource/pyproject.toml +0 -0
  66. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-tool/.python-version +0 -0
  67. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-tool/README.md +0 -0
  68. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-tool/mcp_simple_tool/__init__.py +0 -0
  69. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-tool/mcp_simple_tool/__main__.py +0 -0
  70. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-tool/mcp_simple_tool/server.py +0 -0
  71. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/examples/servers/simple-tool/pyproject.toml +0 -0
  72. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/pyproject.toml +0 -0
  73. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/__init__.py +0 -0
  74. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/client/__init__.py +0 -0
  75. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/client/__main__.py +0 -0
  76. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/client/session.py +0 -0
  77. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/client/sse.py +0 -0
  78. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/client/stdio.py +0 -0
  79. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/py.typed +0 -0
  80. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/server/__init__.py +0 -0
  81. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/server/__main__.py +0 -0
  82. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/server/models.py +0 -0
  83. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/server/session.py +0 -0
  84. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/server/sse.py +0 -0
  85. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/server/stdio.py +0 -0
  86. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/server/websocket.py +0 -0
  87. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/shared/__init__.py +0 -0
  88. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/shared/context.py +0 -0
  89. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/shared/exceptions.py +0 -0
  90. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/shared/memory.py +0 -0
  91. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/shared/progress.py +0 -0
  92. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/shared/session.py +0 -0
  93. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/shared/version.py +0 -0
  94. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/src/mcp_wcgw/types.py +0 -0
  95. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/tests/__init__.py +0 -0
  96. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/tests/client/__init__.py +0 -0
  97. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/tests/client/test_session.py +0 -0
  98. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/tests/client/test_stdio.py +0 -0
  99. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/tests/conftest.py +0 -0
  100. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/tests/server/__init__.py +0 -0
  101. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/tests/server/test_session.py +0 -0
  102. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/tests/server/test_stdio.py +0 -0
  103. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/tests/shared/test_memory.py +0 -0
  104. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/tests/test_types.py +0 -0
  105. {wcgw-2.7.0 → wcgw-2.7.2}/src/mcp_wcgw/uv.lock +0 -0
  106. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/__init__.py +0 -0
  107. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/__init__.py +0 -0
  108. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/__main__.py +0 -0
  109. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/cli.py +0 -0
  110. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/common.py +0 -0
  111. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/computer_use.py +0 -0
  112. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/diff-instructions.txt +0 -0
  113. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/file_ops/diff_edit.py +0 -0
  114. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/file_ops/search_replace.py +0 -0
  115. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/mcp_server/Readme.md +0 -0
  116. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/mcp_server/__init__.py +0 -0
  117. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/openai_utils.py +0 -0
  118. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/repo_ops/display_tree.py +0 -0
  119. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/repo_ops/path_prob.py +0 -0
  120. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/repo_ops/paths_model.vocab +0 -0
  121. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/repo_ops/paths_tokens.model +0 -0
  122. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/repo_ops/repo_context.py +0 -0
  123. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/client/sys_utils.py +0 -0
  124. {wcgw-2.7.0 → wcgw-2.7.2}/src/wcgw/relay/static/privacy.txt +0 -0
  125. {wcgw-2.7.0 → wcgw-2.7.2}/static/claude-ss.jpg +0 -0
  126. {wcgw-2.7.0 → wcgw-2.7.2}/static/computer-use.jpg +0 -0
  127. {wcgw-2.7.0 → wcgw-2.7.2}/static/example.jpg +0 -0
  128. {wcgw-2.7.0 → wcgw-2.7.2}/static/rocket-icon.png +0 -0
  129. {wcgw-2.7.0 → wcgw-2.7.2}/static/ss1.png +0 -0
  130. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/file_ops/test_diff_edit.py +0 -0
  131. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/file_ops/test_search_replace.py +0 -0
  132. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/repo_ops/__init__.py +0 -0
  133. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/repo_ops/test_display_tree.py +0 -0
  134. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/repo_ops/test_display_tree_simple.py +0 -0
  135. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/repo_ops/test_path_prob.py +0 -0
  136. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/repo_ops/test_repo_context.py +0 -0
  137. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/test_anthropic_client_utils.py +0 -0
  138. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/test_openai_utils.py +0 -0
  139. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/test_tools_file_ops.py +0 -0
  140. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/test_tools_files.py +0 -0
  141. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/test_tools_shell.py +0 -0
  142. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/test_tools_validation.py +0 -0
  143. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/tools/__init__.py +0 -0
  144. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/tools/test_command_validation.py +0 -0
  145. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/tools/test_file_operations.py +0 -0
  146. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/tools/test_files/test1.py +0 -0
  147. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/tools/test_files/test2.py +0 -0
  148. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/tools/test_files/test_file.py +0 -0
  149. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/tools/test_terminal_output.py +0 -0
  150. {wcgw-2.7.0 → wcgw-2.7.2}/tests/client/tools/test_user_interaction.py +0 -0
  151. {wcgw-2.7.0 → wcgw-2.7.2}/tests/test_anthropic_client.py +0 -0
  152. {wcgw-2.7.0 → wcgw-2.7.2}/tests/test_basic.py +0 -0
  153. {wcgw-2.7.0 → wcgw-2.7.2}/tests/test_common.py +0 -0
  154. {wcgw-2.7.0 → wcgw-2.7.2}/tests/test_computer_use.py +0 -0
  155. {wcgw-2.7.0 → wcgw-2.7.2}/tests/test_computer_use_base.py +0 -0
  156. {wcgw-2.7.0 → wcgw-2.7.2}/tests/test_computer_use_shell.py +0 -0
  157. {wcgw-2.7.0 → wcgw-2.7.2}/tests/test_sys_utils.py +0 -0
  158. {wcgw-2.7.0 → wcgw-2.7.2}/tests/test_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wcgw
3
- Version: 2.7.0
3
+ Version: 2.7.2
4
4
  Summary: Shell and coding agent on claude and chatgpt
5
5
  Project-URL: Homepage, https://github.com/rusiaaman/wcgw
6
6
  Author-email: Aman Rusia <gapypi@arcfu.com>
@@ -33,7 +33,7 @@ Description-Content-Type: text/markdown
33
33
  - Chatgpt - Allows custom gpt to talk to your shell via a relay server. (linux or mac)
34
34
 
35
35
 
36
- ⚠️ Warning: do not use this repo if you aren't scared of "Autonomous shell command execution"
36
+ ⚠️ Warning: do not allow BashCommand tool without reviewing the command, it may result in data loss.
37
37
 
38
38
  [![Tests](https://github.com/rusiaaman/wcgw/actions/workflows/python-tests.yml/badge.svg?branch=main)](https://github.com/rusiaaman/wcgw/actions/workflows/python-tests.yml)
39
39
  [![Mypy strict](https://github.com/rusiaaman/wcgw/actions/workflows/python-types.yml/badge.svg?branch=main)](https://github.com/rusiaaman/wcgw/actions/workflows/python-types.yml)
@@ -41,6 +41,8 @@ Description-Content-Type: text/markdown
41
41
  [![codecov](https://codecov.io/gh/rusiaaman/wcgw/graph/badge.svg)](https://codecov.io/gh/rusiaaman/wcgw)
42
42
 
43
43
  ## Updates
44
+ - [8 Jan 2025] Context saving tool for saving relevant file paths along with a description in a single file. Can be used as a task checkpoint or for knowledge transfer.
45
+
44
46
  - [29 Dec 2024] Syntax checking on file writing and edits is now stable. Made `initialize` tool call useful; sending smart repo structure to claude if any repo is referenced. Large file handling is also now improved.
45
47
 
46
48
  - [9 Dec 2024] [Vscode extension to paste context on Claude app](https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw)
@@ -55,7 +57,18 @@ Description-Content-Type: text/markdown
55
57
  - ⚡ **Large file edit**: Supports large file incremental edits to avoid token limit issues. Faster than full file write.
56
58
  - ⚡ **Syntax checking on edits**: Reports feedback to the LLM if its edits have any syntax errors, so that it can redo it.
57
59
  - ⚡ **Interactive Command Handling**: Supports interactive commands using arrow keys, interrupt, and ansi escape sequences.
58
- - ⚡ **Full Shell Access**: No restrictions, complete control.
60
+ - ⚡ **File protections**:
61
+ - The AI needs to read a file at least once before it's allowed to edit or rewrite it. This avoids accidental overwrites.
62
+ - Avoids context filling up while reading very large files. Files get chunked based on token length.
63
+ - On initialisation the provided workspace's directory structure is returned after selecting important files (based on .gitignore as well as a statistical approach)
64
+ - File edit based on search-replace tries to find correct search block if it has multiple matches based on previous search blocks. Fails otherwise (for correctness).
65
+ - File edit has spacing tolerant matching, with warning on issues like indentation mismatch. If there's no match, the closest match is returned to the AI to fix its mistakes.
66
+ - Using Aider-like search and replace, which has better performance than tool call based search and replace.
67
+ - ⚡ **Shell optimisations**:
68
+ - Only one command is allowed to be run at a time, simplifying management and avoiding rogue processes. There's only single shell instance at any point of time.
69
+ - Current working directory is always returned after any shell command to prevent AI from getting lost.
70
+ - Command polling exits after a quick timeout to avoid slow feedback. However, status checking has wait tolerance based on fresh output streaming from a command. Both of these approach combined provides a good shell interaction experience.
71
+ - ⚡ **Saving repo context in a single file**: Task checkpointing using "ContextSave" tool saves detailed context in a single file. Tasks can later be resumed in a new chat asking "Resume `task id`". The saved file can be used to do other kinds of knowledge transfer, such as taking help from another AI.
59
72
 
60
73
  ## Top use cases examples
61
74
 
@@ -129,6 +142,11 @@ over here
129
142
 
130
143
  Then ask claude to execute shell commands, read files, edit files, run your code, etc.
131
144
 
145
+ #### Task checkpoint or knowledge transfer
146
+ - You can do a task checkpoint or a knowledge transfer by attaching "KnowledgeTransfer" prompt using "Attach from MCP" button.
147
+ - On running "KnowledgeTransfer" prompt, the "ContextSave" tool will be called saving the task description and all file content together in a single file. An id for the task will be generated.
148
+ - You can in a new chat say "Resume '<task id>'", the AI should then call "Initialize" with the task id and load the context from there.
149
+ - Or you can directly open the file generated and share it with another AI for help.
132
150
 
133
151
  ### [Optional] Vs code extension
134
152
  https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw
@@ -4,7 +4,7 @@
4
4
  - Chatgpt - Allows custom gpt to talk to your shell via a relay server. (linux or mac)
5
5
 
6
6
 
7
- ⚠️ Warning: do not use this repo if you aren't scared of "Autonomous shell command execution"
7
+ ⚠️ Warning: do not allow BashCommand tool without reviewing the command, it may result in data loss.
8
8
 
9
9
  [![Tests](https://github.com/rusiaaman/wcgw/actions/workflows/python-tests.yml/badge.svg?branch=main)](https://github.com/rusiaaman/wcgw/actions/workflows/python-tests.yml)
10
10
  [![Mypy strict](https://github.com/rusiaaman/wcgw/actions/workflows/python-types.yml/badge.svg?branch=main)](https://github.com/rusiaaman/wcgw/actions/workflows/python-types.yml)
@@ -12,6 +12,8 @@
12
12
  [![codecov](https://codecov.io/gh/rusiaaman/wcgw/graph/badge.svg)](https://codecov.io/gh/rusiaaman/wcgw)
13
13
 
14
14
  ## Updates
15
+ - [8 Jan 2025] Context saving tool for saving relevant file paths along with a description in a single file. Can be used as a task checkpoint or for knowledge transfer.
16
+
15
17
  - [29 Dec 2024] Syntax checking on file writing and edits is now stable. Made `initialize` tool call useful; sending smart repo structure to claude if any repo is referenced. Large file handling is also now improved.
16
18
 
17
19
  - [9 Dec 2024] [Vscode extension to paste context on Claude app](https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw)
@@ -26,7 +28,18 @@
26
28
  - ⚡ **Large file edit**: Supports large file incremental edits to avoid token limit issues. Faster than full file write.
27
29
  - ⚡ **Syntax checking on edits**: Reports feedback to the LLM if its edits have any syntax errors, so that it can redo it.
28
30
  - ⚡ **Interactive Command Handling**: Supports interactive commands using arrow keys, interrupt, and ansi escape sequences.
29
- - ⚡ **Full Shell Access**: No restrictions, complete control.
31
+ - ⚡ **File protections**:
32
+ - The AI needs to read a file at least once before it's allowed to edit or rewrite it. This avoids accidental overwrites.
33
+ - Avoids context filling up while reading very large files. Files get chunked based on token length.
34
+ - On initialisation the provided workspace's directory structure is returned after selecting important files (based on .gitignore as well as a statistical approach)
35
+ - File edit based on search-replace tries to find correct search block if it has multiple matches based on previous search blocks. Fails otherwise (for correctness).
36
+ - File edit has spacing tolerant matching, with warning on issues like indentation mismatch. If there's no match, the closest match is returned to the AI to fix its mistakes.
37
+ - Using Aider-like search and replace, which has better performance than tool call based search and replace.
38
+ - ⚡ **Shell optimisations**:
39
+ - Only one command is allowed to be run at a time, simplifying management and avoiding rogue processes. There's only single shell instance at any point of time.
40
+ - Current working directory is always returned after any shell command to prevent AI from getting lost.
41
+ - Command polling exits after a quick timeout to avoid slow feedback. However, status checking has wait tolerance based on fresh output streaming from a command. Both of these approach combined provides a good shell interaction experience.
42
+ - ⚡ **Saving repo context in a single file**: Task checkpointing using "ContextSave" tool saves detailed context in a single file. Tasks can later be resumed in a new chat asking "Resume `task id`". The saved file can be used to do other kinds of knowledge transfer, such as taking help from another AI.
30
43
 
31
44
  ## Top use cases examples
32
45
 
@@ -100,6 +113,11 @@ over here
100
113
 
101
114
  Then ask claude to execute shell commands, read files, edit files, run your code, etc.
102
115
 
116
+ #### Task checkpoint or knowledge transfer
117
+ - You can do a task checkpoint or a knowledge transfer by attaching "KnowledgeTransfer" prompt using "Attach from MCP" button.
118
+ - On running "KnowledgeTransfer" prompt, the "ContextSave" tool will be called saving the task description and all file content together in a single file. An id for the task will be generated.
119
+ - You can in a new chat say "Resume '<task id>'", the AI should then call "Initialize" with the task id and load the context from there.
120
+ - Or you can directly open the file generated and share it with another AI for help.
103
121
 
104
122
  ### [Optional] Vs code extension
105
123
  https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw
@@ -290,16 +290,16 @@
290
290
  }
291
291
  }
292
292
  },
293
- "/v1/knowledge_transfer": {
293
+ "/v1/context_save": {
294
294
  "post": {
295
295
  "x-openai-isConsequential": false,
296
- "summary": "Knowledge Transfer",
297
- "operationId": "knowledge_transfer_v1_knowledge_transfer_post",
296
+ "summary": "Context Save",
297
+ "operationId": "context_save_v1_context_save_post",
298
298
  "requestBody": {
299
299
  "content": {
300
300
  "application/json": {
301
301
  "schema": {
302
- "$ref": "#/components/schemas/KTWithUUID"
302
+ "$ref": "#/components/schemas/ContextSaveWithUUID"
303
303
  }
304
304
  }
305
305
  },
@@ -312,7 +312,7 @@
312
312
  "application/json": {
313
313
  "schema": {
314
314
  "type": "string",
315
- "title": "Response Knowledge Transfer V1 Knowledge Transfer Post"
315
+ "title": "Response Context Save V1 Context Save Post"
316
316
  }
317
317
  }
318
318
  }
@@ -427,6 +427,44 @@
427
427
  ],
428
428
  "title": "CommandWithUUID"
429
429
  },
430
+ "ContextSaveWithUUID": {
431
+ "properties": {
432
+ "id": {
433
+ "type": "string",
434
+ "title": "Id"
435
+ },
436
+ "project_root_path": {
437
+ "type": "string",
438
+ "title": "Project Root Path"
439
+ },
440
+ "description": {
441
+ "type": "string",
442
+ "title": "Description"
443
+ },
444
+ "relevant_file_globs": {
445
+ "items": {
446
+ "type": "string"
447
+ },
448
+ "type": "array",
449
+ "title": "Relevant File Globs"
450
+ },
451
+ "user_id": {
452
+ "type": "string",
453
+ "format": "uuid",
454
+ "title": "User Id"
455
+ }
456
+ },
457
+ "additionalProperties": false,
458
+ "type": "object",
459
+ "required": [
460
+ "id",
461
+ "project_root_path",
462
+ "description",
463
+ "relevant_file_globs",
464
+ "user_id"
465
+ ],
466
+ "title": "ContextSaveWithUUID"
467
+ },
430
468
  "FileEditWithUUID": {
431
469
  "properties": {
432
470
  "file_path": {
@@ -498,64 +536,6 @@
498
536
  ],
499
537
  "title": "InitializeWithUUID"
500
538
  },
501
- "KTWithUUID": {
502
- "properties": {
503
- "id": {
504
- "type": "string",
505
- "title": "Id"
506
- },
507
- "project_root_path": {
508
- "type": "string",
509
- "title": "Project Root Path"
510
- },
511
- "objective": {
512
- "type": "string",
513
- "title": "Objective"
514
- },
515
- "all_user_instructions": {
516
- "type": "string",
517
- "title": "All User Instructions"
518
- },
519
- "current_status_of_the_task": {
520
- "type": "string",
521
- "title": "Current Status Of The Task"
522
- },
523
- "all_issues_snippets": {
524
- "type": "string",
525
- "title": "All Issues Snippets"
526
- },
527
- "relevant_file_paths": {
528
- "items": {
529
- "type": "string"
530
- },
531
- "type": "array",
532
- "title": "Relevant File Paths"
533
- },
534
- "build_and_development_instructions": {
535
- "type": "string",
536
- "title": "Build And Development Instructions"
537
- },
538
- "user_id": {
539
- "type": "string",
540
- "format": "uuid",
541
- "title": "User Id"
542
- }
543
- },
544
- "additionalProperties": false,
545
- "type": "object",
546
- "required": [
547
- "id",
548
- "project_root_path",
549
- "objective",
550
- "all_user_instructions",
551
- "current_status_of_the_task",
552
- "all_issues_snippets",
553
- "relevant_file_paths",
554
- "build_and_development_instructions",
555
- "user_id"
556
- ],
557
- "title": "KTWithUUID"
558
- },
559
539
  "ReadFileWithUUID": {
560
540
  "properties": {
561
541
  "file_paths": {
@@ -44,6 +44,11 @@ Instructions for `BashInteraction`
44
44
  Instructions for `ResetShell`
45
45
  - Resets the shell. Use only if all interrupts and prompt reset attempts have failed repeatedly.
46
46
 
47
+ Instructions for `ContextSave`
48
+ - Saves provided description and file contents of all the relevant file paths or globs in a single text file.
49
+ - Provide random unqiue id or whatever user provided.
50
+ - Leave project path as empty string if no project path
51
+
47
52
  Instructions for `FileEdit`:
48
53
  - Use absolute file path only.
49
54
  - Use SEARCH/REPLACE blocks to edit the file.
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  authors = [{ name = "Aman Rusia", email = "gapypi@arcfu.com" }]
3
3
  name = "wcgw"
4
- version = "2.7.0"
4
+ version = "2.7.2"
5
5
  description = "Shell and coding agent on claude and chatgpt"
6
6
  readme = "README.md"
7
7
  requires-python = ">=3.11, <3.13"
@@ -25,10 +25,10 @@ from typer import Typer
25
25
  from ..types_ import (
26
26
  BashCommand,
27
27
  BashInteraction,
28
+ ContextSave,
28
29
  FileEdit,
29
30
  GetScreenInfo,
30
31
  Keyboard,
31
- KnowledgeTransfer,
32
32
  Mouse,
33
33
  ReadFiles,
34
34
  ReadImage,
@@ -130,7 +130,12 @@ def loop(
130
130
  memory = None
131
131
  if resume:
132
132
  try:
133
- memory = load_memory(resume)
133
+ _, memory = load_memory(
134
+ resume,
135
+ 8000,
136
+ lambda x: default_enc.encode(x).ids,
137
+ lambda x: default_enc.decode(x),
138
+ )
134
139
  except OSError:
135
140
  if resume == "latest":
136
141
  resume_path = sorted(Path(".wcgw").iterdir(), key=os.path.getmtime)[-1]
@@ -215,22 +220,12 @@ def loop(
215
220
  """,
216
221
  ),
217
222
  ToolParam(
218
- input_schema=KnowledgeTransfer.model_json_schema(),
219
- name="KnowledgeTransfer",
223
+ input_schema=ContextSave.model_json_schema(),
224
+ name="ContextSave",
220
225
  description="""
221
- Write detailed description in order to do a KT, if the user asks for it.
222
- Save all information necessary for a person to understand the task and the problems.
223
-
224
- - `all_user_instructions` should contain all instructions user shared in the conversation.
225
- - `current_status_of_the_task` should contain only what is already achieved, not what's remaining.
226
- - `all_issues_snippets` should only contain snippets of error, traceback, file snippets, commands, etc., no comments or solutions (important!).
227
- - Be very verbose in `all_issues_snippets` providing as much error context as possible.
228
- - Provide an id if the user hasn't provided one.
229
- - This tool will return a text file path where the information is saved.
230
- - After the tool completes succesfully, tell the user the task id and the generate file path. (important!)
231
- - Leave arguments as empty string if they aren't relevant.
232
- - This tool marks end of your conversation, do not run any further tools after calling this.
233
- - Provide absolute file paths only in `relevant_file_paths` containing all relevant files.
226
+ Saves provided description and file contents of all the relevant file paths or globs in a single text file.
227
+ - Provide random unqiue id or whatever user provided.
228
+ - Leave project path as empty string if no project path
234
229
  """,
235
230
  ),
236
231
  ]
@@ -14,6 +14,7 @@ from mcp_wcgw.types import Tool as ToolParam
14
14
  from ...types_ import (
15
15
  BashCommand,
16
16
  BashInteraction,
17
+ ContextSave,
17
18
  FileEdit,
18
19
  GetScreenInfo,
19
20
  Initialize,
@@ -46,14 +47,47 @@ async def handle_read_resource(uri: AnyUrl) -> str:
46
47
 
47
48
  @server.list_prompts() # type: ignore
48
49
  async def handle_list_prompts() -> list[types.Prompt]:
49
- return []
50
+ return [
51
+ types.Prompt(
52
+ name="KnowledgeTransfer",
53
+ description="Prompt for invoking ContextSave tool in order to do a comprehensive knowledge transfer of a coding task. Prompts to save detailed error log and instructions.",
54
+ )
55
+ ]
50
56
 
51
57
 
52
58
  @server.get_prompt() # type: ignore
53
59
  async def handle_get_prompt(
54
60
  name: str, arguments: dict[str, str] | None
55
61
  ) -> types.GetPromptResult:
56
- return types.GetPromptResult(messages=[])
62
+ messages = []
63
+ if name == "KnowledgeTransfer":
64
+ messages = [
65
+ types.PromptMessage(
66
+ role="user",
67
+ content=types.TextContent(
68
+ type="text",
69
+ text="""Use `ContextSave` tool to do a knowledge transfer of the task in hand.
70
+ Write detailed description in order to do a KT.
71
+ Save all information necessary for a person to understand the task and the problems.
72
+
73
+ Format the `description` field using Markdown with the following sections.
74
+ - "# Objective" section containing project and task objective.
75
+ - "# All user instructions" section should be provided containing all instructions user shared in the conversation.
76
+ - "# Current status of the task" should be provided containing only what is already achieved, not what's remaining.
77
+ - "# All issues with snippets" section containing snippets of error, traceback, file snippets, commands, etc. But no comments or solutions.
78
+ - Be very verbose in the all issues with snippets section providing as much error context as possible.
79
+ - "# Build and development instructions" section containing instructions to build or run project or run tests, or envrionment related information. Only include what's known. Leave empty if unknown.
80
+ - After the tool completes succesfully, tell me the task id and the file path the tool generated (important!)
81
+ - This tool marks end of your conversation, do not run any further tools after calling this.
82
+
83
+ Provide all relevant file paths in order to understand and solve the the task. Err towards providing more file paths than fewer.
84
+
85
+ (Note to self: this conversation can then be resumed later asking "Resume `<generated id>`" which should call Initialize tool)
86
+ """,
87
+ ),
88
+ )
89
+ ]
90
+ return types.GetPromptResult(messages=messages)
57
91
 
58
92
 
59
93
  @server.list_tools() # type: ignore
@@ -153,24 +187,14 @@ async def handle_list_tools() -> list[types.Tool]:
153
187
  """
154
188
  + diffinstructions,
155
189
  ),
156
- # ToolParam(
157
- # inputSchema=KnowledgeTransfer.model_json_schema(),
158
- # name="KnowledgeTransfer",
159
- # description="""
160
- # Write detailed description in order to do a KT, if the user asks for it.
161
- # Save all information necessary for a person to understand the task and the problems.
162
- # - `all_user_instructions` should contain all instructions user shared in the conversation.
163
- # - `current_status_of_the_task` should contain only what is already achieved, not what's remaining.
164
- # - `all_issues_snippets` should only contain snippets of error, traceback, file snippets, commands, etc., no comments or solutions (important!).
165
- # - Be very verbose in `all_issues_snippets` providing as much error context as possible.
166
- # - Provide an id if the user hasn't provided one.
167
- # - This tool will return a text file path where the information is saved.
168
- # - After the tool completes succesfully, tell the user the task id and the generate file path. (important!)
169
- # - Leave arguments as empty string if they aren't relevant.
170
- # - This tool marks end of your conversation, do not run any further tools after calling this.
171
- # - Provide absolute file paths only in `relevant_file_paths` containing all relevant files.
172
- # """,
173
- # ),
190
+ ToolParam(
191
+ inputSchema=ContextSave.model_json_schema(),
192
+ name="ContextSave",
193
+ description="""
194
+ Saves provided description and file contents of all the relevant file paths or globs in a single text file.
195
+ - Provide random unqiue id or whatever user provided.
196
+ - Leave project path as empty string if no project path""",
197
+ ),
174
198
  ]
175
199
  if COMPUTER_USE_ON_DOCKER_ENABLED:
176
200
  tools += [
@@ -0,0 +1,78 @@
1
+ import os
2
+ import re
3
+ import shlex
4
+ from typing import Callable, Optional
5
+
6
+ from ..types_ import ContextSave
7
+
8
+
9
+ def get_app_dir_xdg() -> str:
10
+ xdg_data_dir = os.environ.get("XDG_DATA_HOME", os.path.expanduser("~/.local/share"))
11
+ return os.path.join(xdg_data_dir, "wcgw")
12
+
13
+
14
+ def format_memory(task_memory: ContextSave, relevant_files: str) -> str:
15
+ memory_data = ""
16
+ if task_memory.project_root_path:
17
+ memory_data += (
18
+ f"# PROJECT ROOT = {shlex.quote(task_memory.project_root_path)}\n"
19
+ )
20
+ memory_data += task_memory.description
21
+
22
+ memory_data += (
23
+ "\n\n"
24
+ + "# Relevant file paths\n"
25
+ + ", ".join(map(shlex.quote, task_memory.relevant_file_globs))
26
+ )
27
+
28
+ memory_data += "\n\n# Relevant Files:\n" + relevant_files
29
+
30
+ return memory_data
31
+
32
+
33
+ def save_memory(task_memory: ContextSave, relevant_files: str) -> str:
34
+ app_dir = get_app_dir_xdg()
35
+ memory_dir = os.path.join(app_dir, "memory")
36
+ os.makedirs(memory_dir, exist_ok=True)
37
+
38
+ task_id = task_memory.id
39
+ if not task_id:
40
+ raise Exception("Task id can not be empty")
41
+ memory_data = format_memory(task_memory, relevant_files)
42
+
43
+ memory_file_full = os.path.join(memory_dir, f"{task_id}.txt")
44
+
45
+ with open(memory_file_full, "w") as f:
46
+ f.write(memory_data)
47
+
48
+ return memory_file_full
49
+
50
+
51
+ def load_memory[T](
52
+ task_id: str,
53
+ max_tokens: Optional[int],
54
+ encoder: Callable[[str], list[T]],
55
+ decoder: Callable[[list[T]], str],
56
+ ) -> tuple[str, str]:
57
+ app_dir = get_app_dir_xdg()
58
+ memory_dir = os.path.join(app_dir, "memory")
59
+ memory_file = os.path.join(memory_dir, f"{task_id}.txt")
60
+
61
+ with open(memory_file, "r") as f:
62
+ data = f.read()
63
+
64
+ if max_tokens:
65
+ toks = encoder(data)
66
+ if len(toks) > max_tokens:
67
+ toks = toks[: max(0, max_tokens - 10)]
68
+ data = decoder(toks)
69
+ data += "\n(... truncated)"
70
+
71
+ project_root_match = re.search(r"# PROJECT ROOT = \s*(.*?)\s*$", data, re.MULTILINE)
72
+ project_root_path = ""
73
+ if project_root_match:
74
+ matched_path = project_root_match.group(1)
75
+ parsed_ = shlex.split(matched_path)
76
+ if parsed_ and len(parsed_) == 1:
77
+ project_root_path = parsed_[0]
78
+ return project_root_path, data
@@ -26,8 +26,8 @@ from typer import Typer
26
26
  from ..types_ import (
27
27
  BashCommand,
28
28
  BashInteraction,
29
+ ContextSave,
29
30
  FileEdit,
30
- KnowledgeTransfer,
31
31
  ReadFiles,
32
32
  ReadImage,
33
33
  ResetShell,
@@ -39,6 +39,7 @@ from .openai_utils import get_input_cost, get_output_cost
39
39
  from .tools import (
40
40
  DoneFlag,
41
41
  ImageData,
42
+ default_enc,
42
43
  get_tool_output,
43
44
  initialize,
44
45
  which_tool,
@@ -124,7 +125,12 @@ def loop(
124
125
  memory = None
125
126
  if resume:
126
127
  try:
127
- memory = load_memory(resume)
128
+ _, memory = load_memory(
129
+ resume,
130
+ 8000,
131
+ lambda x: default_enc.encode(x).ids,
132
+ lambda x: default_enc.decode(x),
133
+ )
128
134
  except OSError:
129
135
  if resume == "latest":
130
136
  resume_path = sorted(Path(".wcgw").iterdir(), key=os.path.getmtime)[-1]
@@ -211,22 +217,12 @@ def loop(
211
217
  description="Resets the shell. Use only if all interrupts and prompt reset attempts have failed repeatedly.",
212
218
  ),
213
219
  openai.pydantic_function_tool(
214
- KnowledgeTransfer,
220
+ ContextSave,
215
221
  description="""
216
- Write detailed description in order to do a KT, if the user asks for it.
217
- Save all information necessary for a person to understand the task and the problems.
218
-
219
- - `all_user_instructions` should contain all instructions user shared in the conversation.
220
- - `current_status_of_the_task` should contain only what is already achieved, not what's remaining.
221
- - `all_issues_snippets` should only contain snippets of error, traceback, file snippets, commands, etc., no comments or solutions (important!).
222
- - Be very verbose in `all_issues_snippets` providing as much error context as possible.
223
- - Provide an id if the user hasn't provided one.
224
- - This tool will return a text file path where the information is saved.
225
- - After the tool completes succesfully, tell the user the task id and the generate file path. (important!)
226
- - Leave arguments as empty string if they aren't relevant.
227
- - This tool marks end of your conversation, do not run any further tools after calling this.
228
- - Provide absolute file paths only in `relevant_file_paths` containing all relevant files.
229
- """,
222
+
223
+ Saves provided description and file contents of all the relevant file paths or globs in a single text file.
224
+ - Provide random unqiue id or whatever user provided.
225
+ - Leave project path as empty string if no project path""",
230
226
  ),
231
227
  ]
232
228