@comate/zulu 1.4.0-beta.2 → 1.4.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/comate-engine/assets/skills/auto-commit/SKILL.md +241 -0
- package/comate-engine/assets/skills/auto-commit/references/data_structures.md +183 -0
- package/comate-engine/assets/skills/auto-commit/references/interaction_instruction.md +220 -0
- package/comate-engine/assets/skills/auto-commit/references/issue_type_mapping.json +19 -0
- package/comate-engine/assets/skills/auto-commit/references/query_reference.md +176 -0
- package/comate-engine/assets/skills/auto-commit/scripts/build_git_commit_payload.py +195 -0
- package/comate-engine/assets/skills/auto-commit/scripts/build_icafe_cards_payload.py +80 -0
- package/comate-engine/assets/skills/auto-commit/scripts/cache_manager.py +69 -0
- package/comate-engine/assets/skills/auto-commit/scripts/create_card_cli.py +67 -0
- package/comate-engine/assets/skills/auto-commit/scripts/git_diff_cli.py +201 -0
- package/comate-engine/assets/skills/auto-commit/scripts/git_utils.py +230 -0
- package/comate-engine/assets/skills/auto-commit/scripts/icafe/__init__.py +66 -0
- package/comate-engine/assets/skills/auto-commit/scripts/icafe/client.py +473 -0
- package/comate-engine/assets/skills/auto-commit/scripts/icafe/farseer.py +52 -0
- package/comate-engine/assets/skills/auto-commit/scripts/icafe/matching.py +784 -0
- package/comate-engine/assets/skills/auto-commit/scripts/logger.py +32 -0
- package/comate-engine/assets/skills/auto-commit/scripts/match_card_cli.py +41 -0
- package/comate-engine/assets/skills/auto-commit/scripts/payload_validators.py +309 -0
- package/comate-engine/assets/skills/auto-commit/scripts/recognize_card_cli.py +63 -0
- package/comate-engine/assets/skills/{automation-browser-comate → automation-browser}/SKILL.md +1 -0
- package/comate-engine/assets/skills/{cnap-comate → cnap}/SKILL.md +1 -0
- package/comate-engine/assets/skills/code-review/SKILL.md +202 -0
- package/comate-engine/assets/skills/code-review/agents/correctness-reviewer.md +62 -0
- package/comate-engine/assets/skills/code-review/agents/custom-reviewer.md +53 -0
- package/comate-engine/assets/skills/code-review/agents/meta-reviewer.md +84 -0
- package/comate-engine/assets/skills/code-review/agents/reliability-reviewer.md +72 -0
- package/comate-engine/assets/skills/code-review/agents/reuse-reviewer.md +101 -0
- package/comate-engine/assets/skills/code-review/agents/style-reviewer.md +65 -0
- package/comate-engine/assets/skills/code-review/evals/SKILL.md +334 -0
- package/comate-engine/assets/skills/code-review/evals/agents/gt-generator.md +76 -0
- package/comate-engine/assets/skills/code-review/evals/agents/miner.md +87 -0
- package/comate-engine/assets/skills/code-review/evals/agents/score-judge.md +168 -0
- package/comate-engine/assets/skills/code-review/evals/references/cli-query-template.md +114 -0
- package/comate-engine/assets/skills/code-review/evals/references/gt-schema.md +77 -0
- package/comate-engine/assets/skills/code-review/references/custom-rules/RULE_TEMPLATE.md +141 -0
- package/comate-engine/assets/skills/code-review/references/dispatch-template.md +142 -0
- package/comate-engine/assets/skills/code-review/references/output-schema.md +197 -0
- package/comate-engine/assets/skills/code-review/references/report-format.md +41 -0
- package/comate-engine/assets/skills/code-review/references/rules/Go/GO_AUTH_RULES.md +29 -0
- package/comate-engine/assets/skills/code-review/references/rules/Go/GO_CORRECTNESS_RULES.md +111 -0
- package/comate-engine/assets/skills/code-review/references/rules/Go/GO_RESOURCE_CONCURRENCY_RULES.md +190 -0
- package/comate-engine/assets/skills/code-review/references/rules/Go/GO_STYLE_RULES.md +354 -0
- package/comate-engine/assets/skills/code-review/references/rules/Java/JAVA_AUTH_RULES.md +34 -0
- package/comate-engine/assets/skills/code-review/references/rules/Java/JAVA_CORRECTNESS_RULES.md +207 -0
- package/comate-engine/assets/skills/code-review/references/rules/Java/JAVA_RESOURCE_CONCURRENCY_RULES.md +220 -0
- package/comate-engine/assets/skills/code-review/references/rules/Java/JAVA_STYLE_RULES.md +306 -0
- package/comate-engine/assets/skills/code-review/references/rules/Js/JS_AUTH_RULES.md +48 -0
- package/comate-engine/assets/skills/code-review/references/rules/Js/JS_CORRECTNESS_RULES.md +364 -0
- package/comate-engine/assets/skills/code-review/references/rules/Js/JS_RESOURCE_CONCURRENCY_RULES.md +180 -0
- package/comate-engine/assets/skills/code-review/references/rules/Js/JS_STYLE_RULES.md +350 -0
- package/comate-engine/assets/skills/code-review/references/rules/Python/PYTHON_AUTH_RULES.md +38 -0
- package/comate-engine/assets/skills/code-review/references/rules/Python/PYTHON_CORRECTNESS_RULES.md +255 -0
- package/comate-engine/assets/skills/code-review/references/rules/Python/PYTHON_RESOURCE_CONCURRENCY_RULES.md +180 -0
- package/comate-engine/assets/skills/code-review/references/rules/Python/PYTHON_STYLE_RULES.md +195 -0
- package/comate-engine/assets/skills/code-review/references/telemetry.md +27 -0
- package/comate-engine/assets/skills/{code-security-comate → code-security}/SKILL.md +1 -0
- package/comate-engine/assets/skills/{comate-docs-comate → comate-docs}/SKILL.md +1 -1
- package/comate-engine/assets/skills/create-automation-tasks-comate/SKILL.md +300 -0
- package/comate-engine/assets/skills/create-automation-tasks-comate/references/backend_dev.md +109 -0
- package/comate-engine/assets/skills/create-automation-tasks-comate/references/env_setup.md +130 -0
- package/comate-engine/assets/skills/create-automation-tasks-comate/references/frontend_dev.md +74 -0
- package/comate-engine/assets/skills/create-automation-tasks-comate/references/git_operations.md +88 -0
- package/comate-engine/assets/skills/create-automation-tasks-comate/references/long_running_task.md +96 -0
- package/comate-engine/assets/skills/create-automation-tasks-comate/references/testing_strategy.md +94 -0
- package/comate-engine/assets/skills/create-automation-tasks-comate/scripts/check_config.py +397 -0
- package/comate-engine/assets/skills/{create-image-comate → create-image}/SKILL.md +14 -9
- package/comate-engine/assets/skills/{create-rule-comate → create-rule}/SKILL.md +1 -0
- package/comate-engine/assets/skills/{create-skill-comate → create-skill}/SKILL.md +2 -3
- package/comate-engine/assets/skills/{figma2code-comate → figma2code}/SKILL.md +1 -0
- package/comate-engine/assets/skills/{get-ugate-token-comate → get-ugate-token}/SKILL.md +97 -13
- package/comate-engine/assets/skills/get-ugate-token/getUgateToken.py +244 -0
- package/comate-engine/assets/skills/{icafe-comate → icafe}/SKILL.md +1 -13
- package/comate-engine/assets/skills/{icode-comate → icode}/SKILL.md +1 -0
- package/comate-engine/fallbackServer.js +1 -1
- package/comate-engine/node_modules/@baidu/comate-browser-use/dist/launch-chrome/index.js +1 -1
- package/comate-engine/node_modules/@baidu/comate-browser-use/package.json +5 -5
- package/comate-engine/node_modules/@comate/plugin-shared-internals/dist/index.js +3 -3
- package/comate-engine/package.json +1 -1
- package/comate-engine/server.js +137 -77
- package/dist/bundle/index.js +20 -9
- package/package.json +1 -1
- package/comate-engine/assets/skills/get-ugate-token-comate/getUgateToken.py +0 -150
- /package/comate-engine/assets/skills/{cnap-comate → cnap}/references/cases.md +0 -0
- /package/comate-engine/assets/skills/{cnap-comate → cnap}/references/deploy-troubleshoot.md +0 -0
- /package/comate-engine/assets/skills/{cnap-comate → cnap}/references/install.md +0 -0
- /package/comate-engine/assets/skills/{cnap-comate → cnap}/references/kubectl.md +0 -0
- /package/comate-engine/assets/skills/{cnap-comate → cnap}/references/login.md +0 -0
- /package/comate-engine/assets/skills/{cnap-comate → cnap}/references/oncall.md +0 -0
- /package/comate-engine/assets/skills/{cnap-comate → cnap}/scripts/install_cnap_cli.sh +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/references/credential_hosting.md +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/references/vul_repair-go_sql_injection.md +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/references/vul_repair-java_sql_injection.md +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/references/vul_repair-php_sql_injection.md +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/references/vul_repair-python_sql_injection.md +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/references/vul_repair_sensitive.md +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/scripts/credential_hosting.py +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/scripts/credential_poll.py +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/scripts/http_client.py +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/scripts/parse_scan_result.py +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/scripts/repair_vulnerability.py +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/scripts/report_chat.py +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/scripts/scan_vulnerability.py +0 -0
- /package/comate-engine/assets/skills/{code-security-comate → code-security}/scripts/utils.py +0 -0
- /package/comate-engine/assets/skills/{comate-docs-comate → comate-docs}/references/doc-map-extended.md +0 -0
- /package/comate-engine/assets/skills/{comate-docs-comate → comate-docs}/references/models-and-billing.md +0 -0
- /package/comate-engine/assets/skills/{comate-docs-comate → comate-docs}/references/product-overview.md +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/LICENSE.txt +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/agents/analyzer.md +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/agents/comparator.md +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/agents/grader.md +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/assets/eval_review.html +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/eval-viewer/generate_review.py +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/eval-viewer/viewer.html +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/references/schemas.md +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/scripts/__init__.py +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/scripts/__pycache__/aggregate_benchmark.cpython-311.pyc +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/scripts/aggregate_benchmark.py +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/scripts/generate_report.py +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/scripts/package_skill.py +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/scripts/quick_validate.py +0 -0
- /package/comate-engine/assets/skills/{create-skill-comate → create-skill}/scripts/utils.py +0 -0
- /package/comate-engine/assets/skills/{create-subagent-comate → create-subagent}/SKILL.md +0 -0
- /package/comate-engine/assets/skills/{figma2code-comate → figma2code}/references/codeConnect.md +0 -0
- /package/comate-engine/assets/skills/{figma2code-comate → figma2code}/references/designToken.md +0 -0
- /package/comate-engine/assets/skills/{figma2code-comate → figma2code}/references/image2design.md +0 -0
- /package/comate-engine/assets/skills/{find-skills-comate → find-skills}/SKILL.md +0 -0
- /package/comate-engine/assets/skills/{find-skills-comate → find-skills}/scripts/fetch_skills.py +0 -0
- /package/comate-engine/assets/skills/{find-skills-comate → find-skills}/scripts/get_download_url.py +0 -0
- /package/comate-engine/assets/skills/{find-skills-comate → find-skills}/scripts/install_skill.py +0 -0
- /package/comate-engine/assets/skills/{find-skills-comate → find-skills}/scripts/preview_skill.py +0 -0
- /package/comate-engine/assets/skills/{icafe-comate → icafe}/references/ai-workflows.md +0 -0
- /package/comate-engine/assets/skills/{icafe-comate → icafe}/references/commands.md +0 -0
- /package/comate-engine/assets/skills/{icafe-comate → icafe}/references/error-handling.md +0 -0
- /package/comate-engine/assets/skills/{icafe-comate → icafe}/references/git-auto-bindcard-workflow.md +0 -0
- /package/comate-engine/assets/skills/{icafe-comate → icafe}/references/git-bindcard-workflow.md +0 -0
- /package/comate-engine/assets/skills/{icafe-comate → icafe}/references/iql-syntax.md +0 -0
- /package/comate-engine/assets/skills/{icafe-comate → icafe}/references/platform-concepts.md +0 -0
- /package/comate-engine/assets/skills/{icafe-comate → icafe}/references/smart-create-workflow.md +0 -0
- /package/comate-engine/assets/skills/{icafe-comate → icafe}/references/smart-find-workflow.md +0 -0
- /package/comate-engine/assets/skills/{icafe-comate → icafe}/references/smart-update-workflow.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/add_reviewers.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/build_fetch_command.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/check_repo_permission.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/create_branch.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/create_draft_comment.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_ai_cr_result.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_ai_review.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_diff_content.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_diff_file.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_machine_check.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_my_reviews.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_person_commit.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_person_repo.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_repo_branch.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_repo_config.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_repo_members.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_repo_reviews.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_review_comments.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_review_info.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/get_submit_settings.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/icode-api.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/publish_comments.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/set_review_score.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/start_ai_review.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/submit_review.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/api/trigger_ai_cr.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/feature/add-reviewer.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/feature/fix-machine-check.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/feature/merge-cr.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/feature/ssh-setup.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/feature/submit-acr.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/feature/submit-cr.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/git/clone.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/git/icode-git.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/git/push.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/git/push_cr.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/install.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/references/login.md +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/scripts/add-reviewer.sh +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/scripts/common.sh +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/scripts/fix-machine-check.sh +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/scripts/merge-cr.sh +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/scripts/ssh-setup.sh +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/scripts/submit-acr.sh +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/scripts/submit-cr.sh +0 -0
- /package/comate-engine/assets/skills/{icode-comate → icode}/scripts/test-preflight.sh +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/SKILL.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/examples.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/add_member.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/change_scope.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/copy_doc.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/create_doc.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/delete_doc.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/edit_content.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/move_doc.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/query_comment.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/query_content.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/query_flowchart.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/query_permission.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/query_recent_view.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/query_repo.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/query_user_info.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/update_member.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/references/upload_attachment.md +0 -0
- /package/comate-engine/assets/skills/{ku-operator-comate → ku-operator}/scripts/ku_operator.py +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""smart-commit 统一日志模块
|
|
2
|
+
|
|
3
|
+
日志写入 ~/.comate-engine/log/kernel-yyyy-mm-dd.log
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from datetime import date
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_logger(name: str = "smart-commit") -> logging.Logger:
|
|
12
|
+
"""获取 smart-commit 日志实例
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
name: 日志名称,默认 "smart-commit"
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
配置好的 Logger 实例,写入 ~/.comate-engine/log/kernel-yyyy-mm-dd.log
|
|
19
|
+
"""
|
|
20
|
+
logger = logging.getLogger(f"comate.{name}")
|
|
21
|
+
if not logger.handlers:
|
|
22
|
+
log_dir = Path.home() / ".comate-engine" / "log"
|
|
23
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
24
|
+
log_file = log_dir / f"kernel-{date.today().isoformat()}.log"
|
|
25
|
+
handler = logging.FileHandler(log_file, encoding="utf-8")
|
|
26
|
+
handler.setFormatter(logging.Formatter(
|
|
27
|
+
"[%(asctime)s] [smart-commit] [%(levelname)s] %(message)s",
|
|
28
|
+
datefmt="%Y-%m-%d %H:%M:%S"
|
|
29
|
+
))
|
|
30
|
+
logger.addHandler(handler)
|
|
31
|
+
logger.setLevel(logging.DEBUG)
|
|
32
|
+
return logger
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""命令行工具:查询 iCafe 匹配卡片
|
|
2
|
+
|
|
3
|
+
用法:
|
|
4
|
+
python3 match_card_cli.py --username "dongkexin01"
|
|
5
|
+
|
|
6
|
+
输出:
|
|
7
|
+
JSON 格式的匹配结果,包含 cards、space_prefix、available_types 等字段。
|
|
8
|
+
失败时输出 {"error": "错误信息"} 或 {"disabled": true, "message": "..."}。
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
|
|
16
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
17
|
+
|
|
18
|
+
from cache_manager import update_icafe_result
|
|
19
|
+
from icafe.matching import find_matching_card
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main():
|
|
23
|
+
"""解析命令行参数并查询匹配卡片。"""
|
|
24
|
+
parser = argparse.ArgumentParser(description="查询 iCafe 匹配卡片")
|
|
25
|
+
parser.add_argument("--username", default=None, help="用户名,如 dongkexin01")
|
|
26
|
+
args = parser.parse_args()
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
username = args.username or os.environ.get("COMATE_USERNAME")
|
|
30
|
+
result = find_matching_card(current_user=username)
|
|
31
|
+
output = json.dumps(result, ensure_ascii=False)
|
|
32
|
+
print(output)
|
|
33
|
+
if isinstance(result, dict) and "error" not in result:
|
|
34
|
+
update_icafe_result(result)
|
|
35
|
+
except Exception as e:
|
|
36
|
+
print(json.dumps({"error": f"查询匹配卡片异常: {type(e).__name__}: {e}"}))
|
|
37
|
+
sys.exit(1)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
main()
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"""共享 payload 验证和转换函数
|
|
2
|
+
|
|
3
|
+
为 build_icafe_cards_payload.py 和 build_git_commit_payload.py 提供验证和转换逻辑。
|
|
4
|
+
每个验证函数返回错误列表(list[str]),空列表表示验证通过。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _check_type(value, expected_type, path):
|
|
11
|
+
"""检查值的类型,返回错误列表。"""
|
|
12
|
+
if not isinstance(value, expected_type):
|
|
13
|
+
type_name = expected_type.__name__ if isinstance(expected_type, type) else str(expected_type)
|
|
14
|
+
actual_name = type(value).__name__
|
|
15
|
+
if expected_type is str and isinstance(value, (int, float)):
|
|
16
|
+
actual_name = "数字"
|
|
17
|
+
return [f"'{path}' 应为 {type_name},实际为 {actual_name}"]
|
|
18
|
+
return []
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def convert_icafe_cards_payload(raw):
|
|
22
|
+
"""将模型传入的原始数据转换为 camelCase payload。
|
|
23
|
+
|
|
24
|
+
接受 snake_case 或 camelCase 的混合输入,完成转换和合并。
|
|
25
|
+
模型只需要把 match_card_cli.py 的输出原封传入,加上 viewMode 和 cards(排序后)。
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
raw: 模型传入的原始 dict
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
(converted_data, errors)
|
|
32
|
+
"""
|
|
33
|
+
errors = []
|
|
34
|
+
|
|
35
|
+
if not isinstance(raw, dict):
|
|
36
|
+
return None, ["输入必须是一个 JSON 对象"]
|
|
37
|
+
|
|
38
|
+
# 从 raw 中提取字段,兼容 snake_case 和 camelCase
|
|
39
|
+
cards = raw.get("cards", [])
|
|
40
|
+
space_prefix = raw.get("spacePrefix") or raw.get("space_prefix", "")
|
|
41
|
+
space_id = raw.get("spaceId") or raw.get("space_id", 0)
|
|
42
|
+
space_name = raw.get("spaceName") or raw.get("space_name", "")
|
|
43
|
+
available_spaces = raw.get("availableSpaces") or raw.get("available_spaces", [])
|
|
44
|
+
view_mode = raw.get("viewMode") or raw.get("view_mode", "")
|
|
45
|
+
defaults_raw = raw.get("defaults", {})
|
|
46
|
+
|
|
47
|
+
# 构建 defaults
|
|
48
|
+
if isinstance(defaults_raw, dict):
|
|
49
|
+
defaults = {
|
|
50
|
+
"title": defaults_raw.get("title", ""),
|
|
51
|
+
"typeId": defaults_raw.get("typeId") or defaults_raw.get("type_id", ""),
|
|
52
|
+
"typeName": defaults_raw.get("typeName") or defaults_raw.get("type_name", ""),
|
|
53
|
+
"spaceId": defaults_raw.get("spaceId") or defaults_raw.get("space_id", 0),
|
|
54
|
+
}
|
|
55
|
+
else:
|
|
56
|
+
defaults = {"title": "", "typeId": "", "typeName": "", "spaceId": 0}
|
|
57
|
+
|
|
58
|
+
# 如果模型没传 defaults 但 raw 里有顶层字段,从顶层取
|
|
59
|
+
if not defaults.get("typeId") and raw.get("available_types"):
|
|
60
|
+
defaults["typeId"] = str(raw["available_types"][0]["id"]) if raw["available_types"] else ""
|
|
61
|
+
defaults["typeName"] = raw["available_types"][0]["name"] if raw["available_types"] else ""
|
|
62
|
+
if not defaults.get("spaceId") and space_id:
|
|
63
|
+
defaults["spaceId"] = space_id
|
|
64
|
+
|
|
65
|
+
data = {
|
|
66
|
+
"cards": cards,
|
|
67
|
+
"spacePrefix": space_prefix,
|
|
68
|
+
"spaceId": space_id,
|
|
69
|
+
"spaceName": space_name,
|
|
70
|
+
"availableSpaces": available_spaces,
|
|
71
|
+
"viewMode": view_mode,
|
|
72
|
+
"defaults": defaults,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# 验证
|
|
76
|
+
errors.extend(_validate_icafe_cards(data))
|
|
77
|
+
|
|
78
|
+
return data, errors
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _validate_icafe_cards(data):
|
|
82
|
+
"""验证转换后的 icafe-cards payload。"""
|
|
83
|
+
errors = []
|
|
84
|
+
|
|
85
|
+
# cards
|
|
86
|
+
if not isinstance(data["cards"], list):
|
|
87
|
+
errors.append("'cards' 应为数组")
|
|
88
|
+
else:
|
|
89
|
+
for i, card in enumerate(data["cards"]):
|
|
90
|
+
if not isinstance(card, dict):
|
|
91
|
+
errors.append(f"'cards[{i}]' 应为对象")
|
|
92
|
+
continue
|
|
93
|
+
for key in ("sequence", "title", "type", "status"):
|
|
94
|
+
if key not in card:
|
|
95
|
+
errors.append(f"'cards[{i}].{key}' 缺失")
|
|
96
|
+
elif not isinstance(card[key], str):
|
|
97
|
+
# sequence 可能是数字,转成字符串
|
|
98
|
+
if key == "sequence":
|
|
99
|
+
card[key] = str(card[key])
|
|
100
|
+
else:
|
|
101
|
+
errors.append(f"'cards[{i}].{key}' 应为字符串")
|
|
102
|
+
|
|
103
|
+
# spacePrefix
|
|
104
|
+
if not isinstance(data["spacePrefix"], str):
|
|
105
|
+
errors.append("'spacePrefix' 应为字符串")
|
|
106
|
+
elif not data["spacePrefix"]:
|
|
107
|
+
errors.append("'spacePrefix' 不能为空字符串")
|
|
108
|
+
|
|
109
|
+
# spaceId
|
|
110
|
+
if not isinstance(data["spaceId"], (int, float)):
|
|
111
|
+
errors.append("'spaceId' 应为数字")
|
|
112
|
+
|
|
113
|
+
# spaceName
|
|
114
|
+
if not isinstance(data["spaceName"], str):
|
|
115
|
+
errors.append("'spaceName' 应为字符串")
|
|
116
|
+
|
|
117
|
+
# availableSpaces
|
|
118
|
+
if not isinstance(data["availableSpaces"], list):
|
|
119
|
+
errors.append("'availableSpaces' 应为数组")
|
|
120
|
+
else:
|
|
121
|
+
for i, space in enumerate(data["availableSpaces"]):
|
|
122
|
+
if not isinstance(space, dict):
|
|
123
|
+
errors.append(f"'availableSpaces[{i}]' 应为对象")
|
|
124
|
+
continue
|
|
125
|
+
for key in ("id", "prefix", "name", "types"):
|
|
126
|
+
if key not in space:
|
|
127
|
+
errors.append(f"'availableSpaces[{i}].{key}' 缺失")
|
|
128
|
+
# types 检查(但允许为空)
|
|
129
|
+
if "types" in space and isinstance(space["types"], list):
|
|
130
|
+
for j, t in enumerate(space["types"]):
|
|
131
|
+
if not isinstance(t, dict):
|
|
132
|
+
errors.append(f"'availableSpaces[{i}].types[{j}]' 应为对象")
|
|
133
|
+
continue
|
|
134
|
+
if "id" not in t:
|
|
135
|
+
errors.append(f"'availableSpaces[{i}].types[{j}].id' 缺失")
|
|
136
|
+
if "name" not in t:
|
|
137
|
+
errors.append(f"'availableSpaces[{i}].types[{j}].name' 缺失")
|
|
138
|
+
|
|
139
|
+
# viewMode
|
|
140
|
+
valid_modes = ("list", "create")
|
|
141
|
+
if not isinstance(data["viewMode"], str):
|
|
142
|
+
errors.append(f"'viewMode' 应为字符串,取值范围为 {valid_modes}")
|
|
143
|
+
elif data["viewMode"] not in valid_modes:
|
|
144
|
+
errors.append(f"'viewMode' 应为 {valid_modes} 之一,实际为 '{data['viewMode']}'")
|
|
145
|
+
|
|
146
|
+
# defaults
|
|
147
|
+
if not isinstance(data["defaults"], dict):
|
|
148
|
+
errors.append("'defaults' 应为对象")
|
|
149
|
+
else:
|
|
150
|
+
defaults = data["defaults"]
|
|
151
|
+
for key in ("title", "typeId", "typeName", "spaceId"):
|
|
152
|
+
if key not in defaults:
|
|
153
|
+
errors.append(f"'defaults.{key}' 缺失")
|
|
154
|
+
if "title" in defaults:
|
|
155
|
+
errors.extend(_check_type(defaults["title"], str, "defaults.title"))
|
|
156
|
+
if "typeId" in defaults:
|
|
157
|
+
errors.extend(_check_type(defaults["typeId"], str, "defaults.typeId"))
|
|
158
|
+
if "typeName" in defaults:
|
|
159
|
+
errors.extend(_check_type(defaults["typeName"], str, "defaults.typeName"))
|
|
160
|
+
if "spaceId" in defaults:
|
|
161
|
+
if not isinstance(defaults["spaceId"], (int, float)):
|
|
162
|
+
errors.append("'defaults.spaceId' 应为数字")
|
|
163
|
+
else:
|
|
164
|
+
defaults["spaceId"] = int(defaults["spaceId"])
|
|
165
|
+
|
|
166
|
+
# spaceId 转为 int
|
|
167
|
+
if isinstance(data["spaceId"], float):
|
|
168
|
+
data["spaceId"] = int(data["spaceId"])
|
|
169
|
+
|
|
170
|
+
return errors
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def convert_git_commit_payload(raw):
|
|
174
|
+
"""将模型传入的原始数据转换为并验证 git-commit payload。
|
|
175
|
+
|
|
176
|
+
模型需要传入 commitMessage、boundCard、workspaces。
|
|
177
|
+
workspaces 中的 diffSummary 保持 snake_case(与 git_diff_cli.py 输出一致)。
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
raw: 模型传入的原始 dict
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
(converted_data, errors)
|
|
184
|
+
"""
|
|
185
|
+
errors = []
|
|
186
|
+
|
|
187
|
+
if not isinstance(raw, dict):
|
|
188
|
+
return None, ["输入必须是一个 JSON 对象"]
|
|
189
|
+
|
|
190
|
+
commit_message = raw.get("commitMessage") or raw.get("commit_message", "")
|
|
191
|
+
bound_card = raw.get("boundCard") or raw.get("boundCard") or raw.get("icafe_card")
|
|
192
|
+
workspaces = raw.get("workspaces", [])
|
|
193
|
+
|
|
194
|
+
data = {
|
|
195
|
+
"commitMessage": commit_message,
|
|
196
|
+
"boundCard": bound_card,
|
|
197
|
+
"workspaces": workspaces,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
errors.extend(_validate_git_commit(data))
|
|
201
|
+
|
|
202
|
+
return data, errors
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _validate_git_commit(data):
|
|
206
|
+
"""验证转换后的 git-commit payload。"""
|
|
207
|
+
errors = []
|
|
208
|
+
|
|
209
|
+
# commitMessage
|
|
210
|
+
if not isinstance(data["commitMessage"], str):
|
|
211
|
+
errors.append("'commitMessage' 应为字符串")
|
|
212
|
+
elif not data["commitMessage"]:
|
|
213
|
+
errors.append("'commitMessage' 不能为空字符串")
|
|
214
|
+
|
|
215
|
+
# boundCard
|
|
216
|
+
bound_card = data["boundCard"]
|
|
217
|
+
if bound_card is not None and not isinstance(bound_card, dict):
|
|
218
|
+
errors.append("'boundCard' 应为对象或 null")
|
|
219
|
+
elif isinstance(bound_card, dict):
|
|
220
|
+
for key in ("sequence", "title", "type", "status", "spacePrefix"):
|
|
221
|
+
if key not in bound_card:
|
|
222
|
+
errors.append(f"'boundCard.{key}' 缺失")
|
|
223
|
+
for key in ("sequence", "title", "type", "status", "spacePrefix"):
|
|
224
|
+
if key in bound_card and not isinstance(bound_card[key], str):
|
|
225
|
+
# sequence 可能是数字
|
|
226
|
+
if key == "sequence":
|
|
227
|
+
bound_card[key] = str(bound_card[key])
|
|
228
|
+
else:
|
|
229
|
+
errors.append(f"'boundCard.{key}' 应为字符串")
|
|
230
|
+
|
|
231
|
+
# workspaces
|
|
232
|
+
if not isinstance(data["workspaces"], list):
|
|
233
|
+
if isinstance(data["workspaces"], str):
|
|
234
|
+
errors.append("'workspaces' 应为数组,不能是字符串")
|
|
235
|
+
else:
|
|
236
|
+
errors.append("'workspaces' 应为数组")
|
|
237
|
+
elif len(data["workspaces"]) == 0:
|
|
238
|
+
errors.append("'workspaces' 数组不能为空")
|
|
239
|
+
else:
|
|
240
|
+
for i, ws in enumerate(data["workspaces"]):
|
|
241
|
+
p = f"workspaces[{i}]"
|
|
242
|
+
if not isinstance(ws, dict):
|
|
243
|
+
errors.append(f"'{p}' 应为对象")
|
|
244
|
+
continue
|
|
245
|
+
|
|
246
|
+
ws_required = {"workspace", "repoName", "currentBranch",
|
|
247
|
+
"remoteBranches", "hasChanges", "diffSummary"}
|
|
248
|
+
for key in ws_required:
|
|
249
|
+
if key not in ws:
|
|
250
|
+
errors.append(f"'{p}.{key}' 缺失")
|
|
251
|
+
|
|
252
|
+
if "workspace" in ws:
|
|
253
|
+
errors.extend(_check_type(ws["workspace"], str, f"{p}.workspace"))
|
|
254
|
+
if "repoName" in ws:
|
|
255
|
+
errors.extend(_check_type(ws["repoName"], str, f"{p}.repoName"))
|
|
256
|
+
if "currentBranch" in ws:
|
|
257
|
+
errors.extend(_check_type(ws["currentBranch"], str, f"{p}.currentBranch"))
|
|
258
|
+
|
|
259
|
+
# remoteBranches
|
|
260
|
+
if "remoteBranches" in ws:
|
|
261
|
+
if not isinstance(ws["remoteBranches"], list):
|
|
262
|
+
errors.append(f"'{p}.remoteBranches' 应为数组")
|
|
263
|
+
else:
|
|
264
|
+
for j, branch in enumerate(ws["remoteBranches"]):
|
|
265
|
+
bp = f"{p}.remoteBranches[{j}]"
|
|
266
|
+
if not isinstance(branch, dict):
|
|
267
|
+
errors.append(f"'{bp}' 应为对象")
|
|
268
|
+
continue
|
|
269
|
+
if "name" not in branch:
|
|
270
|
+
errors.append(f"'{bp}.name' 缺失")
|
|
271
|
+
elif not isinstance(branch["name"], str):
|
|
272
|
+
errors.append(f"'{bp}.name' 应为字符串")
|
|
273
|
+
if "isCurrent" not in branch:
|
|
274
|
+
errors.append(f"'{bp}.isCurrent' 缺失")
|
|
275
|
+
elif not isinstance(branch["isCurrent"], bool):
|
|
276
|
+
errors.append(f"'{bp}.isCurrent' 应为布尔值")
|
|
277
|
+
|
|
278
|
+
# hasChanges + diffSummary 一致性
|
|
279
|
+
if "hasChanges" in ws:
|
|
280
|
+
if not isinstance(ws["hasChanges"], bool):
|
|
281
|
+
errors.append(f"'{p}.hasChanges' 应为布尔值")
|
|
282
|
+
else:
|
|
283
|
+
ds = ws.get("diffSummary")
|
|
284
|
+
if not ws["hasChanges"] and ds is not None:
|
|
285
|
+
errors.append(f"'{p}.hasChanges' 为 false 时,'{p}.diffSummary' 必须为 null")
|
|
286
|
+
elif ws["hasChanges"] and ds is None:
|
|
287
|
+
errors.append(f"'{p}.hasChanges' 为 true 时,'{p}.diffSummary' 不能为 null")
|
|
288
|
+
elif ws["hasChanges"] and isinstance(ds, dict):
|
|
289
|
+
if "changed_files" not in ds:
|
|
290
|
+
errors.append(f"'{p}.diffSummary.changed_files' 缺失")
|
|
291
|
+
elif not isinstance(ds["changed_files"], list):
|
|
292
|
+
errors.append(f"'{p}.diffSummary.changed_files' 应为数组")
|
|
293
|
+
else:
|
|
294
|
+
for k, cf in enumerate(ds["changed_files"]):
|
|
295
|
+
cfp = f"{p}.diffSummary.changed_files[{k}]"
|
|
296
|
+
if not isinstance(cf, dict):
|
|
297
|
+
errors.append(f"'{cfp}' 应为对象")
|
|
298
|
+
continue
|
|
299
|
+
for fkey, ftype in [("file", str), ("insertions", int), ("deletions", int)]:
|
|
300
|
+
if fkey not in cf:
|
|
301
|
+
errors.append(f"'{cfp}.{fkey}' 缺失")
|
|
302
|
+
elif not isinstance(cf[fkey], ftype):
|
|
303
|
+
errors.append(f"'{cfp}.{fkey}' 应为 {ftype.__name__}")
|
|
304
|
+
if "stat_summary" not in ds:
|
|
305
|
+
errors.append(f"'{p}.diffSummary.stat_summary' 缺失")
|
|
306
|
+
elif not isinstance(ds["stat_summary"], str):
|
|
307
|
+
errors.append(f"'{p}.diffSummary.stat_summary' 应为字符串")
|
|
308
|
+
|
|
309
|
+
return errors
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""命令行工具:通过链接或卡片 ID 识别并获取 iCafe 卡片详情
|
|
2
|
+
|
|
3
|
+
用法:
|
|
4
|
+
python3 recognize_card_cli.py --link "DevOps-iScan-35835"
|
|
5
|
+
python3 recognize_card_cli.py --link "https://console.cloud.baidu-int.com/devops/icafe/issue/xxxx/show"
|
|
6
|
+
|
|
7
|
+
输出:
|
|
8
|
+
JSON 格式的卡片详情,包含 sequence、title、type、status、spacePrefix 等字段。
|
|
9
|
+
失败时输出 {"error": "错误信息"}。
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
18
|
+
|
|
19
|
+
from icafe.client import ICafeQueryClient
|
|
20
|
+
from icafe.matching import parse_card_id_from_link
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def main():
|
|
24
|
+
"""识别 iCafe 卡片的主函数"""
|
|
25
|
+
parser = argparse.ArgumentParser(description="识别 iCafe 卡片")
|
|
26
|
+
parser.add_argument("--link", required=True,
|
|
27
|
+
help="卡片链接或卡片 ID,示例: "
|
|
28
|
+
"'DevOps-iScan-35835' 或 "
|
|
29
|
+
"'https://console.cloud.baidu-int.com/devops/icafe/issue/DevOps-iScan-35835/show'")
|
|
30
|
+
args = parser.parse_args()
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
parsed = parse_card_id_from_link(args.link)
|
|
34
|
+
if not parsed:
|
|
35
|
+
print(json.dumps({"error": "无法解析卡片链接或 ID,请检查格式"}))
|
|
36
|
+
sys.exit(1)
|
|
37
|
+
|
|
38
|
+
space_prefix = parsed["space_prefix"]
|
|
39
|
+
card_id = parsed["card_id"]
|
|
40
|
+
|
|
41
|
+
client = ICafeQueryClient()
|
|
42
|
+
card_detail = client.get_card_by_id(space_id=space_prefix, card_id=card_id)
|
|
43
|
+
|
|
44
|
+
if card_detail and card_detail.get("cards"):
|
|
45
|
+
card = card_detail["cards"][0]
|
|
46
|
+
print(json.dumps({
|
|
47
|
+
"success": True,
|
|
48
|
+
"sequence": card_id,
|
|
49
|
+
"title": card.get("title", ""),
|
|
50
|
+
"type": card.get("type", ""),
|
|
51
|
+
"status": card.get("status", ""),
|
|
52
|
+
"spacePrefix": space_prefix,
|
|
53
|
+
}))
|
|
54
|
+
else:
|
|
55
|
+
print(json.dumps({"error": "无法获取卡片信息,请检查链接或 ID 是否正确"}))
|
|
56
|
+
sys.exit(1)
|
|
57
|
+
except Exception as e:
|
|
58
|
+
print(json.dumps({"error": f"识别卡片异常: {type(e).__name__}: {e}"}))
|
|
59
|
+
sys.exit(1)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
main()
|
package/comate-engine/assets/skills/{automation-browser-comate → automation-browser}/SKILL.md
RENAMED
|
@@ -15,6 +15,7 @@ description: |
|
|
|
15
15
|
- API documentation, blog posts, or articles
|
|
16
16
|
- Quick content lookup without interaction
|
|
17
17
|
For complex tasks or information-heavy pages, use `delegate_subtask` to invoke a subagent with this skill.
|
|
18
|
+
hidden: true
|
|
18
19
|
---
|
|
19
20
|
|
|
20
21
|
# Comate Automation Browser
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-review
|
|
3
|
+
description: >-
|
|
4
|
+
使用此 skill 审查代码变更(git diff、暂存区改动、分支差异或指定 commit),检查 bug、安全风险、性能问题和代码质量。当用户想要审查、检视或检查代码改动时触发——包括"code review"、"review my changes"、"帮我审查代码"、"看看改动有没有问题"、"review HEAD~N"、"check my PR"、"CR"、"帮我过一遍"、"这段改动有没有问题",或任何在合入/推送前评估代码变更是否正确安全的请求。此 skill 检查 diff 并输出按优先级排序的问题清单与修复建议。
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Code Review
|
|
8
|
+
|
|
9
|
+
此 skill 用于对当前代码变更进行结构化审查。默认遵循 **review-first** 工作流:先收集范围、执行审查、输出报告,只有在用户明确要求后才进入修复阶段。
|
|
10
|
+
|
|
11
|
+
## 核心原则
|
|
12
|
+
|
|
13
|
+
1. **范围优先于结论**:先确认要审什么,再开始审查,避免误把"看当前改动"扩大成"审整个分支"。
|
|
14
|
+
2. **风险优先于规模**:文件数和行数只用于粗分级,真实模式由风险特征决定。
|
|
15
|
+
3. **证据优先于偏好**:只报告有明确代码证据的问题,不输出纯风格偏好建议。
|
|
16
|
+
4. **简洁优先于详尽**:每条 finding 用 1-2 句话说清风险和建议,不堆砌文字。用户需要快速扫描,不是阅读论文。
|
|
17
|
+
5. **上下文按需加载**:默认读取 diff 和局部上下文,只有在判断需要时才扩展到调用链、类型定义和相邻文件。
|
|
18
|
+
6. **结果可执行**:每个 finding 都要说明影响、触发场景或证据,并给出具体建议。
|
|
19
|
+
7. **失败可降级**:并行审查失败时要自动降级,而不是中断整次 review。
|
|
20
|
+
|
|
21
|
+
## SubAgent 调用规范
|
|
22
|
+
|
|
23
|
+
本 skill 通过 `delegate_subtask` 工具启动审查 SubAgent。每个 SubAgent 是独立的 Agent 实例,拥有只读工具集,能够自行获取 diff、搜索代码库、读取文件。
|
|
24
|
+
|
|
25
|
+
- **agent_type 固定为 `"Explore"`**
|
|
26
|
+
- **query**:只传递路径和范围,**不注入文件原文**——让 SubAgent 自行读取指令文件
|
|
27
|
+
- 深度审查模式下,所有 `delegate_subtask` 调用**必须在同一轮响应中并行发起**,不要串行等待
|
|
28
|
+
|
|
29
|
+
> Query 构建模板和各模式的完整调用示例见 `{SKILL_DIR}/references/dispatch-template.md`。主 Agent 执行 Step 3/4/5 时须读取该文件获取模板。
|
|
30
|
+
|
|
31
|
+
## 工作流程
|
|
32
|
+
|
|
33
|
+
### Step 1:确定审查范围与审查模式
|
|
34
|
+
|
|
35
|
+
本步骤需要在**一轮响应中**完成以下全部决策:确认范围 → 输出统计 → 风险分级 → 选择审查模式。
|
|
36
|
+
|
|
37
|
+
#### 1a:确定范围
|
|
38
|
+
|
|
39
|
+
**用户显式指定范围时**:直接使用用户给出的范围(如 `review HEAD~3`、`review main..feature`)。
|
|
40
|
+
|
|
41
|
+
**用户未指定范围时**:通过 git 命令探测当前变更状态,按以下优先级选择范围:
|
|
42
|
+
1. **工作区变更优先**:staged、unstaged、untracked 中只要有任意变更,就以工作区内容为审查范围,不要扩大到整个分支
|
|
43
|
+
2. **分支级审查**:仅当工作区无变更时,回退到当前分支相对于目标分支的变更
|
|
44
|
+
3. **最近一次提交**:如果以上都没有内容,回退到最近一次提交的变更
|
|
45
|
+
4. 如果仍没有内容,提示用户手动指定审查范围
|
|
46
|
+
|
|
47
|
+
> **重要**:
|
|
48
|
+
> - 尽量通过**一次 `run_command`** 完成探测,避免多轮串行调用
|
|
49
|
+
> - 主 Agent 只需获取变更文件列表和统计信息即可做决策,**不要获取完整 diff 原文**,完整 diff 由 SubAgent 自行获取
|
|
50
|
+
> - 确定范围后,记录下对应的 **基准 git diff 命令**(如 `git diff --cached`、`git diff <merge-base> HEAD`),后续写入每个 SubAgent 的 query 中,确保所有 SubAgent 基于同一个基准变更
|
|
51
|
+
|
|
52
|
+
对于 untracked 文件:小文件直接读取全文并标记为 `[新文件]`;大文件只读取关键片段并在报告里说明为局部审查。
|
|
53
|
+
|
|
54
|
+
#### 1b:范围过滤
|
|
55
|
+
|
|
56
|
+
默认跳过以下低价值输入,除非用户明确要求或这些文件正是问题核心:
|
|
57
|
+
- lockfile
|
|
58
|
+
- 构建产物、snapshot、minified 文件
|
|
59
|
+
- 二进制文件
|
|
60
|
+
- 纯格式化噪音变更
|
|
61
|
+
|
|
62
|
+
以下类型的变更即使很小,也应保留并提高风险等级:
|
|
63
|
+
- 权限、鉴权、token、配置下发
|
|
64
|
+
- 命令执行、文件读写、路径拼接
|
|
65
|
+
- 网络请求、序列化/反序列化、持久化存储
|
|
66
|
+
- 应用启动或初始化入口、事件分发链路、共享状态
|
|
67
|
+
|
|
68
|
+
> **过滤结果必须体现在 diff 命令中**:将过滤后的文件列表写入 git diff 的路径参数(如 `git diff --cached -- src/a.ts src/b.ts`),或用 `:(exclude)` 排除低价值文件(如 `git diff --cached -- . ':(exclude)package-lock.json'`)。
|
|
69
|
+
|
|
70
|
+
#### 1c:统计信息与风险分级
|
|
71
|
+
|
|
72
|
+
向用户展示变更概览:变更文件数、新增/删除行数(如已获取)、是否包含新文件、是否命中高风险目录或关键词。
|
|
73
|
+
|
|
74
|
+
结合以下风险信号做分级(不要只看文件数和行数):
|
|
75
|
+
- 是否命中高风险目录、模块或文件类型
|
|
76
|
+
- 是否修改公共 API、类型定义、协议、持久化结构
|
|
77
|
+
- 是否涉及异步流程、状态同步、缓存、并发
|
|
78
|
+
- 是否涉及命令执行、路径、网络、鉴权、输入校验
|
|
79
|
+
- 是否引入新文件或新增较大逻辑块
|
|
80
|
+
|
|
81
|
+
#### 1d:选择审查模式
|
|
82
|
+
|
|
83
|
+
**常规审查**:满足以下条件时使用单 Agent 综合审查。
|
|
84
|
+
- 文件数 <= 5
|
|
85
|
+
- 变更总行数 <= 200
|
|
86
|
+
- 未命中高风险模块
|
|
87
|
+
- 没有显著的新流程、新协议或新持久化结构
|
|
88
|
+
|
|
89
|
+
**深度审查**:出现任一条件时使用 4 个 SubAgent 并行审查。
|
|
90
|
+
- 文件数 > 5
|
|
91
|
+
- 变更总行数 > 200
|
|
92
|
+
- 命中高风险模块或边界能力
|
|
93
|
+
- 存在新增文件、新主流程或明显跨模块改动
|
|
94
|
+
|
|
95
|
+
**超大变更降级**:当变更非常大(例如 > 20 个文件或 > 800 行)时,不要一次性把所有上下文塞给所有 Agent。应按文件组或风险模块拆分,优先审查高风险部分,并在报告中说明存在"分批审查"或"抽样审查"。
|
|
96
|
+
|
|
97
|
+
### Step 2:加载审查知识
|
|
98
|
+
|
|
99
|
+
主 Agent 只需处理**业务规则**:如果仓库中存在 `.comate/rules/`、`CLAUDE.md`、`.cursorrules`、`.github/copilot-instructions.md` 等规则文件,只读取与本次变更直接相关的规则,提取 1-2 句话摘要写入 SubAgent query。与当前改动无关的规则不要注入。
|
|
100
|
+
|
|
101
|
+
#### 自定义规则探测
|
|
102
|
+
|
|
103
|
+
检查 `{SKILL_DIR}/references/custom-rules/` 目录:
|
|
104
|
+
- 如果存在**非模板**的 `.md` 文件(`RULE_TEMPLATE.md` 不算)→ 标记 `HAS_CUSTOM_RULES = true`
|
|
105
|
+
- 如果目录不存在、为空或只有 `RULE_TEMPLATE.md` → 标记 `HAS_CUSTOM_RULES = false`
|
|
106
|
+
|
|
107
|
+
> 探测方式:一次 glob 或 ls 即可确认,无需读取规则文件内容。此标记用于 Step 3/4 决定是否追加 custom-reviewer SubAgent。
|
|
108
|
+
|
|
109
|
+
### Step 3:发起审查
|
|
110
|
+
|
|
111
|
+
读取 `{SKILL_DIR}/references/dispatch-template.md` 获取调用模板,根据 Step 1 选择的审查模式构建 query 并发起 SubAgent 调用。
|
|
112
|
+
|
|
113
|
+
> SubAgent 会自行决定上下文获取策略(读取 diff 附近代码、搜索调用链、查找类型定义等),主 Agent 无需在 query 中指定上下文获取步骤。
|
|
114
|
+
|
|
115
|
+
### Step 4:执行审查
|
|
116
|
+
|
|
117
|
+
设 `SKILL_DIR` 为本 skill 目录的绝对路径(即 SKILL.md 所在目录)。
|
|
118
|
+
|
|
119
|
+
按 `{SKILL_DIR}/references/dispatch-template.md` 中对应模式(常规/深度)的模板发起 `delegate_subtask` 调用。若 `HAS_CUSTOM_RULES = true`,在同一轮响应中追加 custom-reviewer 调用。
|
|
120
|
+
|
|
121
|
+
每个 SubAgent 会自行读取对应的 reviewer 指令和输出格式,自行决定重点关注 diff 的哪些部分。
|
|
122
|
+
|
|
123
|
+
### Step 5:Meta-Review 与结果归并
|
|
124
|
+
|
|
125
|
+
当深度审查至少成功返回 2 个维度结果时,按 `{SKILL_DIR}/references/dispatch-template.md` 中 Meta-Review 模板发起调用。Meta-Review 的 query 中**必须包含已有的 findings 结果(JSON)**。
|
|
126
|
+
|
|
127
|
+
#### 归并规则
|
|
128
|
+
|
|
129
|
+
收集所有结果后,执行以下处理:
|
|
130
|
+
1. **先应用 Meta-Review actions**,再追加 `missed_findings`
|
|
131
|
+
2. **去重**:只有在"同一文件、重叠或相邻代码段、同一类别、同一根因"时才去重,不要机械按行号合并不同问题
|
|
132
|
+
3. **合并相近问题**:同一文件的重复模式可合并为一条,但要保留所有关键位置
|
|
133
|
+
4. **按严重等级排序**:`P0 > P1 > P2 > P3`
|
|
134
|
+
5. **统一重新编号**:输出给用户的最终编号使用连续数字,保留来源维度作为辅助信息
|
|
135
|
+
|
|
136
|
+
### Step 6:输出 Review 报告
|
|
137
|
+
|
|
138
|
+
按 `{SKILL_DIR}/references/report-format.md` 中定义的模板和规则输出报告。简洁是第一优先级。
|
|
139
|
+
|
|
140
|
+
### Step 7:埋点上报与收尾
|
|
141
|
+
|
|
142
|
+
静默执行埋点上报(详见 `{SKILL_DIR}/references/telemetry.md`),任何失败不阻塞用户交互,不向用户展示错误信息。
|
|
143
|
+
|
|
144
|
+
### Step 8:用户交互
|
|
145
|
+
|
|
146
|
+
完成报告后**必须暂停**,使用 `ask_user_question` 工具向用户提供下一步选项,**不要自动执行任何修复或提交操作**。
|
|
147
|
+
|
|
148
|
+
调用 `ask_user_question` 时,根据实际审查结果动态构建选项:
|
|
149
|
+
|
|
150
|
+
- 如果存在 P0/P1 问题,提供以下选项:
|
|
151
|
+
1. 修复全部问题
|
|
152
|
+
2. 仅修复 P0/P1
|
|
153
|
+
3. 选择性修复(稍后指定编号)
|
|
154
|
+
4. 仅记录问题,不改代码
|
|
155
|
+
|
|
156
|
+
- 如果只有 P2/P3 问题,提供以下选项:
|
|
157
|
+
1. 修复全部问题
|
|
158
|
+
2. 选择性修复(稍后指定编号)
|
|
159
|
+
3. 仅记录问题,不改代码
|
|
160
|
+
|
|
161
|
+
- 如果未发现问题,跳过此步骤,直接告知用户审查通过。
|
|
162
|
+
|
|
163
|
+
在用户通过 `ask_user_question` 明确选择前:
|
|
164
|
+
- 不要自动修改代码
|
|
165
|
+
- 不要自动提交代码
|
|
166
|
+
- 不要把 review 结论当作已执行修复
|
|
167
|
+
|
|
168
|
+
用户选择修复后:
|
|
169
|
+
- 如果用户选择"选择性修复",追问具体要修复的 finding 编号
|
|
170
|
+
- 优先修复 P0/P1
|
|
171
|
+
- 修复后可建议重新运行 review 或最小化验证
|
|
172
|
+
|
|
173
|
+
## 严重等级定义
|
|
174
|
+
|
|
175
|
+
| 等级 | 标记 | 含义 | 处理建议 |
|
|
176
|
+
|------|------|------|----------|
|
|
177
|
+
| `P0` | 🔴 | 明确的严重 bug、安全漏洞、数据损坏或崩溃风险 | 必须阻断合入 |
|
|
178
|
+
| `P1` | 🟠 | 高概率逻辑问题、显著性能问题、重要边界错误 | 合入前应修复 |
|
|
179
|
+
| `P2` | 🟡 | 中等可维护性或稳定性问题 | 建议本次修复或创建后续任务 |
|
|
180
|
+
| `P3` | 🔵 | 低风险改进项 | 可选优化 |
|
|
181
|
+
|
|
182
|
+
## 资源文件
|
|
183
|
+
|
|
184
|
+
SubAgent 通过 `SKILL_DIR` 路径自行读取以下文件:
|
|
185
|
+
|
|
186
|
+
- `agents/reuse-reviewer.md`、`agents/style-reviewer.md`、`agents/reliability-reviewer.md`、`agents/correctness-reviewer.md`:四个维度的审查指令
|
|
187
|
+
- `agents/custom-reviewer.md`:自定义规则扫描指令(仅 `HAS_CUSTOM_RULES = true` 时被调用)
|
|
188
|
+
- `agents/meta-reviewer.md`:Meta-Review 指令
|
|
189
|
+
- `references/output-schema.md`:SubAgent 输出结构
|
|
190
|
+
- `references/dispatch-template.md`:SubAgent 调度模板(主 Agent 读取)
|
|
191
|
+
- `references/report-format.md`:报告输出格式(主 Agent 读取)
|
|
192
|
+
- `references/telemetry.md`:埋点上报逻辑(主 Agent 读取)
|
|
193
|
+
- `references/custom-rules/*.md`:用户自定义审查规则文件(`RULE_TEMPLATE.md` 为模板,不参与扫描)
|
|
194
|
+
|
|
195
|
+
## 备注
|
|
196
|
+
|
|
197
|
+
> 以下为执行底线,当流程细节与这些原则冲突时,以此为准。
|
|
198
|
+
|
|
199
|
+
- 宁可漏报低风险问题,也不输出无证据的 finding
|
|
200
|
+
- 上下文不足时写"不足以确认",不强行下结论
|
|
201
|
+
- 修复阶段只改被选中的 finding 对应代码,不顺带重构或添加无关改进
|
|
202
|
+
- 任何埋点/工具链失败均静默跳过,不阻塞用户交互
|