Compare commits

..

439 Commits

Author SHA1 Message Date
boob.yang
c3de57a2b3
Merge pull request #145 from devchat-ai/update_test_api3
refactor: Remove redundant task query in test API upload command
2025-03-21 13:29:19 +00:00
bobo.yang
f2f0a10a9e refactor: Remove redundant task query in test API upload command
- Remove unnecessary API call to fetch tasks
- Simplify test execution flow by eliminating wait_for_task_done call
- Improve code efficiency in the test API upload command
2025-03-21 21:24:46 +08:00
long2ice
607ce67792
Merge pull request #144 from devchat-ai/update_test_api2
fix: Add flush=True to print statements and improve task status check
2025-03-21 11:35:34 +00:00
bobo.yang
42c4386562 fix: Add flush=True to print statements and improve task status check
- Added flush=True to print statements for better real-time logging
- Replaced single status check with a list of statuses to continue waiting
- Defined constants for task status values for better code readability
2025-03-21 19:28:49 +08:00
boob.yang
0be6ca7e33
Merge pull request #143 from devchat-ai/api-auth
refactor: get api auth id from docs
2025-03-21 10:11:57 +00:00
long2ice
21fe8dd34f refactor: Update delete_old_apidocs function to accept apidocs as a parameter
This commit modifies the delete_old_apidocs function to take a list of apidocs as an argument, ensuring it operates on the current set of API documentation. Additionally, it updates the main function to pass the retrieved apidocs when calling delete_old_apidocs.
2025-03-21 18:10:21 +08:00
boob.yang
7262e03ccf
Merge pull request #141 from devchat-ai/refactor-workflows-desc
refactor: Update command descriptions and remove unused workflow files
2025-03-12 08:49:23 +00:00
long2ice
07d916c831 refactor: Update command descriptions and remove unused workflow files
This commit includes:
- Clarified and standardized descriptions for various command.yml files
- Removed obsolete workflow files (aider/command.yml, pr/command.yml, merico/ask-code/command.yml)
- Updated README for pr.custom_suggestions
- Translated some descriptions from Chinese to English
2025-03-12 16:36:15 +08:00
kagami
5ebcb808a3
Merge pull request #140 from devchat-ai/update_workflows
feat: Add workflow module and API endpoints for various functionalities
2025-03-11 06:53:42 +00:00
bobo.yang
ceff998daf fix lint error 2025-03-11 14:39:27 +08:00
bobo.yang
05683a04b4 fix lint error 2025-03-11 14:37:26 +08:00
bobo.yang
2dc0f049d8 fix lint errors 2025-03-11 14:35:52 +08:00
bobo.yang
d40cc0f34b fix lint errors 2025-03-11 14:32:33 +08:00
bobo.yang
46f80573ad fix lint errors 2025-03-11 14:29:37 +08:00
bobo.yang
1de60c73c9 fix lint errors 2025-03-11 14:27:07 +08:00
bobo.yang
433daf1603 fix lint errors 2025-03-11 14:26:11 +08:00
bobo.yang
946d9dcf25 fix lint errors 2025-03-11 14:24:28 +08:00
bobo.yang
cceb4c1dfb fix lint errors 2025-03-11 14:19:20 +08:00
bobo.yang
7353fe1df4 fix lint errors 2025-03-11 14:05:35 +08:00
bobo.yang
4dcdcc65e6 disable stream output when refactor code 2025-03-11 13:43:17 +08:00
bobo.yang
1538d658d8 move /github /gitlab /aider /pr from merico to community 2025-03-11 13:34:01 +08:00
bobo.yang
7e15ab24cd add /refactor.api 2025-03-11 13:32:05 +08:00
bobo.yang
99b7aca0fc add /test.api.upload 2025-03-11 13:31:50 +08:00
bobo.yang
344fbff719 add /chatflow.ask and /chatflow.gen 2025-03-11 13:29:58 +08:00
bobo yang
1c0e5e045f feat: Add workflow module with command execution support
- Create workflow package with call module for script execution
- Implement workflow_call function to execute commands with arguments
- Add helper functions to locate and run workflow scripts in various paths
2025-03-11 13:26:53 +08:00
boob.yang
2a8accc06a
Merge pull request #137 from devchat-ai/update_commit_prompt
docs: Update commit message prompt format
2025-03-10 12:33:14 +00:00
bobo.yang
8d0b75a86d docs: Update commit message prompt format
- Remove closing reference section from example output
- Remove instruction about issue closing reference
- Simplify prompt by removing redundant constraints
2025-03-10 16:57:48 +08:00
boob.yang
4fdd536226
Merge pull request #139 from devchat-ai/github-username
feat: Add GitHub username retrieval function
2025-03-10 08:52:46 +00:00
long2ice
9490359c37 feat: Add GitHub username retrieval function
- Implement `get_github_username()` to fetch GitHub username via API
- Update `get_selected_issue_ids()` to use GitHub username instead of git username
- Enhance GitHub issue selection workflow with authenticated username retrieval
2025-03-10 16:38:08 +08:00
boob.yang
e8d960794c
Merge pull request #138 from devchat-ai/issue-repo
feat: Enhance GitHub issue handling in commit workflow
2025-03-10 08:19:56 +00:00
long2ice
1cd1ac0c88 feat: Enhance GitHub issue handling in commit workflow
- Update `get_selected_issue_ids()` to return repository context for cross-repository issue closing
- Modify commit message generation to support cross-repository issue references
- Improve issue selection logic to handle different repository scenarios
- Add support for appending full repository issue references when issues are from different repositories
2025-03-10 16:17:59 +08:00
boob.yang
06d707575e
Merge pull request #136 from devchat-ai/github-commit
feat: Add GitHub issue selection and auto-close functionality
2025-03-10 07:44:57 +00:00
long2ice
e786d16bbb feat: Add GitHub issue selection and auto-close functionality
- Implement `get_selected_issue_ids()` to allow users to select and close GitHub issues during commit
- Add support for automatically appending "Closes #IssueNumber" to commit messages
- Enhance commit workflow with dynamic issue tracking and resolution
- Integrate new GitHub API functions to retrieve user's assigned open issues
2025-03-10 14:00:27 +08:00
kagami
99b55db6ff
Merge pull request #135 from devchat-ai/update_refactor
refactor: Update rewrite.py with Chinese prompts and improve code structure
2025-03-07 07:37:22 +00:00
kagami
44e9b7bd26
Merge pull request #134 from devchat-ai/update_commit
feat: Enhance git workflow with push functionality and improve error handling
2025-03-07 07:36:42 +00:00
bobo.yang
083c714ac0 style: improve code formatting and whitespace
- Remove trailing whitespaces in Step class
- Improve formatting in GitHub and GitLab commit modules
- Fix indentation in error message output
- Add proper line spacing between functions
2025-03-07 13:02:06 +08:00
bobo.yang
5a0340e8e9 refactor: Clean up code structure and improve formatting
- Organize imports and remove unused imports
- Format code with consistent indentation and line breaks
- Remove empty lines and redundant whitespace
- Improve function parameter formatting for better readability
2025-03-07 13:00:43 +08:00
bobo.yang
021efac1d9 refactor: Update rewrite.py with Chinese prompts and symbol analysis
- Translate prompts to Chinese for better localization
- Add symbol analysis functionality to detect missing definitions
- Implement context code gathering for better refactoring results
- Add helper functions for project root detection and symbol definition lookup
2025-03-07 12:00:49 +08:00
bobo.yang
bb0ed153c7 remove /commit, use github|gitlab.commit replace it 2025-03-07 11:41:09 +08:00
bobo.yang
389ad70c2e docs: Add example output to commit message prompts
- Added example commit message format to GitHub prompt file
- Added example commit message format to GitLab prompt file
- Demonstrates proper structure with feature type and API details
2025-03-07 11:39:33 +08:00
bobo.yang
6b04c3de11 fix: Improve git push error handling and feedback
- Replace subprocess_check_output with subprocess_run for better error handling
- Add specific error messages and formatting for push failures
- Implement exit code when push fails to properly indicate failure
2025-03-07 11:38:29 +08:00
bobo.yang
e591361e69 style: Improve error message formatting for failed push
- Enhanced error output for branch determination failure by adding
double newline for better readability in terminal output
2025-03-07 11:10:38 +08:00
bobo.yang
bb1afee665 fix: Remove extra newlines in error message output
- Removed extra newlines from error message in push_changes function
- Simplified error output formatting for better readability
- Maintained consistent error handling pattern
2025-03-07 11:07:34 +08:00
bobo.yang
f6c4d52b90 fix: Improve error message formatting for branch detection failure
- Enhance readability of error message when current branch cannot be determined
- Add double newline after error message for better visual separation
- Maintain consistent output formatting with other status messages
2025-03-07 11:05:20 +08:00
bobo.yang
e36da6da6c fix: Remove extra newlines in error message output
- Modified error message in push_changes() to remove extra newlines
- Improved consistency in error message formatting
- Simplified stderr output for failed branch determination
2025-03-07 11:03:58 +08:00
bobo.yang
c307e1ae43 fix: Add newline after push failure message
- Updated error output in push_changes() to include newlines after failure
- Improves readability of error messages in the terminal output
- Maintains consistency with successful push message formatting
2025-03-07 11:02:59 +08:00
bobo.yang
1f158fb047 fix: Remove newline after push failure message
- Modified error output in push_changes() function to remove trailing newlines
- Keeps error messages more consistent with standard error formatting
- Improves log readability when capturing stderr output
2025-03-07 11:02:20 +08:00
bobo.yang
c59cd3fcb8 fix: Improve error message formatting for failed branch detection
- Enhanced error message display when current branch cannot be determined
- Added newline characters for better readability in console output
- Maintains consistent formatting with other status messages
2025-03-07 11:01:19 +08:00
bobo.yang
b5aa4b22ac style: Improve console output formatting in push_changes
- Add newlines after push status messages for better readability
- Ensure consistent formatting for success and error messages
- Update output formatting in git push operations
2025-03-07 11:00:41 +08:00
bobo.yang
316567c83e docs: Update commit message prompt format
- Added markdown codeblock format specification for responses
- Changed format of issue reference to use angle brackets
- Added instruction to only output the commit message codeblock
2025-03-07 10:51:16 +08:00
bobo.yang
2f24253997 feat: Add push functionality to commit workflow
- Added ask_for_push() function to prompt user for pushing changes
- Implemented push_changes() function to push commits to remote
- Updated workflow steps from 2 to 3 and improved command line args handling
2025-03-07 10:41:38 +08:00
bobo.yang
90d7e0b7b9 feat: Add push functionality to commit workflow
- Fixed Step markdown formatting in chatmark/step.py
- Added push capability with user confirmation after commit
- Improved command line argument handling with better defaults
2025-03-07 08:58:37 +08:00
kagami
f4a4dbc529
Merge pull request #133 from devchat-ai/feat/update-vscode-text-selection
feat: Enhance VSCode text selection handling
2024-11-28 05:58:51 +00:00
bobo.yang
656c2287e4 fix lint error 2024-11-28 13:15:44 +08:00
bobo yang
d1321f4863 feat: Enhance VSCode text selection handling
- Add functions to get selected and visible text
- Update visible_lines() to use new get_visible_text()
- Refactor selected_lines() to use get_selected_text()
2024-11-28 12:48:01 +08:00
kagami
ed9898d038
Merge pull request #132 from devchat-ai/feat/add-multi-select-dropdown
feat: Add MultiSelect widget to chatmark library
2024-11-14 11:04:31 +00:00
bobo.yang
5da21b00d5 feat: Add MultiSelect widget and update imports
- Implement MultiSelect widget inheriting from Checkbox
- Update import order in __init__.py for consistency
- Prepare groundwork for multi-select dropdown functionality
2024-11-14 19:03:47 +08:00
bobo.yang
b8e2a0bef8 feat: Refactor MultiSelect to inherit from Checkbox
- Rename multiSelect class to MultiSelect for consistency
- Inherit MultiSelect from Checkbox to reduce code duplication
- Remove redundant properties and methods in MultiSelect class
2024-11-14 18:58:35 +08:00
bobo.yang
014579d557 feat: Add MultiSelect widget to chatmark library
- Implement MultiSelect class in widgets.py
- Update __init__.py to export MultiSelect
- Add support for multiple option selection with checkboxes
2024-11-14 18:45:59 +08:00
kagami
6d34ceb8e2
Merge pull request #131 from devchat-ai/feature/switch-submodule-directories
refactor: Replace subprocess calls with subprocess_check_output
2024-11-14 07:49:32 +00:00
bobo.yang
b0e7369929 fix lint errors 2024-11-14 15:04:27 +08:00
bobo.yang
2c1a10c4ce add gitlab workflows 2024-11-14 14:58:53 +08:00
bobo.yang
41a1de7bbb refactor: Replace os.system with subprocess_run in git add
- Replaced os.system with subprocess_run for git add command
- Updated import to include subprocess_run from git_api
- Ensured compatibility with existing git operations
2024-11-14 12:39:29 +08:00
bobo.yang
5585ff9fc2 fix lint error 2024-11-14 12:28:26 +08:00
bobo yang
2525010384 refactor: Replace subprocess calls with subprocess_check_output
- Replaced all instances of subprocess.check_output with subprocess_check_output
- Added subprocess_check_output function to handle current repo directory
- Updated git commands to use the new subprocess_check_output function
2024-11-14 12:23:09 +08:00
kagami
a4942d8527
Merge pull request #130 from devchat-ai/update_readme
Update README
2024-07-19 06:23:00 +00:00
bobo
ced0e1b111 update readme 2024-07-19 14:12:34 +08:00
kagami
b3b01a31ba
Merge pull request #129 from devchat-ai/update_pr_readme
feat: Add README files and update PR command structure
2024-07-19 04:54:04 +00:00
bobo
e03d1eb5dd docs: Add README for commit command and update YAML
- Add README.md explaining usage and steps of commit command
- Include optional issue closing feature in README
- Update command.yml to reference new README.md for help
2024-07-19 12:52:17 +08:00
bobo
1a7a272d08 feat: Add README files and update PR command structure
- Add README.md for PR command and its subcommands
- Update command.yml files to include help references
- Modify requirements.txt to use pr_env branch
- Add configuration options for PR inline review
2024-07-19 12:52:17 +08:00
kagami
a4005b6326
Merge pull request #128 from devchat-ai/auto_apply_fix_issue
feat: Enhance issue fixing and add aider integration
2024-07-19 04:42:19 +00:00
bobo
4a3b29c15e update README.md 2024-07-19 10:07:42 +08:00
bobo
7c30ca2135 fix lint error 2024-07-18 16:22:22 +08:00
bobo
c47261b06f chore: Ignore .aider* files in .gitignore 2024-07-18 16:02:33 +08:00
bobo
4e38d7785b feat: Add aider integration workflow command 2024-07-18 16:02:25 +08:00
bobo
c4352d8486 feat: Enhance fix_issue workflow with aider integration
- Add README instructions for fix_issue command usage
- Implement aider-based issue fixing when available
- Improve error handling and output formatting
- Refactor main function for better modularity
2024-07-18 16:01:08 +08:00
bobo
3980e6f996 feat: Add ask_issue workflow for automated lint error fixing
- Implement ask_issue command with README, command.yml, and main.py
- Create workflow to generate fix solutions using LLM
- Add functionality to extract and process diagnostics from IDE
2024-07-18 16:00:24 +08:00
bobo
f9fe89c5c0 feat: Remove unused RPC call for symbol definitions
- Delete get_symbol_defines_in_selected_code() function
- Clean up unused RPC call decorator
- Improve code organization in vscode_service.py
2024-07-18 15:45:04 +08:00
bobo
6ef65bc3ca feat: Add select_range method to IDEService
- Implement new RPC method for text selection in files
- Include parameters for file name and selection coordinates
- Add functionality to cancel current selection
2024-07-18 15:44:06 +08:00
bobo
7f0b440e42 chore: Add autoedit parameter to diff_apply method 2024-07-04 17:07:59 +08:00
kagami
d218bf7711
Merge pull request #127 from devchat-ai/add_fix_issue_command
feat: Add fix_issue command and new IDE service methods
2024-07-02 00:54:24 +00:00
bobo
8830931562 feat: Refactor fix_issue command to improve code readability and maintainability 2024-07-01 21:42:18 +08:00
bobo
ecdee052aa fix lint error 2024-07-01 21:39:44 +08:00
bobo
8a15ea83f2 fix lint error 2024-07-01 21:37:29 +08:00
bobo
d8d1c34406 fix: Update rules_path to "sonar-rspec" for consistency 2024-07-01 21:27:58 +08:00
bobo
89d19679f5 fix: Handle error cases and exit with non-zero status 2024-07-01 21:27:58 +08:00
bobo
9d07b91a3e feat: Add fix_issue command
- Implement new command to automatically fix lint errors
- Create main.py with functions for issue detection and fixing
- Add command.yml and README.md for fix_issue functionality
2024-07-01 21:27:57 +08:00
bobo
a8b6b4ea63 feat: Add new IDE service methods
- Implement get_diagnostics_in_range for code diagnostics
- Add get_collapsed_code method for code collapsing
- Introduce get_extension_tools_path for tool path retrieval
2024-07-01 21:27:57 +08:00
kagami
7b19535fd7
Merge pull request #126 from devchat-ai/update_workflows
Refactor and Enhance PR Creation and Review Features
2024-07-01 06:04:53 +00:00
bobo
5f4ebe5a5c Update PR requirements.txt 2024-07-01 13:55:15 +08:00
bobo
eb08230b60 update pr requirements.txt 2024-07-01 12:32:29 +08:00
bobo
bb3d04d7a9 fix lint error 2024-06-30 16:11:31 +08:00
bobo
8cbb645fa8 fix lint error 2024-06-30 16:07:38 +08:00
bobo
da9f21e1dc refactor: Rename config functions and parameters
- Renamed `read_config` to `read_config_item` and updated its usage
- Renamed `save_config` to `save_config_item` and updated its usage
- Renamed `save_branch` parameter to `base_branch` in `save_last_base_branch`
2024-06-30 15:48:54 +08:00
bobo
3a15d11026 feat: Add interactive base branch input for PR creation
- Introduce functions to read and save last base branch from config
- Modify PR creation and update commands to use dynamic base branch
- Enable user interaction to edit base branch during PR operations
2024-06-30 15:42:39 +08:00
bobo
5595097aed feat: Add configuration for inline PR review activation
- Introduced `read_review_inline_config` to enable inline code comments based on config
- Added new configuration file `command.py` to manage PR review inline settings
- Updated `command.py` to conditionally set inline code comments based on new config
2024-06-30 14:55:30 +08:00
bobo
fa308c36ab refactor: Simplify branch name generation and include issue ID
- Removed issue ID from branch name prompt in command.py
- Modified get_issue_or_task to return issue ID for branch naming
- Updated branch name generation to append issue ID if available
2024-06-30 14:17:39 +08:00
kagami
bf6e266b87
Merge pull request #125 from devchat-ai/handle_llm_error
Handle llm error
2024-06-18 10:48:10 +00:00
bobo
780fe10a98 fix: Handle error cases and exit with non-zero status
- Added error handling to main functions in multiple modules
- Ensured sys.exit(1) is called when responses are not successful
- Improved robustness by checking response validity before proceeding
2024-06-18 18:21:25 +08:00
bobo
df15fba131 Refactor TextEditor to handle block flags in text 2024-06-18 18:17:57 +08:00
kagami
060900a86c
Merge pull request #124 from devchat-ai/use_select_model_in_github_commands
Refactor code to remove model parameter from @chat_json decorator
2024-05-28 10:22:14 +00:00
bobo
a3706c79f8 Refactor code to remove model parameter from @chat_json decorator 2024-05-28 18:10:31 +08:00
boob.yang
95bd6d02f1
Merge pull request #123 from devchat-ai/fix-text-editor
Fix handling block flag for new_text in text editor
2024-05-28 07:04:42 +00:00
kagami
b1a2fa39b6 Fix handling block flag for new_text in text editor 2024-05-28 14:35:01 +08:00
kagami
eecad6f3dd
Merge pull request #122 from devchat-ai/fix_invliad_text_edit_error
Refactor TextEditor to handle block flags in text
2024-05-27 06:59:22 +00:00
bobo
79e6e80d82 Refactor TextEditor to handle block flags in text 2024-05-27 14:12:21 +08:00
kagami
379f356d15
Merge pull request #121 from devchat-ai/update_model_context_size_for_pr
Refactor config_util.py to handle gitlab host input
2024-05-24 13:33:23 +00:00
bobo
f0e33f9e74 Refactor config_util.py to handle gitlab host input 2024-05-24 21:31:15 +08:00
boob.yang
619ac6532a
Merge pull request #120 from devchat-ai/ref-file-for-test
Improve finding reference file for writing test
2024-05-24 02:07:56 +00:00
kagami
1146444fbd Adjust import order 2024-05-24 10:03:06 +08:00
kagami
1a303b4b0c Improve writing test prompt 2024-05-24 09:56:19 +08:00
kagami
b0fe0b4be7 Improve finding reference tests 2024-05-24 09:56:19 +08:00
kagami
094e715f79 Detect test files using regexp 2024-05-24 09:56:19 +08:00
kagami
264912f3f1
Merge pull request #119 from devchat-ai/optimize_gitlab_setting
Refactor config_util.py to handle gitlab host input
2024-05-24 00:29:28 +00:00
bobo
4ead9f6b67 Refactor config_util.py to handle gitlab host input 2024-05-23 20:35:16 +08:00
kagami
e008f17af1
Merge pull request #117 from devchat-ai/optimize_pr
chore: Update logging level to DEBUG in command.py
2024-05-22 09:05:48 +00:00
bobo
62b450d677 Refactor config_util.py to handle gitlab host input 2024-05-22 16:57:16 +08:00
bobo
14b3197543 chore: Refactor config_util.py to handle gitlab host input 2024-05-22 16:56:13 +08:00
bobo
24bd31288a chore: Update logging level to DEBUG in command.py 2024-05-22 16:46:27 +08:00
boob.yang
813ae0f59d
Merge pull request #116 from devchat-ai/ignore-cache-dir
Ignore cache dir
2024-05-21 10:13:00 +00:00
kagami
d0a0a3e090 Ignore cache dir 2024-05-21 11:23:33 +08:00
Tim
d6c0ce7b40
Merge pull request #114 from devchat-ai/update_gitlab_repo_type
chore: Update gitlab host in config_util.py
2024-05-20 13:36:08 +00:00
bobo
a7566e5055 chore: Update gitlab host in config_util.py 2024-05-20 21:24:31 +08:00
Tim
ec187a0c1b
Merge pull request #113 from devchat-ai/fix_gitlab_host_in_pr
chore: Update gitlab host in config_util.py
2024-05-20 12:27:40 +00:00
bobo
e883bf6f4f chore: Update gitlab host in config_util.py 2024-05-20 20:20:18 +08:00
bobo
6091f1c149 chore: Update gitlab host in config_util.py 2024-05-20 20:17:18 +08:00
kagami
da12ac1fb9
Merge pull request #112 from devchat-ai/remove_github_logging
chore: Improve error handling and logging in commit.py and git_api.py
2024-05-19 10:59:25 +00:00
bobo
4b6827d0f9 chore: Improve error handling and logging in commit.py and git_api.py 2024-05-19 18:52:04 +08:00
boob.yang
2f3a423741
Merge pull request #110 from devchat-ai/improve-interim-output
Improve interim output to print model response time
2024-05-19 08:06:00 +00:00
kagami
60c4c3d882 Print model response time for each step 2024-05-19 16:00:42 +08:00
kagami
adc78c431b Reorganize unit tests steps 2024-05-19 15:56:58 +08:00
boob.yang
ccf6ba3d1a
Merge pull request #109 from devchat-ai/fix-format
Fix format issues in /pr & /github
2024-05-19 07:51:19 +00:00
kagami
71a8def4c4 Ignore some E402 & E501 in pr/ & github/ 2024-05-19 15:46:11 +08:00
kagami
62bbd1ac29 Fix format issues in pr/ & github/ 2024-05-19 15:34:26 +08:00
kagami
b8a44d2f67 Improve Makefile 2024-05-19 15:32:34 +08:00
kagami
bbc53e488e
Merge pull request #107 from devchat-ai/log_time_for_step
chore: Add logging for step duration in Step class
2024-05-19 01:27:19 +00:00
Rankin Zheng
ff37ed592c
Merge pull request #108 from devchat-ai/add_pr_git_workflow
Add pr git workflow
2024-05-18 14:18:18 +00:00
bobo
634b3a7d63 Add github and pr workflow commands 2024-05-18 22:05:51 +08:00
bobo
fa8058b5ff chore: Refactor Step class to improve logging of step duration 2024-05-18 14:55:17 +08:00
bobo
53dc01015f chore: Add logging for step duration in Step class 2024-05-18 14:50:24 +08:00
boob.yang
cd7b56b4fe
Merge pull request #105 from devchat-ai/handle-readme
Handle readme manually
2024-05-16 07:33:08 +00:00
kagami
c212e704a1 Handle readme manually 2024-05-16 15:03:17 +08:00
Tim
5bf05e04a5
Merge pull request #104 from devchat-ai/fix-import
Fix import issue of unit_tests in a quick way for Windows
2024-05-15 09:26:21 +00:00
kagami
1c47b32987 Fix import issue of unit_tests in a quick way 2024-05-15 16:55:50 +08:00
kagami
5c6395adcc
Merge pull request #103 from devchat-ai/fix-env-name
Fix the env-name for ask-code
2024-05-14 12:20:19 +08:00
kagami
fa04ed820e Fix the env-name for ask-code 2024-05-14 12:17:56 +08:00
boob.yang
ea5288e4f1
Merge pull request #102 from devchat-ai/remove_addition_context_for_fix_workflow
Remove visual code block for /fix command
2024-05-14 02:59:09 +00:00
bobo
c4a206bbe6 Remove visual code block for /fix command 2024-05-14 10:31:36 +08:00
kagami
a9015f2a37
Merge pull request #101 from devchat-ai/fix_renames_chinese_bug
Refactor prompt in main.py for improved readability
2024-05-13 07:52:19 +00:00
bobo
c770b55a6e Refactor prompt in main.py for improved readability 2024-05-13 15:36:58 +08:00
bobo
3b3fcaeef9 Refactor prompt in main.py for improved readability 2024-05-13 15:21:05 +08:00
kagami
75de378f66
Merge pull request #98 from devchat-ai/fix_refactor_errors_to_script_branch
Fix refactor errors to script branch
2024-05-13 15:04:35 +08:00
boob.yang
0805ab223e
Merge pull request #99 from devchat-ai/scripts-to-gitlab
Sync scripts branch to gitlab
2024-05-11 18:10:39 +08:00
kagami
784fec4238 Sync scripts branch to gitlab 2024-05-11 17:35:15 +08:00
bobo
e45956edde Refactor imports and remove duplicate code in main.py 2024-05-11 16:55:05 +08:00
bobo
13ac7c466a Refactor imports and remove duplicate code in main.py 2024-05-11 16:51:53 +08:00
bobo
1b4540a7a8 Refactor code and improve comments in main.py 2024-05-11 16:45:49 +08:00
bobo
0d610cfb31 Refactor command.yml and rewrite.py for improved code readability and error handling 2024-05-11 16:45:49 +08:00
kagami
9ccec5058e
Merge pull request #95 from devchat-ai/scripts-ci
Config ci on scripts branch
2024-05-09 22:41:09 +08:00
kagami
fdf98281ea Config ci on scripts branch 2024-05-09 22:38:53 +08:00
kagami
c905c7c850 Remove llm_api module 2024-05-09 22:23:49 +08:00
kagami
b3cc1eb54f Add user_settings example 2024-05-09 22:23:49 +08:00
kagami
ec518753c0 Adjust unit_tests 2024-05-09 22:23:49 +08:00
kagami
f596f7729d Adjust refactor 2024-05-09 22:23:49 +08:00
kagami
d69f270262 Adjust fix 2024-05-09 22:23:49 +08:00
kagami
f7a47915c8 Adjust explain 2024-05-09 22:23:49 +08:00
kagami
a867c23be1 Adjust docstring 2024-05-09 22:23:49 +08:00
kagami
55e30a9592 Adjust commit 2024-05-09 22:23:49 +08:00
kagami
25572af366 Adjust comments 2024-05-09 22:23:49 +08:00
kagami
17d55bd324 Adjust ask-code 2024-05-09 22:23:49 +08:00
kagami
dabd12f5cf Adjust lib/ide_service 2024-05-09 22:23:49 +08:00
kagami
b87414e38d Adjust lib/chatmark 2024-05-09 22:18:51 +08:00
kagami
8b33eaa947 Update ruff config 2024-05-09 22:18:51 +08:00
kagami
d81c33d1da Update Makefile 2024-05-09 22:18:51 +08:00
kagami
b63e48c8a4 Remove the outdated code/ and expl_struct/ 2024-05-09 22:18:51 +08:00
kagami
704f2e3b92 Remove outdated requirements.txt 2024-05-09 22:18:51 +08:00
kagami
d9967f91ce Replace configuration.toml with config.yml 2024-05-09 22:18:51 +08:00
kagami
6a969358af Rename libs to lib 2024-05-09 22:18:51 +08:00
kagami
db3fe4cbc6 Move the existing workflows to merico/ 2024-05-09 22:18:51 +08:00
kagami
ec374b6250 Init the repo structure for workflow engine 2.0 2024-05-09 22:18:51 +08:00
Tim
daea79e719
Merge pull request #94 from devchat-ai/ide-service-exception
Add try-catch for some ide services
2024-04-29 15:11:31 +08:00
kagami
ec0103eaf3 Add try-catch for some ide services 2024-04-29 15:05:46 +08:00
boob.yang
b7d36a3b7a
Merge pull request #91 from devchat-ai/fix-stream-out
Use chat_completion_stream_out for streaming output
2024-04-24 21:23:29 +08:00
kagami
686c355b98 Use chat_completion_stream_out for streaming output 2024-04-24 21:15:19 +08:00
boob.yang
efbe2ca507
Merge pull request #90 from devchat-ai/improve-prompts-for-fix
Improve prompts for fix
2024-04-11 12:49:32 +08:00
Luo Tim
bb0a5e3d04 Improve prompts for fix 2024-04-11 12:13:15 +08:00
boob.yang
507cf9e3c1
Merge pull request #89 from devchat-ai/improve-prompts-for-comments
Improve prompts for comments
2024-04-11 12:04:23 +08:00
Luo Tim
a7deccc441 Improve prompts for comments 2024-04-11 11:47:59 +08:00
boob.yang
1d57a9424e
Merge pull request #88 from devchat-ai/improve-prompts-for-explain
Improve explain prompts
2024-04-11 11:00:13 +08:00
Luo Tim
612db5fa6a Improve explain prompts 2024-04-11 10:58:06 +08:00
boob.yang
e0627bf780
Merge pull request #87 from devchat-ai/feat/improve-readme-guide
Improve Workflow Guides and Image Spacing Adjustment
2024-04-02 11:04:41 +08:00
Rankin Zheng
fc192d3de6 fix: Add spacing to increase the distance between images. 2024-04-02 10:51:47 +08:00
Rankin Zheng
ae9fca1442 feat: improve refactor workflow guide. 2024-04-02 10:49:05 +08:00
Rankin Zheng
2eb2d8abb0 feat: improve explain workflow guide. 2024-04-02 10:38:39 +08:00
Rankin Zheng
2272ab55bd feat: improve fix workflow guide. 2024-04-02 10:30:23 +08:00
Rankin Zheng
ddc236f297 feat: improve comments workflow guide. 2024-04-02 10:17:25 +08:00
Rankin Zheng
b66cfc9a4f feat: improve docstring workflow guide. 2024-04-02 09:36:06 +08:00
kagami
4938eeb74c
Merge pull request #86 from devchat-ai/enhancement/chinese-language-support-workflows-#315
Implement Chinese Language Support for Workflow Outputs
2024-04-02 08:33:10 +08:00
Rankin Zheng
86b81459e0 improve: update unit tests workflow guide. 2024-04-02 08:19:53 +08:00
bobo
574dbaf9ba fix lint error 2024-04-01 20:54:24 +08:00
bobo
025858a231 feat: Implement Chinese language support in workflows
- Removed explicit language parameter for commit commands
- Introduced language detection and bilingual messages
- Deleted specific Chinese command file for streamlined approach
2024-04-01 20:46:25 +08:00
Tim
c1ce229c64
Merge pull request #85 from devchat-ai/fix_input_field_error
Enhance Non-Selection Behavior and Validate Selection Across Modules
2024-04-01 19:04:41 +08:00
bobo
09d23d34a8 fix lint error 2024-04-01 16:55:10 +08:00
bobo
5395639347 fix: Improve selection validation logic across modules
- Changed the condition to determine selection absence by comparing start and end range instead of checking if text is empty.
- Ensures that a non-selection (where start and end range are the same) correctly triggers the absence of selection error.
- Applied this logic uniformly in comments, docstring, explain, fix, and refactor modules.
2024-04-01 16:46:47 +08:00
bobo
852706d25d feat: Display README when no code is selected
- Add feature to show README.md when no text is selected
- Modify all command and main modules to support this feature
- Remove 'input: required' from command.yml files for flexibility
2024-04-01 16:41:25 +08:00
Rankin Zheng
ceb280012d
Merge pull request #84 from devchat-ai/docs/add-input-field-desc-#312
feat: add fix/comments workflow
2024-03-30 00:51:55 +08:00
Rankin Zheng
3a0600ae9e feat: add fix/comments workflow 2024-03-30 00:46:08 +08:00
Rankin Zheng
e3cb0725a0
Merge pull request #82 from devchat-ai/docs/add-input-field-desc-#312
Update Workflow Command Documentation to Include 'input' Field Descriptions
2024-03-30 00:41:37 +08:00
Rankin Zheng
ad4c2310d3 feat: add more readme file 2024-03-30 00:39:47 +08:00
Rankin Zheng
e9cac56372 feat:move refact.name to refactor readme file 2024-03-30 00:34:37 +08:00
Rankin Zheng
70c926166a Add workflow readme file 2024-03-30 00:32:22 +08:00
bobo
cc61a3e600 docs: Add input field descriptions to commands
- Include `input: required` in the YAML of various commands
- Clarify the necessity of user input in workflow executions
- Ensure workflow documentation is comprehensive and clear
2024-03-29 19:14:50 +08:00
Tim
355686d280
Merge pull request #81 from devchat-ai/enhancement/workflow-recommendations-setup-#304
Add Configuration File for Workflow Recommendations
2024-03-27 20:28:41 +08:00
bobo
8ea2e832bc Update workflow in configuration.toml 2024-03-26 16:40:05 +08:00
bobo
e190aeda25 feat: Add recommended workflows config file
- Created a new configuration.toml for workflow recommendations
- Populated the file with initial recommended workflows
- Ensured proper formatting for easy accessibility
2024-03-26 14:29:04 +08:00
Rankin Zheng
1219dc8fd1
Merge pull request #80 from devchat-ai/remove_release_notes
remove release notes workflow.
2024-03-26 11:48:36 +08:00
boob.yang
84c7596837
remove release notes workflow. 2024-03-26 10:30:11 +08:00
Tim
9dead9b3cf
Merge pull request #79 from devchat-ai/prompt-improvement
Make test case descriptions concise
2024-03-19 11:15:37 +08:00
kagami
6c9bf72a13 Add comment for switching back to gpt3.5 2024-03-19 10:57:29 +08:00
kagami
1ef0bff393 Make test case descriptions concise 2024-03-19 10:57:29 +08:00
Tim
0da8287ad9
Merge pull request #78 from devchat-ai/prompt-improvement
Improve the principles for writing tests
2024-03-18 10:04:02 +08:00
kagami
1896c2b933 Improve the principles for writing tests 2024-03-18 09:30:11 +08:00
Tim
bee6f21535
Merge pull request #77 from devchat-ai/fix-typo
Fix typo
2024-03-15 19:00:07 +08:00
kagami
ef4ea025a9 Fix typo 2024-03-15 17:01:22 +08:00
boob.yang
f753fb7bb2
Merge pull request #76 from devchat-ai/context-info
Show additional context info in summary
2024-03-15 16:56:57 +08:00
kagami
ef6554df5a Update i18n translations 2024-03-15 16:45:30 +08:00
kagami
4fb3b79ebe Print additional context in summary 2024-03-15 16:39:08 +08:00
kagami
e7b3a66ab6 Add range for Context 2024-03-15 16:03:18 +08:00
kagami
6a1fdc829e Use gpt4-turbo for unit_tests as default 2024-03-15 15:21:51 +08:00
boob.yang
ccc1d97c90
Merge pull request #75 from devchat-ai/switch-model
Use env var `DEVCHAT_UNIT_TESTS_USE_USER_MODEL` to switch to user selected model for `/unit_tests`
2024-03-13 14:34:57 +08:00
kagami
c44891a39f Handle token budget when recommend test context 2024-03-13 11:50:27 +08:00
kagami
3b1b24e1b2 Update context size for models 2024-03-13 11:50:27 +08:00
kagami
4b756f7908 Improve the usage of the wrapped api 2024-03-13 11:50:27 +08:00
kagami
48441e2514 Be able to switch between openai api & wrapped api 2024-03-13 11:50:27 +08:00
kagami
bfa4198ba2 Add llm config 2024-03-13 11:50:27 +08:00
Tim
874da1710f
Merge pull request #74 from devchat-ai/refactor/preserve-function-code-docs-#290
Fix Issue with Large Models Dropping Function Code When Adding Docstrings
2024-03-12 18:09:21 +08:00
bobo
7981a7e5bb refactor: Optimize docstring gen without visible code
- Remove references to current visible code in docstring generation
- Ensure large functions retain original code when adding docstrings
- Aim for minimal interference from visible code context in outputs
2024-03-12 16:41:13 +08:00
boob.yang
079faae3a6
Merge pull request #73 from devchat-ai/user-requirements
Allow user to add customized requirements for writing tests
2024-03-12 09:52:54 +08:00
kagami
a55565161c Prevent conflicts between make targets and files 2024-03-12 08:51:33 +08:00
kagami
50ed9b35d1 Update i18n translations 2024-03-12 08:51:33 +08:00
kagami
991267e9d6 Cache user requirement of tests for each repo 2024-03-12 08:51:33 +08:00
kagami
8d32101c80 Allow use to add customized requirements for tests 2024-03-12 08:51:33 +08:00
boob.yang
db6b2f4b4c
Merge pull request #67 from devchat-ai/symbol-context
Add more context for writing tests by analyzing symbols
2024-03-12 07:56:57 +08:00
kagami
1d9cc2f85a Include file path info in Context 2024-03-11 22:18:00 +08:00
kagami
f13ae6530b Fix format issue 2024-03-11 22:18:00 +08:00
kagami
fccfcafe98 Improve finding context by both definition & type definition 2024-03-11 22:18:00 +08:00
kagami
0196eb019f Reorder steps in unit test workflow 2024-03-11 22:18:00 +08:00
kagami
9107b1e963 Use context informations when propose cases 2024-03-11 22:18:00 +08:00
kagami
77dead7745 Add find_def_locations in IDE Service 2024-03-11 22:18:00 +08:00
kagami
26d2a91192 Improve lint issues 2024-03-11 22:18:00 +08:00
kagami
ebbabe321c Integrate finding context in the workflow 2024-03-11 22:18:00 +08:00
kagami
79139fdcc8 Find symbol context using both static analysis and llm recommendation 2024-03-11 22:18:00 +08:00
kagami
01e57e6e48 Add llm assistant to recommend symbol context for testing 2024-03-11 22:18:00 +08:00
kagami
f3a1cd4dee Add symbol utils 2024-03-11 22:18:00 +08:00
kagami
06074e744c Make ide service types hashable 2024-03-11 22:18:00 +08:00
boob.yang
7938975753
Merge pull request #72 from devchat-ai/the-fix-command
Add the fix command
2024-03-11 20:15:31 +08:00
Luo Tim
0addeb462e Add the fix command 2024-03-11 18:57:03 +08:00
boob.yang
cf8ecc7d2f
Merge pull request #71 from devchat-ai/docstring
Improve the prompt of doc comments
2024-03-08 21:22:45 +08:00
Luo Tim
49d3efa5b7 Fix code style 2024-03-08 21:09:10 +08:00
Luo Tim
e320c04eb1 Improve the prompt of doc comments 2024-03-08 19:34:40 +08:00
boob.yang
8d0d1e4f86
Merge pull request #70 from devchat-ai/docstring
Docstring
2024-03-08 13:54:18 +08:00
Luo Tim
d8fe05f4ff Add comments command 2024-03-08 12:11:00 +08:00
Luo Tim
95c29f8aac Add the new /docstring command 2024-03-08 11:28:13 +08:00
Luo Tim
2c7dc280e6 Remove refactor.docstring 2024-03-08 11:27:44 +08:00
boob.yang
18d3c1369e
Merge pull request #69 from devchat-ai/explain-code
Implement explain code workflow
2024-03-08 10:52:18 +08:00
Luo Tim
b903d0fe03 Auto detect language in explain workflow 2024-03-07 10:34:42 +08:00
Luo Tim
f20c258833 Fix key error on explain 2024-03-06 18:06:49 +08:00
Luo Tim
1f541cd4c6 Implement explain code workflow 2024-03-06 09:58:45 +08:00
kagami
84cc241a75
Merge pull request #66 from devchat-ai/feature/add-refactor-workflow
Feature: Add Code Refactoring Commands and Utility Script
2024-02-09 11:15:21 +08:00
bobo
91cea1b59c fix lint error 2024-02-09 11:09:14 +08:00
bobo
62c60a1386 feat: Add refactoring commands and utility script
- Introduced command configurations for code rewriting, docstring optimization, and variable renaming.
- Added a Python utility script for code selection and refactoring operations.
- Implemented functionality to interact with IDE services and apply changes.
2024-02-09 11:04:29 +08:00
kagami
d66ada970b
Merge pull request #65 from devchat-ai/feature/empty-string-check-decorator-#242
Fix: Chat decorator now avoids inserting empty strings
2024-02-05 14:13:00 +08:00
bobo
9e84e88677 fix: Prevent empty string submission in chat decorator
- Added a check to prevent empty strings from being added to the chat
- This ensures no messages with an empty 'content' field are inserted
- Enhances stability and error handling in chat functionality
2024-02-05 12:48:09 +08:00
boob.yang
c6b9ad3e44
Merge pull request #64 from devchat-ai/type-annotation
Improve IDE services with type annotation and casting & Add two interfaces
2024-02-04 09:46:50 +08:00
kagami
ef1c9ef3cb Replace the usage of services functions with IDEService client 2024-02-03 23:43:13 +08:00
kagami
5f1926fcdd Type casting for returns of ide service 2024-02-03 23:15:52 +08:00
kagami
9efc523577 Implement IDEService class 2024-02-03 22:22:42 +08:00
kagami
2288eb480b Add type hint for ide services 2024-02-03 00:36:17 +08:00
kagami
c31817f44a Add type definitions for IDE service 2024-02-03 00:14:37 +08:00
kagami
8d302b1533 Expose get symbols andd find type definitions 2024-02-03 00:13:54 +08:00
boob.yang
82d3fd5055
Merge pull request #63 from devchat-ai/expose-ide-logging
Expose ide_logging in ide service
2024-02-02 10:19:36 +08:00
kagami
ea80e1c4a4 Expose ide_logging in ide service 2024-02-02 10:14:32 +08:00
kagami
98e3219bb1
Merge pull request #62 from devchat-ai/api/python-access-raw-vscode-data-#234
Implement Python API to Enable Direct Access to Raw VSCode Data
2024-02-01 20:16:50 +08:00
bobo
5a8704a58d fix lint error 2024-02-01 17:58:23 +08:00
bobo
366b17d092 feat: Add Python API for accessing raw VSCode data
- Added vscode_services.py to enable direct access to raw data from VSCode.
- Updated ide_services/services.py to use the new rpc_call function.
- Added vscode_services.py for specific VSCode service functionalities.
2024-02-01 17:46:49 +08:00
kagami
f8d8745231
Merge pull request #61 from devchat-ai/optimize_llm_usage
Enhance LLM API with New Features, Refactorings, and Optimizations
2024-01-31 17:11:39 +08:00
bobo
7b6bc1a7bc Add exception handling decorator to pipeline.py 2024-01-31 16:19:36 +08:00
bobo
7d639f93f4 Refactor llm_api module 2024-01-31 16:15:30 +08:00
bobo
b271a13f66 chore: Optimize LLM API function call handling
- Refactored chunks_call to utilize a list of tool calls
- Updated to_dict_content_and_call to handle multiple tool calls
- Enhanced chat_tools to display function call details
2024-01-31 16:14:51 +08:00
bobo
dac115ed32 Refactor llm_api package imports and add new modules 2024-01-31 16:14:51 +08:00
bobo
173fa768e5 Refactor error handling in openai.py 2024-01-31 16:14:51 +08:00
bobo
9a3325469a feat: Add new LLM API features
- Added new chat functionalities for LLM API
- Implemented text confirmation for LLM API
- Updated code for better user interaction
2024-01-31 16:14:51 +08:00
bobo
48b8590ea0 feat: Add new file tools_call.py
- Added new file tools_call.py containing functions and decorators
- Implements tool and function schemas for use in the application
- Includes a function to prompt the user to confirm function calls

.
2024-01-31 16:14:51 +08:00
bobo
212537b8a2 chore: Add memory module for LLM API
- Added memory module for LLM API
- Implemented ChatMemory and FixSizeChatMemory classes
- Included methods for appending, requesting, and responding to memory
2024-01-31 16:14:51 +08:00
bobo
997c3f86dc new openai api 2024-01-31 16:14:50 +08:00
bobo
162c545b74 add openai api pipeline.py 2024-01-31 16:14:15 +08:00
bobo
3e93883c4f feat: Enhance LLM API with new decorators and confirmations
- Added new decorators for LLM functions, parameters, and confirmations.
- Introduced confirmation dialogs for calls and edits within LLM interactions.
- Streamlined integration of LLM tool schemas and response handling.
2024-01-31 16:14:15 +08:00
kagami
0b90fe4032
Merge pull request #59 from devchat-ai/handle_openai_apierror
Refactor Pipeline Imports and Update Exception Handling in LLM API
2024-01-31 15:23:26 +08:00
bobo
b3c0810e54 Refactor pipeline imports and exception handling 2024-01-31 15:22:19 +08:00
bobo
bde44aa50e Update exception handling in llm_api/openai.py 2024-01-31 15:22:19 +08:00
kagami
bc44a69125
Merge pull request #60 from devchat-ai/fix/workflow-tiktoken-special-char-error
Fix token counting logic in relevant_file_finder.py and propose_test.py
2024-01-31 15:20:41 +08:00
bobo
6f737020fc Fix token counting in relevant_file_finder.py and propose_test.py 2024-01-31 13:13:16 +08:00
kagami
bcba74375b
Merge pull request #58 from devchat-ai/fix_chunk_content_none
Fix empty content issue in create_chat_completion_content function
2024-01-29 17:58:25 +08:00
bobo
c83058cbea Fix issue with empty content in create_chat_completion_content function 2024-01-29 16:19:31 +08:00
kagami
5d156e55b2
Merge pull request #57 from devchat-ai/fix/windows-module-not-found-error-#226
Fix Windows ModuleNotFoundError on unit testing workflow
2024-01-29 12:32:23 +08:00
bobo
e8ab8c46fd Imported additional modules and removed redundant imports 2024-01-29 09:41:59 +08:00
bobo
15735d7aee fix: Resolve Windows 'ModuleNotFoundError' in unit testing
- Moved 'sys.path.append' lines to the start of 'main.py'
- Ensured correct directory access for unit tests in Windows environment
2024-01-29 09:37:30 +08:00
kagami
2157a823fb
Merge pull request #56 from devchat-ai/fix_openai_key_error
Add environment variables for OpenAI API key and base URL
2024-01-26 08:59:34 +08:00
bobo
294c2d1574 Add environment variables for OpenAI API key and base URL 2024-01-25 23:33:34 +08:00
boob.yang
dae577bd0b
Merge pull request #46 from devchat-ai/switch-env-again
Revert "Revert "/unit_tests switch to devchat env""
2024-01-25 21:25:53 +08:00
Tim
db9c46d1bf
Merge pull request #55 from devchat-ai/fix_error_keyerror
Fix error handling in generate_commit_message_base_diff function
2024-01-25 18:51:24 +08:00
bobo
4a3dfc848f Fix assert_value syntax error in generate_commit_message_base_diff function 2024-01-25 18:44:09 +08:00
bobo
340c8cbfa9 Fix error handling in generate_commit_message_base_diff function 2024-01-25 18:41:31 +08:00
kagami
491a0d1d77 Revert "Revert "/unit_tests switch to devchat env"" 2024-01-25 17:53:47 +08:00
kagami
847576f902
Merge pull request #51 from devchat-ai/hotfix/git-staged-deletion-flag-#197
Fix staged file deletion flag display in commit workflow
2024-01-25 17:52:44 +08:00
kagami
be63f25f90
Merge pull request #49 from devchat-ai/bugfix/context-overflow-commit-failure-#189
Fix context overflow issue causing commit submission failure
2024-01-25 17:50:43 +08:00
boob.yang
d0fc2a453e
Merge branch 'main' into hotfix/git-staged-deletion-flag-#197 2024-01-24 21:57:33 +08:00
bobo
6f1b5ca2ef Refactor pipeline imports and function calls 2024-01-24 21:26:11 +08:00
bobo
47887ca6f9 Add pipeline module with retry and exception handling functions 2024-01-24 21:23:44 +08:00
bobo
9aa9c44934 assert response error 2024-01-24 18:03:45 +08:00
bobo
f0ed2a64ee Fix commit message length limit 2024-01-24 18:01:29 +08:00
bobo
b81624c764 fix: Improve error handling for context overflows
- Refactor error output for token limit issues to ensure clarity
- Update the error handling strategy to unify exception responses
- Remove redundant error handling blocks for streamlining
2024-01-24 17:34:27 +08:00
bobo
380e727e61 chore: Validate content length before sending to LLM
- Add validation for content length before sending to LLM
- Display an error message if the modified content exceeds the model's length limit
- Exit the program if the content length exceeds the limit
2024-01-24 17:34:27 +08:00
bobo
3d3241f282 chore: Correct lint errors
- Refactored language_prompt to handle Chinese characters
- Updated model_token_limit_error message formatting
- Modified function signature for chat_completion_stream
2024-01-24 17:34:27 +08:00
bobo
c805239183 fix: Resolve context overflow commit failure
- Updated commit/command.yml to use "en" language code
- Updated commit/commit.py to handle model's maximum context length error
- Updated commit/zh/command.yml to use "zh" language code
- Updated libs/llm_api/openai.py to ignore tokens limit error

Closes devchat-ai/devchat#189
2024-01-24 17:34:27 +08:00
kagami
dbdb1ba29d
Merge pull request #53 from devchat-ai/improve-propose-tests
feat: maintain a balance between happy paths and edge cases
2024-01-24 15:14:26 +08:00
Hezheng Yin
d8866a5182 misc: formatting 2024-01-24 15:11:36 +08:00
Hezheng Yin
cd43eb373f feat: maintain a balance between happy paths and edge cases 2024-01-24 15:10:28 +08:00
kagami
6aaeac784f
Merge pull request #50 from devchat-ai/feature/friendly-commit-warning-#188
Improve user interaction for commit errors
2024-01-24 15:08:50 +08:00
bobo
af54106813 fix: Ensure lint error fix
- Fixed lint error in commit/commit.py file
- Updated unstaged_files_show assignment for lint compliance
- Updated subprocess.check_output call for lint adherence
2024-01-23 15:47:31 +08:00
bobo
164156bdc0 chore: Add a letter to indicate modification status
- Added a letter before each modified file to indicate the modification status
- Updated the workflow to display file deletion flag in 'Staged' files
- Fixed the issue where staged files did not display the git status
2024-01-23 15:42:58 +08:00
bobo
20a94c78f5 feat: Improve commit warning messages
- Change error message when no files to commit are found
- Update commit aborted message to be more explicit
- Improve user experience by providing helpful warnings
2024-01-23 14:39:26 +08:00
Henry (Hezheng) Yin
a66d2d33a3
Merge pull request #35 from devchat-ai/user-input-cases
Accept user input for test cases
2024-01-18 09:55:13 -08:00
kagami
00f0fa1343 Update i18n for /unit_tests 2024-01-18 15:45:28 +08:00
kagami
685449821f Accept user cases and print summary of cases and references 2024-01-18 15:45:28 +08:00
kagami
e795e4853e Split unit_tests workflow into several steps 2024-01-17 18:00:36 +08:00
Tim
d0020e838b
Merge pull request #38 from devchat-ai/revert-37-switch-env
Revert "/unit_tests switch to devchat env"
2024-01-17 17:55:52 +08:00
kagami
a5686e759d
Revert "/unit_tests switch to devchat env" 2024-01-17 17:43:25 +08:00
boob.yang
997e631e6c
Merge pull request #37 from devchat-ai/switch-env
/unit_tests switch to devchat env
2024-01-17 17:30:25 +08:00
kagami
7c9c9d6574 Remove client property to unbind from openai api 2024-01-17 17:19:12 +08:00
kagami
a0ce83b21c Update the usage of tiktoken in devchat env 2024-01-17 17:19:12 +08:00
kagami
04c7e6818b Switch to python for devchat 2024-01-17 17:19:12 +08:00
boob.yang
eb7e756877
Merge pull request #36 from devchat-ai/open-chat
Move some code from `chat` to `workflow`
2024-01-17 17:08:35 +08:00
kagami
1974cfea38 Implement other utils in current repo 2024-01-17 15:34:22 +08:00
kagami
1c6f04f6d2 Implement RelevantFileFinder and replace the one from 'chat' 2024-01-17 15:31:21 +08:00
kagami
5f0198d52c Implement file utils and replace those from 'chat' 2024-01-17 15:31:03 +08:00
boob.yang
6330983635
Merge pull request #5 from devchat-ai/expl-struct
Add command to explain repo structure
2024-01-12 12:29:42 +08:00
kagami
4d1fc2fffb Inactivate expl_struct 2024-01-12 12:22:42 +08:00
kagami
6bf05f9b7d Use Step() in expl-struct 2024-01-12 12:21:15 +08:00
kagami
8f46b05be9 Support /expl_struct.zh 2024-01-12 12:15:53 +08:00
kagami
c0f76e6811 Init command /expl_struct 2024-01-12 12:15:53 +08:00
boob.yang
a8969b0038
Merge pull request #34 from devchat-ai/chatmark-step
Implement Step in chatmark
2024-01-12 11:49:30 +08:00
kagami
254ddc9372 Use Step() in /unit_tests 2024-01-12 11:21:12 +08:00
kagami
c584b186e0 Implement chatmark Step 2024-01-12 11:12:12 +08:00
boob.yang
70d9db5084
Merge pull request #33 from devchat-ai/multi-ref
Support multiple reference files
2024-01-12 10:02:47 +08:00
kagami
9979f0c668 Update translations for multiple references 2024-01-12 09:03:34 +08:00
kagami
9c1bdf8053 Allow multiple reference files from user input 2024-01-11 21:35:17 +08:00
boob.yang
c0c26094ff
Merge pull request #32 from devchat-ai/activate-ut
Activate /unit_tests workflow
2024-01-10 11:41:22 +08:00
kagami
0ee7015758 Activate /unit_tests workflow 2024-01-10 10:39:10 +08:00
kagami
4f03a00910
Merge pull request #31 from devchat-ai/remove_commit_message_command
chore: Cleanup obsolete commit message automation files
2024-01-05 21:36:54 +08:00
bobo
e929049b68 chore: Remove commit message command
- Removed commit_message/command.yml
- Removed commit_message/prompt.txt
2024-01-05 20:14:04 +08:00
boob.yang
08b2246775
Merge pull request #30 from devchat-ai/clean-repo
Clean repo and sort "import" blocks
2024-01-05 13:26:37 +08:00
kagami
bca2507c2f Sort and format import blocks 2024-01-05 12:27:57 +08:00
kagami
f90ef63606 Enable the isort rules 2024-01-05 12:24:50 +08:00
kagami
56aedf8793 Remove ui_utils/ 2024-01-05 12:24:50 +08:00
kagami
13fe016f21
Merge pull request #28 from devchat-ai/enhance/form-button-labels
Enhance form and widget button label functionality
2024-01-05 12:02:12 +08:00
bobo
05d8e6dda7 format file 2024-01-05 12:01:01 +08:00
bobo
7d5887e98c refactor: Enhance form and button label flexibility
- Make submit and cancel button labels optional in form and widgets
- Refactor chatmark header construction for conditional button labels
- Implement assertion for Radio widget's default_selected option
2024-01-05 12:01:01 +08:00
bobo
57da9e9841 style: Standardize button label parameters
- Add trailing commas to button name parameters in widgets
- Reformat constructor definitions for consistency
- Clean up unnecessary whitespace in widget render logic
2024-01-05 12:01:01 +08:00
bobo
69e178e7a7 feat: Implement default option selection in Radio
- Introduced the default_selected parameter in the Radio widget
- Updated Radio widget to mark default selected option visually
- Removed TODO comment for the default_selected implementation
2024-01-05 12:01:01 +08:00
bobo
21217d2bb7 feat: Add customizable button labels to forms and widgets
- Form and TextEditor classes now accept submit_button_name and cancel_button_name
- Widget's chatmark header updated with customizable submit and cancel labels
- Adjusted initialization of Checkbox and Radio classes with button label parameters
2024-01-05 12:01:01 +08:00
kagami
c5d4272cbb Update message for TokenBudgetExceededException 2024-01-05 11:08:50 +08:00
kagami
7db4a678f4 Rafactor command interface to accept a single string only 2024-01-05 11:08:50 +08:00
kagami
7d3594c928
Merge pull request #16 from devchat-ai/ut-workflow
Implement `/unit_tests` workflow
2024-01-05 10:02:54 +08:00
kagami
824fa014b2 Rename command.yml to avoid releasing 2024-01-04 17:19:08 +08:00
kagami
5ab2749aa8 Update i18n for new strings 2024-01-04 17:19:08 +08:00
kagami
0bc33d8bf8 Validate user input 2024-01-04 17:19:08 +08:00
kagami
a64c881815 Rename /gen_ut to /unit_tests 2024-01-04 17:19:08 +08:00
kagami
c4d6e82ae9 Improve adjusting context to fit token budget 2024-01-04 17:19:08 +08:00
kagami
8b12669505 Use chatmark module for user input 2024-01-04 17:19:08 +08:00
kagami
d2160b6736 Update token budgets 2024-01-04 17:19:08 +08:00
kagami
05cce75127 Update translations 2024-01-04 17:19:08 +08:00
kagami
278ca673b7 Improve the output of token budget exception 2024-01-04 17:19:08 +08:00
kagami
59e05c7640 Set retry for create_chat_completion_content 2024-01-04 17:19:08 +08:00
kagami
4704f51be1 Adjust content to fit token budget and handle budget exceeded exception 2024-01-04 17:19:08 +08:00
kagami
28123663de Use relative path in inner logic 2024-01-04 17:19:08 +08:00
kagami
fda4ad2a02 Manage prompts in a single file and ignore line-too-long error 2024-01-04 17:19:08 +08:00
kagami
3be880eabd Use create completion wrappers in propose_test and write_tests 2024-01-04 17:19:08 +08:00
kagami
40934b8869 Implement wrappers to create completion content and chunks respectively using stream mode 2024-01-04 17:19:08 +08:00
kagami
75ff48c6bc Support different languages in write_tests 2024-01-04 17:19:08 +08:00
kagami
925c0890c1 Mark and translate messages 2024-01-04 17:19:08 +08:00
kagami
ed03cbf08a Support different languages in llm chatting 2024-01-04 17:19:08 +08:00
kagami
6305c8347a Output the final answer in streaming mode 2024-01-04 17:19:08 +08:00
kagami
9246d4d32d Init i18n support 2024-01-04 17:19:08 +08:00
kagami
8459e69713 Extract function content when line numbers are provided 2024-01-04 17:19:08 +08:00
kagami
53cbca5c69 Init /gen_ut 2024-01-04 17:19:08 +08:00
kagami
0b837ff045
Merge pull request #27 from devchat-ai/bugfix/commit-empty-file-list#158
Fix empty file list display in /commit view
2024-01-04 16:41:03 +08:00
bobo
ae1a3bb400 fix: Prevent empty file list in commit prompt
- Ensure the commit prompt correctly handles when no files are staged
- Clean up excessive whitespace in code for readability
- Simplify the creation of the Form object by removing unnecessary newlines
2024-01-04 16:22:08 +08:00
bobo
d496d6b9de fix: Handle empty file selection list more gracefully
- Fix variable naming consistency in get_marked_files
- Ensure selections are stored even when unstaged file list is empty
- Combine staged and unstaged files correctly to avoid errors
2024-01-04 16:18:40 +08:00
bobo
005f1fae7b fix: Handle commit flow for empty file lists
- Omit displaying emptiness for staged and unstaged file sections
- Use conditional checks to append file lists and checkboxes
- Ensure selections are retrieved even if no files are staged/unstaged
2024-01-04 15:12:22 +08:00
kagami
d19faf4f5c
Merge pull request #26 from devchat-ai/fix/gitlab-sync-error
fix: Add fetch depth to GitHub repository checkout
2024-01-04 12:36:38 +08:00
bobo
d53433d618 fix: Add fetch depth to GitHub repository checkout
- Add fetch-depth option to GitHub repository checkout step for improved syncing
- Update sync-to-gitlab.yml workflow file
- Ensure proper setup of Git for synchronization
2024-01-04 12:23:59 +08:00
kagami
05625059d5
Merge pull request #25 from devchat-ai/fixes/test-feedback
Fixes/test feedback
2024-01-04 11:17:40 +08:00
bobo
8ac6fb3c6a fix: Update print statements in commit.py
- Update print statements for Step 1/2 and Step 2/2 in commit.py
- Modify the formatting for better readability in the code
- Ensure consistent use of escape characters for line breaks
2024-01-04 11:03:17 +08:00
bobo
64192e0b2c fix: Update git push command in sync-to-gitlab.yml
- Update git push command to force push changes to main branch
- Remove unnecessary git rebase command
- Make adjustments to improve synchronization with GitLab
2024-01-04 11:00:04 +08:00
bobo
36fc46212a refactor: Improve user experience and streamline commit workflow
- Simplify and clarify user prompts and output messages
- Remove unnecessary print statements and text
- Handle commit abort and errors more gracefully
- Improve error logging in OpenAI chat stream handler
2024-01-04 10:59:46 +08:00
kagami
e10817375f
Merge pull request #24 from devchat-ai/fix_sync_error
fix: Resolve sync error with git rebase
2024-01-04 08:52:21 +08:00
bobo
83f6922f63 fix: Resolve sync error with git rebase
- Modify git rebase command to use -Xours strategy option
2024-01-03 21:39:33 +08:00
kagami
b3eb8c6670
Merge pull request #23 from devchat-ai/fix_python_error
fix: Update type hints in form.py
2024-01-03 17:49:48 +08:00
bobo
4ac2167146 fix: Update type hints in form.py
- Update type hints for components to use Union
- Update type hints for components method to use Union
- Fix python error
2024-01-03 17:32:15 +08:00
bobo
f5b430e712 chore: Add function to extract markdown block
- Added function to extract the first Markdown code block from the given text
- Updated the get_current_branch function to include the current repo branch name in the user input
- Enhanced the commit message generation process by extracting the markdown block content
2024-01-03 15:38:46 +08:00
boob.yang
c83b273e64
Merge pull request #22 from devchat-ai/sync_github_to_gitlab
Sync GitHub to gitlab
2024-01-03 15:35:09 +08:00
bobo
328af00e41 use gh-action as user name 2024-01-03 15:32:07 +08:00
bobo
a28b3d676b ci: Downgrade nick-invision/retry action to v2
- Downgrade the GitHub action nick-invision/retry to version 2
- This change addresses compatibility issues with the workflow
2024-01-03 14:59:35 +08:00
bobo
6e7c9e7bed type: ci: Add sync workflow for GitLab
- Add a new GitHub Actions workflow for syncing to GitLab
- Trigger the workflow on push to the main branch
- Remove commented out code for setting GitLab remote URL
2024-01-03 14:59:35 +08:00
bobo
02a0f871e0 type: feat: Add sync workflow to GitLab
- Implement workflow for syncing GitHub repo with GitLab
- Setup GitHub action to checkout, configure Git, and add remote
- Use retry action to fetch, rebase, and push to GitLab repository
2024-01-03 14:59:35 +08:00
kagami
d99a05ebc9
Merge pull request #19 from devchat-ai/update_commit_step_info
Update commit step info
2024-01-03 11:39:47 +08:00
bobo
5d1ddda356 chore: Update commit message 2024-01-03 11:26:04 +08:00
bobo
d4e262dfd9 chore: Update commit message content 2024-01-03 11:20:56 +08:00
bobo
7fbf44cd06 feat: Update chat_completion_stream function signature
- Update the signature of the chat_completion_stream function
- Remove unnecessary line breaks and indents
- Improve code readability and maintainability
2024-01-03 11:20:09 +08:00
bobo
2ec603a944 feat: Update prompt_commit_message_by_diff_user_input_llm_config
- Updated the prompt_commit_message_by_diff_user_input_llm_config to use the "gpt-3.5-turbo-1106" model
- Refactored the print statement in the display_commit_message_and_commit function for better readability
2024-01-03 11:14:56 +08:00
bobo
98233481df chore: Update llm_api in commit.py
- Updated llm_api import to chat_completion_stream
- Updated llm_api config with environment variable
- Improved user prompt for file selection
- Revised user message for commit editing
- Enhanced user guidance in main function
2024-01-03 11:10:35 +08:00
bobo
b5ad6f25ea chore: Update Python script imports
- Updated import from `chat_completion_no_stream` to `chat_completion_stream`
- Updated requirements file name from `requirements.txt` to `requirements-test.txt`
- Renamed requirements file in `run.sh` from `requirements.txt` to `requirements-test.txt`
2024-01-03 11:10:00 +08:00
bobo
788a6f08f8 fix: Update chat_completion_stream function names
- Update function names in openai.py
- Modify function import in __init__.py
- Update function call in openai.py
2024-01-03 11:08:38 +08:00
bobo
8b6767dc7d chore: Update commit message description
- Update commit message description to provide guidance on writing a well-formatted commit message for selected code changes and committing them via Git. Include an issue number if desired (e.g., input "/commit to close #12").
- Update commit message description in Chinese to provide guidance on generating a well-formatted submission message for the selected code changes and committing them via Git. If necessary, it can include the corresponding issue number (e.g., input "/commit to close #12").
2024-01-03 11:06:20 +08:00
bobo
446f80ebad type: refactor: Clean up import and improve readability
- Remove unused List import from typing module
- Reformat Checkbox and Form instantiation for clearer code structure
- Enhance step description in the commit process output
2024-01-02 22:17:05 +08:00
bobo
590b744dc9 type: refactor: Rework file selection and commit prompt UI
- Replace ui_utils with chatmark module for better UX in file selection
- Implement TextEditor class to handle commit message editing
- Switch from ui_checkbox_select to Checkbox and Form classes for file staging
2024-01-02 22:14:03 +08:00
bobo
74b933eecc type: feat: Add new script for test environment setup
- Add run.sh to configure and run test environment
- Ensure Node.js and Python 3 are installed before proceeding
- Install JavaScript and Python dependencies and run test cases
2024-01-02 21:37:02 +08:00
bobo
93178e521e type: style: Improve code readability
- Add blank lines for better code separation
- Consolidate header dict in requests.get call
- Remove unnecessary blank lines for consistency
2024-01-02 21:37:02 +08:00
bobo
51aa71a0cb fix: Remove placeholder from commit message content
- Remove the 'Closes #IssueNumber' placeholder in the commit message
- Ensure commit messages are generated without closing reference by default
- Implement code to strip the specific placeholder text
2024-01-02 21:37:02 +08:00
bobo
6af7ff68cc add commit prompt tests 2024-01-02 21:37:02 +08:00
bobo
86d087dd12 refactor: Improve readability and syntax in codebase
- Reformatted multiline strings for clarity in commit.py
- Applied consistent quotation marks for string literals in commit.py
- Introduced newlines between rpc_call decorator functions in services.py
2024-01-02 21:37:02 +08:00
bobo
ea809d8ac1 docs: Add docstring for read_prompt_from_file function
- Enhance read_prompt_from_file with a detailed docstring
- Specify parameters, return type, and possible raised exceptions
- Improve function's usability and maintainability with clear documentation
2024-01-02 21:37:02 +08:00
bobo
5891e22194 refactor: Update model configuration for diff prompt
- Change LLM model in commit prompt script from gpt-3.5-turbo to gpt-4
2024-01-02 21:37:02 +08:00
bobo
ce6fcddd82 feat: Added commit message prompt
- Added a new file `diffCommitMessagePrompt.txt` that provides guidelines for creating commit messages based on the provided diff.
- The guidelines include the structure of the commit message, summary of changes, and optional closing reference.
- The commit message should adhere to best practices, such as keeping the title under 50 characters and each summary line under 72 characters.
2024-01-02 21:37:02 +08:00
bobo
47e2bd9b9b feat: Add stream_out parameter to chat_completion_no_stream
- Add stream_out parameter to chat_completion_no_stream function
- Print delta content when stream_out is True
- Ensure seamless streaming of chat completion response
2024-01-02 21:37:02 +08:00
bobo
68b4258660 feat: Update commit.py to read prompt from file
- Removed unused imports and updated file reading functionality
- Set prompt from the diffCommitMessagePrompt.txt file
- Added error handling for file not found and reading exceptions
2024-01-02 21:37:02 +08:00
bobo
6de24f0d06 refactor: Refactor code to remove unused functions
- Removed unused functions `gpt_file_summary`, `gpt_file_group`, `get_file_summaries`, `get_file_summaries_and_groups`, `get_marked_files`, `generate_commit_message_base_file_summaries`
- Updated function `get_marked_files` to accept only `modified_files` and `staged_files`
- Updated function `generate_commit_message_base_diff` to provide a more descriptive start message for the commit workflow
2024-01-02 21:37:02 +08:00
bobo
960a8b9494 feat: Add progress indicators to commit script
- Implemented step-wise progress indicators in commit.py
- Enhanced user feedback during file modifications
- Improved commit message generation with feedback loops
2024-01-02 21:37:02 +08:00
244 changed files with 14253 additions and 1314 deletions

View File

@ -2,9 +2,9 @@ name: Dev CI
on:
pull_request:
branches: [ main ]
branches: [ main, scripts ]
push:
branches: [ main ]
branches: [ main, scripts ]
jobs:
lint-and-test:
@ -15,9 +15,6 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: "3.11.4"
- name: install workflows-command dependencies
run: |
pip install -r requirements.txt
- name: install dev dependencies
run: |
pip install -r requirements-dev.txt

34
.github/workflows/sync-to-gitlab.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: Sync to GitLab
on:
push:
branches:
- main
- scripts
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout GitHub repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Git
run: |
git config user.name "gh-action"
git config user.email "gh-action@merico.dev"
- name: Add GitLab remote
run: |
git remote add gitlab https://oauth2:${{ secrets.GITLAB_ACCESS_TOKEN }}@gitlab.com/devchat-ai/workflows.git
- name: Retry Command
uses: nick-invision/retry@v2
with:
timeout_minutes: 10
max_attempts: 3
command: |
git fetch gitlab &&
git push gitlab --force $GITHUB_REF_NAME:$GITHUB_REF_NAME

8
.gitignore vendored
View File

@ -1,4 +1,12 @@
.vscode
__pycache__/
.DS_Store
tmp/
cache/
custom/*
!custom/config.yml.example
user_settings.yml
.aider*

View File

@ -1,20 +1,23 @@
.PHONY: setup-dev check fix
div = $(shell printf '=%.0s' {1..120})
setup-dev:
@echo "Setting up development environment..."
@echo "Installing dev dependencies..."
@~/.chat/mamba/envs/devchat-commands/bin/pip install -r requirements-dev.txt
@pip install -r requirements-dev.txt
@echo "Done!"
T="."
check:
@echo ${div}
~/.chat/mamba/envs/devchat-commands/bin/python -m ruff check .
~/.chat/mamba/envs/devchat-commands/bin/python -m ruff format . --check
ruff check $(T)
ruff format $(T) --check
@echo "Done!"
fix:
@echo ${div}
~/.chat/mamba/envs/devchat-commands/bin/python -m ruff format .
ruff format $(T)
@echo ${div}
~/.chat/mamba/envs/devchat-commands/bin/python -m ruff check . --fix
ruff check $(T) --fix
@echo "Done!"

View File

@ -1,9 +1,2 @@
# workflows
DevChat workflows (the `sys` directory)
## Quick Start
```shell
cd ~/.chat/workflows
git clone https://github.com/devchat-ai/workflows.git sys
```
DevChat workflows management for workflow engine 2.0.

View File

@ -1 +0,0 @@
description: Generate code with a general template embedded into the prompt.

View File

@ -1,28 +0,0 @@
As a software developer assistant, your tasks are to:
- Provide a clear and concise response to address the user's requirements.
- Write code and give advice based on given code or information in the <context> if provided.
- Follow language-specific best practices and common coding standards.
When responding:
1. First summarize the requirements or provided information in your own words.
The summary should better be written in bullet points (excluding code).
2. When modifying the provided code, include the entire modified functions, but exclude any unmodified functions.
If any global statements are changed, include the full global statements; otherwise, do not include them.
3. Enclose code or changes within blocks using triple backticks (```), and include the programming language and the file path.
For example:
```python path=./path/to/file.py
print("Hello, World!")
```
Do your best to deduce the file path based on the given <context> or previous messages.
If you are still uncertain about the file path of the code, feel free to omit it.
4. Use separate code blocks for different files.
5. When providing a suggestion or instruction, begin by explaining the reason behind it.
6. You may not receive all the direct information needed for your task.
Analyze the given <context> to understand how existing code was written, and use this knowledge for your task.
7. Note that not all previous messages or contexts are necessarily relevant.
8. Respond in the language of the request.
You may encounter duplicate or conflicting messages or contexts, and the later ones should be considered as the most accurate.
If you need more information, ask for it.

View File

@ -1 +0,0 @@
description: Generate code with a Python-specific template embedded into the prompt.

View File

@ -1,5 +0,0 @@
When writing Python code, maintain compliance with PEP-8 guidelines:
- Include type hints where appropriate.
- Provide docstrings for classes and functions.
- Specify an encoding when opening documents. E.g., `open(file_path, encoding="utf-8")`.
- Follow other best practices in PEP-8.

View File

@ -1,5 +0,0 @@
description: Writes a well-formatted commit message for selected code changes and commits them via Git. Include an issue number if desired (e.g., input "/commit to close #12").
hint: to close Issue #issue_number
input: optional
steps:
- run: $devchat_python $command_path/commit.py "$input" "english"

View File

@ -1,485 +0,0 @@
# flake8: noqa: E402
import os
import re
import sys
import json
import subprocess
from typing import List
sys.path.append(os.path.join(os.path.dirname(__file__), "..", "libs"))
sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "libs"))
sys.path.append(os.path.dirname(__file__))
from ui_utils import ui_checkbox_select, ui_text_edit, CheckboxOption # noqa: E402
from llm_api import chat_completion_no_stream, chat_completion_no_stream_return_json # noqa: E402
from ide_services.services import log_info
from prompts import (
PROMPT_SUMMARY_FOR_FILES,
PROMPT_GROUP_FILES,
PROMPT_COMMIT_MESSAGE_BY_DIFF_USER_INPUT,
PROMPT_COMMIT_MESSAGE_BY_SUMMARY_USER_INPUT,
PROMPT_SUMMARY_FOR_FILES_RETRY,
PROMPT_GROUP_FILES_RETRY,
prompt_summary_for_files_llm_config,
prompt_group_files_llm_config,
prompt_commit_message_by_diff_user_input_llm_config,
prompt_commit_message_by_summary_user_input_llm_config,
)
language = ""
def assert_value(value, message):
"""
判断给定的value是否为True如果是则输出指定的message并终止程序
Args:
value: 用于判断的值
message: 如果value为True时需要输出的信息
Returns:
无返回值
"""
if value:
print(message, file=sys.stderr, flush=True)
sys.exit(-1)
def decode_path(encoded_path):
octal_pattern = re.compile(r"\\[0-7]{3}")
if octal_pattern.search(encoded_path):
bytes_path = encoded_path.encode("utf-8").decode("unicode_escape").encode("latin1")
decoded_path = bytes_path.decode("utf-8")
return decoded_path
else:
return encoded_path
def get_modified_files():
"""
获取当前修改文件列表以及已经staged的文件列表
Args:
Returns:
tuple: 包含两个list的元组第一个list包含当前修改过的文件第二个list包含已经staged的文件
"""
""" 获取当前修改文件列表以及已经staged的文件列表"""
output = subprocess.check_output(["git", "status", "-s", "-u"], text=True, encoding="utf-8")
lines = output.split("\n")
modified_files = []
staged_files = []
def strip_file_name(file_name):
file = file_name.strip()
if file.startswith('"'):
file = file[1:-1]
return file
for line in lines:
if len(line) > 2:
status, filename = line[:2], decode_path(line[3:])
# check wether filename is a directory
if os.path.isdir(filename):
continue
modified_files.append(os.path.normpath(strip_file_name(filename)))
if status == "M " or status == "A ":
staged_files.append(os.path.normpath(strip_file_name(filename)))
return modified_files, staged_files
def gpt_file_summary(diff, diff_files, user_input):
"""
生成GPT对话获取文件差异内容的摘要
Args:
diff (str): 文件差异内容
diff_files (List[str]): 文件差异列表
user_input (str): 用户输入
Returns:
dict: 文件路径作为键摘要内容作为值的字典
"""
global language
prompt = PROMPT_SUMMARY_FOR_FILES.replace("{__DIFF__}", f"{diff}").replace(
"{__USER_INPUT__}", f"{user_input}"
)
messages = [
{
"role": "user",
"content": prompt
+ (" \nPlease response summaries in chinese" if language == "chinese" else ""),
}
]
normpath_summaries = {}
retry_times = 0
while retry_times < 3:
retry_times += 1
file_summaries = chat_completion_no_stream_return_json(
messages, prompt_summary_for_files_llm_config
)
if not file_summaries:
continue
for key, value in file_summaries.items():
normpath_summaries[os.path.normpath(key)] = value
missed_files = [file for file in diff_files if file not in normpath_summaries]
if len(missed_files) > 0:
prompt_retry = PROMPT_SUMMARY_FOR_FILES_RETRY.replace(
"{__MISSED_FILES__}", f"{missed_files}"
)
messages.append({"role": "assistant", "content": json.dumps(file_summaries)})
messages.append(
{
"role": "user",
"content": prompt_retry
+ (" \nPlease response summaries in chinese" if language == "chinese" else ""),
}
)
else:
break
return normpath_summaries
def gpt_file_group(diff, diff_files):
"""
根据diff和diff_files列表对文件进行分组返回分组结果
Args:
diff (str): 差异信息
diff_files (List[str]): 文件列表
Returns:
List[Dict]: 文件分组结果每个分组是一个字典包含"name""files"两个键值对
分别表示分组名称和该分组下的文件列表
"""
prompt = PROMPT_GROUP_FILES.replace("{__DIFF__}", f"{diff}")
messages = [{"role": "user", "content": prompt}]
file_groups = []
retry_times = 0
while retry_times < 3:
retry_times += 1
file_groups = chat_completion_no_stream_return_json(messages, prompt_group_files_llm_config)
if not file_groups:
continue
if "groups" in file_groups:
file_groups = file_groups["groups"]
grouped_files = []
for group in file_groups:
grouped_files.extend(group["files"])
missed_files = [file for file in diff_files if file not in grouped_files]
if len(missed_files) > 0:
prompt_retry = PROMPT_GROUP_FILES_RETRY.replace("{__MISSED_FILES__}", f"{missed_files}")
messages.append({"role": "assistant", "content": json.dumps(file_groups)})
messages.append({"role": "user", "content": prompt_retry})
else:
break
return file_groups
def get_file_summaries(modified_files, staged_files, user_input):
"""
计算git暂存区文件的差异并生成对应的AI模型输入格式
Args:
modified_files (list): 当前工作区的修改文件列表
staged_files (list): 已暂存文件列表
user_input (str): 用户输入信息
Returns:
dict: AI模型输出格式包含normpath_summaries和modified_files两个key-value对
"""
diffs = []
for file in modified_files:
if file not in staged_files:
subprocess.check_output(["git", "add", file])
diff = subprocess.check_output(["git", "diff", "--cached", file])
if file not in staged_files:
subprocess.check_output(["git", "reset", file])
diffs.append(diff.decode("utf-8"))
# total_diff = subprocess.check_output(["git", "diff", "HEAD"])
total_diff_decoded = "\n".join(diffs) # total_diff.decode('utf-8')
if len(total_diff_decoded) > 15000:
print("Current diff length:", len(total_diff_decoded), flush=True)
return {}
# 在prompt中明确处置AI模型的输出格式需求
normpath_summaries = gpt_file_summary(total_diff_decoded, modified_files, user_input)
return normpath_summaries
def get_file_summaries_and_groups(modified_files, staged_files, user_input):
"""
获取已修改文件的摘要和分组
Args:
modified_files (List[str]): 已修改的文件列表
staged_files (List[str]): 已暂存的文件列表
user_input (str): 用户输入
Returns:
Tuple[Dict[str, Any], List[Dict[str, Any]]]: 包含以下两个元素的元组
- 文件摘要信息字典类型键为文件路径值为该文件对应的摘要信息
- 文件分组信息列表类型每个元素为包含以下三个键值对的字典
* group_id组ID
* files属于该分组的文件列表
* summary该分组的摘要信息
"""
diffs = []
for file in modified_files:
if file not in staged_files:
subprocess.check_output(["git", "add", file])
diff = subprocess.check_output(["git", "diff", "--cached", file])
if file not in staged_files:
subprocess.check_output(["git", "reset", file])
diffs.append(diff.decode("utf-8"))
# total_diff = subprocess.check_output(["git", "diff", "HEAD"])
total_diff_decoded = "\n".join(diffs) # total_diff.decode('utf-8')
if len(total_diff_decoded) > 15000:
print("Current diff length:", len(total_diff_decoded), flush=True)
return {}, []
# 在prompt中明确处置AI模型的输出格式需求
normpath_summaries = gpt_file_summary(total_diff_decoded, modified_files, user_input)
print(
f"""
``` file summary
{json.dumps(normpath_summaries, indent=4)}
```
"""
)
# 通过AI模型对提交文件进行分组分组的依据是按修改内容的关联性。
file_groups = gpt_file_group(total_diff_decoded, modified_files)
print(
f"""
``` group
{json.dumps(file_groups, indent=4)}
```
"""
)
return normpath_summaries, file_groups
def get_marked_files(modified_files, staged_files, file_summaries):
"""
根据给定的参数获取用户选中以供提交的文件
Args:
modified_files (List[str]): 用户已修改文件列表
staged_files (List[str]): 用户已staged文件列表
file_summaries (Dict[str, str]): 文件摘要信息key为文件名value为摘要信息
file_groups (List[Dict[str, Any]]): 文件分组信息每个元素是一个字典
包含两个key值分别为 "importance_level" "files"
分别表示文件的重要程度和该重要程度下的文件列表
Returns:
List[str]: 用户选中的文件列表
"""
options: List[CheckboxOption] = []
options += [
CheckboxOption(file, file + " - " + file_summaries.get(file, ""), "Staged", True)
for file in staged_files
]
options += [
CheckboxOption(file, file + " - " + file_summaries.get(file, ""), "Unstaged", False)
for file in modified_files
if file not in staged_files
]
selected_files = ui_checkbox_select("Select the files you've changed that you wish to include in this commit, then click 'Submit'.", options)
return selected_files
def rebuild_stage_list(user_files):
"""
根据用户选中文件重新构建stage列表
Args:
user_files: 用户选中的文件列表
Returns:
None
"""
# Unstage all files
subprocess.check_output(["git", "reset"])
# Stage all user_files
for file in user_files:
os.system(f'git add "{file}"')
def get_diff():
"""
获取暂存区文件的Diff信息
Args:
Returns:
bytes: 返回bytes类型是git diff --cached命令的输出结果
"""
return subprocess.check_output(["git", "diff", "--cached"])
def generate_commit_message_base_diff(user_input, diff):
"""
根据diff信息通过AI生成一个commit消息
Args:
user_input (str): 用户输入的commit信息
diff (str): 提交的diff信息
Returns:
str: 生成的commit消息
"""
global language
language_prompt = (
"You must response commit message in chinese。\n" if language == "chinese" else ""
)
prompt = PROMPT_COMMIT_MESSAGE_BY_DIFF_USER_INPUT.replace("{__DIFF__}", f"{diff}").replace(
"{__USER_INPUT__}", f"{user_input + language_prompt}"
)
if len(str(prompt)) > 10000:
print(
"Due to the large size of the diff data, "
"generating a commit message through AI would be very costly, therefore, "
"it is not recommended to use AI for generating the description. "
"Please manually edit the commit message before submitting."
)
return {"content": ""}
messages = [{"role": "user", "content": prompt}]
response = chat_completion_no_stream(
messages, prompt_commit_message_by_diff_user_input_llm_config
)
assert_value(not response, "")
return response
def generate_commit_message_base_file_summaries(user_input, file_summaries):
"""
根据文件摘要生成通过AI生成的提交消息
Args:
user_input (str): 用户输入
file_summaries (list[dict]): 文件摘要列表
Returns:
str: 提交消息
"""
global language
language_prompt = (
"Please response commit message in chinese.\n" if language == "chinese" else ""
)
prompt = PROMPT_COMMIT_MESSAGE_BY_SUMMARY_USER_INPUT.replace(
"{__USER_INPUT__}", f"{user_input}"
).replace("{__FILE_SUMMARY__}", f"{json.dumps(file_summaries, indent=4)}")
# Call AI model to generate commit message
messages = [{"role": "user", "content": language_prompt + prompt}]
response = chat_completion_no_stream(
messages, prompt_commit_message_by_summary_user_input_llm_config
)
assert_value(not response, "")
return response
def display_commit_message_and_commit(commit_message):
"""
展示提交信息并提交
Args:
commit_message: 提交信息
Returns:
None
"""
new_commit_message = ui_text_edit("I've drafted a commit message for the code changes you selected. You can edit this message in the widget below. After confirming the message, click 'Commit', and I will proceed with the commit using this message.", commit_message)
if not new_commit_message:
return
subprocess.check_output(["git", "commit", "-m", new_commit_message])
def check_git_installed():
try:
subprocess.run(
["git", "--version"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=True,
)
return True
except subprocess.CalledProcessError:
print("Git is not installed on your system.", file=sys.stderr, flush=True)
except FileNotFoundError:
print("Git is not installed on your system.", file=sys.stderr, flush=True)
except Exception:
print("Git is not installed on your system.", file=sys.stderr, flush=True)
return False
def main():
global language
try:
log_info("Start commit workflow ...")
# Ensure enough command line arguments are provided
if len(sys.argv) < 3:
print("Usage: python script.py <user_input> <language>", file=sys.stderr, flush=True)
sys.exit(-1)
user_input = sys.argv[1]
language = sys.argv[2]
if not check_git_installed():
sys.exit(-1)
modified_files, staged_files = get_modified_files()
if len(modified_files) == 0:
print("No files to commit.", file=sys.stderr, flush=True)
sys.exit(-1)
file_summaries = get_file_summaries(modified_files, staged_files, user_input)
selected_files = get_marked_files(modified_files, staged_files, file_summaries)
if not selected_files:
print("No files selected, commit aborted.")
return
rebuild_stage_list(selected_files)
summaries_for_select_files = {
file: file_summaries[file] for file in selected_files if file in file_summaries
}
if len(summaries_for_select_files.keys()) < len(selected_files):
diff = get_diff()
commit_message = generate_commit_message_base_diff(user_input, diff)
else:
commit_message = generate_commit_message_base_file_summaries(
user_input, summaries_for_select_files
)
display_commit_message_and_commit(commit_message["content"])
sys.exit(0)
except Exception as err:
print("Exception:", err, file=sys.stderr, flush=True)
sys.exit(-1)
if __name__ == "__main__":
main()

View File

@ -1,183 +0,0 @@
# ruff: noqa
# summary changes for files based diff
# diff => {__DIFF__}
PROMPT_SUMMARY_FOR_FILES = """
Objective: **Create concise summaries for each modified file based on the provided diff changes and any additional user input.**
**Instructions:**
1. Review the diff changes and user input to understand the context and content of the modifications.
2. Write a summary for each file that has been modified, capturing the essence of the changes.
3. Use the filename from the diff as the key, and the summary as the value in the output JSON object.
**Response Format:**
```json
{
\"filename1 with path\": \"Summary of the changes made in filename1\",
\"filename2 with path\": \"Summary of the changes made in filename2\",
...
}
```
**Constraints:**
- Ensure that the summaries are accurate and reflect the changes made.
- Ensure that the summary is concise and does not exceed 200 characters.
- The response must be in JSON format, with filenames as keys and summaries as values.
- Do not include any additional text or output outside of the JSON format.
- The keys in the JSON object should correspond to real filenames present in the diff changes.
**User Input:**
```
{__USER_INPUT__}
```
**Diff Changes:**
```
{__DIFF__}
```
---
Based on the provided diff changes and any additional user input, please generate a JSON object containing summaries for each modified file.
"""
prompt_summary_for_files_llm_config = {"model": "gpt-3.5-turbo-1106"}
# ask summaries for missed files
# missed files => {__MISSED_FILES__}
PROMPT_SUMMARY_FOR_FILES_RETRY = """
The following files are missed in your summary:
{__MISSED_FILES__}
"""
# group changes for files based diff
# diff => {__DIFF__}
PROMPT_GROUP_FILES = """
Objective: **Categorize the modified files from a diff into groups based on their relevance to each other, and assign an importance level to each group. Limit the number of groups to a maximum of three.**
**Instructions:**
1. **Analysis:** Review the diff content to discern related changes. Group files that are part of the same logical change, ensuring that the code will compile and run correctly post-commit.
2. **Atomic Grouping:** Aim for the smallest possible groups. Each should represent a single, cohesive modification for clarity and independent comprehension. Do not exceed three groups in total.
3. **Importance Level:** Rate each group's importance on a scale of 1 to 10, with 1 being the most critical. Consider the impact on functionality, urgency of fixes, and feature significance.
**Response Format:**
- Use JSON format for your response.
- Include all files from the diff content.
- Structure the JSON as shown in the example below.
**Example Output:**
```json
{
"groups": [
{\"files\": [\"fileA\", \"fileB\"], \"group\": \"Feature Improvement\", \"importance_level\": 5},
{\"files\": [\"fileC\"], \"group\": \"Bug Fix\", \"importance_level\": 1},
{\"files\": [\"fileD\", \"fileE\"], \"group\": \"Code Refactoring\", \"importance_level\": 3}
]
}
```
**Constraints:**
- Ensure the JSON output is valid and contains no additional text or characters.
- Each group must be self-contained, with no cross-group dependencies.
- The importance level should accurately reflect the priority for committing the changes.
- The total number of groups must not exceed three.
- Follows the JSON structure shown in the example above.
**Diff Content:**
```
{__DIFF__}
```
---
Based on the provided diff content, group the files accordingly and assign an appropriate importance level to each group, following the instructions and constraints.
"""
prompt_group_files_llm_config = {"model": "gpt-3.5-turbo-1106"}
# re-group files based missed files
# missed files => {__MISSED_FILES__}
PROMPT_GROUP_FILES_RETRY = """
The following files are missed in your response:
{__MISSED_FILES__}
Please re-group the files again, don't miss any file.
"""
# generate commit message based diff and user_input
# diff => {__DIFF__}
# user_input => {__USER_INPUT__}
PROMPT_COMMIT_MESSAGE_BY_DIFF_USER_INPUT = """
Objective:** Create a commit message that concisely summarizes the changes made to the codebase as reflected by the provided diff. The commit message should also take into account any additional context or instructions given by the user.
**Commit Message Structure:**
1. **Title Line:** Start with a type from the following options: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, etc. Follow the type with a concise title. Format: `type: Title`. Only one title line is allowed.
2. **Summary:** Provide a summary of all changes in no more than three detailed message lines. Each line should be prefixed with a \"-\".
3. **Closing Reference (Optional):** If applicable, include a closing reference line in the format `Closes #IssueNumber`. Only include this if you know the exact issue number.
**Response Format:**
```
type: Title
Detail message line 1
Detail message line 2
Detail message line 3
Closes #IssueNumber
```
**Constraints:**
- Do not include markdown block flags (```) or the placeholder text \"commit_message\" in your response.
- Adhere to best practices for commit messages:
- Keep the title under 50 characters.
- Keep each summary line under 72 characters.
- If the exact issue number is unknown, omit the closing reference line.
**User Input:** `{__USER_INPUT__}`
**Code Changes:**
```
{__DIFF__}
```
---
Please use the above structure to generate a commit message that meets the specified criteria.
"""
prompt_commit_message_by_diff_user_input_llm_config = {"model": "gpt-3.5-turbo-1106"}
# generate commit message based file summary and user_input
# file_summary => {__FILE_SUMMARY__}
# user_input => {__USER_INPUT__}
PROMPT_COMMIT_MESSAGE_BY_SUMMARY_USER_INPUT = """
Objective:** Generate a commit message that accurately reflects the changes made to the codebase, as summarized by the AI-generated file summary and any additional user input.
**Commit Message Structure:**
1. **Title Line:** Begin with a type from the following options: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, etc. The title should be concise and informative. Format: `type: Title`. Only one title line is allowed.
2. **Summary:** Condense the changes into 1-3 detailed message lines, each beginning with a \"-\".
3. **Closing Reference (Optional):** If known, include a closing reference in the format `Closes #IssueNumber`. If the exact issue number is unknown, omit this line.
**Response Format:**
```
type: Title
Detail message line 1
Detail message line 2
Detail message line 3
Closes #IssueNumber
```
**Constraints:**
- Exclude markdown code block flags (```) and the placeholder \"commit_message\" from your response.
- Follow commit message best practices:
- Title line should be under 50 characters.
- Each summary line should be under 72 characters.
- If the issue number is not provided, do not include the closing reference line.
**User Input:** `{__USER_INPUT__}`
**File Summary:**
```
{__FILE_SUMMARY__}
```
---
Please create a commit message following the above guidelines based on the provided file summary and user input.
"""
prompt_commit_message_by_summary_user_input_llm_config = {"model": "gpt-4-1106-preview"}

View File

@ -1,5 +0,0 @@
description: 为你选定的代码变更生成格式规范的提交信息,并通过 Git 提交。如需要可包含对应 issue 编号(例如,输入“/commit to close #12”
hint: to close Issue #issue_number
input: optional
steps:
- run: $devchat_python $command_path/../commit.py "$input" "chinese"

View File

@ -1 +0,0 @@
description: Generate a commit message for the given git diff.

View File

@ -1,22 +0,0 @@
As a software developer assistant, your task is to provide clear and concise responses and write commit messages based on given code, requirements, or conversations.
Follow these guidelines:
1. A commit message should include a title and multiple body lines.
2. Adhere to best practices. Keep the title under 50 characters and each body line under 72 characters.
3. Format all commit messages by enclosing each message within a block of triple backticks (```), and include 'commitmsg' alongside the beginning backticks.
For example:
```commitmsg
The title
- The first bullet point.
- The second bullet point.
```
4. Utilize the diff output in the <context> to create the summary.
5. Utilize the previous messages, if provided in the end of this prompt, to improve the title or bullet points by clearly conveying the intention of code changes.
Note that not all previous messages are necessarily relevant.
For example, disregard any previous commit messages you have written.
You may encounter duplicate or conflicting messages, and the later messages should be considered as the most accurate.
6. Prioritize the diff output in the given <context> and focus on actual code changes.
Disregard any previous messages unrelated to the diff output.
If you need more information, ask for it.

3
community/README.md Normal file
View File

@ -0,0 +1,3 @@
# Workflows
Workflows for DevChat contributed by the community.

25
community/aider/README.md Normal file
View File

@ -0,0 +1,25 @@
### aider 操作指南
aider是一个AI辅助的代码编辑工具,可以根据自然语言指令修改代码。
用途:
根据用户提供的指令,自动分析和修改已添加到aider中的代码文件。
使用方法:
1. 使用 `/aider.files.add` 命令添加需要处理的文件
2. 输入 `/aider <message>` 命令,其中 `<message>` 是你想要aider执行的任务描述
3. 等待aider生成建议的更改
4. 在IDE中查看每个文件的Diff视图,选择是否接受修改
5. 对于多个文件的更改,系统会在每个文件之后询问是否继续查看下一个文件的更改
注意事项:
- 使用前必须先添加文件到aider,否则会提示使用 'aider.files.add' 命令
- 可以使用 `aider.files.remove` 命令从aider中移除文件
- 所有更改都会在IDE中以Diff视图形式展示,你可以决定是否应用这些更改
- aider使用OpenAI的API,请确保已正确设置API密钥
示例:
/aider 重构这段代码以提高性能
额外信息:
aider支持多种编程语言,可以执行代码重构、bug修复、性能优化等任务。它会分析当前添加的所有文件,并提供整体的改进建议。

213
community/aider/command.py Normal file
View File

@ -0,0 +1,213 @@
import json
import os
import subprocess
import sys
from devchat.ide import IDEService
from lib.chatmark import Button
GLOBAL_CONFIG_PATH = os.path.join(os.path.expanduser("~"), ".chat", ".workflow_config.json")
def save_config(config_path, item, value):
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config = json.load(f)
else:
config = {}
config[item] = value
with open(config_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=4)
def write_python_path_to_config():
"""
Write the current system Python path to the configuration.
"""
python_path = sys.executable
save_config(GLOBAL_CONFIG_PATH, "aider_python", python_path)
print(f"Python path '{python_path}' has been written to the configuration.")
def get_aider_files():
"""
.chat/.aider_files文件中读取aider文件列表
"""
aider_files_path = os.path.join(".chat", ".aider_files")
if not os.path.exists(aider_files_path):
return []
with open(aider_files_path, "r") as f:
return [line.strip() for line in f if line.strip()]
def run_aider(message, files):
"""
运行aider命令
"""
python = sys.executable
model = os.environ.get("LLM_MODEL", "gpt-3.5-turbo-1106")
cmd = [
python,
"-m",
"aider",
"--model",
f"openai/{model}",
"--yes",
"--no-auto-commits",
"--dry-run",
"--no-pretty",
"--message",
message,
] + files
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
has_started = False
aider_output = ""
for line in process.stdout:
if "run with --help" in line or 'run "aider --help"' in line:
has_started = True
continue
if has_started:
aider_output += line
print(line, end="", flush=True)
return_code = process.wait()
if return_code != 0:
for line in process.stderr:
print(f"Error: {line.strip()}", file=sys.stderr)
sys.exit(return_code)
return aider_output
def apply_changes(changes, files):
"""
应用aider生成的更改
"""
changes_file = ".chat/changes.txt"
os.makedirs(os.path.dirname(changes_file), exist_ok=True)
with open(changes_file, "w") as f:
f.write(changes)
python = sys.executable
model = os.environ.get("LLM_MODEL", "gpt-3.5-turbo-1106")
cmd = [
python,
"-m",
"aider",
"--model",
f"openai/{model}",
"--yes",
"--no-auto-commits",
"--apply",
changes_file,
] + files
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
has_started = False
for line in process.stdout:
if "Model:" in line:
has_started = True
continue
if has_started:
print(line, end="", flush=True)
return_code = process.wait()
if return_code != 0:
for line in process.stderr:
print(f"Error: {line.strip()}", file=sys.stderr)
sys.exit(return_code)
os.remove(changes_file)
def main():
"""
Main function to run the aider command.
This function performs the following tasks:
1. Checks for correct command-line usage
2. Writes the current Python path to the configuration
3. Retrieves the list of files to be processed
4. Runs the aider command with the given message
5. Applies the suggested changes
6. Displays the differences in the IDE
Usage: python command.py <message>
"""
if len(sys.argv) < 2:
print("Usage: python command.py <message>", file=sys.stderr)
sys.exit(1)
write_python_path_to_config()
message = sys.argv[1]
files = get_aider_files()
if not files:
print(
"No files added to aider. Please add files using 'aider.files.add' command.",
file=sys.stderr,
)
sys.exit(1)
print("Running aider...\n", flush=True)
changes = run_aider(message, files)
if not changes:
print("No changes suggested by aider.")
sys.exit(0)
print("\nApplying changes...\n", flush=True)
# 保存原始文件内容
original_contents = {}
for file in files:
with open(file, "r") as f:
original_contents[file] = f.read()
# 应用更改
apply_changes(changes, files)
# 读取更新后的文件内容
updated_contents = {}
for file in files:
with open(file, "r") as f:
updated_contents[file] = f.read()
# 还原原始文件内容
for file in files:
with open(file, "w") as f:
f.write(original_contents[file])
# 使用 IDEService 展示差异
ide_service = IDEService()
for index, file in enumerate(files):
ide_service.diff_apply(file, updated_contents[file])
if index < len(files) - 1:
# 等待用户确认
button = Button(
["Show Next Changes", "Cancel"],
)
button.render()
idx = button.clicked
if idx == 0:
continue
else:
break
print("Changes have been displayed in the IDE.")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,9 @@
description: "aider command"
workflow_python:
env_name: devchat-aider-env
version: 3.11.0
dependencies: requirements.txt
input: required
help: README.md
steps:
- run: $workflow_python $command_path/command.py "$input"

View File

@ -0,0 +1,23 @@
### aider.files.add
这个命令用于将文件添加到aider的处理列表中。
用途:
添加指定文件到aider,使其包含在后续的aider操作中。
使用方法:
/aider.files.add <file_path>
参数:
- <file_path>: 要添加的文件路径(必需)
注意事项:
- 文件路径必须是有效的格式
- 已存在于列表中的文件不会重复添加
- 成功添加后会显示当前的aider文件列表
示例:
/aider.files.add src/main.py
额外信息:
这个命令会将文件路径保存到.chat/.aider_files文件中。如果.chat目录不存在,会自动创建。

View File

@ -0,0 +1,66 @@
import os
import sys
def is_valid_path(path):
"""
检查路径是否为有效的文件路径形式
"""
try:
# 尝试规范化路径
normalized_path = os.path.normpath(path)
# 检查路径是否是绝对路径或相对路径
return (
os.path.isabs(normalized_path)
or not os.path.dirname(normalized_path) == normalized_path
)
except Exception:
return False
def add_file(file_path):
# 1. 检查是否为有效的文件路径形式
if not is_valid_path(file_path):
print(f"Error: '{file_path}' is not a valid file path format.", file=sys.stderr)
sys.exit(1)
# 获取绝对路径
abs_file_path = file_path.strip()
# 2. 将新增文件路径存储到.chat/.aider_files文件中
aider_files_path = os.path.join(".chat", ".aider_files")
# 确保.chat目录存在
os.makedirs(os.path.dirname(aider_files_path), exist_ok=True)
# 读取现有文件列表
existing_files = set()
if os.path.exists(aider_files_path):
with open(aider_files_path, "r") as f:
existing_files = set(line.strip() for line in f)
# 添加新文件
existing_files.add(abs_file_path)
# 写入更新后的文件列表
with open(aider_files_path, "w") as f:
for file in sorted(existing_files):
f.write(f"{file}\n")
print(f"Added '{abs_file_path}' to aider files.")
print("\nCurrent aider files:")
for file in sorted(existing_files):
print(f"- {file}")
def main():
if len(sys.argv) != 2 or sys.argv[1].strip() == "":
print("Usage: /aider.files.add <file_path>", file=sys.stderr)
sys.exit(1)
file_path = sys.argv[1]
add_file(file_path)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: "add files to aider"
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,19 @@
### aider.files.list
这个命令用于列出当前在aider处理列表中的所有文件。
用途:
显示所有已添加到aider中的文件,提供当前aider正在处理的文件概览。
使用方法:
/aider.files.list
注意事项:
- 如果没有文件被添加到aider,会显示相应的提示消息
- 文件列表按字母顺序排序显示
示例:
/aider.files.list
额外信息:
这个命令会读取.chat/.aider_files文件的内容来获取文件列表。如果该文件不存在,会提示尚未添加任何文件。

View File

@ -0,0 +1,31 @@
import os
import sys
def list_files():
aider_files_path = os.path.join(".chat", ".aider_files")
# 确保.chat/.aider_files文件存在
if not os.path.exists(aider_files_path):
print("No files have been added to aider yet.")
sys.exit(0)
# 读取文件列表
with open(aider_files_path, "r") as f:
files = [line.strip() for line in f]
# 打印文件列表
if files:
print("Aider files:")
for file in sorted(files):
print(f"- {file}")
else:
print("No files found in aider.")
def main():
list_files()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,4 @@
description: "list files in aider"
help: README.md
steps:
- run: $devchat_python $command_path/command.py

View File

@ -0,0 +1,23 @@
### aider.files.remove
这个命令用于从aider处理列表中移除指定的文件。
用途:
将指定文件从aider的处理列表中删除,使其不再包含在后续的aider操作中。
使用方法:
/aider.files.remove <file_path>
参数:
- <file_path>: 要移除的文件路径(必需)
注意事项:
- 文件路径必须是有效的格式
- 如果指定的文件不在列表中,会显示相应的提示消息
- 成功移除后会显示更新后的aider文件列表
示例:
/aider.files.remove src/main.py
额外信息:
这个命令会更新.chat/.aider_files文件,从中删除指定的文件路径。如果文件不存在于列表中,操作会安全退出。

View File

@ -0,0 +1,72 @@
import os
import sys
def is_valid_path(path):
"""
检查路径是否为有效的文件路径形式
"""
try:
# 尝试规范化路径
normalized_path = os.path.normpath(path)
# 检查路径是否是绝对路径或相对路径
return (
os.path.isabs(normalized_path)
or not os.path.dirname(normalized_path) == normalized_path
)
except Exception:
return False
def remove_file(file_path):
# 1. 检查是否为有效的文件路径形式
if not is_valid_path(file_path):
print(f"Error: '{file_path}' is not a valid file path format.", file=sys.stderr)
sys.exit(1)
# 获取绝对路径
abs_file_path = file_path.strip()
# 2. 从.chat/.aider_files文件中移除指定文件路径
aider_files_path = os.path.join(".chat", ".aider_files")
# 确保.chat目录存在
if not os.path.exists(aider_files_path):
print(f"Error: '{aider_files_path}' does not exist.", file=sys.stderr)
sys.exit(1)
# 读取现有文件列表
existing_files = set()
with open(aider_files_path, "r") as f:
existing_files = set(line.strip() for line in f)
# 检查文件是否在列表中
if abs_file_path not in existing_files:
print(f"'{abs_file_path}' is not in aider files.")
sys.exit(0)
# 移除文件
existing_files.remove(abs_file_path)
# 写入更新后的文件列表
with open(aider_files_path, "w") as f:
for file in sorted(existing_files):
f.write(f"{file}\n")
print(f"Removed '{abs_file_path}' from aider files.")
print("\nCurrent aider files:")
for file in sorted(existing_files):
print(f"- {file}")
def main():
if len(sys.argv) != 2 or sys.argv[1].strip() == "":
print("Usage: /aider.files.remove <file_path>", file=sys.stderr)
sys.exit(1)
file_path = sys.argv[1]
remove_file(file_path)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: "remove files from aider"
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,2 @@
git+https://gitee.com/imlaji/aider.git@main
git+https://gitee.com/devchat-ai/devchat.git@aider

View File

@ -0,0 +1,24 @@
### code_task_summary
根据当前分支或指定的Issue,生成代码任务摘要。
#### 用途
- 自动生成简洁的代码任务描述
- 帮助开发者快速理解任务要点
- 用于更新项目配置或文档
#### 使用方法
执行命令: `/github.code_task_summary [issue_url]`
- 如不提供issue_url,将基于当前分支名称提取Issue信息
- 如提供issue_url,将直接使用该Issue的内容
#### 操作流程
1. 获取Issue信息
2. 生成代码任务摘要
3. 允许用户编辑摘要
4. 更新项目配置文件
#### 注意事项
- 确保Git仓库配置正确
- 需要有效的GitHub Token以访问API

View File

@ -0,0 +1,120 @@
import json
import os
import sys
from devchat.llm import chat_json
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, ui_edit # noqa: E402
from git_api import ( # noqa: E402
check_git_installed,
get_current_branch,
get_github_repo,
get_issue_info,
is_issue_url,
read_issue_by_url,
)
def extract_issue_id(branch_name):
if "#" in branch_name:
return branch_name.split("#")[-1]
return None
# Function to generate a random branch name
PROMPT = (
"You are a coding engineer, required to summarize the ISSUE description into a coding task description of no more than 50 words. \n" # noqa: E501
"The ISSUE description is as follows: {issue_body}, please summarize the corresponding coding task description.\n" # noqa: E501
'The coding task description should be output in JSON format, in the form of: {{"summary": "code task summary"}}\n' # noqa: E501
)
@chat_json(prompt=PROMPT)
def generate_code_task_summary(issue_body):
pass
@ui_edit(ui_type="editor", description="Edit code task summary:")
def edit_code_task_summary(task_summary):
pass
def get_issue_or_task(task):
if is_issue_url(task):
issue = read_issue_by_url(task.strip())
assert_exit(not issue, "Failed to read issue.", exit_code=-1)
return json.dumps({"id": issue["number"], "title": issue["title"], "body": issue["body"]})
else:
return task
def get_issue_json(issue_id, task):
issue = {"id": "no issue id", "title": "", "body": task}
if issue_id:
issue = get_issue_info(issue_id)
assert_exit(not issue, "Failed to retrieve issue with ID: {issue_id}", exit_code=-1)
issue = {
"id": issue_id,
"html_url": issue["html_url"],
"title": issue["title"],
"body": issue["body"],
}
return issue
# Main function
def main():
print("Start update code task summary ...", end="\n\n", flush=True)
is_git_installed = check_git_installed()
assert_exit(not is_git_installed, "Git is not installed.", exit_code=-1)
task = sys.argv[1]
repo_name = get_github_repo()
branch_name = get_current_branch()
issue_id = extract_issue_id(branch_name)
# print basic info, repo_name, branch_name, issue_id
print("repo name:", repo_name, end="\n\n")
print("branch name:", branch_name, end="\n\n")
print("issue id:", issue_id, end="\n\n")
issue = get_issue_json(issue_id, task)
assert_exit(not issue["body"], "Failed to retrieve issue with ID: {issue_id}", exit_code=-1)
# Generate 5 branch names
print("Generating code task summary ...", end="\n\n", flush=True)
code_task_summary = generate_code_task_summary(issue_body=issue["body"])
assert_exit(not code_task_summary, "Failed to generate code task summary.", exit_code=-1)
assert_exit(
not code_task_summary.get("summary", None),
"Failed to generate code task summary, missing summary field in result.",
exit_code=-1,
)
code_task_summary = code_task_summary["summary"]
# Select branch name
code_task_summary = edit_code_task_summary(code_task_summary)
assert_exit(not code_task_summary, "Failed to edit code task summary.", exit_code=-1)
code_task_summary = code_task_summary[0]
# create and checkout branch
print("Updating code task summary to config:")
config_file = os.path.join(".chat", "complete.config")
if os.path.exists(config_file):
with open(config_file, "r") as f:
config = json.load(f)
config["taskDescription"] = code_task_summary
else:
config = {"taskDescription": code_task_summary}
with open(config_file, "w") as f:
json.dump(config, f, indent=4)
print("Code task summary has updated")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Generate code task summary.'
input: optional
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1 @@
description: Root of github commands.

View File

@ -0,0 +1,23 @@
### commit
自动生成提交信息并执行Git提交。
#### 用途
- 生成规范的提交信息
- 简化Git提交流程
- 保持提交历史的一致性
#### 使用方法
执行命令: `/github.commit [message]`
- message: 可选的用户输入,用于辅助生成提交信息
#### 操作流程
1. 选择要提交的文件
2. 生成提交信息
3. 允许用户编辑提交信息
4. 执行Git提交
#### 注意事项
- 确保已选择需要提交的文件
- 生成的提交信息可能需要进一步修改以符合项目规范

View File

@ -0,0 +1,6 @@
description: 'Writes a well-formatted commit message for selected code changes and commits them via Git. Include an issue number if desired (e.g., input "/commit to close #12").'
hint: to close Issue #issue_number
input: optional
help: README.md
steps:
- run: $devchat_python $command_path/commit.py "$input" "english"

View File

@ -0,0 +1,539 @@
# flake8: noqa: E402
import os
import re
import subprocess
import sys
from devchat.llm import chat_completion_stream
from lib.chatmark import Button, Checkbox, Form, TextEditor
from lib.ide_service import IDEService
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit # noqa: E402
from git_api import (
get_github_repo,
get_github_repo_issues,
get_github_username,
get_issue_info,
subprocess_check_output,
subprocess_run,
)
diff_too_large_message_en = (
"Commit failed. The modified content is too long "
"and exceeds the model's length limit. "
"You can try to make partial changes to the file and submit multiple times. "
"Making small changes and submitting them multiple times is a better practice."
)
diff_too_large_message_zh = (
"提交失败。修改内容太长,超出模型限制长度,"
"可以尝试选择部分修改文件多次提交,小修改多提交是更好的做法。"
)
COMMIT_PROMPT_LIMIT_SIZE = 20000
def extract_markdown_block(text):
"""
Extracts the first Markdown code block from the given text without the language specifier.
:param text: A string containing Markdown text
:return: The content of the first Markdown code block, or None if not found
"""
# 正则表达式匹配Markdown代码块忽略可选的语言类型标记
pattern = r"```(?:\w+)?\s*\n(.*?)\n```"
match = re.search(pattern, text, re.DOTALL)
if match:
# 返回第一个匹配的代码块内容,去除首尾的反引号和语言类型标记
# 去除块结束标记前的一个换行符,但保留其他内容
block_content = match.group(1)
return block_content
else:
return text
# Read the prompt from the diffCommitMessagePrompt.txt file
def read_prompt_from_file(filename):
"""
Reads the content of a file and returns it as a string.
This function is designed to read a prompt message from a text file.
It expects the file to be encoded in UTF-8 and will strip any leading
or trailing whitespace from the content of the file. If the file does
not exist or an error occurs during reading, the function logs an error
message and exits the script.
Parameters:
- filename (str): The path to the file that contains the prompt message.
Returns:
- str: The content of the file as a string.
Raises:
- FileNotFoundError: If the file does not exist.
- Exception: If any other error occurs during file reading.
"""
try:
with open(filename, "r", encoding="utf-8") as file:
return file.read().strip()
except FileNotFoundError:
IDEService().ide_logging(
"error",
f"File {filename} not found. "
"Please make sure it exists in the same directory as the script.",
)
sys.exit(1)
except Exception as e:
IDEService().ide_logging(
"error", f"An error occurred while reading the file {filename}: {e}"
)
sys.exit(1)
# Read the prompt content from the file
script_path = os.path.dirname(__file__)
PROMPT_FILENAME = os.path.join(script_path, "diffCommitMessagePrompt.txt")
PROMPT_COMMIT_MESSAGE_BY_DIFF_USER_INPUT = read_prompt_from_file(PROMPT_FILENAME)
prompt_commit_message_by_diff_user_input_llm_config = {
"model": os.environ.get("LLM_MODEL", "gpt-3.5-turbo-1106")
}
language = ""
def assert_value(value, message):
"""
判断给定的value是否为True如果是则输出指定的message并终止程序
Args:
value: 用于判断的值
message: 如果value为True时需要输出的信息
Returns:
无返回值
"""
if value:
print(message, file=sys.stderr, flush=True)
sys.exit(-1)
def decode_path(encoded_path):
octal_pattern = re.compile(r"\\[0-7]{3}")
if octal_pattern.search(encoded_path):
bytes_path = encoded_path.encode("utf-8").decode("unicode_escape").encode("latin1")
decoded_path = bytes_path.decode("utf-8")
return decoded_path
else:
return encoded_path
def get_modified_files():
"""
获取当前修改文件列表以及已经staged的文件列表
Args:
Returns:
tuple: 包含两个list的元组第一个list包含当前修改过的文件第二个list包含已经staged的文件
"""
""" 获取当前修改文件列表以及已经staged的文件列表"""
output = subprocess_check_output(["git", "status", "-s", "-u"], text=True, encoding="utf-8")
lines = output.split("\n")
modified_files = []
staged_files = []
def strip_file_name(file_name):
file = file_name.strip()
if file.startswith('"'):
file = file[1:-1]
return file
for line in lines:
if len(line) > 2:
status, filename = line[:2], decode_path(line[3:])
# check wether filename is a directory
if os.path.isdir(filename):
continue
modified_files.append(os.path.normpath(strip_file_name(filename)))
if status == "M " or status == "A " or status == "D ":
staged_files.append(os.path.normpath(strip_file_name(filename)))
return modified_files, staged_files
def get_marked_files(modified_files, staged_files):
"""
根据给定的参数获取用户选中以供提交的文件
Args:
modified_files (List[str]): 用户已修改文件列表
staged_files (List[str]): 用户已staged文件列表
Returns:
List[str]: 用户选中的文件列表
"""
# Create two Checkbox instances for staged and unstaged files
staged_checkbox = Checkbox(staged_files, [True] * len(staged_files))
unstaged_files = [file for file in modified_files if file not in staged_files]
unstaged_checkbox = Checkbox(unstaged_files, [False] * len(unstaged_files))
# Create a Form with both Checkbox instances
form_list = []
if len(staged_files) > 0:
form_list.append("Staged:\n\n")
form_list.append(staged_checkbox)
if len(unstaged_files) > 0:
form_list.append("Unstaged:\n\n")
form_list.append(unstaged_checkbox)
form = Form(form_list, submit_button_name="Continue")
# Render the Form and get user input
form.render()
# Retrieve the selected files from both Checkbox instances
staged_checkbox_selections = staged_checkbox.selections if staged_checkbox.selections else []
unstaged_selections = unstaged_checkbox.selections if unstaged_checkbox.selections else []
selected_staged_files = [staged_files[idx] for idx in staged_checkbox_selections]
selected_unstaged_files = [unstaged_files[idx] for idx in unstaged_selections]
# Combine the selections from both checkboxes
selected_files = selected_staged_files + selected_unstaged_files
return selected_files
def rebuild_stage_list(user_files):
"""
根据用户选中文件重新构建stage列表
Args:
user_files: 用户选中的文件列表
Returns:
None
"""
# Unstage all files
subprocess_check_output(["git", "reset"])
# Stage all user_files
for file in user_files:
subprocess_run(["git", "add", file])
def get_diff():
"""
获取暂存区文件的Diff信息
Args:
Returns:
bytes: 返回bytes类型是git diff --cached命令的输出结果
"""
return subprocess_check_output(["git", "diff", "--cached"])
def get_current_branch():
try:
# 使用git命令获取当前分支名称
result = subprocess_check_output(
["git", "branch", "--show-current"], stderr=subprocess.STDOUT
).strip()
# 将结果从bytes转换为str
current_branch = result.decode("utf-8")
return current_branch
except subprocess.CalledProcessError:
# 如果发生错误,打印错误信息
return None
except FileNotFoundError:
# 如果未找到git命令可能是没有安装git或者不在PATH中
return None
def generate_commit_message_base_diff(user_input, diff, issue):
"""
根据diff信息通过AI生成一个commit消息
Args:
user_input (str): 用户输入的commit信息
diff (str): 提交的diff信息
Returns:
str: 生成的commit消息
"""
global language
language_prompt = "You must response commit message in chinese。\n" if language == "zh" else ""
prompt = (
PROMPT_COMMIT_MESSAGE_BY_DIFF_USER_INPUT.replace("{__DIFF__}", f"{diff}")
.replace("{__USER_INPUT__}", f"{user_input + language_prompt}")
.replace("{__ISSUE__}", f"{issue}")
)
model_token_limit_error = (
diff_too_large_message_en if language == "en" else diff_too_large_message_zh
)
if len(str(prompt)) > COMMIT_PROMPT_LIMIT_SIZE:
print(model_token_limit_error, flush=True)
sys.exit(0)
messages = [{"role": "user", "content": prompt}]
response = chat_completion_stream(messages, prompt_commit_message_by_diff_user_input_llm_config)
if (
not response["content"]
and response.get("error", None)
and f"{response['error']}".find("This model's maximum context length is") > 0
):
print(model_token_limit_error)
sys.exit(0)
assert_value(not response["content"], response.get("error", ""))
response["content"] = extract_markdown_block(response["content"])
return response
def display_commit_message_and_commit(commit_message):
"""
展示提交信息并提交
Args:
commit_message: 提交信息
Returns:
None
"""
text_editor = TextEditor(commit_message, submit_button_name="Commit")
text_editor.render()
new_commit_message = text_editor.new_text
if not new_commit_message:
return None
return subprocess_check_output(["git", "commit", "-m", new_commit_message])
def extract_issue_id(branch_name):
if "#" in branch_name:
return branch_name.split("#")[-1]
return None
def get_issue_json(issue_id):
issue = {"id": "no issue id", "title": "", "body": ""}
if issue_id:
issue = get_issue_info(issue_id)
assert_exit(not issue, "Failed to retrieve issue with ID: {issue_id}", exit_code=-1)
issue = {
"id": issue_id,
"html_url": issue["html_url"],
"title": issue["title"],
"body": issue["body"],
}
return issue
def check_git_installed():
try:
subprocess.run(
["git", "--version"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=True,
)
return True
except subprocess.CalledProcessError:
print("Git is not installed on your system.", file=sys.stderr, flush=True)
except FileNotFoundError:
print("Git is not installed on your system.", file=sys.stderr, flush=True)
except Exception:
print("Git is not installed on your system.", file=sys.stderr, flush=True)
return False
def ask_for_push():
"""
询问用户是否要推送(push)更改到远程仓库
Returns:
bool: 用户是否选择推送
"""
print(
"Step 3/3: Would you like to push your commit to the remote repository?",
end="\n\n",
flush=True,
)
button = Button(["Yes, push now", "No, I'll push later"])
button.render()
return button.clicked == 0 # 如果用户点击第一个按钮(Yes)则返回True
def push_changes():
"""
推送更改到远程仓库
Returns:
bool: 推送是否成功
"""
try:
current_branch = get_current_branch()
if not current_branch:
print(
"Could not determine current branch. Push failed.",
end="\n\n",
file=sys.stderr,
flush=True,
)
return False
print(f"Pushing changes to origin/{current_branch}...", end="\n\n", flush=True)
result = subprocess_run(
["git", "push", "origin", current_branch],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
if result.returncode != 0:
print(f"Push failed: {result.stderr}", end="\n\n", flush=True)
return False
print("Push completed successfully.", end="\n\n", flush=True)
return True
except subprocess.CalledProcessError as e:
print(f"Push failed: {str(e)}", end="\n\n", file=sys.stderr, flush=True)
return False
except Exception as e:
print(
f"An unexpected error occurred: {str(e)}",
end="\n\n",
file=sys.stderr,
flush=True,
)
return False
def get_selected_issue_ids():
"""
获取用户选中的issue id
Returns:
list: 用户选中的issue id列表
"""
name = get_github_username()
issue_repo = get_github_repo(True)
issues = get_github_repo_issues(issue_repo, assignee=name, state="open")
if issues:
checkbox = Checkbox(
[f"#{issue['number']}: {issue['title']}" for issue in issues],
title="Select the issues you want to close",
)
checkbox.render()
return [issues[idx]["number"] for idx in checkbox.selections]
def main():
global language
try:
print("Let's follow the steps below.\n\n")
# Ensure enough command line arguments are provided
if len(sys.argv) < 2:
print(
"Usage: python script.py <user_input> <language>",
file=sys.stderr,
flush=True,
)
sys.exit(-1)
user_input = sys.argv[1]
language = "english"
if len(sys.argv) > 2:
language = sys.argv[2]
if not check_git_installed():
sys.exit(-1)
print(
"Step 1/3: Select the files you've changed that you wish to include in this commit, "
"then click 'Submit'.",
end="\n\n",
flush=True,
)
modified_files, staged_files = get_modified_files()
if len(modified_files) == 0:
print("No files to commit.", file=sys.stderr, flush=True)
sys.exit(-1)
selected_files = get_marked_files(modified_files, staged_files)
if not selected_files:
print("No files selected, commit aborted.")
return
rebuild_stage_list(selected_files)
print(
"Step 2/3: Review the commit message I've drafted for you. "
"Edit it below if needed. Then click 'Commit' to proceed with "
"the commit using this message.",
end="\n\n",
flush=True,
)
diff = get_diff()
branch_name = get_current_branch()
issue_id = extract_issue_id(branch_name)
issue = str(get_issue_json(issue_id))
if branch_name:
user_input += "\ncurrent repo branch name is:" + branch_name
commit_message = generate_commit_message_base_diff(user_input, diff, issue)
# TODO
# remove Closes #IssueNumber in commit message
commit_message["content"] = (
commit_message["content"]
.replace("Closes #IssueNumber", "")
.replace("No specific issue to close", "")
.replace("No specific issue mentioned.", "")
)
# add closes #IssueNumber in commit message from issues from user selected
issue_ids = get_selected_issue_ids()
if issue_ids:
issue_repo = get_github_repo(True)
owner_repo = get_github_repo()
closes_issue_contents = []
for issue_id in issue_ids:
closes_issue_contents.append(
f"#{issue_id}" if owner_repo == issue_repo else f"{issue_repo}#{issue_id}"
)
commit_message["content"] += f"\n\nCloses {', '.join(closes_issue_contents)}"
commit_result = display_commit_message_and_commit(commit_message["content"])
if not commit_result:
print("Commit aborted.", flush=True)
else:
# 添加推送步骤
if ask_for_push():
if not push_changes():
print("Push failed.", flush=True)
sys.exit(-1)
print("Commit completed.", flush=True)
sys.exit(0)
except Exception as err:
print("Exception:", err, file=sys.stderr, flush=True)
sys.exit(-1)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,45 @@
Objective:** Generate a commit message that succinctly describes the codebase changes reflected in the provided diff, while incorporating any extra context or guidance from the user.
**Commit Message Structure:**
1. **Title Line:** Choose a type such as `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, and so on, and couple it with a succinct title. Use the format: `type: Title`. Only one title line is permissible.
2. **Summary:** Summarize all adjustments concisely within a maximum of three detailed message lines. Prefix each line with a \"-\".
3. **Closing Reference (Conditional):** Include the line `Closes #IssueNumber` only if a specific, relevant issue number has been mentioned in the user input.
**Response Format:**
Response should be in the following markdown codeblock format:
```commit
type: Title
- Detail message line 1
- Detail message line 2
- Detail message line 3
```
Only output the commit message codeblock, don't include any other text.
**Constraints:**
- Exclude markdown code block indicators (```) and the placeholder \"commit_message\" from your response.
- Follow commit message best practices:
- Limit the title length to 50 characters.
- Limit each summary line to 72 characters.
**User Input:** `{__USER_INPUT__}`
Determine if `{__USER_INPUT__}` contains a reference to closing an issue. If so, include the closing reference in the commit message. Otherwise, exclude it.
**Code Changes:**
```
{__DIFF__}
```
Related issue:
{__ISSUE__}
Utilize the provided format to craft a commit message that adheres to the stipulated criteria.
example output:
```commit
feature: add update user info API
- add post method api /user/update
- implement update user info logic
```

View File

@ -0,0 +1,5 @@
description: '为你选定的代码变更生成格式规范的提交信息,并通过 Git 提交。如需要可包含对应 issue 编号(例如,输入“/commit to close #12”'
hint: to close Issue #issue_number
input: optional
steps:
- run: $devchat_python $command_path/../commit.py "$input" "chinese"

View File

@ -0,0 +1,78 @@
import functools
import sys
from lib.chatmark import Checkbox, Form, Radio, TextEditor
def create_ui_objs(ui_decls, args):
ui_objs = []
editors = []
for i, ui in enumerate(ui_decls):
editor = ui[0](args[i])
if ui[1]:
# this is the title of UI object
editors.append(ui[1])
editors.append(editor)
ui_objs.append(editor)
return ui_objs, editors
def edit_form(uis, args):
ui_objs, editors = create_ui_objs(uis, args)
form = Form(editors)
form.render()
values = []
for obj in ui_objs:
if isinstance(obj, TextEditor):
values.append(obj.new_text)
elif isinstance(obj, Radio):
values.append(obj.selection)
else:
# TODO
pass
return values
def editor(description):
def decorator_edit(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
uis = wrapper.uis[::-1]
return edit_form(uis, args)
if hasattr(func, "uis"):
wrapper.uis = func.uis
else:
wrapper.uis = []
wrapper.uis.append((TextEditor, description))
return wrapper
return decorator_edit
def ui_edit(ui_type, description):
def decorator_edit(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
uis = wrapper.uis[::-1]
return edit_form(uis, args)
if hasattr(func, "uis"):
wrapper.uis = func.uis
else:
wrapper.uis = []
ui_type_class = {"editor": TextEditor, "radio": Radio, "checkbox": Checkbox}[ui_type]
wrapper.uis.append((ui_type_class, description))
return wrapper
return decorator_edit
def assert_exit(condition, message, exit_code=-1):
if condition:
if exit_code == 0:
print(message, end="\n\n", flush=True)
else:
print(message, end="\n\n", file=sys.stderr, flush=True)
sys.exit(exit_code)

View File

@ -0,0 +1,19 @@
### config
配置GitHub工作流所需的设置。
#### 用途
- 设置Issue仓库URL
- 配置GitHub Token
#### 使用方法
执行命令: `/github.config`
#### 操作流程
1. 输入Issue仓库URL(可选)
2. 输入GitHub Token
3. 保存配置信息
#### 注意事项
- GitHub Token应妥善保管,不要泄露
- 配置信息将保存在本地文件中

View File

@ -0,0 +1,88 @@
import json
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import editor # noqa: E402
def read_issue_url():
config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config_data = json.load(f)
if "issue_repo" in config_data:
return config_data["issue_repo"]
return ""
def save_issue_url(issue_url):
config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
# make dirs
os.makedirs(os.path.dirname(config_path), exist_ok=True)
config_data = {}
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config_data = json.load(f)
config_data["issue_repo"] = issue_url
with open(config_path, "w+", encoding="utf-8") as f:
json.dump(config_data, f, indent=4)
def read_github_token():
config_path = os.path.join(os.path.expanduser("~/.chat"), ".workflow_config.json")
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config_data = json.load(f)
if "github_token" in config_data:
return config_data["github_token"]
return ""
def save_github_token(github_token):
config_path = os.path.join(os.path.expanduser("~/.chat"), ".workflow_config.json")
config_data = {}
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config_data = json.load(f)
config_data["github_token"] = github_token
with open(config_path, "w+", encoding="utf-8") as f:
json.dump(config_data, f, indent=4)
@editor(
"Please specify the issue's repository, "
"If the issue is within this repository, no need to specify. "
"Otherwise, format as: username/repository-name"
)
@editor("Input your github TOKEN to access github api:")
def edit_issue(issue_url, github_token):
pass
def main():
print("start config git settings ...", end="\n\n", flush=True)
issue_url = read_issue_url()
github_token = read_github_token()
issue_url, github_token = edit_issue(issue_url, github_token)
if issue_url:
save_issue_url(issue_url)
if github_token:
save_github_token(github_token)
else:
print("Please specify the github token to access github api.")
sys.exit(0)
print("config git settings successfully.")
sys.exit(0)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,4 @@
description: 'Config required settings for GIT workflows.'
help: README.md
steps:
- run: $devchat_python $command_path/command.py

587
community/github/git_api.py Normal file
View File

@ -0,0 +1,587 @@
import json
import os
import subprocess
import sys
import time
import requests
from lib.chatmark import TextEditor
from lib.ide_service import IDEService
def read_github_token():
config_path = os.path.join(os.path.expanduser("~/.chat"), ".workflow_config.json")
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config_data = json.load(f)
if "github_token" in config_data:
return config_data["github_token"]
# ask user to input github token
server_access_token_editor = TextEditor("", "Please input your GITHUB access TOKEN to access:")
server_access_token_editor.render()
server_access_token = server_access_token_editor.new_text
if not server_access_token:
print("Please input your GITHUB access TOKEN to continue.")
sys.exit(-1)
return server_access_token
current_repo_dir = None
def get_current_repo():
"""
获取当前文件所在的仓库信息
"""
global current_repo_dir
if not current_repo_dir:
selected_data = IDEService().get_selected_range().dict()
current_file = selected_data.get("abspath", None)
if not current_file:
return None
current_dir = os.path.dirname(current_file)
try:
# 获取仓库根目录
current_repo_dir = (
subprocess.check_output(
["git", "rev-parse", "--show-toplevel"],
stderr=subprocess.DEVNULL,
cwd=current_dir,
)
.decode("utf-8")
.strip()
)
except subprocess.CalledProcessError:
# 如果发生错误可能不在git仓库中
return None
return current_repo_dir
def subprocess_check_output(*popenargs, timeout=None, **kwargs):
# 将 current_dir 添加到 kwargs 中的 cwd 参数
current_repo = get_current_repo()
if current_repo:
kwargs["cwd"] = kwargs.get("cwd", current_repo)
# 调用 subprocess.check_output
return subprocess.check_output(*popenargs, timeout=timeout, **kwargs)
def subprocess_run(
*popenargs, input=None, capture_output=False, timeout=None, check=False, **kwargs
):
current_repo = get_current_repo()
if current_repo:
kwargs["cwd"] = kwargs.get("cwd", current_repo)
# 调用 subprocess.run
return subprocess.run(
*popenargs,
input=input,
capture_output=capture_output,
timeout=timeout,
check=check,
**kwargs,
)
def subprocess_call(*popenargs, timeout=None, **kwargs):
current_repo = get_current_repo()
if current_repo:
kwargs["cwd"] = kwargs.get("cwd", current_repo)
# 调用 subprocess.call
return subprocess.call(*popenargs, timeout=timeout, **kwargs)
def subprocess_check_call(*popenargs, timeout=None, **kwargs):
current_repo = get_current_repo()
if current_repo:
kwargs["cwd"] = kwargs.get("cwd", current_repo)
# 调用 subprocess.check_call
return subprocess.check_call(*popenargs, timeout=timeout, **kwargs)
GITHUB_ACCESS_TOKEN = read_github_token()
GITHUB_API_URL = "https://api.github.com"
def create_issue(title, body):
headers = {
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
"Accept": "application/vnd.github.v3+json",
}
data = {
"title": title,
"body": body,
}
issue_api_url = f"https://api.github.com/repos/{get_github_repo(True)}/issues"
response = requests.post(issue_api_url, headers=headers, data=json.dumps(data))
if response.status_code == 201:
print("Issue created successfully!")
return response.json()
else:
print(f"Failed to create issue: {response.content}", file=sys.stderr, end="\n\n")
return None
def update_issue_body(issue_url, issue_body):
"""
Update the body text of a GitHub issue.
:param issue_url: The API URL of the issue to update.
:param issue_body: The new body text for the issue.
"""
headers = {
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
"Accept": "application/vnd.github.v3+json",
}
data = {
"body": issue_body,
}
issue_api_url = f"https://api.github.com/repos/{get_github_repo(True)}/issues"
api_url = f"{issue_api_url}/{issue_url.split('/')[-1]}"
response = requests.patch(api_url, headers=headers, data=json.dumps(data))
if response.status_code == 200:
print("Issue updated successfully!")
return response.json()
else:
print(f"Failed to update issue: {response.status_code}")
return None
# parse sub tasks in issue body
def parse_sub_tasks(body):
sub_tasks = []
lines = body.split("\n")
for line in lines:
if line.startswith("- ["):
sub_tasks.append(line[2:])
return sub_tasks
def update_sub_tasks(body, tasks):
# remove all existing tasks
lines = body.split("\n")
updated_body = "\n".join(line for line in lines if not line.startswith("- ["))
# add new tasks
updated_body += "\n" + "\n".join(f"- {task}" for task in tasks)
return updated_body
def update_task_issue_url(body, task, issue_url):
# task is like:
# [ ] task name
# [x] task name
# replace task name with issue url, like:
# [ ] [task name](url)
# [x] [task name](url)
if task.find("] ") == -1:
return None
task = task[task.find("] ") + 2 :]
return body.replace(task, f"[{task}]({issue_url})")
def check_git_installed():
"""
Check if Git is installed on the local machine.
Tries to execute 'git --version' command to determine the presence of Git.
Returns:
bool: True if Git is installed, False otherwise.
"""
try:
subprocess_run(
["git", "--version"],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
return True
except subprocess.CalledProcessError:
print("Git is not installed on your system.")
return False
def create_and_checkout_branch(branch_name):
subprocess_run(["git", "checkout", "-b", branch_name], check=True)
def is_issue_url(task):
issue_url = f"https://github.com/{get_github_repo(True)}/issues"
return task.strip().startswith(issue_url)
def read_issue_by_url(issue_url):
issue_number = issue_url.split("/")[-1]
# Construct the API endpoint URL
issue_api_url = f"https://api.github.com/repos/{get_github_repo(True)}/issues"
api_url = f"{issue_api_url}/{issue_number}"
# Send a GET request to the API endpoint
headers = {
"Accept": "application/vnd.github.v3+json",
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
}
response = requests.get(api_url, headers=headers)
if response.status_code == 200:
return response.json()
else:
return None
def get_github_repo(issue_repo=False):
try:
config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
if os.path.exists(config_path) and issue_repo:
with open(config_path, "r", encoding="utf-8") as f:
config_data = json.load(f)
if "issue_repo" in config_data:
print(
"current issue repo:",
config_data["issue_repo"],
end="\n\n",
file=sys.stderr,
flush=True,
)
return config_data["issue_repo"]
# 使用git命令获取当前仓库的URL
result = subprocess_check_output(
["git", "remote", "get-url", "origin"], stderr=subprocess.STDOUT
).strip()
# 将结果从bytes转换为str并提取出仓库信息
repo_url = result.decode("utf-8")
# 假设repo_url的格式为https://github.com/username/repo.git
parts = repo_url.split("/")
repo = parts[-1].replace(".git", "")
username = parts[-2].split(":")[-1]
github_repo = f"{username}/{repo}"
IDEService().ide_logging("debug", f"current github repo: {github_repo}")
return github_repo
except subprocess.CalledProcessError as e:
print(e)
# 如果发生错误,打印错误信息
return None
except FileNotFoundError:
# 如果未找到git命令可能是没有安装git或者不在PATH中
print("==> File not found...")
return None
# 获取当前分支名称
def get_current_branch():
try:
# 使用git命令获取当前分支名称
result = subprocess_check_output(
["git", "branch", "--show-current"], stderr=subprocess.STDOUT
).strip()
# 将结果从bytes转换为str
current_branch = result.decode("utf-8")
return current_branch
except subprocess.CalledProcessError:
# 如果发生错误,打印错误信息
return None
except FileNotFoundError:
# 如果未找到git命令可能是没有安装git或者不在PATH中
return None
def get_parent_branch():
current_branch = get_current_branch()
if current_branch is None:
return None
try:
# 使用git命令获取当前分支的父分支引用
result = subprocess_check_output(
["git", "rev-parse", "--abbrev-ref", f"{current_branch}@{1}"],
stderr=subprocess.STDOUT,
).strip()
# 将结果从bytes转换为str
parent_branch_ref = result.decode("utf-8")
print("==>", parent_branch_ref)
if parent_branch_ref == current_branch:
# 如果父分支引用和当前分支相同,说明当前分支可能是基于一个没有父分支的提交创建的
return None
# 使用git命令获取父分支的名称
result = subprocess_check_output(
["git", "name-rev", "--name-only", "--exclude=tags/*", parent_branch_ref],
stderr=subprocess.STDOUT,
).strip()
parent_branch_name = result.decode("utf-8")
return parent_branch_name
except subprocess.CalledProcessError as e:
print(e)
# 如果发生错误,打印错误信息
return None
except FileNotFoundError:
# 如果未找到git命令可能是没有安装git或者不在PATH中
print("==> File not found...")
return None
def get_issue_info(issue_id):
# Construct the API endpoint URL
issue_api_url = f"https://api.github.com/repos/{get_github_repo(True)}/issues"
api_url = f"{issue_api_url}/{issue_id}"
# Send a GET request to the API endpoint
headers = {
"Accept": "application/vnd.github.v3+json",
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
}
response = requests.get(api_url, headers=headers)
if response.status_code == 200:
return response.json()
else:
return None
def get_issue_info_by_url(issue_url):
# get issue id from issue_url
def get_issue_id(issue_url):
# Extract the issue id from the issue_url
issue_id = issue_url.split("/")[-1]
return issue_id
return get_issue_info(get_issue_id(issue_url))
# 获取当前分支自从与base_branch分叉以来的历史提交信息
def get_commit_messages(base_branch):
# 找到当前分支与base_branch的分叉点
merge_base = subprocess_run(
["git", "merge-base", "HEAD", base_branch],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
# 检查是否成功找到分叉点
if merge_base.returncode != 0:
raise RuntimeError(f"Error finding merge base: {merge_base.stderr.strip()}")
# 获取分叉点的提交哈希
merge_base_commit = merge_base.stdout.strip()
# 获取从分叉点到当前分支的所有提交信息
result = subprocess_run(
["git", "log", f"{merge_base_commit}..HEAD"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
# 检查git log命令是否成功执行
if result.returncode != 0:
raise RuntimeError(f"Error retrieving commit messages: {result.stderr.strip()}")
# 返回提交信息列表
return result.stdout
# 创建PR
def create_pull_request(title, body, head, base, repo_name):
url = f"{GITHUB_API_URL}/repos/{repo_name}/pulls"
print("url:", url, end="\n\n")
headers = {
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
"Content-Type": "application/json",
}
payload = {"title": title, "body": body, "head": head, "base": base}
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.status_code == 201:
return response.json()
print(response.text, end="\n\n", file=sys.stderr)
return None
def run_command_with_retries(command, retries=3, delay=5):
for attempt in range(retries):
try:
subprocess_check_call(command)
return True
except subprocess.CalledProcessError as e:
print(f"Command failed: {e}")
if attempt < retries - 1:
print(f"Retrying... (attempt {attempt + 1}/{retries})")
time.sleep(delay)
else:
print("All retries failed.")
return False
def check_unpushed_commits():
try:
# 获取当前分支的本地提交和远程提交的差异
result = subprocess_check_output(["git", "cherry", "-v"]).decode("utf-8").strip()
# 如果结果不为空说明存在未push的提交
return bool(result)
except subprocess.CalledProcessError as e:
print(f"Error checking for unpushed commits: {e}")
return True
def auto_push():
# 获取当前分支名
if not check_unpushed_commits():
return True
try:
branch = (
subprocess_check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"])
.strip()
.decode("utf-8")
)
except subprocess.CalledProcessError as e:
print(f"Error getting current branch: {e}")
return False
# 检查当前分支是否有对应的远程分支
remote_branch_exists = subprocess_call(["git", "ls-remote", "--exit-code", "origin", branch])
push_command = ["git", "push", "origin", branch]
if remote_branch_exists == 0:
# 如果存在远程分支则直接push提交
return run_command_with_retries(push_command)
else:
# 如果不存在远程分支则发布并push提交
push_command.append("-u")
return run_command_with_retries(push_command)
def get_recently_pr(repo):
url = f"{GITHUB_API_URL}/repos/{repo}/pulls?state=open&sort=updated"
headers = {
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
"Accept": "application/vnd.github.v3+json",
}
response = requests.get(url, headers=headers)
print("=>:", url)
branch_name = get_current_branch()
if response.status_code == 200:
prs = response.json()
for pr in prs:
if pr["head"]["ref"] == branch_name:
return pr
return None
else:
return None
def update_pr(pr_number, title, body, repo_name):
url = f"{GITHUB_API_URL}/repos/{repo_name}/pulls/{pr_number}"
headers = {
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
"Content-Type": "application/json",
}
payload = {"title": title, "body": body}
response = requests.patch(url, headers=headers, data=json.dumps(payload))
if response.status_code == 200:
print(f"PR updated successfully: {response.json()['html_url']}")
return response.json()
else:
print("Failed to update PR.")
return None
def get_last_base_branch(default_branch):
"""read last base branch from config file"""
def read_config_item(config_path, item):
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config = json.load(f)
return config.get(item)
return None
project_config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
last_base_branch = read_config_item(project_config_path, "last_base_branch")
if last_base_branch:
return last_base_branch
return default_branch
def save_last_base_branch(base_branch=None):
"""save last base branch to config file"""
def save_config_item(config_path, item, value):
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config = json.load(f)
else:
config = {}
config[item] = value
with open(config_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=4)
if not base_branch:
base_branch = get_current_branch()
project_config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
save_config_item(project_config_path, "last_base_branch", base_branch)
def get_github_username():
url = f"{GITHUB_API_URL}/user"
headers = {
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
"Accept": "application/vnd.github.v3+json",
}
response = requests.get(url, headers=headers)
return response.json()["login"]
def get_github_repo_issues(
owner_repo,
milestone=None,
state=None,
assignee=None,
creator=None,
mentioned=None,
labels=None,
sort=None,
direction=None,
since=None,
per_page=None,
page=None,
):
url = f"{GITHUB_API_URL}/repos/{owner_repo}/issues"
headers = {
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
"Accept": "application/vnd.github.v3+json",
}
params = {
"milestone": milestone,
"state": state,
"assignee": assignee,
"creator": creator,
"mentioned": mentioned,
"labels": labels,
"sort": sort,
"direction": direction,
"since": since,
"per_page": per_page,
"page": page,
}
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
return response.json()
else:
return None

View File

@ -0,0 +1,19 @@
### list_issue_tasks
列出指定Issue中的任务列表。
#### 用途
- 查看Issue中的子任务
- 跟踪任务进度
#### 使用方法
执行命令: `/github.list_issue_tasks <issue_url>`
#### 操作流程
1. 获取指定Issue的信息
2. 解析Issue内容中的任务列表
3. 显示任务列表
#### 注意事项
- 需要提供有效的Issue URL
- 任务应以特定格式在Issue中列出(如: - [ ] 任务描述)

View File

@ -0,0 +1,53 @@
import os
import sys
from devchat.llm import chat_json
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, editor # noqa: E402
from git_api import create_issue # noqa: E402
# Function to generate issue title and body using LLM
PROMPT = (
"Based on the following description, "
"suggest a title and a detailed body for a GitHub issue:\n\n"
"Description: {description}\n\n"
'Output format: {{"title": "<title>", "body": "<body>"}} '
)
@chat_json(prompt=PROMPT)
def generate_issue_content(description):
pass
@editor("Edit issue title:")
@editor("Edit issue body:")
def edit_issue(title, body):
pass
# Main function
def main():
print("start new_issue ...", end="\n\n", flush=True)
assert_exit(len(sys.argv) < 2, "Missing argument.", exit_code=-1)
description = sys.argv[1]
print("Generating issue content ...", end="\n\n", flush=True)
issue_json_ob = generate_issue_content(description=description)
assert_exit(not issue_json_ob, "Failed to generate issue content.", exit_code=-1)
issue_title, issue_body = edit_issue(issue_json_ob["title"], issue_json_ob["body"])
assert_exit(not issue_title, "Issue creation cancelled.", exit_code=0)
print("New Issue:", issue_title, "body:", issue_body, end="\n\n", flush=True)
print("Creating issue ...", end="\n\n", flush=True)
issue = create_issue(issue_title, issue_body)
assert_exit(not issue, "Failed to create issue.", exit_code=-1)
print("New Issue:", issue["html_url"], end="\n\n", flush=True)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'List issue tasks.'
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,21 @@
### new_branch
基于当前分支创建新分支并切换到新分支。
#### 用途
- 快速创建新的功能或修复分支
- 保持工作区隔离
#### 使用方法
执行命令: `/github.new_branch <description>`
- description: 新分支的简短描述或相关Issue URL
#### 操作流程
1. 生成多个分支名建议
2. 用户选择或编辑分支名
3. 创建新分支并切换
#### 注意事项
- 确保当前分支的更改已提交
- 如提供Issue URL,会自动关联Issue编号到分支名

View File

@ -0,0 +1,95 @@
import json
import os
import sys
from devchat.llm import chat_json
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, ui_edit # noqa: E402
from git_api import ( # noqa: E402
check_git_installed,
create_and_checkout_branch,
is_issue_url,
read_issue_by_url,
save_last_base_branch,
)
# Function to generate a random branch name
PROMPT = (
"Give me 5 different git branch names, "
"mainly hoping to express: {task}, "
"Good branch name should looks like: <type>/<main content>,"
"the final result is output in JSON format, "
'as follows: {{"names":["name1", "name2", .. "name5"]}}\n'
)
@chat_json(prompt=PROMPT)
def generate_branch_name(task):
pass
@ui_edit(ui_type="radio", description="Select a branch name")
def select_branch_name_ui(branch_names):
pass
def select_branch_name(branch_names):
[branch_selection] = select_branch_name_ui(branch_names)
assert_exit(branch_selection is None, "No branch selected.", exit_code=0)
return branch_names[branch_selection]
def get_issue_or_task(task):
if is_issue_url(task):
issue = read_issue_by_url(task.strip())
assert_exit(not issue, "Failed to read issue.", exit_code=-1)
return json.dumps(
{"id": issue["number"], "title": issue["title"], "body": issue["body"]}
), issue["number"]
else:
return task, None
# Main function
def main():
print("Start create branch ...", end="\n\n", flush=True)
is_git_installed = check_git_installed()
assert_exit(not is_git_installed, "Git is not installed.", exit_code=-1)
task = sys.argv[1]
assert_exit(
not task,
"You need input something about the new branch, or input a issue url.",
exit_code=-1,
)
# read issue by url
task, issue_id = get_issue_or_task(task)
# Generate 5 branch names
print("Generating branch names ...", end="\n\n", flush=True)
branch_names = generate_branch_name(task=task)
assert_exit(not branch_names, "Failed to generate branch names.", exit_code=-1)
branch_names = branch_names["names"]
for index, branch_name in enumerate(branch_names):
if issue_id:
branch_names[index] = f"{branch_name}-#{issue_id}"
# Select branch name
selected_branch = select_branch_name(branch_names)
# save base branch name
save_last_base_branch()
# create and checkout branch
print(f"Creating and checking out branch: {selected_branch}")
create_and_checkout_branch(selected_branch)
print("Branch has create and checkout")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Create new branch based current branch, and checkout new branch.'
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,21 @@
### new_issue
创建新的GitHub Issue。
#### 用途
- 快速创建标准格式的Issue
- 记录任务、bug或功能请求
#### 使用方法
执行命令: `/github.new_issue <description>`
- description: Issue的简短描述
#### 操作流程
1. 基于描述生成Issue标题和正文
2. 允许用户编辑Issue内容
3. 创建GitHub Issue
#### 注意事项
- 需要有创建Issue的权限
- 生成的内容可能需要进一步完善

View File

@ -0,0 +1,52 @@
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, editor # noqa: E402
from devchat.llm import chat_json # noqa: E402
from git_api import create_issue # noqa: E402
# Function to generate issue title and body using LLM
PROMPT = (
"Based on the following description, "
"suggest a title and a detailed body for a GitHub issue:\n\n"
"Description: {description}\n\n"
'Output as valid JSON format: {{"title": "<title>", "body": "<body> use \\n as new line flag."}} ' # noqa: E501
)
@chat_json(prompt=PROMPT)
def generate_issue_content(description):
pass
@editor("Edit issue title:")
@editor("Edit issue body:")
def edit_issue(title, body):
pass
# Main function
def main():
print("start new_issue ...", end="\n\n", flush=True)
assert_exit(len(sys.argv) < 2, "Missing argument.", exit_code=-1)
description = sys.argv[1]
print("Generating issue content ...", end="\n\n", flush=True)
issue_json_ob = generate_issue_content(description=description)
assert_exit(not issue_json_ob, "Failed to generate issue content.", exit_code=-1)
issue_title, issue_body = edit_issue(issue_json_ob["title"], issue_json_ob["body"])
assert_exit(not issue_title, "Issue creation cancelled.", exit_code=0)
print("New Issue:", issue_title, "body:", issue_body, end="\n\n", flush=True)
print("Creating issue ...", end="\n\n", flush=True)
issue = create_issue(issue_title, issue_body)
assert_exit(not issue, "Failed to create issue.", exit_code=-1)
print("New Issue:", issue["html_url"], end="\n\n", flush=True)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Create new issue.'
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,94 @@
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", ".."))
from common_util import assert_exit, editor, ui_edit # noqa: E402
from devchat.llm import chat_json # noqa: E402
from git_api import ( # noqa: E402
create_issue,
get_issue_info_by_url,
parse_sub_tasks,
update_issue_body,
update_task_issue_url,
)
# Function to generate issue title and body using LLM
PROMPT = (
"Following is parent issue content:\n"
"{issue_content}\n\n"
"Based on the following issue task: {task}"
"suggest a title and a detailed body for a GitHub issue:\n\n"
'Output format: {{"title": "<title>", "body": "<body>"}} '
)
@chat_json(prompt=PROMPT)
def generate_issue_content(issue_content, task):
pass
@editor("Edit issue title:")
@editor("Edit issue body:")
def edit_issue(title, body):
pass
@ui_edit(ui_type="radio", description="Select a task to create issue:")
def select_task(tasks):
pass
def get_issue_json(issue_url):
issue = get_issue_info_by_url(issue_url)
assert_exit(not issue, "Failed to retrieve issue with ID: {issue_id}", exit_code=-1)
return {
"id": issue["number"],
"html_url": issue["html_url"],
"title": issue["title"],
"body": issue["body"],
}
# Main function
def main():
print("start new_issue ...", end="\n\n", flush=True)
assert_exit(len(sys.argv) < 2, "Missing argument.", exit_code=-1)
issue_url = sys.argv[1]
old_issue = get_issue_json(issue_url)
assert_exit(not old_issue, "Failed to retrieve issue with: {issue_url}", exit_code=-1)
tasks = parse_sub_tasks(old_issue["body"])
assert_exit(not tasks, "No tasks in issue body.")
# select task from tasks
[task] = select_task(tasks)
assert_exit(task is None, "No task selected.")
task = tasks[task]
print("task:", task, end="\n\n", flush=True)
print("Generating issue content ...", end="\n\n", flush=True)
issue_json_ob = generate_issue_content(issue_content=old_issue, task=task)
assert_exit(not issue_json_ob, "Failed to generate issue content.", exit_code=-1)
issue_title, issue_body = edit_issue(issue_json_ob["title"], issue_json_ob["body"])
assert_exit(not issue_title, "Issue creation cancelled.", exit_code=0)
print("New Issue:", issue_title, "body:", issue_body, end="\n\n", flush=True)
print("Creating issue ...", end="\n\n", flush=True)
issue = create_issue(issue_title, issue_body)
assert_exit(not issue, "Failed to create issue.", exit_code=-1)
print("New Issue:", issue["html_url"], end="\n\n", flush=True)
# update issue task with new issue url
new_body = update_task_issue_url(old_issue["body"], task, issue["html_url"])
assert_exit(not new_body, f"{task} parse error.")
new_issue = update_issue_body(issue_url, new_body)
assert_exit(not new_issue, "Failed to update issue body.")
print("Issue tasks updated successfully!", end="\n\n", flush=True)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Create new issue.'
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,22 @@
### new_pr
创建新的Pull Request。
#### 用途
- 自动生成PR标题和描述
- 简化代码审查流程
#### 使用方法
执行命令: `/github.new_pr [additional_info]`
- additional_info: 可选的附加信息
#### 操作流程
1. 获取当前分支信息和相关Issue
2. 生成PR标题和描述
3. 允许用户编辑PR内容
4. 创建Pull Request
#### 注意事项
- 确保当前分支有未合并的更改
- 需要有创建PR的权限

View File

@ -0,0 +1,120 @@
import json
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, ui_edit # noqa: E402
from devchat.llm import chat_json # noqa: E402
from git_api import ( # noqa: E402
auto_push,
create_pull_request,
get_commit_messages,
get_current_branch,
get_github_repo,
get_issue_info,
get_last_base_branch,
save_last_base_branch,
)
# 从分支名称中提取issue id
def extract_issue_id(branch_name):
if "#" in branch_name:
return branch_name.split("#")[-1]
return None
# 使用LLM模型生成PR内容
PROMPT = (
"Create a pull request title and body based on "
"the following issue and commit messages, if there is an "
"issue, close that issue in PR body as <user>/<repo>#issue_id:\n"
"Issue: {issue}\n"
"Commits:\n{commit_messages}\n"
"Other information:\n{user_input}\n\n"
"The response result should format as JSON object as following:\n"
'{{"title": "pr title", "body": "pr body"}}'
)
@chat_json(prompt=PROMPT)
def generate_pr_content_llm(issue, commit_message, user_input):
pass
def generate_pr_content(issue, commit_messages, user_input):
response = generate_pr_content_llm(
issue=json.dumps(issue), commit_messages=commit_messages, user_input=user_input
)
assert_exit(not response, "Failed to generate PR content.", exit_code=-1)
return response.get("title"), response.get("body")
@ui_edit(ui_type="editor", description="Edit PR title:")
@ui_edit(ui_type="editor", description="Edit PR body:")
def edit_pr(title, body):
pass
@ui_edit(ui_type="editor", description="Edit base branch:")
def edit_base_branch(base_branch):
pass
def get_issue_json(issue_id):
issue = {"id": "no issue id", "title": "", "body": ""}
if issue_id:
issue = get_issue_info(issue_id)
assert_exit(not issue, "Failed to retrieve issue with ID: {issue_id}", exit_code=-1)
issue = {
"id": issue_id,
"html_url": issue["html_url"],
"title": issue["title"],
"body": issue["body"],
}
return issue
# 主函数
def main():
print("start new_pr ...", end="\n\n", flush=True)
base_branch = get_last_base_branch("main")
base_branch = edit_base_branch(base_branch)
if isinstance(base_branch, list) and len(base_branch) > 0:
base_branch = base_branch[0]
save_last_base_branch(base_branch)
repo_name = get_github_repo()
branch_name = get_current_branch()
issue_id = extract_issue_id(branch_name)
# print basic info, repo_name, branch_name, issue_id
print("repo name:", repo_name, end="\n\n")
print("branch name:", branch_name, end="\n\n")
print("issue id:", issue_id, end="\n\n")
issue = get_issue_json(issue_id)
commit_messages = get_commit_messages(base_branch)
print("generating pr title and body ...", end="\n\n", flush=True)
user_input = sys.argv[1]
pr_title, pr_body = generate_pr_content(issue, commit_messages, user_input)
assert_exit(not pr_title, "Failed to generate PR content.", exit_code=-1)
pr_title, pr_body = edit_pr(pr_title, pr_body)
assert_exit(not pr_title, "PR creation cancelled.", exit_code=0)
is_push_success = auto_push()
assert_exit(not is_push_success, "Failed to push changes.", exit_code=-1)
pr = create_pull_request(pr_title, pr_body, branch_name, base_branch, repo_name)
assert_exit(not pr, "Failed to create PR.", exit_code=-1)
print(f"PR created successfully: {pr['html_url']}")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Create new PR.'
input: optional
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,22 @@
### update_issue_tasks
更新指定Issue中的任务列表。
#### 用途
- 添加、修改或删除Issue中的子任务
- 更新任务进度
#### 使用方法
执行命令: `/github.update_issue_tasks`
#### 操作流程
1. 输入Issue URL
2. 显示当前任务列表
3. 用户输入更新建议
4. 生成新的任务列表
5. 允许用户编辑新任务列表
6. 更新Issue内容
#### 注意事项
- 需要有编辑Issue的权限
- 小心不要删除或覆盖重要信息

View File

@ -0,0 +1,101 @@
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, editor # noqa: E402
from devchat.llm import chat_json # noqa: E402
from git_api import ( # noqa: E402
get_issue_info_by_url,
parse_sub_tasks,
update_issue_body,
update_sub_tasks,
)
TASKS_PROMPT = (
"Following is my git issue content.\n"
"{issue_data}\n\n"
"Sub task in issue is like:- [ ] task name\n"
"'[ ] task name' will be as sub task content\n\n"
"Following is my idea to update sub tasks:\n"
"{user_input}\n\n"
"Please output all tasks in JSON format as:"
'{{"tasks": ["[ ] task1", "[ ] task2"]}}'
)
@chat_json(prompt=TASKS_PROMPT)
def generate_issue_tasks(issue_data, user_input):
pass
def to_task_str(tasks):
task_str = ""
for task in tasks:
task_str += task + "\n"
return task_str
@editor("Edit issue old tasks:")
@editor("Edit issue new tasks:")
def edit_issue_tasks(old_tasks, new_tasks):
pass
@editor("Input ISSUE url:")
def input_issue_url(url):
pass
@editor("How to update tasks:")
def update_tasks_input(user_input):
pass
def get_issue_json(issue_url):
issue = get_issue_info_by_url(issue_url)
assert_exit(not issue, "Failed to retrieve issue with ID: {issue_id}", exit_code=-1)
return {
"id": issue["number"],
"html_url": issue["html_url"],
"title": issue["title"],
"body": issue["body"],
}
# Main function
def main():
print("start issue tasks update ...", end="\n\n", flush=True)
[issue_url] = input_issue_url("")
assert_exit(not issue_url, "No issue url.")
print("issue url:", issue_url, end="\n\n", flush=True)
issue = get_issue_json(issue_url)
old_tasks = parse_sub_tasks(issue["body"])
print(f"```tasks\n{to_task_str(old_tasks)}\n```", end="\n\n", flush=True)
[user_input] = update_tasks_input("")
assert_exit(not user_input, "No user input")
new_tasks = generate_issue_tasks(issue_data=issue, user_input=user_input)
assert_exit(not new_tasks, "No new tasks.")
print("new_tasks:", new_tasks, end="\n\n", flush=True)
assert_exit(not new_tasks.get("tasks", []), "No new tasks.")
print("new tasks:", to_task_str(new_tasks["tasks"]), end="\n\n", flush=True)
new_tasks = new_tasks["tasks"]
[old_tasks, new_tasks] = edit_issue_tasks(to_task_str(old_tasks), to_task_str(new_tasks))
assert_exit(not new_tasks, "No new tasks.")
print("new tasks:", new_tasks, end="\n\n", flush=True)
new_body = update_sub_tasks(issue["body"], new_tasks.split("\n"))
new_issue = update_issue_body(issue_url, new_body)
assert_exit(not new_issue, "Failed to update issue body.")
print("Issue tasks updated successfully!", end="\n\n", flush=True)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Update issue tasks.'
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,20 @@
### update_pr
更新现有的Pull Request。
#### 用途
- 更新PR的标题和描述
- 反映最新的代码变更
#### 使用方法
执行命令: `/github.update_pr`
#### 操作流程
1. 获取最近的PR信息
2. 重新生成PR标题和描述
3. 允许用户编辑PR内容
4. 更新Pull Request
#### 注意事项
- 确保有更新PR的权限
- 更新前请确认是否有新的提交需要推送

View File

@ -0,0 +1,122 @@
import json
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, ui_edit # noqa: E402
from devchat.llm import ( # noqa: E402
chat_json,
)
from git_api import ( # noqa: E402
auto_push,
get_commit_messages,
get_current_branch,
get_github_repo,
get_issue_info,
get_last_base_branch,
get_recently_pr,
save_last_base_branch,
update_pr,
)
# 从分支名称中提取issue id
def extract_issue_id(branch_name):
if "#" in branch_name:
return branch_name.split("#")[-1]
return None
# 使用LLM模型生成PR内容
PROMPT = (
"Create a pull request title and body based on "
"the following issue and commit messages, if there is an "
"issue, close that issue in PR body as <user>/<repo>#issue_id:\n"
"Issue: {issue}\n"
"Commits:\n{commit_messages}\n"
"The response result should format as JSON object as following:\n"
'{{"title": "pr title", "body": "pr body"}}'
)
@chat_json(prompt=PROMPT)
def generate_pr_content_llm(issue, commit_messages):
pass
def generate_pr_content(issue, commit_messages):
response = generate_pr_content_llm(issue=json.dumps(issue), commit_messages=commit_messages)
assert_exit(not response, "Failed to generate PR content.", exit_code=-1)
return response.get("title"), response.get("body")
@ui_edit(ui_type="editor", description="Edit PR title:")
@ui_edit(ui_type="editor", description="Edit PR body:")
def edit_pr(title, body):
pass
@ui_edit(ui_type="editor", description="Edit base branch:")
def edit_base_branch(base_branch):
pass
def get_issue_json(issue_id):
issue = {"id": "no issue id", "title": "", "body": ""}
if issue_id:
issue = get_issue_info(issue_id)
assert_exit(not issue, "Failed to retrieve issue with ID: {issue_id}", exit_code=-1)
issue = {
"id": issue_id,
"html_url": issue["html_url"],
"title": issue["title"],
"body": issue["body"],
}
return issue
# 主函数
def main():
print("start update_pr ...", end="\n\n", flush=True)
base_branch = get_last_base_branch("main")
base_branch = edit_base_branch(base_branch)
if isinstance(base_branch, list) and len(base_branch) > 0:
base_branch = base_branch[0]
save_last_base_branch(base_branch)
repo_name = get_github_repo()
branch_name = get_current_branch()
issue_id = extract_issue_id(branch_name)
# print basic info, repo_name, branch_name, issue_id
print("repo name:", repo_name, end="\n\n")
print("branch name:", branch_name, end="\n\n")
print("issue id:", issue_id, end="\n\n")
issue = get_issue_json(issue_id)
commit_messages = get_commit_messages(base_branch)
recent_pr = get_recently_pr(repo_name)
assert_exit(not recent_pr, "Failed to get recent PR.", exit_code=-1)
print("generating pr title and body ...", end="\n\n", flush=True)
pr_title, pr_body = generate_pr_content(issue, commit_messages)
assert_exit(not pr_title, "Failed to generate PR content.", exit_code=-1)
pr_title, pr_body = edit_pr(pr_title, pr_body)
assert_exit(not pr_title, "PR creation cancelled.", exit_code=0)
is_push_success = auto_push()
assert_exit(not is_push_success, "Failed to push changes.", exit_code=-1)
pr = update_pr(recent_pr["number"], pr_title, pr_body, repo_name)
assert_exit(not pr, "Failed to update PR.", exit_code=-1)
print(f"PR updated successfully: {pr['html_url']}")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Update PR.'
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,24 @@
### code_task_summary
根据当前分支或指定的Issue,生成代码任务摘要。
#### 用途
- 自动生成简洁的代码任务描述
- 帮助开发者快速理解任务要点
- 用于更新项目配置或文档
#### 使用方法
执行命令: `/github.code_task_summary [issue_url]`
- 如不提供issue_url,将基于当前分支名称提取Issue信息
- 如提供issue_url,将直接使用该Issue的内容
#### 操作流程
1. 获取Issue信息
2. 生成代码任务摘要
3. 允许用户编辑摘要
4. 更新项目配置文件
#### 注意事项
- 确保Git仓库配置正确
- 需要有效的GitHub Token以访问API

View File

@ -0,0 +1,124 @@
import json
import os
import sys
from devchat.llm import chat_json
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, ui_edit # noqa: E402
from git_api import ( # noqa: E402
check_git_installed,
get_current_branch,
get_gitlab_issue_repo,
get_issue_info,
is_issue_url,
read_issue_by_url,
)
def extract_issue_id(branch_name):
if "#" in branch_name:
return branch_name.split("#")[-1]
return None
# Function to generate a random branch name
PROMPT = (
"You are a coding engineer, required to summarize the ISSUE description into a coding task description of no more than 50 words. \n" # noqa: E501
"The ISSUE description is as follows: {issue_body}, please summarize the corresponding coding task description.\n" # noqa: E501
'The coding task description should be output in JSON format, in the form of: {{"summary": "code task summary"}}\n' # noqa: E501
)
@chat_json(prompt=PROMPT)
def generate_code_task_summary(issue_body):
pass
@ui_edit(ui_type="editor", description="Edit code task summary:")
def edit_code_task_summary(task_summary):
pass
def get_issue_or_task(task):
if is_issue_url(task):
issue = read_issue_by_url(task.strip())
assert_exit(not issue, "Failed to read issue.", exit_code=-1)
return json.dumps(
{"id": issue["iid"], "title": issue["title"], "description": issue["description"]}
)
else:
return task
def get_issue_json(issue_id, task):
issue = {"id": "no issue id", "title": "", "description": task}
if issue_id:
issue = get_issue_info(issue_id)
assert_exit(not issue, f"Failed to retrieve issue with ID: {issue_id}", exit_code=-1)
issue = {
"id": issue_id,
"web_url": issue["web_url"],
"title": issue["title"],
"description": issue["description"],
}
return issue
# Main function
def main():
print("Start update code task summary ...", end="\n\n", flush=True)
is_git_installed = check_git_installed()
assert_exit(not is_git_installed, "Git is not installed.", exit_code=-1)
task = sys.argv[1]
repo_name = get_gitlab_issue_repo()
branch_name = get_current_branch()
issue_id = extract_issue_id(branch_name)
# print basic info, repo_name, branch_name, issue_id
print("repo name:", repo_name, end="\n\n")
print("branch name:", branch_name, end="\n\n")
print("issue id:", issue_id, end="\n\n")
issue = get_issue_json(issue_id, task)
assert_exit(
not issue["description"], f"Failed to retrieve issue with ID: {issue_id}", exit_code=-1
)
# Generate 5 branch names
print("Generating code task summary ...", end="\n\n", flush=True)
code_task_summary = generate_code_task_summary(issue_body=issue["description"])
assert_exit(not code_task_summary, "Failed to generate code task summary.", exit_code=-1)
assert_exit(
not code_task_summary.get("summary", None),
"Failed to generate code task summary, missing summary field in result.",
exit_code=-1,
)
code_task_summary = code_task_summary["summary"]
# Select branch name
code_task_summary = edit_code_task_summary(code_task_summary)
assert_exit(not code_task_summary, "Failed to edit code task summary.", exit_code=-1)
code_task_summary = code_task_summary[0]
# create and checkout branch
print("Updating code task summary to config:")
config_file = os.path.join(".chat", "complete.config")
if os.path.exists(config_file):
with open(config_file, "r") as f:
config = json.load(f)
config["taskDescription"] = code_task_summary
else:
config = {"taskDescription": code_task_summary}
with open(config_file, "w") as f:
json.dump(config, f, indent=4)
print("Code task summary has updated")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Generate code task summary.'
input: optional
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1 @@
description: Root of gitlab commands.

View File

@ -0,0 +1,23 @@
### commit
自动生成提交信息并执行Git提交。
#### 用途
- 生成规范的提交信息
- 简化Git提交流程
- 保持提交历史的一致性
#### 使用方法
执行命令: `/github.commit [message]`
- message: 可选的用户输入,用于辅助生成提交信息
#### 操作流程
1. 选择要提交的文件
2. 生成提交信息
3. 允许用户编辑提交信息
4. 执行Git提交
#### 注意事项
- 确保已选择需要提交的文件
- 生成的提交信息可能需要进一步修改以符合项目规范

View File

View File

@ -0,0 +1,6 @@
description: 'Writes a well-formatted commit message for selected code changes and commits them via Git. Include an issue number if desired (e.g., input "/commit to close #12").'
hint: to close Issue #issue_number
input: optional
help: README.md
steps:
- run: $devchat_python $command_path/commit.py "$input" "english"

View File

@ -0,0 +1,494 @@
# flake8: noqa: E402
import os
import re
import subprocess
import sys
from devchat.llm import chat_completion_stream
from lib.chatmark import Button, Checkbox, Form, TextEditor
from lib.ide_service import IDEService
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit # noqa: E402
from git_api import get_issue_info, subprocess_check_output, subprocess_run
diff_too_large_message_en = (
"Commit failed. The modified content is too long "
"and exceeds the model's length limit. "
"You can try to make partial changes to the file and submit multiple times. "
"Making small changes and submitting them multiple times is a better practice."
)
diff_too_large_message_zh = (
"提交失败。修改内容太长,超出模型限制长度,"
"可以尝试选择部分修改文件多次提交,小修改多提交是更好的做法。"
)
COMMIT_PROMPT_LIMIT_SIZE = 20000
def extract_markdown_block(text):
"""
Extracts the first Markdown code block from the given text without the language specifier.
:param text: A string containing Markdown text
:return: The content of the first Markdown code block, or None if not found
"""
# 正则表达式匹配Markdown代码块忽略可选的语言类型标记
pattern = r"```(?:\w+)?\s*\n(.*?)\n```"
match = re.search(pattern, text, re.DOTALL)
if match:
# 返回第一个匹配的代码块内容,去除首尾的反引号和语言类型标记
# 去除块结束标记前的一个换行符,但保留其他内容
block_content = match.group(1)
return block_content
else:
return text
# Read the prompt from the diffCommitMessagePrompt.txt file
def read_prompt_from_file(filename):
"""
Reads the content of a file and returns it as a string.
This function is designed to read a prompt message from a text file.
It expects the file to be encoded in UTF-8 and will strip any leading
or trailing whitespace from the content of the file. If the file does
not exist or an error occurs during reading, the function logs an error
message and exits the script.
Parameters:
- filename (str): The path to the file that contains the prompt message.
Returns:
- str: The content of the file as a string.
Raises:
- FileNotFoundError: If the file does not exist.
- Exception: If any other error occurs during file reading.
"""
try:
with open(filename, "r", encoding="utf-8") as file:
return file.read().strip()
except FileNotFoundError:
IDEService().ide_logging(
"error",
f"File {filename} not found. "
"Please make sure it exists in the same directory as the script.",
)
sys.exit(1)
except Exception as e:
IDEService().ide_logging(
"error", f"An error occurred while reading the file {filename}: {e}"
)
sys.exit(1)
# Read the prompt content from the file
script_path = os.path.dirname(__file__)
PROMPT_FILENAME = os.path.join(script_path, "diffCommitMessagePrompt.txt")
PROMPT_COMMIT_MESSAGE_BY_DIFF_USER_INPUT = read_prompt_from_file(PROMPT_FILENAME)
prompt_commit_message_by_diff_user_input_llm_config = {
"model": os.environ.get("LLM_MODEL", "gpt-3.5-turbo-1106")
}
language = ""
def assert_value(value, message):
"""
判断给定的value是否为True如果是则输出指定的message并终止程序
Args:
value: 用于判断的值
message: 如果value为True时需要输出的信息
Returns:
无返回值
"""
if value:
print(message, file=sys.stderr, flush=True)
sys.exit(-1)
def decode_path(encoded_path):
octal_pattern = re.compile(r"\\[0-7]{3}")
if octal_pattern.search(encoded_path):
bytes_path = encoded_path.encode("utf-8").decode("unicode_escape").encode("latin1")
decoded_path = bytes_path.decode("utf-8")
return decoded_path
else:
return encoded_path
def get_modified_files():
"""
获取当前修改文件列表以及已经staged的文件列表
Args:
Returns:
tuple: 包含两个list的元组第一个list包含当前修改过的文件第二个list包含已经staged的文件
"""
""" 获取当前修改文件列表以及已经staged的文件列表"""
output = subprocess_check_output(["git", "status", "-s", "-u"], text=True, encoding="utf-8")
lines = output.split("\n")
modified_files = []
staged_files = []
def strip_file_name(file_name):
file = file_name.strip()
if file.startswith('"'):
file = file[1:-1]
return file
for line in lines:
if len(line) > 2:
status, filename = line[:2], decode_path(line[3:])
# check wether filename is a directory
if os.path.isdir(filename):
continue
modified_files.append(os.path.normpath(strip_file_name(filename)))
if status == "M " or status == "A " or status == "D ":
staged_files.append(os.path.normpath(strip_file_name(filename)))
return modified_files, staged_files
def get_marked_files(modified_files, staged_files):
"""
根据给定的参数获取用户选中以供提交的文件
Args:
modified_files (List[str]): 用户已修改文件列表
staged_files (List[str]): 用户已staged文件列表
Returns:
List[str]: 用户选中的文件列表
"""
# Create two Checkbox instances for staged and unstaged files
staged_checkbox = Checkbox(staged_files, [True] * len(staged_files))
unstaged_files = [file for file in modified_files if file not in staged_files]
unstaged_checkbox = Checkbox(unstaged_files, [False] * len(unstaged_files))
# Create a Form with both Checkbox instances
form_list = []
if len(staged_files) > 0:
form_list.append("Staged:\n\n")
form_list.append(staged_checkbox)
if len(unstaged_files) > 0:
form_list.append("Unstaged:\n\n")
form_list.append(unstaged_checkbox)
form = Form(form_list, submit_button_name="Continue")
# Render the Form and get user input
form.render()
# Retrieve the selected files from both Checkbox instances
staged_checkbox_selections = staged_checkbox.selections if staged_checkbox.selections else []
unstaged_selections = unstaged_checkbox.selections if unstaged_checkbox.selections else []
selected_staged_files = [staged_files[idx] for idx in staged_checkbox_selections]
selected_unstaged_files = [unstaged_files[idx] for idx in unstaged_selections]
# Combine the selections from both checkboxes
selected_files = selected_staged_files + selected_unstaged_files
return selected_files
def rebuild_stage_list(user_files):
"""
根据用户选中文件重新构建stage列表
Args:
user_files: 用户选中的文件列表
Returns:
None
"""
# Unstage all files
subprocess_check_output(["git", "reset"])
# Stage all user_files
for file in user_files:
subprocess_run(["git", "add", file])
def get_diff():
"""
获取暂存区文件的Diff信息
Args:
Returns:
bytes: 返回bytes类型是git diff --cached命令的输出结果
"""
return subprocess_check_output(["git", "diff", "--cached"])
def get_current_branch():
try:
# 使用git命令获取当前分支名称
result = subprocess_check_output(
["git", "branch", "--show-current"], stderr=subprocess.STDOUT
).strip()
# 将结果从bytes转换为str
current_branch = result.decode("utf-8")
return current_branch
except subprocess.CalledProcessError:
# 如果发生错误,打印错误信息
return None
except FileNotFoundError:
# 如果未找到git命令可能是没有安装git或者不在PATH中
return None
def generate_commit_message_base_diff(user_input, diff, issue):
"""
根据diff信息通过AI生成一个commit消息
Args:
user_input (str): 用户输入的commit信息
diff (str): 提交的diff信息
Returns:
str: 生成的commit消息
"""
global language
language_prompt = "You must response commit message in chinese。\n" if language == "zh" else ""
prompt = (
PROMPT_COMMIT_MESSAGE_BY_DIFF_USER_INPUT.replace("{__DIFF__}", f"{diff}")
.replace("{__USER_INPUT__}", f"{user_input + language_prompt}")
.replace("{__ISSUE__}", f"{issue}")
)
model_token_limit_error = (
diff_too_large_message_en if language == "en" else diff_too_large_message_zh
)
if len(str(prompt)) > COMMIT_PROMPT_LIMIT_SIZE:
print(model_token_limit_error, flush=True)
sys.exit(0)
messages = [{"role": "user", "content": prompt}]
response = chat_completion_stream(messages, prompt_commit_message_by_diff_user_input_llm_config)
if (
not response["content"]
and response.get("error", None)
and f"{response['error']}".find("This model's maximum context length is") > 0
):
print(model_token_limit_error)
sys.exit(0)
assert_value(not response["content"], response.get("error", ""))
response["content"] = extract_markdown_block(response["content"])
return response
def display_commit_message_and_commit(commit_message):
"""
展示提交信息并提交
Args:
commit_message: 提交信息
Returns:
None
"""
text_editor = TextEditor(commit_message, submit_button_name="Commit")
text_editor.render()
new_commit_message = text_editor.new_text
if not new_commit_message:
return None
return subprocess_check_output(["git", "commit", "-m", new_commit_message])
def extract_issue_id(branch_name):
if "#" in branch_name:
return branch_name.split("#")[-1]
return None
def get_issue_json(issue_id):
issue = {"id": "no issue id", "title": "", "description": ""}
if issue_id:
issue = get_issue_info(issue_id)
assert_exit(not issue, f"Failed to retrieve issue with ID: {issue_id}", exit_code=-1)
issue = {
"id": issue_id,
"web_url": issue["web_url"],
"title": issue["title"],
"description": issue["description"],
}
return issue
def check_git_installed():
try:
subprocess.run(
["git", "--version"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=True,
)
return True
except subprocess.CalledProcessError:
print("Git is not installed on your system.", file=sys.stderr, flush=True)
except FileNotFoundError:
print("Git is not installed on your system.", file=sys.stderr, flush=True)
except Exception:
print("Git is not installed on your system.", file=sys.stderr, flush=True)
return False
def ask_for_push():
"""
询问用户是否要推送(push)更改到远程仓库
Returns:
bool: 用户是否选择推送
"""
print(
"Step 3/3: Would you like to push your commit to the remote repository?",
end="\n\n",
flush=True,
)
button = Button(["Yes, push now", "No, I'll push later"])
button.render()
return button.clicked == 0 # 如果用户点击第一个按钮(Yes)则返回True
def push_changes():
"""
推送更改到远程仓库
Returns:
bool: 推送是否成功
"""
try:
current_branch = get_current_branch()
if not current_branch:
print(
"Could not determine current branch. Push failed.",
end="\n\n",
file=sys.stderr,
flush=True,
)
return False
print(f"Pushing changes to origin/{current_branch}...", end="\n\n", flush=True)
result = subprocess_run(
["git", "push", "origin", current_branch],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
if result.returncode != 0:
print(f"Push failed: {result.stderr}", end="\n\n", flush=True)
return False
print("Push completed successfully.", end="\n\n", flush=True)
return True
except subprocess.CalledProcessError as e:
print(f"Push failed: {str(e)}", end="\n\n", file=sys.stderr, flush=True)
return False
except Exception as e:
print(f"An unexpected error occurred: {str(e)}", end="\n\n", file=sys.stderr, flush=True)
return False
def main():
global language
try:
print("Let's follow the steps below.\n\n")
# Ensure enough command line arguments are provided
if len(sys.argv) < 2:
print("Usage: python script.py <user_input> <language>", file=sys.stderr, flush=True)
sys.exit(-1)
user_input = sys.argv[1]
language = "english"
if len(sys.argv) > 2:
language = sys.argv[2]
if not check_git_installed():
sys.exit(-1)
print(
"Step 1/3: Select the files you've changed that you wish to include in this commit, "
"then click 'Submit'.",
end="\n\n",
flush=True,
)
modified_files, staged_files = get_modified_files()
if len(modified_files) == 0:
print("No files to commit.", file=sys.stderr, flush=True)
sys.exit(-1)
selected_files = get_marked_files(modified_files, staged_files)
if not selected_files:
print("No files selected, commit aborted.")
return
rebuild_stage_list(selected_files)
print(
"Step 2/3: Review the commit message I've drafted for you. "
"Edit it below if needed. Then click 'Commit' to proceed with "
"the commit using this message.",
end="\n\n",
flush=True,
)
diff = get_diff()
branch_name = get_current_branch()
issue_id = extract_issue_id(branch_name)
issue = str(get_issue_json(issue_id))
if branch_name:
user_input += "\ncurrent repo branch name is:" + branch_name
commit_message = generate_commit_message_base_diff(user_input, diff, issue)
# TODO
# remove Closes #IssueNumber in commit message
commit_message["content"] = (
commit_message["content"]
.replace("Closes #IssueNumber", "")
.replace("No specific issue to close", "")
.replace("No specific issue mentioned.", "")
)
commit_result = display_commit_message_and_commit(commit_message["content"])
if not commit_result:
print("Commit aborted.", flush=True)
else:
# 添加推送步骤
if ask_for_push():
if not push_changes():
print("Push failed.", flush=True)
sys.exit(-1)
print("Commit completed.", flush=True)
sys.exit(0)
except Exception as err:
print("Exception:", err, file=sys.stderr, flush=True)
sys.exit(-1)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,49 @@
Objective:** Generate a commit message that succinctly describes the codebase changes reflected in the provided diff, while incorporating any extra context or guidance from the user.
**Commit Message Structure:**
1. **Title Line:** Choose a type such as `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, and so on, and couple it with a succinct title. Use the format: `type: Title`. Only one title line is permissible.
2. **Summary:** Summarize all adjustments concisely within a maximum of three detailed message lines. Prefix each line with a \"-\".
3. **Closing Reference (Conditional):** Include the line `Closes #IssueNumber` only if a specific, relevant issue number has been mentioned in the user input.
**Response Format:**
Response should be in the following markdown codeblock format:
```commit
type: Title
- Detail message line 1
- Detail message line 2
- Detail message line 3
Closes <#IssueNumber>
```
Only append the \"Closes #IssueNumber\" if the user input explicitly references an issue to close.
Only output the commit message codeblock, don't include any other text.
**Constraints:**
- Exclude markdown code block indicators (```) and the placeholder \"commit_message\" from your response.
- Follow commit message best practices:
- Limit the title length to 50 characters.
- Limit each summary line to 72 characters.
- If the precise issue number is not known or not stated by the user, do not include the closing reference.
**User Input:** `{__USER_INPUT__}`
Determine if `{__USER_INPUT__}` contains a reference to closing an issue. If so, include the closing reference in the commit message. Otherwise, exclude it.
**Code Changes:**
```
{__DIFF__}
```
Related issue:
{__ISSUE__}
Utilize the provided format to craft a commit message that adheres to the stipulated criteria.
example output:
```commit
feature: add update user info API
- add post method api /user/update
- implement update user info logic
```

View File

@ -0,0 +1,5 @@
description: '为你选定的代码变更生成格式规范的提交信息,并通过 Git 提交。如需要可包含对应 issue 编号(例如,输入“/commit to close #12”'
hint: to close Issue #issue_number
input: optional
steps:
- run: $devchat_python $command_path/../commit.py "$input" "chinese"

View File

@ -0,0 +1,78 @@
import functools
import sys
from lib.chatmark import Checkbox, Form, Radio, TextEditor
def create_ui_objs(ui_decls, args):
ui_objs = []
editors = []
for i, ui in enumerate(ui_decls):
editor = ui[0](args[i])
if ui[1]:
# this is the title of UI object
editors.append(ui[1])
editors.append(editor)
ui_objs.append(editor)
return ui_objs, editors
def edit_form(uis, args):
ui_objs, editors = create_ui_objs(uis, args)
form = Form(editors)
form.render()
values = []
for obj in ui_objs:
if isinstance(obj, TextEditor):
values.append(obj.new_text)
elif isinstance(obj, Radio):
values.append(obj.selection)
else:
# TODO
pass
return values
def editor(description):
def decorator_edit(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
uis = wrapper.uis[::-1]
return edit_form(uis, args)
if hasattr(func, "uis"):
wrapper.uis = func.uis
else:
wrapper.uis = []
wrapper.uis.append((TextEditor, description))
return wrapper
return decorator_edit
def ui_edit(ui_type, description):
def decorator_edit(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
uis = wrapper.uis[::-1]
return edit_form(uis, args)
if hasattr(func, "uis"):
wrapper.uis = func.uis
else:
wrapper.uis = []
ui_type_class = {"editor": TextEditor, "radio": Radio, "checkbox": Checkbox}[ui_type]
wrapper.uis.append((ui_type_class, description))
return wrapper
return decorator_edit
def assert_exit(condition, message, exit_code=-1):
if condition:
if exit_code == 0:
print(message, end="\n\n", flush=True)
else:
print(message, end="\n\n", file=sys.stderr, flush=True)
sys.exit(exit_code)

View File

@ -0,0 +1,19 @@
### config
配置GitHub工作流所需的设置。
#### 用途
- 设置Issue仓库URL
- 配置GitHub Token
#### 使用方法
执行命令: `/github.config`
#### 操作流程
1. 输入Issue仓库URL(可选)
2. 输入GitHub Token
3. 保存配置信息
#### 注意事项
- GitHub Token应妥善保管,不要泄露
- 配置信息将保存在本地文件中

View File

@ -0,0 +1,88 @@
import json
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import editor # noqa: E402
def read_issue_url():
config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config_data = json.load(f)
if "git_issue_repo" in config_data:
return config_data["git_issue_repo"]
return ""
def save_issue_url(issue_url):
config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
# make dirs
os.makedirs(os.path.dirname(config_path), exist_ok=True)
config_data = {}
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config_data = json.load(f)
config_data["git_issue_repo"] = issue_url
with open(config_path, "w+", encoding="utf-8") as f:
json.dump(config_data, f, indent=4)
def read_gitlab_token():
config_path = os.path.join(os.path.expanduser("~/.chat"), ".workflow_config.json")
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config_data = json.load(f)
if "gitlab_token" in config_data:
return config_data["gitlab_token"]
return ""
def save_gitlab_token(github_token):
config_path = os.path.join(os.path.expanduser("~/.chat"), ".workflow_config.json")
config_data = {}
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config_data = json.load(f)
config_data["gitlab_token"] = github_token
with open(config_path, "w+", encoding="utf-8") as f:
json.dump(config_data, f, indent=4)
@editor(
"Please specify the issue's repository, "
"If the issue is within this repository, no need to specify. "
"Otherwise, format as: username/repository-name"
)
@editor("Input your github TOKEN to access github api:")
def edit_issue(issue_url, github_token):
pass
def main():
print("start config git settings ...", end="\n\n", flush=True)
issue_url = read_issue_url()
github_token = read_gitlab_token()
issue_url, github_token = edit_issue(issue_url, github_token)
if issue_url:
save_issue_url(issue_url)
if github_token:
save_gitlab_token(github_token)
else:
print("Please specify the github token to access github api.")
sys.exit(0)
print("config git settings successfully.")
sys.exit(0)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,4 @@
description: 'Config required settings for GIT workflows.'
help: README.md
steps:
- run: $devchat_python $command_path/command.py

611
community/gitlab/git_api.py Normal file
View File

@ -0,0 +1,611 @@
import json
import os
import re
import subprocess
import sys
import time
import requests
from lib.chatmark import TextEditor
from lib.ide_service import IDEService
def read_gitlab_token():
config_path = os.path.join(os.path.expanduser("~/.chat"), ".workflow_config.json")
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config_data = json.load(f)
if "gitlab_token" in config_data:
return config_data["gitlab_token"]
# ask user to input gitlab token
server_access_token_editor = TextEditor("", "Please input your GitLab access TOKEN to access:")
server_access_token_editor.render()
server_access_token = server_access_token_editor.new_text
if not server_access_token:
print("Please input your GitLab access TOKEN to continue.")
sys.exit(-1)
return server_access_token
current_repo_dir = None
def get_current_repo():
"""
获取当前文件所在的仓库信息
"""
global current_repo_dir
if not current_repo_dir:
selected_data = IDEService().get_selected_range().dict()
current_file = selected_data.get("abspath", None)
if not current_file:
return None
current_dir = os.path.dirname(current_file)
try:
# 获取仓库根目录
current_repo_dir = (
subprocess.check_output(
["git", "rev-parse", "--show-toplevel"],
stderr=subprocess.DEVNULL,
cwd=current_dir,
)
.decode("utf-8")
.strip()
)
except subprocess.CalledProcessError:
# 如果发生错误可能不在git仓库中
return None
return current_repo_dir
def subprocess_check_output(*popenargs, timeout=None, **kwargs):
# 将 current_dir 添加到 kwargs 中的 cwd 参数
current_repo = get_current_repo()
if current_repo:
kwargs["cwd"] = kwargs.get("cwd", current_repo)
# 调用 subprocess.check_output
return subprocess.check_output(*popenargs, timeout=timeout, **kwargs)
def subprocess_run(
*popenargs, input=None, capture_output=False, timeout=None, check=False, **kwargs
):
current_repo = get_current_repo()
if current_repo:
kwargs["cwd"] = kwargs.get("cwd", current_repo)
# 调用 subprocess.run
return subprocess.run(
*popenargs,
input=input,
capture_output=capture_output,
timeout=timeout,
check=check,
**kwargs,
)
def subprocess_call(*popenargs, timeout=None, **kwargs):
current_repo = get_current_repo()
if current_repo:
kwargs["cwd"] = kwargs.get("cwd", current_repo)
# 调用 subprocess.call
return subprocess.call(*popenargs, timeout=timeout, **kwargs)
def subprocess_check_call(*popenargs, timeout=None, **kwargs):
current_repo = get_current_repo()
if current_repo:
kwargs["cwd"] = kwargs.get("cwd", current_repo)
# 调用 subprocess.check_call
return subprocess.check_call(*popenargs, timeout=timeout, **kwargs)
GITLAB_ACCESS_TOKEN = read_gitlab_token()
GITLAB_API_URL = "https://gitlab.com/api/v4"
def create_issue(title, description):
headers = {
"Private-Token": GITLAB_ACCESS_TOKEN,
"Content-Type": "application/json",
}
data = {
"title": title,
"description": description,
}
project_id = get_gitlab_project_id()
issue_api_url = f"{GITLAB_API_URL}/projects/{project_id}/issues"
response = requests.post(issue_api_url, headers=headers, json=data)
if response.status_code == 201:
print("Issue created successfully!")
return response.json()
else:
print(f"Failed to create issue: {response.content}", file=sys.stderr, end="\n\n")
return None
def update_issue_body(issue_iid, issue_body):
headers = {
"Private-Token": GITLAB_ACCESS_TOKEN,
"Content-Type": "application/json",
}
data = {
"description": issue_body,
}
project_id = get_gitlab_project_id()
api_url = f"{GITLAB_API_URL}/projects/{project_id}/issues/{issue_iid}"
response = requests.put(api_url, headers=headers, json=data)
if response.status_code == 200:
print("Issue updated successfully!")
return response.json()
else:
print(f"Failed to update issue: {response.status_code}")
return None
def get_gitlab_project_id():
try:
result = subprocess_check_output(
["git", "remote", "get-url", "origin"], stderr=subprocess.STDOUT
).strip()
repo_url = result.decode("utf-8")
print(f"Original repo URL: {repo_url}", file=sys.stderr)
if repo_url.startswith("git@"):
# Handle SSH URL format
parts = repo_url.split(":")
project_path = parts[1].replace(".git", "")
elif repo_url.startswith("https://"):
# Handle HTTPS URL format
parts = repo_url.split("/")
project_path = "/".join(parts[3:]).replace(".git", "")
else:
raise ValueError(f"Unsupported Git URL format: {repo_url}")
print(f"Extracted project path: {project_path}", file=sys.stderr)
encoded_project_path = requests.utils.quote(project_path, safe="")
print(f"Encoded project path: {encoded_project_path}", file=sys.stderr)
return encoded_project_path
except subprocess.CalledProcessError as e:
print(f"Error executing git command: {e}", file=sys.stderr)
return None
except Exception as e:
print(f"Error in get_gitlab_project_id: {e}", file=sys.stderr)
return None
# parse sub tasks in issue description
def parse_sub_tasks(description):
sub_tasks = []
lines = description.split("\n")
for line in lines:
if line.startswith("- ["):
sub_tasks.append(line[2:])
return sub_tasks
def update_sub_tasks(description, tasks):
# remove all existing tasks
lines = description.split("\n")
updated_body = "\n".join(line for line in lines if not line.startswith("- ["))
# add new tasks
updated_body += "\n" + "\n".join(f"- {task}" for task in tasks)
return updated_body
def update_task_issue_url(description, task, issue_url):
# task is like:
# [ ] task name
# [x] task name
# replace task name with issue url, like:
# [ ] [task name](url)
# [x] [task name](url)
if task.find("] ") == -1:
return None
task = task[task.find("] ") + 2 :]
return description.replace(task, f"[{task}]({issue_url})")
def check_git_installed():
"""
Check if Git is installed on the local machine.
Tries to execute 'git --version' command to determine the presence of Git.
Returns:
bool: True if Git is installed, False otherwise.
"""
try:
subprocess_run(
["git", "--version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
return True
except subprocess.CalledProcessError:
print("Git is not installed on your system.")
return False
def create_and_checkout_branch(branch_name):
subprocess_run(["git", "checkout", "-b", branch_name], check=True)
def is_issue_url(task):
task = task.strip()
# 使用正则表达式匹配 http 或 https 开头issues/数字 结尾的 URL
pattern = r"^(http|https)://.*?/issues/\d+$"
is_issue = bool(re.match(pattern, task))
# print(f"Task to check: {task}", file=sys.stderr)
# print(f"Is issue URL: {is_issue}", file=sys.stderr)
return is_issue
def read_issue_by_url(issue_url):
# Extract the issue number and project path from the URL
issue_url = issue_url.replace("/-/", "/")
parts = issue_url.split("/")
issue_number = parts[-1]
project_path = "/".join(
parts[3:-2]
) # Assumes URL format: https://gitlab.com/project/path/-/issues/number
# URL encode the project path
encoded_project_path = requests.utils.quote(project_path, safe="")
# Construct the API endpoint URL
api_url = f"{GITLAB_API_URL}/projects/{encoded_project_path}/issues/{issue_number}"
# Send a GET request to the API endpoint
headers = {
"Private-Token": GITLAB_ACCESS_TOKEN,
"Content-Type": "application/json",
}
response = requests.get(api_url, headers=headers)
if response.status_code == 200:
return response.json()
else:
print(f"Error fetching issue: {response.status_code}", file=sys.stderr)
print(f"Response content: {response.text}", file=sys.stderr)
return None
def get_gitlab_issue_repo(issue_repo=False):
try:
config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
if os.path.exists(config_path) and issue_repo:
with open(config_path, "r", encoding="utf-8") as f:
config_data = json.load(f)
if "git_issue_repo" in config_data:
issue_repo = requests.utils.quote(config_data["git_issue_repo"], safe="")
print(
"current issue repo:",
config_data["git_issue_repo"],
end="\n\n",
file=sys.stderr,
flush=True,
)
return config_data["git_issue_repo"]
return get_gitlab_project_id()
except subprocess.CalledProcessError as e:
print(e)
# 如果发生错误,打印错误信息
return None
except FileNotFoundError:
# 如果未找到git命令可能是没有安装git或者不在PATH中
print("==> File not found...")
return None
# 获取当前分支名称
def get_current_branch():
try:
# 使用git命令获取当前分支名称
result = subprocess_check_output(
["git", "branch", "--show-current"], stderr=subprocess.STDOUT
).strip()
# 将结果从bytes转换为str
current_branch = result.decode("utf-8")
return current_branch
except subprocess.CalledProcessError:
# 如果发生错误,打印错误信息
return None
except FileNotFoundError:
# 如果未找到git命令可能是没有安装git或者不在PATH中
return None
def get_parent_branch():
current_branch = get_current_branch()
if current_branch is None:
return None
try:
# 使用git命令获取当前分支的父分支引用
result = subprocess_check_output(
["git", "rev-parse", "--abbrev-ref", f"{current_branch}@{1}"], stderr=subprocess.STDOUT
).strip()
# 将结果从bytes转换为str
parent_branch_ref = result.decode("utf-8")
if parent_branch_ref == current_branch:
# 如果父分支引用和当前分支相同,说明当前分支可能是基于一个没有父分支的提交创建的
return None
# 使用git命令获取父分支的名称
result = subprocess_check_output(
["git", "name-rev", "--name-only", "--exclude=tags/*", parent_branch_ref],
stderr=subprocess.STDOUT,
).strip()
parent_branch_name = result.decode("utf-8")
return parent_branch_name
except subprocess.CalledProcessError as e:
print(e)
# 如果发生错误,打印错误信息
return None
except FileNotFoundError:
# 如果未找到git命令可能是没有安装git或者不在PATH中
print("==> File not found...")
return None
def get_issue_info(issue_id):
# 获取 GitLab 项目 ID
project_id = get_gitlab_issue_repo()
# 构造 GitLab API 端点 URL
api_url = f"{GITLAB_API_URL}/projects/{project_id}/issues/{issue_id}"
# 发送 GET 请求到 API 端点
headers = {
"Private-Token": GITLAB_ACCESS_TOKEN,
"Content-Type": "application/json",
}
response = requests.get(api_url, headers=headers)
if response.status_code == 200:
return response.json()
else:
print(f"Failed to get issue info. Status code: {response.status_code}", file=sys.stderr)
print(f"Response content: {response.text}", file=sys.stderr)
return None
def get_issue_info_by_url(issue_url):
# get issue id from issue_url
def get_issue_id(issue_url):
# Extract the issue id from the issue_url
issue_id = issue_url.split("/")[-1]
return issue_id
return get_issue_info(get_issue_id(issue_url))
# 获取当前分支自从与base_branch分叉以来的历史提交信息
def get_commit_messages(base_branch):
# 找到当前分支与base_branch的分叉点
merge_base = subprocess_run(
["git", "merge-base", "HEAD", base_branch],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
# 检查是否成功找到分叉点
if merge_base.returncode != 0:
raise RuntimeError(f"Error finding merge base: {merge_base.stderr.strip()}")
# 获取分叉点的提交哈希
merge_base_commit = merge_base.stdout.strip()
# 获取从分叉点到当前分支的所有提交信息
result = subprocess_run(
["git", "log", f"{merge_base_commit}..HEAD"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
# 检查git log命令是否成功执行
if result.returncode != 0:
raise RuntimeError(f"Error retrieving commit messages: {result.stderr.strip()}")
# 返回提交信息列表
return result.stdout
# 创建PR
def create_pull_request(title, description, source_branch, target_branch, project_id):
url = f"{GITLAB_API_URL}/projects/{project_id}/merge_requests"
headers = {"Private-Token": GITLAB_ACCESS_TOKEN, "Content-Type": "application/json"}
payload = {
"title": title,
"description": description,
"source_branch": source_branch,
"target_branch": target_branch,
}
response = requests.post(url, headers=headers, json=payload)
if response.status_code == 201:
response_json = response.json()
return response_json
print(response.text, end="\n\n", file=sys.stderr)
return None
def get_recently_mr(project_id):
project_id = requests.utils.quote(project_id, safe="")
url = (
f"{GITLAB_API_URL}/projects/{project_id}/"
"merge_requests?state=opened&order_by=updated_at&sort=desc"
)
headers = {
"Private-Token": GITLAB_ACCESS_TOKEN,
"Content-Type": "application/json",
}
response = requests.get(url, headers=headers)
branch_name = get_current_branch()
if response.status_code == 200:
mrs = response.json()
for mr in mrs:
if mr["source_branch"] == branch_name:
return mr
return None
else:
return None
def run_command_with_retries(command, retries=3, delay=5):
for attempt in range(retries):
try:
subprocess_check_call(command)
return True
except subprocess.CalledProcessError as e:
print(f"Command failed: {e}")
if attempt < retries - 1:
print(f"Retrying... (attempt {attempt + 1}/{retries})")
time.sleep(delay)
else:
print("All retries failed.")
return False
def update_mr(project_id, mr_iid, title, description):
project_id = requests.utils.quote(project_id, safe="")
url = f"{GITLAB_API_URL}/projects/{project_id}/merge_requests/{mr_iid}"
headers = {"Private-Token": GITLAB_ACCESS_TOKEN, "Content-Type": "application/json"}
payload = {"title": title, "description": description}
response = requests.put(url, headers=headers, json=payload)
if response.status_code == 200:
print(f"MR updated successfully: {response.json()['web_url']}")
return response.json()
else:
print("Failed to update MR.")
return None
def check_unpushed_commits():
try:
# 获取当前分支的本地提交和远程提交的差异
result = subprocess_check_output(["git", "cherry", "-v"]).decode("utf-8").strip()
# 如果结果不为空说明存在未push的提交
return bool(result)
except subprocess.CalledProcessError as e:
print(f"Error checking for unpushed commits: {e}")
return True
def auto_push():
# 获取当前分支名
if not check_unpushed_commits():
return True
try:
branch = (
subprocess_check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"])
.strip()
.decode("utf-8")
)
except subprocess.CalledProcessError as e:
print(f"Error getting current branch: {e}")
return False
# 检查当前分支是否有对应的远程分支
remote_branch_exists = subprocess_call(["git", "ls-remote", "--exit-code", "origin", branch])
push_command = ["git", "push", "origin", branch]
if remote_branch_exists == 0:
# 如果存在远程分支则直接push提交
return run_command_with_retries(push_command)
else:
# 如果不存在远程分支则发布并push提交
push_command.append("-u")
return run_command_with_retries(push_command)
def get_recently_pr(repo):
url = f"{GITLAB_API_URL}/repos/{repo}/pulls?state=open&sort=updated"
headers = {
"Authorization": f"token {GITLAB_ACCESS_TOKEN}",
"Accept": "application/vnd.github.v3+json",
}
response = requests.get(url, headers=headers)
branch_name = get_current_branch()
if response.status_code == 200:
prs = response.json()
for pr in prs:
if pr["head"]["ref"] == branch_name:
return pr
return None
else:
return None
def update_pr(pr_number, title, description, repo_name):
url = f"{GITLAB_API_URL}/repos/{repo_name}/pulls/{pr_number}"
headers = {"Authorization": f"token {GITLAB_ACCESS_TOKEN}", "Content-Type": "application/json"}
payload = {"title": title, "description": description}
response = requests.patch(url, headers=headers, data=json.dumps(payload))
if response.status_code == 200:
print(f"PR updated successfully: {response.json()['web_url']}")
return response.json()
else:
print("Failed to update PR.")
return None
def get_last_base_branch(default_branch):
"""read last base branch from config file"""
def read_config_item(config_path, item):
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config = json.load(f)
return config.get(item)
return None
project_config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
last_base_branch = read_config_item(project_config_path, "last_base_branch")
if last_base_branch:
return last_base_branch
return default_branch
def save_last_base_branch(base_branch=None):
"""save last base branch to config file"""
def save_config_item(config_path, item, value):
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config = json.load(f)
else:
config = {}
config[item] = value
with open(config_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=4)
if not base_branch:
base_branch = get_current_branch()
project_config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
save_config_item(project_config_path, "last_base_branch", base_branch)

View File

@ -0,0 +1,19 @@
### list_issue_tasks
列出指定Issue中的任务列表。
#### 用途
- 查看Issue中的子任务
- 跟踪任务进度
#### 使用方法
执行命令: `/github.list_issue_tasks <issue_url>`
#### 操作流程
1. 获取指定Issue的信息
2. 解析Issue内容中的任务列表
3. 显示任务列表
#### 注意事项
- 需要提供有效的Issue URL
- 任务应以特定格式在Issue中列出(如: - [ ] 任务描述)

View File

@ -0,0 +1,53 @@
import os
import sys
from devchat.llm import chat_json
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, editor # noqa: E402
from git_api import create_issue # noqa: E402
# Function to generate issue title and description using LLM
PROMPT = (
"Based on the following description, "
"suggest a title and a detailed description for a GitHub issue:\n\n"
"Description: {description}\n\n"
'Output format: {{"title": "<title>", "description": "<description>"}} '
)
@chat_json(prompt=PROMPT)
def generate_issue_content(description):
pass
@editor("Edit issue title:")
@editor("Edit issue description:")
def edit_issue(title, description):
pass
# Main function
def main():
print("start new_issue ...", end="\n\n", flush=True)
assert_exit(len(sys.argv) < 2, "Missing argument.", exit_code=-1)
description = sys.argv[1]
print("Generating issue content ...", end="\n\n", flush=True)
issue_json_ob = generate_issue_content(description=description)
assert_exit(not issue_json_ob, "Failed to generate issue content.", exit_code=-1)
issue_title, issue_body = edit_issue(issue_json_ob["title"], issue_json_ob["description"])
assert_exit(not issue_title, "Issue creation cancelled.", exit_code=0)
print("New Issue:", issue_title, "description:", issue_body, end="\n\n", flush=True)
print("Creating issue ...", end="\n\n", flush=True)
issue = create_issue(issue_title, issue_body)
assert_exit(not issue, "Failed to create issue.", exit_code=-1)
print("New Issue:", issue["web_url"], end="\n\n", flush=True)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'List issue tasks.'
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,21 @@
### new_branch
基于当前分支创建新分支并切换到新分支。
#### 用途
- 快速创建新的功能或修复分支
- 保持工作区隔离
#### 使用方法
执行命令: `/github.new_branch <description>`
- description: 新分支的简短描述或相关Issue URL
#### 操作流程
1. 生成多个分支名建议
2. 用户选择或编辑分支名
3. 创建新分支并切换
#### 注意事项
- 确保当前分支的更改已提交
- 如提供Issue URL,会自动关联Issue编号到分支名

View File

@ -0,0 +1,95 @@
import json
import os
import sys
from devchat.llm import chat_json
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, ui_edit # noqa: E402
from git_api import ( # noqa: E402
check_git_installed,
create_and_checkout_branch,
is_issue_url,
read_issue_by_url,
save_last_base_branch,
)
# Function to generate a random branch name
PROMPT = (
"Give me 5 different git branch names, "
"mainly hoping to express: {task}, "
"Good branch name should looks like: <type>/<main content>,"
"the final result is output in JSON format, "
'as follows: {{"names":["name1", "name2", .. "name5"]}}\n'
)
@chat_json(prompt=PROMPT)
def generate_branch_name(task):
pass
@ui_edit(ui_type="radio", description="Select a branch name")
def select_branch_name_ui(branch_names):
pass
def select_branch_name(branch_names):
[branch_selection] = select_branch_name_ui(branch_names)
assert_exit(branch_selection is None, "No branch selected.", exit_code=0)
return branch_names[branch_selection]
def get_issue_or_task(task):
if is_issue_url(task):
issue = read_issue_by_url(task.strip())
assert_exit(not issue, "Failed to read issue.", exit_code=-1)
return json.dumps(
{"id": issue["iid"], "title": issue["title"], "description": issue["description"]}
), issue["iid"]
else:
return task, None
# Main function
def main():
print("Start create branch ...", end="\n\n", flush=True)
is_git_installed = check_git_installed()
assert_exit(not is_git_installed, "Git is not installed.", exit_code=-1)
task = sys.argv[1]
assert_exit(
not task,
"You need input something about the new branch, or input a issue url.",
exit_code=-1,
)
# read issue by url
task, issue_id = get_issue_or_task(task)
# Generate 5 branch names
print("Generating branch names ...", end="\n\n", flush=True)
branch_names = generate_branch_name(task=task)
assert_exit(not branch_names, "Failed to generate branch names.", exit_code=-1)
branch_names = branch_names["names"]
for index, branch_name in enumerate(branch_names):
if issue_id:
branch_names[index] = f"{branch_name}-#{issue_id}"
# Select branch name
selected_branch = select_branch_name(branch_names)
# save base branch name
save_last_base_branch()
# create and checkout branch
print(f"Creating and checking out branch: {selected_branch}")
create_and_checkout_branch(selected_branch)
print("Branch has create and checkout")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Create new branch based current branch, and checkout new branch.'
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,21 @@
### new_issue
创建新的GitHub Issue。
#### 用途
- 快速创建标准格式的Issue
- 记录任务、bug或功能请求
#### 使用方法
执行命令: `/github.new_issue <description>`
- description: Issue的简短描述
#### 操作流程
1. 基于描述生成Issue标题和正文
2. 允许用户编辑Issue内容
3. 创建GitHub Issue
#### 注意事项
- 需要有创建Issue的权限
- 生成的内容可能需要进一步完善

View File

@ -0,0 +1,52 @@
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, editor # noqa: E402
from devchat.llm import chat_json # noqa: E402
from git_api import create_issue # noqa: E402
# Function to generate issue title and description using LLM
PROMPT = (
"Based on the following description, "
"suggest a title and a detailed description for a GitHub issue:\n\n"
"Description: {description}\n\n"
'Output as valid JSON format: {{"title": "<title>", "description": "<description> use \\n as new line flag."}} ' # noqa: E501
)
@chat_json(prompt=PROMPT)
def generate_issue_content(description):
pass
@editor("Edit issue title:")
@editor("Edit issue description:")
def edit_issue(title, description):
pass
# Main function
def main():
print("start new_issue ...", end="\n\n", flush=True)
assert_exit(len(sys.argv) < 2, "Missing argument.", exit_code=-1)
description = sys.argv[1]
print("Generating issue content ...", end="\n\n", flush=True)
issue_json_ob = generate_issue_content(description=description)
assert_exit(not issue_json_ob, "Failed to generate issue content.", exit_code=-1)
issue_title, issue_body = edit_issue(issue_json_ob["title"], issue_json_ob["description"])
assert_exit(not issue_title, "Issue creation cancelled.", exit_code=0)
print("New Issue:", issue_title, "description:", issue_body, end="\n\n", flush=True)
print("Creating issue ...", end="\n\n", flush=True)
issue = create_issue(issue_title, issue_body)
assert_exit(not issue, "Failed to create issue.", exit_code=-1)
print("New Issue:", issue["web_url"], end="\n\n", flush=True)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Create new issue.'
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,94 @@
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", ".."))
from common_util import assert_exit, editor, ui_edit # noqa: E402
from devchat.llm import chat_json # noqa: E402
from git_api import ( # noqa: E402
create_issue,
get_issue_info_by_url,
parse_sub_tasks,
update_issue_body,
update_task_issue_url,
)
# Function to generate issue title and description using LLM
PROMPT = (
"Following is parent issue content:\n"
"{issue_content}\n\n"
"Based on the following issue task: {task}"
"suggest a title and a detailed description for a GitHub issue:\n\n"
'Output format: {{"title": "<title>", "description": "<description>"}} '
)
@chat_json(prompt=PROMPT)
def generate_issue_content(issue_content, task):
pass
@editor("Edit issue title:")
@editor("Edit issue description:")
def edit_issue(title, description):
pass
@ui_edit(ui_type="radio", description="Select a task to create issue:")
def select_task(tasks):
pass
def get_issue_json(issue_url):
issue = get_issue_info_by_url(issue_url)
assert_exit(not issue, f"Failed to retrieve issue with ID: {issue_url}", exit_code=-1)
return {
"id": issue["iid"],
"web_url": issue["web_url"],
"title": issue["title"],
"description": issue["description"],
}
# Main function
def main():
print("start new_issue ...", end="\n\n", flush=True)
assert_exit(len(sys.argv) < 2, "Missing argument.", exit_code=-1)
issue_url = sys.argv[1]
old_issue = get_issue_json(issue_url)
assert_exit(not old_issue, "Failed to retrieve issue with: {issue_url}", exit_code=-1)
tasks = parse_sub_tasks(old_issue["get_issue_json"])
assert_exit(not tasks, "No tasks in issue description.")
# select task from tasks
[task] = select_task(tasks)
assert_exit(task is None, "No task selected.")
task = tasks[task]
print("task:", task, end="\n\n", flush=True)
print("Generating issue content ...", end="\n\n", flush=True)
issue_json_ob = generate_issue_content(issue_content=old_issue, task=task)
assert_exit(not issue_json_ob, "Failed to generate issue content.", exit_code=-1)
issue_title, issue_body = edit_issue(issue_json_ob["title"], issue_json_ob["description"])
assert_exit(not issue_title, "Issue creation cancelled.", exit_code=0)
print("New Issue:", issue_title, "description:", issue_body, end="\n\n", flush=True)
print("Creating issue ...", end="\n\n", flush=True)
issue = create_issue(issue_title, issue_body)
assert_exit(not issue, "Failed to create issue.", exit_code=-1)
print("New Issue:", issue["web_url"], end="\n\n", flush=True)
# update issue task with new issue url
new_body = update_task_issue_url(old_issue["description"], task, issue["web_url"])
assert_exit(not new_body, f"{task} parse error.")
new_issue = update_issue_body(issue_url, new_body)
assert_exit(not new_issue, "Failed to update issue description.")
print("Issue tasks updated successfully!", end="\n\n", flush=True)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Create new issue.'
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,22 @@
### new_pr
创建新的Pull Request。
#### 用途
- 自动生成PR标题和描述
- 简化代码审查流程
#### 使用方法
执行命令: `/github.new_pr [additional_info]`
- additional_info: 可选的附加信息
#### 操作流程
1. 获取当前分支信息和相关Issue
2. 生成PR标题和描述
3. 允许用户编辑PR内容
4. 创建Pull Request
#### 注意事项
- 确保当前分支有未合并的更改
- 需要有创建PR的权限

View File

@ -0,0 +1,120 @@
import json
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, ui_edit # noqa: E402
from devchat.llm import chat_json # noqa: E402
from git_api import ( # noqa: E402
auto_push,
create_pull_request,
get_commit_messages,
get_current_branch,
get_gitlab_issue_repo,
get_issue_info,
get_last_base_branch,
save_last_base_branch,
)
# 从分支名称中提取issue id
def extract_issue_id(branch_name):
if "#" in branch_name:
return branch_name.split("#")[-1]
return None
# 使用LLM模型生成PR内容
PROMPT = (
"Create a pull request title and description based on "
"the following issue and commit messages, if there is an "
"issue, close that issue in PR description as <user>/<repo>#issue_id:\n"
"Issue: {issue}\n"
"Commits:\n{commit_messages}\n"
"Other information:\n{user_input}\n\n"
"The response result should format as JSON object as following:\n"
'{{"title": "pr title", "description": "pr description"}}'
)
@chat_json(prompt=PROMPT)
def generate_pr_content_llm(issue, commit_message, user_input):
pass
def generate_pr_content(issue, commit_messages, user_input):
response = generate_pr_content_llm(
issue=json.dumps(issue), commit_messages=commit_messages, user_input=user_input
)
assert_exit(not response, "Failed to generate PR content.", exit_code=-1)
return response.get("title"), response.get("description")
@ui_edit(ui_type="editor", description="Edit PR title:")
@ui_edit(ui_type="editor", description="Edit PR description:")
def edit_pr(title, description):
pass
@ui_edit(ui_type="editor", description="Edit base branch:")
def edit_base_branch(base_branch):
pass
def get_issue_json(issue_id):
issue = {"id": "no issue id", "title": "", "description": ""}
if issue_id:
issue = get_issue_info(issue_id)
assert_exit(not issue, f"Failed to retrieve issue with ID: {issue_id}", exit_code=-1)
issue = {
"id": issue_id,
"web_url": issue["web_url"],
"title": issue["title"],
"description": issue["description"],
}
return issue
# 主函数
def main():
print("start new_pr ...", end="\n\n", flush=True)
base_branch = get_last_base_branch("main")
base_branch = edit_base_branch(base_branch)
if isinstance(base_branch, list) and len(base_branch) > 0:
base_branch = base_branch[0]
save_last_base_branch(base_branch)
repo_name = get_gitlab_issue_repo()
branch_name = get_current_branch()
issue_id = extract_issue_id(branch_name)
# print basic info, repo_name, branch_name, issue_id
print("repo name:", repo_name, end="\n\n")
print("branch name:", branch_name, end="\n\n")
print("issue id:", issue_id, end="\n\n")
issue = get_issue_json(issue_id)
commit_messages = get_commit_messages(base_branch)
print("generating pr title and description ...", end="\n\n", flush=True)
user_input = sys.argv[1]
pr_title, pr_body = generate_pr_content(issue, commit_messages, user_input)
assert_exit(not pr_title, "Failed to generate PR content.", exit_code=-1)
pr_title, pr_body = edit_pr(pr_title, pr_body)
assert_exit(not pr_title, "PR creation cancelled.", exit_code=0)
is_push_success = auto_push()
assert_exit(not is_push_success, "Failed to push changes.", exit_code=-1)
pr = create_pull_request(pr_title, pr_body, branch_name, base_branch, repo_name)
assert_exit(not pr, "Failed to create PR.", exit_code=-1)
print(f"PR created successfully: {pr['web_url']}")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Create new PR.'
input: optional
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,22 @@
### update_issue_tasks
更新指定Issue中的任务列表。
#### 用途
- 添加、修改或删除Issue中的子任务
- 更新任务进度
#### 使用方法
执行命令: `/github.update_issue_tasks`
#### 操作流程
1. 输入Issue URL
2. 显示当前任务列表
3. 用户输入更新建议
4. 生成新的任务列表
5. 允许用户编辑新任务列表
6. 更新Issue内容
#### 注意事项
- 需要有编辑Issue的权限
- 小心不要删除或覆盖重要信息

View File

@ -0,0 +1,101 @@
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, editor # noqa: E402
from devchat.llm import chat_json # noqa: E402
from git_api import ( # noqa: E402
get_issue_info_by_url,
parse_sub_tasks,
update_issue_body,
update_sub_tasks,
)
TASKS_PROMPT = (
"Following is my git issue content.\n"
"{issue_data}\n\n"
"Sub task in issue is like:- [ ] task name\n"
"'[ ] task name' will be as sub task content\n\n"
"Following is my idea to update sub tasks:\n"
"{user_input}\n\n"
"Please output all tasks in JSON format as:"
'{{"tasks": ["[ ] task1", "[ ] task2"]}}'
)
@chat_json(prompt=TASKS_PROMPT)
def generate_issue_tasks(issue_data, user_input):
pass
def to_task_str(tasks):
task_str = ""
for task in tasks:
task_str += task + "\n"
return task_str
@editor("Edit issue old tasks:")
@editor("Edit issue new tasks:")
def edit_issue_tasks(old_tasks, new_tasks):
pass
@editor("Input ISSUE url:")
def input_issue_url(url):
pass
@editor("How to update tasks:")
def update_tasks_input(user_input):
pass
def get_issue_json(issue_url):
issue = get_issue_info_by_url(issue_url)
assert_exit(not issue, f"Failed to retrieve issue with ID: {issue_url}", exit_code=-1)
return {
"id": issue["iid"],
"web_url": issue["web_url"],
"title": issue["title"],
"description": issue["description"],
}
# Main function
def main():
print("start issue tasks update ...", end="\n\n", flush=True)
[issue_url] = input_issue_url("")
assert_exit(not issue_url, "No issue url.")
print("issue url:", issue_url, end="\n\n", flush=True)
issue = get_issue_json(issue_url)
old_tasks = parse_sub_tasks(issue["description"])
print(f"```tasks\n{to_task_str(old_tasks)}\n```", end="\n\n", flush=True)
[user_input] = update_tasks_input("")
assert_exit(not user_input, "No user input")
new_tasks = generate_issue_tasks(issue_data=issue, user_input=user_input)
assert_exit(not new_tasks, "No new tasks.")
print("new_tasks:", new_tasks, end="\n\n", flush=True)
assert_exit(not new_tasks.get("tasks", []), "No new tasks.")
print("new tasks:", to_task_str(new_tasks["tasks"]), end="\n\n", flush=True)
new_tasks = new_tasks["tasks"]
[old_tasks, new_tasks] = edit_issue_tasks(to_task_str(old_tasks), to_task_str(new_tasks))
assert_exit(not new_tasks, "No new tasks.")
print("new tasks:", new_tasks, end="\n\n", flush=True)
new_body = update_sub_tasks(issue["description"], new_tasks.split("\n"))
new_issue = update_issue_body(issue_url, new_body)
assert_exit(not new_issue, "Failed to update issue description.")
print("Issue tasks updated successfully!", end="\n\n", flush=True)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
description: 'Update issue tasks.'
input: required
help: README.md
steps:
- run: $devchat_python $command_path/command.py "$input"

View File

@ -0,0 +1,20 @@
### update_pr
更新现有的Pull Request。
#### 用途
- 更新PR的标题和描述
- 反映最新的代码变更
#### 使用方法
执行命令: `/github.update_pr`
#### 操作流程
1. 获取最近的PR信息
2. 重新生成PR标题和描述
3. 允许用户编辑PR内容
4. 更新Pull Request
#### 注意事项
- 确保有更新PR的权限
- 更新前请确认是否有新的提交需要推送

View File

@ -0,0 +1,122 @@
import json
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit, ui_edit # noqa: E402
from devchat.llm import ( # noqa: E402
chat_json,
)
from git_api import ( # noqa: E402
auto_push,
get_commit_messages,
get_current_branch,
get_gitlab_issue_repo,
get_issue_info,
get_last_base_branch,
get_recently_pr,
save_last_base_branch,
update_pr,
)
# 从分支名称中提取issue id
def extract_issue_id(branch_name):
if "#" in branch_name:
return branch_name.split("#")[-1]
return None
# 使用LLM模型生成PR内容
PROMPT = (
"Create a pull request title and description based on "
"the following issue and commit messages, if there is an "
"issue, close that issue in PR description as <user>/<repo>#issue_id:\n"
"Issue: {issue}\n"
"Commits:\n{commit_messages}\n"
"The response result should format as JSON object as following:\n"
'{{"title": "pr title", "description": "pr description"}}'
)
@chat_json(prompt=PROMPT)
def generate_pr_content_llm(issue, commit_messages):
pass
def generate_pr_content(issue, commit_messages):
response = generate_pr_content_llm(issue=json.dumps(issue), commit_messages=commit_messages)
assert_exit(not response, "Failed to generate PR content.", exit_code=-1)
return response.get("title"), response.get("description")
@ui_edit(ui_type="editor", description="Edit PR title:")
@ui_edit(ui_type="editor", description="Edit PR description:")
def edit_pr(title, description):
pass
@ui_edit(ui_type="editor", description="Edit base branch:")
def edit_base_branch(base_branch):
pass
def get_issue_json(issue_id):
issue = {"id": "no issue id", "title": "", "description": ""}
if issue_id:
issue = get_issue_info(issue_id)
assert_exit(not issue, f"Failed to retrieve issue with ID: {issue_id}", exit_code=-1)
issue = {
"id": issue_id,
"web_url": issue["web_url"],
"title": issue["title"],
"description": issue["description"],
}
return issue
# 主函数
def main():
print("start update_pr ...", end="\n\n", flush=True)
base_branch = get_last_base_branch("main")
base_branch = edit_base_branch(base_branch)
if isinstance(base_branch, list) and len(base_branch) > 0:
base_branch = base_branch[0]
save_last_base_branch(base_branch)
repo_name = get_gitlab_issue_repo()
branch_name = get_current_branch()
issue_id = extract_issue_id(branch_name)
# print basic info, repo_name, branch_name, issue_id
print("repo name:", repo_name, end="\n\n")
print("branch name:", branch_name, end="\n\n")
print("issue id:", issue_id, end="\n\n")
issue = get_issue_json(issue_id)
commit_messages = get_commit_messages(base_branch)
recent_pr = get_recently_pr(repo_name)
assert_exit(not recent_pr, "Failed to get recent PR.", exit_code=-1)
print("generating pr title and description ...", end="\n\n", flush=True)
pr_title, pr_body = generate_pr_content(issue, commit_messages)
assert_exit(not pr_title, "Failed to generate PR content.", exit_code=-1)
pr_title, pr_body = edit_pr(pr_title, pr_body)
assert_exit(not pr_title, "PR creation cancelled.", exit_code=0)
is_push_success = auto_push()
assert_exit(not is_push_success, "Failed to push changes.", exit_code=-1)
pr = update_pr(recent_pr["iid"], pr_title, pr_body, repo_name)
assert_exit(not pr, "Failed to update PR.", exit_code=-1)
print(f"PR updated successfully: {pr['web_url']}")
if __name__ == "__main__":
main()

Some files were not shown because too many files have changed in this diff Show More