wcgw 2.7.2__tar.gz → 2.8.1__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 (159) hide show
  1. {wcgw-2.7.2 → wcgw-2.8.1}/PKG-INFO +19 -2
  2. {wcgw-2.7.2 → wcgw-2.8.1}/README.md +18 -1
  3. {wcgw-2.7.2 → wcgw-2.8.1}/gpt_action_json_schema.json +61 -0
  4. {wcgw-2.7.2 → wcgw-2.8.1}/gpt_instructions.txt +4 -0
  5. {wcgw-2.7.2 → wcgw-2.8.1}/pyproject.toml +1 -1
  6. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/anthropic_client.py +8 -16
  7. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/mcp_server/server.py +29 -51
  8. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/memory.py +23 -4
  9. wcgw-2.8.1/src/wcgw/client/modes.py +242 -0
  10. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/openai_client.py +8 -17
  11. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/tools.py +228 -50
  12. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/types_.py +51 -7
  13. wcgw-2.8.1/tests/client/test_memory.py +162 -0
  14. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/test_tools_extended.py +50 -2
  15. wcgw-2.8.1/tests/client/test_tools_file_ops.py +132 -0
  16. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/test_tools_shell.py +8 -3
  17. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/test_tools_validation.py +22 -1
  18. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_command_validation.py +1 -1
  19. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_user_interaction.py +26 -16
  20. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_write_file.py +6 -0
  21. {wcgw-2.7.2 → wcgw-2.8.1}/uv.lock +1 -1
  22. wcgw-2.7.2/tests/client/test_memory.py +0 -78
  23. wcgw-2.7.2/tests/client/test_tools_file_ops.py +0 -155
  24. {wcgw-2.7.2 → wcgw-2.8.1}/.github/workflows/python-publish.yml +0 -0
  25. {wcgw-2.7.2 → wcgw-2.8.1}/.github/workflows/python-tests.yml +0 -0
  26. {wcgw-2.7.2 → wcgw-2.8.1}/.github/workflows/python-types.yml +0 -0
  27. {wcgw-2.7.2 → wcgw-2.8.1}/.gitignore +0 -0
  28. {wcgw-2.7.2 → wcgw-2.8.1}/.gitmodules +0 -0
  29. {wcgw-2.7.2 → wcgw-2.8.1}/.python-version +0 -0
  30. {wcgw-2.7.2 → wcgw-2.8.1}/.vscode/settings.json +0 -0
  31. {wcgw-2.7.2 → wcgw-2.8.1}/LICENSE +0 -0
  32. {wcgw-2.7.2 → wcgw-2.8.1}/openai.md +0 -0
  33. {wcgw-2.7.2 → wcgw-2.8.1}/src/__init__.py +0 -0
  34. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/.git +0 -0
  35. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  36. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  37. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/.github/workflows/main-checks.yml +0 -0
  38. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/.github/workflows/publish-pypi.yml +0 -0
  39. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/.github/workflows/pull-request-checks.yml +0 -0
  40. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/.github/workflows/shared.yml +0 -0
  41. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/.gitignore +0 -0
  42. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/.python-version +0 -0
  43. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/CODE_OF_CONDUCT.md +0 -0
  44. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/CONTRIBUTING.md +0 -0
  45. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/LICENSE +0 -0
  46. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/README.md +0 -0
  47. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/RELEASE.md +0 -0
  48. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/SECURITY.md +0 -0
  49. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/README.md +0 -0
  50. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-prompt/.python-version +0 -0
  51. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-prompt/README.md +0 -0
  52. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-prompt/mcp_simple_prompt/__init__.py +0 -0
  53. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-prompt/mcp_simple_prompt/__main__.py +0 -0
  54. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-prompt/mcp_simple_prompt/server.py +0 -0
  55. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-prompt/pyproject.toml +0 -0
  56. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-resource/.python-version +0 -0
  57. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-resource/README.md +0 -0
  58. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-resource/mcp_simple_resource/__init__.py +0 -0
  59. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-resource/mcp_simple_resource/__main__.py +0 -0
  60. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-resource/mcp_simple_resource/server.py +0 -0
  61. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-resource/pyproject.toml +0 -0
  62. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-tool/.python-version +0 -0
  63. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-tool/README.md +0 -0
  64. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-tool/mcp_simple_tool/__init__.py +0 -0
  65. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-tool/mcp_simple_tool/__main__.py +0 -0
  66. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-tool/mcp_simple_tool/server.py +0 -0
  67. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/examples/servers/simple-tool/pyproject.toml +0 -0
  68. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/pyproject.toml +0 -0
  69. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/__init__.py +0 -0
  70. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/client/__init__.py +0 -0
  71. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/client/__main__.py +0 -0
  72. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/client/session.py +0 -0
  73. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/client/sse.py +0 -0
  74. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/client/stdio.py +0 -0
  75. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/py.typed +0 -0
  76. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/server/__init__.py +0 -0
  77. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/server/__main__.py +0 -0
  78. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/server/models.py +0 -0
  79. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/server/session.py +0 -0
  80. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/server/sse.py +0 -0
  81. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/server/stdio.py +0 -0
  82. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/server/websocket.py +0 -0
  83. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/shared/__init__.py +0 -0
  84. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/shared/context.py +0 -0
  85. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/shared/exceptions.py +0 -0
  86. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/shared/memory.py +0 -0
  87. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/shared/progress.py +0 -0
  88. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/shared/session.py +0 -0
  89. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/shared/version.py +0 -0
  90. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/src/mcp_wcgw/types.py +0 -0
  91. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/tests/__init__.py +0 -0
  92. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/tests/client/__init__.py +0 -0
  93. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/tests/client/test_session.py +0 -0
  94. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/tests/client/test_stdio.py +0 -0
  95. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/tests/conftest.py +0 -0
  96. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/tests/server/__init__.py +0 -0
  97. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/tests/server/test_session.py +0 -0
  98. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/tests/server/test_stdio.py +0 -0
  99. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/tests/shared/test_memory.py +0 -0
  100. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/tests/test_types.py +0 -0
  101. {wcgw-2.7.2 → wcgw-2.8.1}/src/mcp_wcgw/uv.lock +0 -0
  102. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/__init__.py +0 -0
  103. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/__init__.py +0 -0
  104. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/__main__.py +0 -0
  105. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/cli.py +0 -0
  106. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/common.py +0 -0
  107. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/computer_use.py +0 -0
  108. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/diff-instructions.txt +0 -0
  109. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/file_ops/diff_edit.py +0 -0
  110. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/file_ops/search_replace.py +0 -0
  111. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/mcp_server/Readme.md +0 -0
  112. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/mcp_server/__init__.py +0 -0
  113. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/openai_utils.py +0 -0
  114. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/repo_ops/display_tree.py +0 -0
  115. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/repo_ops/path_prob.py +0 -0
  116. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/repo_ops/paths_model.vocab +0 -0
  117. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/repo_ops/paths_tokens.model +0 -0
  118. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/repo_ops/repo_context.py +0 -0
  119. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/client/sys_utils.py +0 -0
  120. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/relay/serve.py +0 -0
  121. {wcgw-2.7.2 → wcgw-2.8.1}/src/wcgw/relay/static/privacy.txt +0 -0
  122. {wcgw-2.7.2 → wcgw-2.8.1}/static/claude-ss.jpg +0 -0
  123. {wcgw-2.7.2 → wcgw-2.8.1}/static/computer-use.jpg +0 -0
  124. {wcgw-2.7.2 → wcgw-2.8.1}/static/example.jpg +0 -0
  125. {wcgw-2.7.2 → wcgw-2.8.1}/static/rocket-icon.png +0 -0
  126. {wcgw-2.7.2 → wcgw-2.8.1}/static/ss1.png +0 -0
  127. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/file_ops/test_diff_edit.py +0 -0
  128. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/file_ops/test_search_replace.py +0 -0
  129. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/repo_ops/__init__.py +0 -0
  130. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/repo_ops/test_display_tree.py +0 -0
  131. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/repo_ops/test_display_tree_simple.py +0 -0
  132. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/repo_ops/test_path_prob.py +0 -0
  133. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/repo_ops/test_repo_context.py +0 -0
  134. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/test_anthropic_client_utils.py +0 -0
  135. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/test_openai_utils.py +0 -0
  136. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/test_tools_basic.py +0 -0
  137. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/test_tools_files.py +0 -0
  138. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/__init__.py +0 -0
  139. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_docker_operations.py +0 -0
  140. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_error_handling.py +0 -0
  141. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_execute_bash.py +0 -0
  142. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_file_operations.py +0 -0
  143. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_files/test1.py +0 -0
  144. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_files/test2.py +0 -0
  145. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_files/test_file.py +0 -0
  146. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_is_int.py +0 -0
  147. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_knowledge_transfer.py +0 -0
  148. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_large_blocks.py +0 -0
  149. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_render_terminal.py +0 -0
  150. {wcgw-2.7.2 → wcgw-2.8.1}/tests/client/tools/test_terminal_output.py +0 -0
  151. {wcgw-2.7.2 → wcgw-2.8.1}/tests/conftest.py +0 -0
  152. {wcgw-2.7.2 → wcgw-2.8.1}/tests/test_anthropic_client.py +0 -0
  153. {wcgw-2.7.2 → wcgw-2.8.1}/tests/test_basic.py +0 -0
  154. {wcgw-2.7.2 → wcgw-2.8.1}/tests/test_common.py +0 -0
  155. {wcgw-2.7.2 → wcgw-2.8.1}/tests/test_computer_use.py +0 -0
  156. {wcgw-2.7.2 → wcgw-2.8.1}/tests/test_computer_use_base.py +0 -0
  157. {wcgw-2.7.2 → wcgw-2.8.1}/tests/test_computer_use_shell.py +0 -0
  158. {wcgw-2.7.2 → wcgw-2.8.1}/tests/test_sys_utils.py +0 -0
  159. {wcgw-2.7.2 → wcgw-2.8.1}/tests/test_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wcgw
3
- Version: 2.7.2
3
+ Version: 2.8.1
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>
@@ -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
+ - [15 Jan 2025] Modes introduced: architect, code-writer, and all powerful wcgw mode.
45
+
44
46
  - [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
47
 
46
48
  - [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.
@@ -64,11 +66,16 @@ Description-Content-Type: text/markdown
64
66
  - 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
67
  - 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
68
  - Using Aider-like search and replace, which has better performance than tool call based search and replace.
67
- - ⚡ **Shell optimisations**:
69
+ - ⚡ **Shell optimizations**:
68
70
  - 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
71
  - Current working directory is always returned after any shell command to prevent AI from getting lost.
70
72
  - 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
73
  - ⚡ **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.
74
+ - ⚡ **Easily switch between various modes**:
75
+ - Ask it to run in 'architect' mode for planning. Inspired by adier's architect mode, work with Claude to come up with a plan first. Leads to better accuracy and prevents premature file editing.
76
+ - Ask it to run in 'code-writer' mode for code editing and project building. You can provide specific paths with wild card support to prevent other files getting edited.
77
+ - By default it runs in 'wcgw' mode that has no restrictions and full authorisation.
78
+ - More details in [Modes section](#modes)
72
79
 
73
80
  ## Top use cases examples
74
81
 
@@ -148,6 +155,16 @@ Then ask claude to execute shell commands, read files, edit files, run your code
148
155
  - 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
156
  - Or you can directly open the file generated and share it with another AI for help.
150
157
 
158
+ #### Modes
159
+ There are three built-in modes. You may ask Claude to run in one of the modes, like "Use 'architect' mode"
160
+ | **Mode** | **Description** | **Allows** | **Denies** | **Invoke prompt** |
161
+ |-----------------|-----------------------------------------------------------------------------|---------------------------------------------------------|----------------------------------------------|----------------------------------------------------------------------------------------------------|
162
+ | **Architect** | Designed for you to work with Claude to investigate and understand your repo. | Read-only commands | FileEdit and Write tool | Run in mode='architect' |
163
+ | **Code-writer** | For code writing and development | Specified path globs for editing or writing, specified commands | FileEdit for paths not matching specified glob, Write for paths not matching specified glob | Run in code writer mode, only 'tests/**' allowed, only uv command allowed |
164
+ | **wcgw** | Default mode with everything allowed | Everything | Nothing | No prompt, or "Run in wcgw mode" |
165
+
166
+ Note: in code-writer mode either all commands are allowed or none are allowed for now. If you give a list of allowed commands, Claude is instructed to run only those commands, but no actual check happens. (WIP)
167
+
151
168
  ### [Optional] Vs code extension
152
169
  https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw
153
170
 
@@ -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
+ - [15 Jan 2025] Modes introduced: architect, code-writer, and all powerful wcgw mode.
16
+
15
17
  - [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
18
 
17
19
  - [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.
@@ -35,11 +37,16 @@
35
37
  - 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
38
  - 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
39
  - Using Aider-like search and replace, which has better performance than tool call based search and replace.
38
- - ⚡ **Shell optimisations**:
40
+ - ⚡ **Shell optimizations**:
39
41
  - 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
42
  - Current working directory is always returned after any shell command to prevent AI from getting lost.
41
43
  - 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
44
  - ⚡ **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.
45
+ - ⚡ **Easily switch between various modes**:
46
+ - Ask it to run in 'architect' mode for planning. Inspired by adier's architect mode, work with Claude to come up with a plan first. Leads to better accuracy and prevents premature file editing.
47
+ - Ask it to run in 'code-writer' mode for code editing and project building. You can provide specific paths with wild card support to prevent other files getting edited.
48
+ - By default it runs in 'wcgw' mode that has no restrictions and full authorisation.
49
+ - More details in [Modes section](#modes)
43
50
 
44
51
  ## Top use cases examples
45
52
 
@@ -119,6 +126,16 @@ Then ask claude to execute shell commands, read files, edit files, run your code
119
126
  - 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
127
  - Or you can directly open the file generated and share it with another AI for help.
121
128
 
129
+ #### Modes
130
+ There are three built-in modes. You may ask Claude to run in one of the modes, like "Use 'architect' mode"
131
+ | **Mode** | **Description** | **Allows** | **Denies** | **Invoke prompt** |
132
+ |-----------------|-----------------------------------------------------------------------------|---------------------------------------------------------|----------------------------------------------|----------------------------------------------------------------------------------------------------|
133
+ | **Architect** | Designed for you to work with Claude to investigate and understand your repo. | Read-only commands | FileEdit and Write tool | Run in mode='architect' |
134
+ | **Code-writer** | For code writing and development | Specified path globs for editing or writing, specified commands | FileEdit for paths not matching specified glob, Write for paths not matching specified glob | Run in code writer mode, only 'tests/**' allowed, only uv command allowed |
135
+ | **wcgw** | Default mode with everything allowed | Everything | Nothing | No prompt, or "Run in wcgw mode" |
136
+
137
+ Note: in code-writer mode either all commands are allowed or none are allowed for now. If you give a list of allowed commands, Claude is instructed to run only those commands, but no actual check happens. (WIP)
138
+
122
139
  ### [Optional] Vs code extension
123
140
  https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw
124
141
 
@@ -408,6 +408,47 @@
408
408
  ],
409
409
  "title": "BashInteractionWithUUID"
410
410
  },
411
+ "CodeWriterMode": {
412
+ "properties": {
413
+ "allowed_globs": {
414
+ "anyOf": [
415
+ {
416
+ "type": "string",
417
+ "const": "all"
418
+ },
419
+ {
420
+ "items": {
421
+ "type": "string"
422
+ },
423
+ "type": "array"
424
+ }
425
+ ],
426
+ "title": "Allowed Globs"
427
+ },
428
+ "allowed_commands": {
429
+ "anyOf": [
430
+ {
431
+ "type": "string",
432
+ "const": "all"
433
+ },
434
+ {
435
+ "items": {
436
+ "type": "string"
437
+ },
438
+ "type": "array"
439
+ }
440
+ ],
441
+ "title": "Allowed Commands"
442
+ }
443
+ },
444
+ "additionalProperties": false,
445
+ "type": "object",
446
+ "required": [
447
+ "allowed_globs",
448
+ "allowed_commands"
449
+ ],
450
+ "title": "CodeWriterMode"
451
+ },
411
452
  "CommandWithUUID": {
412
453
  "properties": {
413
454
  "command": {
@@ -520,6 +561,25 @@
520
561
  "type": "string",
521
562
  "title": "Task Id To Resume"
522
563
  },
564
+ "mode_name": {
565
+ "type": "string",
566
+ "enum": [
567
+ "wcgw",
568
+ "architect",
569
+ "code_writer"
570
+ ],
571
+ "title": "Mode Name"
572
+ },
573
+ "code_writer_config": {
574
+ "anyOf": [
575
+ {
576
+ "$ref": "#/components/schemas/CodeWriterMode"
577
+ },
578
+ {
579
+ "type": "null"
580
+ }
581
+ ]
582
+ },
523
583
  "user_id": {
524
584
  "type": "string",
525
585
  "format": "uuid",
@@ -532,6 +592,7 @@
532
592
  "any_workspace_path",
533
593
  "initial_files_to_read",
534
594
  "task_id_to_resume",
595
+ "mode_name",
535
596
  "user_id"
536
597
  ],
537
598
  "title": "InitializeWithUUID"
@@ -15,6 +15,10 @@ Instructions for `Initialize`:
15
15
  - If the user has mentioned a folder or file with unclear project root, use the file or folder as `any_workspace_path`.
16
16
  - If user has mentioned any files use `initial_files_to_read` to read, use absolute paths only.
17
17
  - If `any_workspace_path` is provided, a tree structure of the workspace will be shown.
18
+ - Leave `any_workspace_path` as empty if no file or folder is mentioned.
19
+ - By default use mode `wcgw`
20
+ - In code-writer mode, set the commands and globs which user asked to set, otherwise use 'all'.
21
+ - In order to change the mode later, call this tool again but be sure to not provide any other argument like task_id_to_resume unnecessarily.
18
22
 
19
23
  Instructions for `BashCommand`:
20
24
  - Execute a bash command. This is stateful (beware with subsequent calls).
@@ -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.2"
4
+ version = "2.8.1"
5
5
  description = "Shell and coding agent on claude and chatgpt"
6
6
  readme = "README.md"
7
7
  requires-python = ">=3.11, <3.13"
@@ -130,7 +130,7 @@ def loop(
130
130
  memory = None
131
131
  if resume:
132
132
  try:
133
- _, memory = load_memory(
133
+ _, memory, _ = load_memory(
134
134
  resume,
135
135
  8000,
136
136
  lambda x: default_enc.encode(x).ids,
@@ -166,6 +166,7 @@ def loop(
166
166
  - The control will return to you in 5 seconds regardless of the status. For heavy commands, keep checking status using BashInteraction till they are finished.
167
167
  - Run long running commands in background using screen instead of "&".
168
168
  - Use longer wait_for_seconds if the command is expected to run for a long time.
169
+ - Do not use 'cat' to read files, use ReadFiles tool instead.
169
170
  """,
170
171
  ),
171
172
  ToolParam(
@@ -281,22 +282,13 @@ Saves provided description and file contents of all the relevant file paths or g
281
282
  ),
282
283
  ]
283
284
 
284
- initial_info = initialize(
285
- os.getcwd(), [], resume if (memory and resume) else "", 8000
285
+ system = initialize(
286
+ os.getcwd(),
287
+ [],
288
+ resume if (memory and resume) else "",
289
+ max_tokens=8000,
290
+ mode="wcgw",
286
291
  )
287
- system = f"""
288
- You're an expert software engineer with shell and code knowledge.
289
-
290
- Instructions:
291
-
292
- - You should use the provided bash execution, reading and writing file tools to complete objective.
293
- - First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
294
- - Always read relevant files before editing.
295
- - Do not provide code snippets unless asked by the user, instead directly add/edit the code.
296
- - Do not install new tools/packages before ensuring no such tools/package or an alternative already exists.
297
-
298
- {initial_info}
299
- """
300
292
 
301
293
  with open(os.path.join(os.path.dirname(__file__), "diff-instructions.txt")) as f:
302
294
  system += f.read()
@@ -28,6 +28,7 @@ from ...types_ import (
28
28
  )
29
29
  from .. import tools
30
30
  from ..computer_use import SLEEP_TIME_MAX_S
31
+ from ..modes import get_kt_prompt
31
32
  from ..tools import DoneFlag, default_enc, get_tool_output, which_tool_name
32
33
 
33
34
  COMPUTER_USE_ON_DOCKER_ENABLED = False
@@ -45,48 +46,35 @@ async def handle_read_resource(uri: AnyUrl) -> str:
45
46
  raise ValueError("No resources available")
46
47
 
47
48
 
48
- @server.list_prompts() # type: ignore
49
- async def handle_list_prompts() -> list[types.Prompt]:
50
- return [
49
+ PROMPTS = {
50
+ "KnowledgeTransfer": (
51
51
  types.Prompt(
52
52
  name="KnowledgeTransfer",
53
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
- ]
54
+ ),
55
+ get_kt_prompt,
56
+ )
57
+ }
58
+
59
+
60
+ @server.list_prompts() # type: ignore
61
+ async def handle_list_prompts() -> list[types.Prompt]:
62
+ return [x[0] for x in PROMPTS.values()]
56
63
 
57
64
 
58
65
  @server.get_prompt() # type: ignore
59
66
  async def handle_get_prompt(
60
67
  name: str, arguments: dict[str, str] | None
61
68
  ) -> types.GetPromptResult:
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
- ]
69
+ messages = [
70
+ types.PromptMessage(
71
+ role="user",
72
+ content=types.TextContent(
73
+ type="text",
74
+ text=PROMPTS[name][1](),
75
+ ),
76
+ )
77
+ ]
90
78
  return types.GetPromptResult(messages=messages)
91
79
 
92
80
 
@@ -117,6 +105,9 @@ async def handle_list_tools() -> list[types.Tool]:
117
105
  - If user has mentioned any files use `initial_files_to_read` to read, use absolute paths only.
118
106
  - If `any_workspace_path` is provided, a tree structure of the workspace will be shown.
119
107
  - Leave `any_workspace_path` as empty if no file or folder is mentioned.
108
+ - By default use mode "wcgw"
109
+ - In "code-writer" mode, set the commands and globs which user asked to set, otherwise use 'all'.
110
+ - In order to change the mode later, call this tool again but be sure to not provide any other argument like task_id_to_resume unnecessarily.
120
111
  """,
121
112
  ),
122
113
  ToolParam(
@@ -263,6 +254,8 @@ async def handle_call_tool(
263
254
  except ValidationError:
264
255
 
265
256
  def try_json(x: str) -> Any:
257
+ if not isinstance(x, str):
258
+ return x
266
259
  try:
267
260
  return json.loads(x)
268
261
  except json.JSONDecodeError:
@@ -284,24 +277,9 @@ async def handle_call_tool(
284
277
  if isinstance(output_or_done, str):
285
278
  if issubclass(tool_type, Initialize):
286
279
  output_or_done += """
287
- ---
288
- You're an expert software engineer with shell and code knowledge.
289
-
290
- Instructions:
291
-
292
- - You should use the provided bash execution, reading and writing file tools to complete objective.
293
- - First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
294
- - Always read relevant files before editing.
295
- - Do not provide code snippets unless asked by the user, instead directly add/edit the code.
296
- - Do not install new tools/packages before ensuring no such tools/package or an alternative already exists.
297
- - Do not use artifacts if you have access to the repository and not asked by the user to provide artifacts/snippets. Directly create/update using shell tools.
298
- - Do not use Ctrl-c or Ctrl-z or interrupt commands without asking the user, because often the program don't show any update but they still are running.
299
- - Do not use echo to write multi-line files, always use FileEdit tool to update a code.
300
-
301
- Additional instructions:
302
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost, or to get absolute cwd.
303
-
304
- Always write production ready, syntactically correct code.
280
+ - Additional important note: as soon as you encounter "The user has chosen to disallow the tool call.", immediately stop doing everything and ask user for the reason.
281
+
282
+ Initialize call done.
305
283
  """
306
284
 
307
285
  content.append(types.TextContent(type="text", text=output_or_done))
@@ -1,7 +1,8 @@
1
+ import json
1
2
  import os
2
3
  import re
3
4
  import shlex
4
- from typing import Callable, Optional
5
+ from typing import Any, Callable, Optional
5
6
 
6
7
  from ..types_ import ContextSave
7
8
 
@@ -30,7 +31,11 @@ def format_memory(task_memory: ContextSave, relevant_files: str) -> str:
30
31
  return memory_data
31
32
 
32
33
 
33
- def save_memory(task_memory: ContextSave, relevant_files: str) -> str:
34
+ def save_memory(
35
+ task_memory: ContextSave,
36
+ relevant_files: str,
37
+ bash_state_dict: Optional[dict[str, Any]] = None,
38
+ ) -> str:
34
39
  app_dir = get_app_dir_xdg()
35
40
  memory_dir = os.path.join(app_dir, "memory")
36
41
  os.makedirs(memory_dir, exist_ok=True)
@@ -45,6 +50,12 @@ def save_memory(task_memory: ContextSave, relevant_files: str) -> str:
45
50
  with open(memory_file_full, "w") as f:
46
51
  f.write(memory_data)
47
52
 
53
+ # Save bash state if provided
54
+ if bash_state_dict is not None:
55
+ state_file = os.path.join(memory_dir, f"{task_id}_bash_state.json")
56
+ with open(state_file, "w") as f:
57
+ json.dump(bash_state_dict, f, indent=2)
58
+
48
59
  return memory_file_full
49
60
 
50
61
 
@@ -53,7 +64,7 @@ def load_memory[T](
53
64
  max_tokens: Optional[int],
54
65
  encoder: Callable[[str], list[T]],
55
66
  decoder: Callable[[list[T]], str],
56
- ) -> tuple[str, str]:
67
+ ) -> tuple[str, str, Optional[dict[str, Any]]]:
57
68
  app_dir = get_app_dir_xdg()
58
69
  memory_dir = os.path.join(app_dir, "memory")
59
70
  memory_file = os.path.join(memory_dir, f"{task_id}.txt")
@@ -75,4 +86,12 @@ def load_memory[T](
75
86
  parsed_ = shlex.split(matched_path)
76
87
  if parsed_ and len(parsed_) == 1:
77
88
  project_root_path = parsed_[0]
78
- return project_root_path, data
89
+
90
+ # Try to load bash state if exists
91
+ state_file = os.path.join(memory_dir, f"{task_id}_bash_state.json")
92
+ bash_state: Optional[dict[str, Any]] = None
93
+ if os.path.exists(state_file):
94
+ with open(state_file) as f:
95
+ bash_state = json.load(f)
96
+
97
+ return project_root_path, data, bash_state