@comate/zulu 1.2.1-beta.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/comate-engine/assets/skills/auto-commit-comate/SKILL.md +260 -0
  2. package/comate-engine/assets/skills/auto-commit-comate/references/data_structures.md +189 -0
  3. package/comate-engine/assets/skills/auto-commit-comate/references/new_version_instruction.md +209 -0
  4. package/comate-engine/assets/skills/auto-commit-comate/references/old_version_instruction.md +208 -0
  5. package/comate-engine/assets/skills/auto-commit-comate/scripts/git_diff_cli.py +196 -0
  6. package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/git_utils.py +20 -10
  7. package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/icafe/client.py +69 -40
  8. package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/icafe/farseer.py +8 -9
  9. package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/icafe/matching.py +65 -9
  10. package/comate-engine/assets/skills/auto-commit-comate/scripts/match_card_cli.py +37 -0
  11. package/comate-engine/assets/skills/cnap-comate/SKILL.md +157 -0
  12. package/comate-engine/assets/skills/cnap-comate/references/cases.md +198 -0
  13. package/comate-engine/assets/skills/cnap-comate/references/deploy-troubleshoot.md +15 -0
  14. package/comate-engine/assets/skills/cnap-comate/references/install.md +43 -0
  15. package/comate-engine/assets/skills/cnap-comate/references/kubectl.md +55 -0
  16. package/comate-engine/assets/skills/cnap-comate/references/login.md +125 -0
  17. package/comate-engine/assets/skills/cnap-comate/references/oncall.md +24 -0
  18. package/comate-engine/assets/skills/cnap-comate/scripts/install_cnap_cli.sh +36 -0
  19. package/comate-engine/assets/skills/code-security/SKILL.md +176 -0
  20. package/comate-engine/assets/skills/code-security/references/credential_hosting.md +102 -0
  21. package/comate-engine/assets/skills/code-security/references/vul_repair_sensitive.md +219 -0
  22. package/comate-engine/assets/skills/code-security/scripts/build_repair_info.py +0 -0
  23. package/comate-engine/assets/skills/code-security/scripts/credential_hosting.py +99 -0
  24. package/comate-engine/assets/skills/code-security/scripts/credential_poll.py +350 -0
  25. package/comate-engine/assets/skills/code-security/scripts/http_client.py +173 -0
  26. package/comate-engine/assets/skills/code-security/scripts/parse_scan_result.py +301 -0
  27. package/comate-engine/assets/skills/code-security/scripts/repair_vulnerability.py +261 -0
  28. package/comate-engine/assets/skills/code-security/scripts/report_chat.py +198 -0
  29. package/comate-engine/assets/skills/code-security/scripts/scan_vulnerability.py +316 -0
  30. package/comate-engine/assets/skills/code-security-comate/SKILL.md +219 -0
  31. package/comate-engine/assets/skills/code-security-comate/references/credential_hosting.md +102 -0
  32. package/comate-engine/assets/skills/code-security-comate/references/vul_repair-go_sql_injection.md +399 -0
  33. package/comate-engine/assets/skills/code-security-comate/references/vul_repair-java_sql_injection.md +591 -0
  34. package/comate-engine/assets/skills/code-security-comate/references/vul_repair-php_sql_injection.md +318 -0
  35. package/comate-engine/assets/skills/code-security-comate/references/vul_repair-python_sql_injection.md +198 -0
  36. package/comate-engine/assets/skills/code-security-comate/references/vul_repair_sensitive.md +219 -0
  37. package/comate-engine/assets/skills/code-security-comate/scripts/credential_hosting.py +87 -0
  38. package/comate-engine/assets/skills/code-security-comate/scripts/credential_poll.py +345 -0
  39. package/comate-engine/assets/skills/code-security-comate/scripts/http_client.py +173 -0
  40. package/comate-engine/assets/skills/code-security-comate/scripts/parse_scan_result.py +392 -0
  41. package/comate-engine/assets/skills/code-security-comate/scripts/repair_vulnerability.py +245 -0
  42. package/comate-engine/assets/skills/code-security-comate/scripts/report_chat.py +145 -0
  43. package/comate-engine/assets/skills/code-security-comate/scripts/scan_vulnerability.py +444 -0
  44. package/comate-engine/assets/skills/code-security-comate/scripts/utils.py +153 -0
  45. package/comate-engine/assets/skills/comate-docs-comate/SKILL.md +148 -0
  46. package/comate-engine/assets/skills/comate-docs-comate/references/doc-map-extended.md +78 -0
  47. package/comate-engine/assets/skills/comate-docs-comate/references/models-and-billing.md +51 -0
  48. package/comate-engine/assets/skills/comate-docs-comate/references/product-overview.md +73 -0
  49. package/comate-engine/assets/skills/comate-docs-comate/references/query_content.md +83 -0
  50. package/comate-engine/assets/skills/comate-docs-comate/references/query_repo.md +57 -0
  51. package/comate-engine/assets/skills/comate-docs-comate/scripts/ku_operator.py +1575 -0
  52. package/comate-engine/assets/skills/create-image-comate/SKILL.md +278 -0
  53. package/comate-engine/assets/skills/create-skill-comate/SKILL.md +308 -217
  54. package/comate-engine/assets/skills/create-skill-comate/agents/analyzer.md +274 -0
  55. package/comate-engine/assets/skills/create-skill-comate/agents/comparator.md +202 -0
  56. package/comate-engine/assets/skills/create-skill-comate/agents/grader.md +223 -0
  57. package/comate-engine/assets/skills/create-skill-comate/assets/eval_review.html +146 -0
  58. package/comate-engine/assets/skills/create-skill-comate/eval-viewer/generate_review.py +489 -0
  59. package/comate-engine/assets/skills/create-skill-comate/eval-viewer/viewer.html +1325 -0
  60. package/comate-engine/assets/skills/create-skill-comate/references/schemas.md +430 -0
  61. package/comate-engine/assets/skills/create-skill-comate/scripts/__init__.py +0 -0
  62. package/comate-engine/assets/skills/create-skill-comate/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  63. package/comate-engine/assets/skills/create-skill-comate/scripts/__pycache__/aggregate_benchmark.cpython-311.pyc +0 -0
  64. package/comate-engine/assets/skills/create-skill-comate/scripts/aggregate_benchmark.py +412 -0
  65. package/comate-engine/assets/skills/create-skill-comate/scripts/generate_report.py +334 -0
  66. package/comate-engine/assets/skills/create-skill-comate/scripts/package_skill.py +140 -0
  67. package/comate-engine/assets/skills/create-skill-comate/scripts/utils.py +53 -0
  68. package/comate-engine/assets/skills/find-skills-comate/SKILL.md +15 -12
  69. package/comate-engine/assets/skills/find-skills-comate/scripts/fetch_skills.py +32 -3
  70. package/comate-engine/assets/skills/get-ugate-token-comate/SKILL.md +159 -0
  71. package/comate-engine/assets/skills/get-ugate-token-comate/getUgateToken.py +150 -0
  72. package/comate-engine/assets/skills/icafe-comate/SKILL.md +240 -0
  73. package/comate-engine/assets/skills/icafe-comate/references/ai-workflows.md +233 -0
  74. package/comate-engine/assets/skills/icafe-comate/references/commands.md +1147 -0
  75. package/comate-engine/assets/skills/icafe-comate/references/error-handling.md +164 -0
  76. package/comate-engine/assets/skills/icafe-comate/references/git-auto-bindcard-workflow.md +201 -0
  77. package/comate-engine/assets/skills/icafe-comate/references/git-bindcard-workflow.md +327 -0
  78. package/comate-engine/assets/skills/icafe-comate/references/iql-syntax.md +327 -0
  79. package/comate-engine/assets/skills/icafe-comate/references/platform-concepts.md +317 -0
  80. package/comate-engine/assets/skills/icafe-comate/references/smart-create-workflow.md +171 -0
  81. package/comate-engine/assets/skills/icafe-comate/references/smart-find-workflow.md +127 -0
  82. package/comate-engine/assets/skills/icafe-comate/references/smart-update-workflow.md +118 -0
  83. package/comate-engine/assets/skills/icode-comate/SKILL.md +366 -0
  84. package/comate-engine/assets/skills/icode-comate/references/api/add_reviewers.md +44 -0
  85. package/comate-engine/assets/skills/icode-comate/references/api/build_fetch_command.md +89 -0
  86. package/comate-engine/assets/skills/icode-comate/references/api/check_repo_permission.md +89 -0
  87. package/comate-engine/assets/skills/icode-comate/references/api/create_branch.md +79 -0
  88. package/comate-engine/assets/skills/icode-comate/references/api/create_draft_comment.md +109 -0
  89. package/comate-engine/assets/skills/icode-comate/references/api/get_ai_cr_result.md +190 -0
  90. package/comate-engine/assets/skills/icode-comate/references/api/get_ai_review.md +97 -0
  91. package/comate-engine/assets/skills/icode-comate/references/api/get_diff_content.md +92 -0
  92. package/comate-engine/assets/skills/icode-comate/references/api/get_diff_file.md +88 -0
  93. package/comate-engine/assets/skills/icode-comate/references/api/get_machine_check.md +73 -0
  94. package/comate-engine/assets/skills/icode-comate/references/api/get_my_reviews.md +115 -0
  95. package/comate-engine/assets/skills/icode-comate/references/api/get_person_commit.md +89 -0
  96. package/comate-engine/assets/skills/icode-comate/references/api/get_person_repo.md +63 -0
  97. package/comate-engine/assets/skills/icode-comate/references/api/get_repo_branch.md +62 -0
  98. package/comate-engine/assets/skills/icode-comate/references/api/get_repo_config.md +91 -0
  99. package/comate-engine/assets/skills/icode-comate/references/api/get_repo_members.md +118 -0
  100. package/comate-engine/assets/skills/icode-comate/references/api/get_repo_reviews.md +91 -0
  101. package/comate-engine/assets/skills/icode-comate/references/api/get_review_comments.md +87 -0
  102. package/comate-engine/assets/skills/icode-comate/references/api/get_review_info.md +81 -0
  103. package/comate-engine/assets/skills/icode-comate/references/api/get_submit_settings.md +105 -0
  104. package/comate-engine/assets/skills/icode-comate/references/api/icode-api.md +86 -0
  105. package/comate-engine/assets/skills/icode-comate/references/api/publish_comments.md +72 -0
  106. package/comate-engine/assets/skills/icode-comate/references/api/set_review_score.md +58 -0
  107. package/comate-engine/assets/skills/icode-comate/references/api/start_ai_review.md +77 -0
  108. package/comate-engine/assets/skills/icode-comate/references/api/submit_review.md +50 -0
  109. package/comate-engine/assets/skills/icode-comate/references/api/trigger_ai_cr.md +63 -0
  110. package/comate-engine/assets/skills/icode-comate/references/feature/add-reviewer.md +92 -0
  111. package/comate-engine/assets/skills/icode-comate/references/feature/fix-machine-check.md +144 -0
  112. package/comate-engine/assets/skills/icode-comate/references/feature/merge-cr.md +100 -0
  113. package/comate-engine/assets/skills/icode-comate/references/feature/ssh-setup.md +106 -0
  114. package/comate-engine/assets/skills/icode-comate/references/feature/submit-acr.md +135 -0
  115. package/comate-engine/assets/skills/icode-comate/references/feature/submit-cr.md +123 -0
  116. package/comate-engine/assets/skills/icode-comate/references/git/clone.md +67 -0
  117. package/comate-engine/assets/skills/icode-comate/references/git/icode-git.md +68 -0
  118. package/comate-engine/assets/skills/icode-comate/references/git/push.md +64 -0
  119. package/comate-engine/assets/skills/icode-comate/references/git/push_cr.md +103 -0
  120. package/comate-engine/assets/skills/icode-comate/references/install.md +144 -0
  121. package/comate-engine/assets/skills/icode-comate/references/login.md +111 -0
  122. package/comate-engine/assets/skills/icode-comate/scripts/add-reviewer.sh +154 -0
  123. package/comate-engine/assets/skills/icode-comate/scripts/common.sh +145 -0
  124. package/comate-engine/assets/skills/icode-comate/scripts/fix-machine-check.sh +131 -0
  125. package/comate-engine/assets/skills/icode-comate/scripts/merge-cr.sh +105 -0
  126. package/comate-engine/assets/skills/icode-comate/scripts/ssh-setup.sh +159 -0
  127. package/comate-engine/assets/skills/icode-comate/scripts/submit-acr.sh +236 -0
  128. package/comate-engine/assets/skills/icode-comate/scripts/submit-cr.sh +104 -0
  129. package/comate-engine/assets/skills/icode-comate/scripts/test-preflight.sh +89 -0
  130. package/comate-engine/assets/skills/ku-operator-comate/SKILL.md +121 -0
  131. package/comate-engine/assets/skills/ku-operator-comate/examples.md +190 -0
  132. package/comate-engine/assets/skills/ku-operator-comate/references/add_member.md +49 -0
  133. package/comate-engine/assets/skills/ku-operator-comate/references/change_scope.md +38 -0
  134. package/comate-engine/assets/skills/ku-operator-comate/references/copy_doc.md +50 -0
  135. package/comate-engine/assets/skills/ku-operator-comate/references/create_doc.md +61 -0
  136. package/comate-engine/assets/skills/ku-operator-comate/references/delete_doc.md +31 -0
  137. package/comate-engine/assets/skills/ku-operator-comate/references/edit_content.md +568 -0
  138. package/comate-engine/assets/skills/ku-operator-comate/references/move_doc.md +45 -0
  139. package/comate-engine/assets/skills/ku-operator-comate/references/query_comment.md +79 -0
  140. package/comate-engine/assets/skills/ku-operator-comate/references/query_content.md +83 -0
  141. package/comate-engine/assets/skills/ku-operator-comate/references/query_flowchart.md +84 -0
  142. package/comate-engine/assets/skills/ku-operator-comate/references/query_permission.md +38 -0
  143. package/comate-engine/assets/skills/ku-operator-comate/references/query_recent_view.md +67 -0
  144. package/comate-engine/assets/skills/ku-operator-comate/references/query_repo.md +57 -0
  145. package/comate-engine/assets/skills/ku-operator-comate/references/query_user_info.md +37 -0
  146. package/comate-engine/assets/skills/ku-operator-comate/references/update_member.md +41 -0
  147. package/comate-engine/assets/skills/ku-operator-comate/references/upload_attachment.md +52 -0
  148. package/comate-engine/assets/skills/ku-operator-comate/scripts/ku_operator.py +1575 -0
  149. package/comate-engine/node_modules/better-sqlite3/node_modules/.bin/prebuild-install +2 -2
  150. package/comate-engine/node_modules/tree-sitter-bash/node_modules/.bin/node-gyp-build +2 -2
  151. package/comate-engine/node_modules/tree-sitter-bash/node_modules/.bin/node-gyp-build-optional +2 -2
  152. package/comate-engine/node_modules/tree-sitter-bash/node_modules/.bin/node-gyp-build-test +2 -2
  153. package/comate-engine/package.json +2 -0
  154. package/comate-engine/server.js +263 -79
  155. package/dist/bundle/index.js +3 -3
  156. package/package.json +1 -1
  157. package/comate-engine/assets/skills/figma2code-comate/codeConnect.md +0 -37
  158. package/comate-engine/assets/skills/figma2code-comate/designToken.md +0 -3
  159. package/comate-engine/assets/skills/figma2code-comate/f2cMcp.md +0 -59
  160. package/comate-engine/assets/skills/smart-commit/SKILL.md +0 -646
  161. package/comate-engine/node_modules/@comate/plugin-host/dist/index-AZIho4HV.js +0 -1
  162. package/comate-engine/node_modules/@comate/plugin-host/dist/user-BIpzRUfb.js +0 -44
  163. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/references/issue_type_mapping.json +0 -0
  164. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/references/query_reference.md +0 -0
  165. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/compat.py +0 -0
  166. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/create_card_cli.py +0 -0
  167. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/icafe/__init__.py +0 -0
  168. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/logger.py +0 -0
  169. /package/comate-engine/assets/skills/{smart-commit → auto-commit-comate}/scripts/recognize_card_cli.py +0 -0
@@ -0,0 +1,208 @@
1
+ # 旧版本 IDE 交互指南
2
+
3
+ 本文档适用于**旧版本 IDE**(IDE 名称占位符未替换、或插件版本 < 4.1.0)的交互方式。旧版本不支持 `__silent:` 和 `__interactive:` 前缀。
4
+
5
+ ---
6
+
7
+ ## 步骤 1:获取 iCafe 数据(旧版本命令)
8
+
9
+ 使用 SKILL.md 步骤 1 中定义的命令模板,**不加 `__silent:` 前缀**直接执行。
10
+
11
+ ---
12
+
13
+ ## 步骤 2:获取 git diff(旧版本命令)
14
+
15
+ 使用 SKILL.md 步骤 2 中定义的命令模板,**不加 `__silent:` 前缀**直接执行。
16
+
17
+ ---
18
+
19
+ ## 步骤 4:展示卡片选择(文本交互)
20
+
21
+ 根据 `viewMode` 输出文本列表。
22
+
23
+ **当 `viewMode == "list"`(有高匹配卡片)时:**
24
+
25
+ 先展示卡片列表(已按匹配度排序,标注匹配理由),再展示新建选项:
26
+
27
+ ```
28
+ 📋 根据代码变更,找到以下匹配的 iCafe 卡片:
29
+
30
+ 1. ⭐ [${spacePrefix}-${card1.sequence}] ${card1.title}
31
+ 类型: ${card1.type} | 状态: ${card1.status}
32
+ 匹配理由: ${reason}
33
+
34
+ 2. [${spacePrefix}-${card2.sequence}] ${card2.title}
35
+ 类型: ${card2.type} | 状态: ${card2.status}
36
+
37
+ (最多显示 10 张卡片,⭐ 标记匹配度较高的卡片)
38
+
39
+ ---
40
+ 🆕 如需新建卡片,为你推荐以下信息:
41
+ - 推荐标题:${result.defaults.title}
42
+ - 推荐空间:${spaceName} (${spacePrefix})
43
+ - 推荐类型:${推荐的类型名称}(类型 ID: ${result.defaults.type_id})
44
+
45
+ ---
46
+ 请回复:
47
+ - 输入序号(如 "1")选择对应卡片
48
+ - 输入卡片 ID(如 "DevOps-iScan-35835")直接关联
49
+ - 输入 "new" 使用推荐信息直接新建卡片
50
+ - 输入 "new 自定义标题" 使用推荐空间和类型、但自定义标题新建
51
+ - 输入 "new?" 查看所有可选空间和类型枚举
52
+ ```
53
+
54
+ **当 `viewMode == "create"`(无高匹配卡片)时:**
55
+
56
+ 先展示新建卡片推荐(突出位置),再附上已有卡片作为备选:
57
+
58
+ ```
59
+ 💡 当前代码变更与已有卡片匹配度较低,建议新建卡片:
60
+
61
+ 🆕 推荐新建卡片信息:
62
+ - 推荐标题:${result.defaults.title}
63
+ - 推荐空间:${spaceName} (${spacePrefix})
64
+ - 推荐类型:${推荐的类型名称}(类型 ID: ${result.defaults.type_id})
65
+
66
+ ---
67
+ 📋 以下是你当前活跃的卡片(供参考):
68
+
69
+ 1. [${spacePrefix}-${card1.sequence}] ${card1.title}
70
+ 类型: ${card1.type} | 状态: ${card1.status}
71
+
72
+ (最多显示 10 张卡片)
73
+
74
+ ---
75
+ 请回复:
76
+ - 输入 "new" 使用推荐信息直接新建卡片
77
+ - 输入 "new 自定义标题" 使用推荐空间和类型、但自定义标题新建
78
+ - 输入序号(如 "1")选择对应卡片
79
+ - 输入卡片 ID(如 "DevOps-iScan-35835")直接关联
80
+ - 输入 "new?" 查看所有可选空间和类型枚举
81
+ ```
82
+
83
+ 如果没有找到卡片,输出:
84
+
85
+ ```
86
+ 📋 未找到可关联的 iCafe 卡片
87
+
88
+ 🆕 为你推荐以下建卡信息:
89
+ - 推荐标题:${result.defaults.title}
90
+ - 推荐空间:${spaceName} (${spacePrefix})
91
+ - 推荐类型:${推荐的类型名称}
92
+
93
+ ---
94
+ 请回复:
95
+ - 输入卡片 ID(如 "DevOps-iScan-35835")直接关联
96
+ - 输入 "new" 使用推荐信息直接新建卡片
97
+ - 输入 "new 自定义标题" 使用推荐空间和类型、但自定义标题新建
98
+ - 输入 "new?" 查看所有可选空间和类型枚举
99
+ ```
100
+
101
+ **推荐类型名称的获取方式:** 优先使用 `result.defaults.type_name`(由 Agent 在步骤 2 中根据 diff 语义推断)。如果为空,从 `result.available_spaces` 中找到当前空间(匹配 `space_prefix`),取其 `types` 列表中 `id` 等于 `result.defaults.type_id` 的类型的 `name`。如果仍然找不到,取该空间 `types` 列表第一个的 `name`。
102
+
103
+ ---
104
+
105
+ ## 步骤 5:处理用户操作(旧版本 IDE)
106
+
107
+ 根据用户在对话中的文本回复:
108
+
109
+ **如果用户输入序号(如 "1"、"2"):**
110
+ - 解析用户选择的卡片,保存 `selected_card` 信息,继续步骤 7
111
+
112
+ **如果用户输入卡片 ID(如 "DevOps-iScan-35835"):**
113
+ - 调用 `recognize_card_cli.py` 获取卡片详情:
114
+ ```
115
+ cd <用户项目目录> && python3 <skill_directory>/scripts/recognize_card_cli.py --link "<卡片ID>"
116
+ ```
117
+ - 保存 `selected_card` 信息,继续步骤 7
118
+
119
+ **如果用户输入 "new"(使用推荐信息直接新建):**
120
+ - 使用 `result` 中的推荐信息调用 `create_card_cli.py` 创建卡片
121
+ - 标题 = `result.defaults.title`,空间 = `result.space_prefix`
122
+ - 类型 = 从 `result.available_spaces` 中匹配当前空间,取 `types` 中 `id` 等于 `result.defaults.type_id` 的类型名称
123
+
124
+ **如果用户输入 "new 自定义标题":**
125
+ - 与 "new" 逻辑相同,但标题使用用户输入的自定义标题(去掉 "new " 前缀后的部分)
126
+
127
+ **如果用户输入 "new?"(查看空间和类型枚举):**
128
+
129
+ 从 `result.available_spaces` 输出完整枚举:
130
+
131
+ ```
132
+ 📋 可选空间和类型:
133
+
134
+ 空间 1: ${space1.name} (${space1.prefix})
135
+ 可选类型:
136
+ - ${type1.name} (ID: ${type1.id})
137
+ - ${type2.name} (ID: ${type2.id})
138
+
139
+ ---
140
+ 请回复以下格式新建卡片:
141
+ new [标题] | [空间前缀] | [类型名称]
142
+ 例如:new 修复登录问题 | dkx | Bug
143
+
144
+ 也可以只指定部分:
145
+ new 修复登录问题 | dkx → 使用指定空间 + 该空间默认类型
146
+ new 修复登录问题 | | Story → 使用推荐空间 + 指定类型
147
+ ```
148
+
149
+ **如果用户输入 "new 标题 | 空间 | 类型"(完整指定):**
150
+ - 按 `|` 分割解析,第一段为标题,第二段(可选)为空间前缀,第三段(可选)为类型名称
151
+ - 为空的部分使用推荐值,调用 `create_card_cli.py` 创建卡片
152
+
153
+ ---
154
+
155
+ ## 步骤 8:展示提交确认(文本确认)
156
+
157
+ **当 `is_icode_repo = true` 且有绑定卡片时:**
158
+
159
+ 输出:
160
+
161
+ ```
162
+ ✅ 已关联卡片: ${spacePrefix}-${sequence}
163
+ 标题: ${title}
164
+ 类型: ${type} | 状态: ${status}
165
+
166
+ ---
167
+ 📝 建议的 commit message:
168
+
169
+ ${spacePrefix}-${sequence} ${brief_description}
170
+
171
+ ---
172
+ 请确认:
173
+ - 回复 "ok" 或 "确认" 使用此 message 提交
174
+ - 回复 "edit: <新message>" 修改后提交(如 "edit: dkx-200 修复登录bug")
175
+ - 回复 "no" 或 "取消" 放弃提交
176
+ ```
177
+
178
+ **当 `is_icode_repo = false` 或无绑定卡片时:**
179
+
180
+ 输出:
181
+
182
+ ```
183
+ 📝 建议的 commit message:
184
+
185
+ ${brief_description}
186
+
187
+ ---
188
+ 请确认:
189
+ - 回复 "ok" 或 "确认" 使用此 message 提交
190
+ - 回复 "edit: <新message>" 修改后提交
191
+ - 回复 "no" 或 "取消" 放弃提交
192
+ ```
193
+
194
+ ---
195
+
196
+ ## 步骤 9:执行提交(旧版本 IDE)
197
+
198
+ **如果用户确认提交(回复 "ok"、"确认"、"yes"):**
199
+ - 执行 `git add . && git commit -m "${commit_message}"`
200
+
201
+ **如果用户修改后提交(回复 "edit: <新message>"):**
202
+ - 使用用户提供的新 message 执行提交
203
+
204
+ **如果用户取消(回复 "no"、"取消"):**
205
+ - 输出取消信息
206
+
207
+ 旧版本 IDE 提交成功后额外提示:
208
+ - `如需推送到远程,请执行:git push origin HEAD:refs/for/<branch>`
@@ -0,0 +1,196 @@
1
+ """命令行工具:获取 workspace 的 git diff 摘要
2
+
3
+ 用法:
4
+ python3 git_diff_cli.py --workspace /path/to/project
5
+
6
+ 输出:
7
+ JSON 格式的 diff 摘要,包含 changed_files、stat_summary、diff_content 等字段。
8
+ 失败时输出 {"error": "错误信息"}。
9
+ """
10
+
11
+ import argparse
12
+ import json
13
+ import os
14
+ import subprocess
15
+ import sys
16
+
17
+ # tracked diff 最大行数
18
+ MAX_TRACKED_DIFF_LINES = 300
19
+ # untracked diff 最大行数
20
+ MAX_UNTRACKED_DIFF_LINES = 200
21
+ # 合并后 diff 最大总行数
22
+ MAX_TOTAL_DIFF_LINES = 500
23
+
24
+
25
+ def run_git(args, cwd, timeout=10):
26
+ """执行 git 命令,返回 stdout 字符串。失败返回空字符串。"""
27
+ try:
28
+ result = subprocess.run(
29
+ ["git"] + args,
30
+ capture_output=True, text=True, encoding="utf-8", errors="replace",
31
+ timeout=timeout, cwd=cwd
32
+ )
33
+ if result.returncode == 0:
34
+ return result.stdout
35
+ return ""
36
+ except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
37
+ return ""
38
+
39
+
40
+ def parse_numstat(cwd):
41
+ """通过 git diff HEAD --numstat 获取 tracked 文件变更统计。"""
42
+ output = run_git(["diff", "HEAD", "--numstat"], cwd)
43
+ files = []
44
+ for line in output.strip().splitlines():
45
+ if not line:
46
+ continue
47
+ parts = line.split("\t")
48
+ if len(parts) != 3:
49
+ continue
50
+ ins_str, del_str, file_path = parts
51
+ # binary 文件的 numstat 输出是 - - filename
52
+ insertions = int(ins_str) if ins_str != "-" else 0
53
+ deletions = int(del_str) if del_str != "-" else 0
54
+ files.append({
55
+ "file": file_path,
56
+ "insertions": insertions,
57
+ "deletions": deletions,
58
+ })
59
+ return files
60
+
61
+
62
+ def get_untracked_files(cwd):
63
+ """获取 untracked 文件列表。"""
64
+ output = run_git(["ls-files", "--others", "--exclude-standard"], cwd)
65
+ return [f for f in output.strip().splitlines() if f]
66
+
67
+
68
+ def get_tracked_diff(cwd):
69
+ """获取 tracked 文件的 diff 内容,截断到 MAX_TRACKED_DIFF_LINES 行。"""
70
+ output = run_git(["diff", "HEAD"], cwd, timeout=30)
71
+ lines = output.splitlines()
72
+ truncated = len(lines) > MAX_TRACKED_DIFF_LINES
73
+ if truncated:
74
+ lines = lines[:MAX_TRACKED_DIFF_LINES]
75
+ return "\n".join(lines), truncated
76
+
77
+
78
+ def get_untracked_diff_and_stats(cwd, untracked_files):
79
+ """获取 untracked 文件的 diff 和变更统计。
80
+
81
+ Returns:
82
+ (changed_files, diff_content, truncated)
83
+ """
84
+ changed_files = []
85
+ diff_lines = []
86
+ total_lines = 0
87
+ truncated = False
88
+
89
+ for file_path in untracked_files:
90
+ full_path = os.path.join(cwd, file_path)
91
+ try:
92
+ with open(full_path, "r", encoding="utf-8", errors="replace") as f:
93
+ lines = f.readlines()
94
+ except (OSError, IOError):
95
+ continue
96
+
97
+ insertions = len(lines)
98
+ if insertions > 0:
99
+ changed_files.append({
100
+ "file": file_path,
101
+ "insertions": insertions,
102
+ "deletions": 0,
103
+ })
104
+
105
+ # 构造 unified diff 格式的输出
106
+ file_diff_lines = [
107
+ f"diff --git a/{file_path} b/{file_path}",
108
+ "new file mode 100644",
109
+ f"--- /dev/null",
110
+ f"+++ b/{file_path}",
111
+ f"@@ -0,0 +1,{insertions} @@",
112
+ ] + [f"+{line.rstrip()}" for line in lines]
113
+
114
+ # 检查总行数上限
115
+ remaining = MAX_UNTRACKED_DIFF_LINES - total_lines
116
+ if remaining <= 0:
117
+ truncated = True
118
+ break
119
+ if len(file_diff_lines) > remaining:
120
+ file_diff_lines = file_diff_lines[:remaining]
121
+ truncated = True
122
+ diff_lines.extend(file_diff_lines)
123
+ total_lines += len(file_diff_lines)
124
+
125
+ return changed_files, "\n".join(diff_lines), truncated
126
+
127
+
128
+ def build_stat_summary(changed_files):
129
+ """构建统计摘要字符串,如 '3 files, +130, -78'。"""
130
+ total_ins = sum(f["insertions"] for f in changed_files)
131
+ total_del = sum(f["deletions"] for f in changed_files)
132
+ n = len(changed_files)
133
+ return f"{n} file{'s' if n != 1 else ''}, +{total_ins}, -{total_del}"
134
+
135
+
136
+ def main():
137
+ """解析命令行参数并输出 workspace 的 git diff 摘要 JSON。"""
138
+ parser = argparse.ArgumentParser(description="获取 workspace 的 git diff 摘要")
139
+ parser.add_argument("--workspace", required=True, help="workspace 路径")
140
+ parser.add_argument("--max-diff-lines", type=int, default=MAX_TOTAL_DIFF_LINES,
141
+ help="diff 内容最大总行数")
142
+ args = parser.parse_args()
143
+
144
+ workspace = os.path.abspath(args.workspace)
145
+ if not os.path.isdir(workspace):
146
+ print(json.dumps({"error": f"workspace 路径不存在: {workspace}"}))
147
+ sys.exit(1)
148
+
149
+ max_total = args.max_diff_lines
150
+
151
+ try:
152
+ # 1. tracked 文件变更统计
153
+ tracked_files = parse_numstat(workspace)
154
+
155
+ # 2. untracked 文件列表
156
+ untracked_files = get_untracked_files(workspace)
157
+
158
+ # 3. tracked diff 内容
159
+ tracked_diff, tracked_truncated = get_tracked_diff(workspace)
160
+
161
+ # 4. untracked diff 和统计
162
+ untracked_changed, untracked_diff, untracked_truncated = \
163
+ get_untracked_diff_and_stats(workspace, untracked_files)
164
+
165
+ # 5. 合并 changed_files
166
+ all_changed = tracked_files + untracked_changed
167
+
168
+ # 6. 合并 diff 内容,检查总行数上限
169
+ tracked_lines = tracked_diff.splitlines() if tracked_diff else []
170
+ untracked_lines = untracked_diff.splitlines() if untracked_diff else []
171
+ all_lines = tracked_lines + untracked_lines
172
+ truncated = tracked_truncated or untracked_truncated or len(all_lines) > max_total
173
+ if len(all_lines) > max_total:
174
+ all_lines = all_lines[:max_total]
175
+ diff_content = "\n".join(all_lines)
176
+
177
+ # 7. 构建输出
178
+ has_changes = bool(all_changed) or bool(untracked_files)
179
+ output = {
180
+ "workspace": workspace,
181
+ "changed_files": all_changed,
182
+ "untracked_files": untracked_files,
183
+ "stat_summary": build_stat_summary(all_changed) if all_changed else "",
184
+ "has_changes": has_changes,
185
+ "diff_content": diff_content,
186
+ "truncated": truncated,
187
+ }
188
+ print(json.dumps(output, ensure_ascii=False))
189
+
190
+ except Exception as e:
191
+ print(json.dumps({"error": f"获取 diff 摘要异常: {type(e).__name__}: {e}"}))
192
+ sys.exit(1)
193
+
194
+
195
+ if __name__ == "__main__":
196
+ main()
@@ -63,7 +63,8 @@ def get_current_user(username: Optional[str] = None) -> Optional[str]:
63
63
  try:
64
64
  result = subprocess.run(
65
65
  ["git", "config", "user.email"],
66
- capture_output=True, text=True, timeout=5
66
+ capture_output=True, text=True, encoding="utf-8", errors="replace",
67
+ timeout=5
67
68
  )
68
69
  if result.returncode == 0 and result.stdout.strip():
69
70
  username = result.stdout.strip().split("@")[0]
@@ -77,7 +78,8 @@ def get_current_user(username: Optional[str] = None) -> Optional[str]:
77
78
  try:
78
79
  result = subprocess.run(
79
80
  ["git", "config", "user.name"],
80
- capture_output=True, text=True, timeout=5
81
+ capture_output=True, text=True, encoding="utf-8", errors="replace",
82
+ timeout=5
81
83
  )
82
84
  if result.returncode == 0 and result.stdout.strip():
83
85
  username = result.stdout.strip()
@@ -112,7 +114,8 @@ def get_git_diff_summary(max_diff_lines: int = DEFAULT_MAX_DIFF_LINES) -> Option
112
114
  try:
113
115
  stat_result = subprocess.run(
114
116
  ["git", "diff", "HEAD", "--stat"],
115
- capture_output=True, text=True, timeout=10
117
+ capture_output=True, text=True, encoding="utf-8", errors="replace",
118
+ timeout=10
116
119
  )
117
120
  if stat_result.returncode != 0 or not stat_result.stdout.strip():
118
121
  logger.info("git diff 无变更")
@@ -136,7 +139,8 @@ def get_git_diff_summary(max_diff_lines: int = DEFAULT_MAX_DIFF_LINES) -> Option
136
139
  try:
137
140
  diff_result = subprocess.run(
138
141
  ["git", "diff", "HEAD"],
139
- capture_output=True, text=True, timeout=30
142
+ capture_output=True, text=True, encoding="utf-8", errors="replace",
143
+ timeout=30
140
144
  )
141
145
  diff_content = diff_result.stdout if diff_result.returncode == 0 else ""
142
146
  except (subprocess.TimeoutExpired, FileNotFoundError):
@@ -178,7 +182,8 @@ def extract_space_ids_from_git_log(
178
182
  try:
179
183
  result = subprocess.run(
180
184
  ["git", "log", "--oneline", "-n", str(max_commits)],
181
- capture_output=True, text=True, timeout=10
185
+ capture_output=True, text=True, encoding="utf-8", errors="replace",
186
+ timeout=10
182
187
  )
183
188
  if result.returncode != 0:
184
189
  return []
@@ -203,17 +208,22 @@ def extract_space_ids_from_git_log(
203
208
  return sorted_prefixes
204
209
 
205
210
  # 策略 2:正则启发式兜底(无已知前缀或精确匹配无结果)
206
- pattern = re.compile(r'\b([a-zA-Z][a-zA-Z0-9_]*)-(\d+)\b')
211
+ # 支持含连字符的复合前缀,如 DevOps-iScan-36261、TPUE-EE-2-22
212
+ # 贪婪匹配:最后一个 -数字 是卡片 ID,前面所有部分都是空间前缀
213
+ pattern = re.compile(r'\b([a-zA-Z][a-zA-Z0-9_]*(?:-[a-zA-Z0-9_]+)*)-(\d+)\b')
207
214
  counter_fallback: Dict[str, int] = {}
208
215
 
209
216
  for line in log_text.splitlines():
210
217
  for match in pattern.finditer(line):
211
- prefix = match.group(1).lower()
212
- if prefix in GIT_LOG_FALSE_POSITIVE_PREFIXES:
218
+ raw_prefix = match.group(1)
219
+ prefix_lower = raw_prefix.lower()
220
+ # 检查前缀首段是否是常见误报(如 feat-xxx、fix-xxx)
221
+ first_segment = raw_prefix.split('-', 1)[0].lower()
222
+ if first_segment in GIT_LOG_FALSE_POSITIVE_PREFIXES:
213
223
  continue
214
- if len(prefix) <= 1:
224
+ if len(raw_prefix) <= 1:
215
225
  continue
216
- counter_fallback[prefix] = counter_fallback.get(prefix, 0) + 1
226
+ counter_fallback[prefix_lower] = counter_fallback.get(prefix_lower, 0) + 1
217
227
 
218
228
  sorted_prefixes = sorted(counter_fallback, key=counter_fallback.get, reverse=True)
219
229
  logger.info("git log 提取前缀: %s, 策略=正则启发式", sorted_prefixes)
@@ -3,13 +3,15 @@
3
3
  包含常量、配置类和 API 客户端。
4
4
  """
5
5
 
6
+ import json as _json
6
7
  import os
8
+ import urllib.error
9
+ import urllib.parse
10
+ import urllib.request
7
11
  from dataclasses import dataclass
8
12
  from pathlib import Path
9
13
  from typing import Dict, List, Any, Optional
10
14
 
11
- import requests
12
-
13
15
  from logger import get_logger
14
16
 
15
17
  logger = get_logger()
@@ -126,34 +128,69 @@ class ICafeQueryClient:
126
128
 
127
129
  def __init__(self, config: Optional[ICafeQueryConfig] = None):
128
130
  self.config = config or ICafeQueryConfig()
129
- self.session = requests.Session()
130
-
131
- self.session.headers.update({
132
- "Content-Type": "application/json"
133
- })
131
+ self._default_headers: Dict[str, str] = {
132
+ "Content-Type": "application/json",
133
+ "User-Agent": "iAPI/1.0.0 (http://iapi.baidu-int.com)",
134
+ }
134
135
 
135
136
  auth_token = self.config._get_auth_token()
136
137
  if auth_token:
137
- self.session.headers["x-ac-Authorization"] = auth_token
138
+ self._default_headers["x-ac-Authorization"] = auth_token
138
139
 
139
- def _get_headers(self) -> Dict[str, str]:
140
- """获取通用请求 headers"""
141
- return {
142
- 'User-Agent': 'iAPI/1.0.0 (http://iapi.baidu-int.com)'
143
- }
140
+ def _http_request(
141
+ self,
142
+ url: str,
143
+ params: Optional[dict] = None,
144
+ data: Optional[dict] = None,
145
+ headers: Optional[Dict[str, str]] = None,
146
+ timeout: Optional[int] = None,
147
+ ) -> Any:
148
+ """发送 HTTP 请求并返回解析后的 JSON
149
+
150
+ Args:
151
+ url: 请求 URL
152
+ params: GET 查询参数
153
+ data: POST 请求体(dict,会被序列化为 JSON)
154
+ headers: 额外 headers(会合并到默认 headers)
155
+ timeout: 超时时间(秒)
156
+
157
+ Returns:
158
+ 解析后的 JSON 对象(dict 或 list)
159
+
160
+ Raises:
161
+ urllib.error.HTTPError: HTTP 状态码非 2xx 时
162
+ urllib.error.URLError: 网络连接失败时
163
+ """
164
+ if timeout is None:
165
+ timeout = self.config.timeout
166
+
167
+ # 合并 headers
168
+ merged_headers = dict(self._default_headers)
169
+ if headers:
170
+ merged_headers.update(headers)
171
+
172
+ # 构建完整 URL
173
+ if params:
174
+ query_string = urllib.parse.urlencode(params, doseq=True)
175
+ url = f"{url}?{query_string}" if "?" not in url else f"{url}&{query_string}"
176
+
177
+ # 构建 Request
178
+ body = None
179
+ if data is not None:
180
+ body = _json.dumps(data).encode("utf-8")
181
+
182
+ req = urllib.request.Request(url, data=body, headers=merged_headers)
183
+
184
+ with urllib.request.urlopen(req, timeout=timeout) as resp:
185
+ return _json.loads(resp.read().decode("utf-8"))
144
186
 
145
- def _get_with_retry(self, url: str, params: dict, max_retries: int = 3) -> requests.Response:
146
- """带重试的 GET 请求"""
187
+ def _get_with_retry(self, url: str, params: dict, max_retries: int = 3) -> Any:
188
+ """带重试的 GET 请求,返回解析后的 JSON"""
147
189
  import time
148
190
  last_exc = None
149
191
  for attempt in range(max_retries + 1):
150
192
  try:
151
- response = self.session.get(
152
- url, params=params, headers=self._get_headers(),
153
- timeout=self.config.timeout
154
- )
155
- response.raise_for_status()
156
- return response
193
+ return self._http_request(url, params=params)
157
194
  except Exception as e:
158
195
  last_exc = e
159
196
  if attempt < max_retries:
@@ -195,7 +232,7 @@ class ICafeQueryClient:
195
232
 
196
233
  Raises:
197
234
  ValueError: 当 space_id 或 iql 为空时
198
- requests.RequestException: 请求失败时
235
+ urllib.error.URLError: 请求失败时
199
236
 
200
237
  IQL 表达式示例:
201
238
  - "类型 = Bug"
@@ -234,8 +271,7 @@ class ICafeQueryClient:
234
271
 
235
272
  url = f"{self.config.base_url}/api/spaces/{space_id}/cards"
236
273
  logger.info("查询卡片: space=%s, iql=%s", space_id, iql)
237
- response = self._get_with_retry(url, params)
238
- result = response.json()
274
+ result = self._get_with_retry(url, params)
239
275
  cards_count = len(result.get("cards", []))
240
276
  logger.info("查询卡片返回: %d 张", cards_count)
241
277
  return result
@@ -263,7 +299,7 @@ class ICafeQueryClient:
263
299
 
264
300
  Raises:
265
301
  ValueError: 当 space_id 或 card_id 为空时
266
- requests.RequestException: 请求失败时
302
+ urllib.error.URLError: 请求失败时
267
303
  """
268
304
  if not space_id or not card_id:
269
305
  raise ValueError("space_id 和 card_id 不能为空")
@@ -279,8 +315,7 @@ class ICafeQueryClient:
279
315
  params['showAccumulate'] = ''
280
316
 
281
317
  url = f"{self.config.base_url}/api/spaces/{space_id}/cards/{card_id}"
282
- response = self._get_with_retry(url, params)
283
- return response.json()
318
+ return self._get_with_retry(url, params)
284
319
 
285
320
  # ========================================
286
321
  # 3. 查询最近访问的空间列表
@@ -297,7 +332,7 @@ class ICafeQueryClient:
297
332
 
298
333
  Raises:
299
334
  ValueError: 当 current_user 为空时
300
- requests.RequestException: 请求失败时
335
+ urllib.error.URLError: 请求失败时
301
336
  """
302
337
  if not current_user:
303
338
  raise ValueError("current_user 不能为空")
@@ -305,8 +340,7 @@ class ICafeQueryClient:
305
340
  logger.info("查询最近访问空间: user=%s, limit=%d", current_user, limit)
306
341
  url = f"{self.config.base_url}/api/v2/space/latest"
307
342
  params = {'currentUser': current_user}
308
- response = self._get_with_retry(url, params)
309
- data = response.json()
343
+ data = self._get_with_retry(url, params)
310
344
 
311
345
  # 对返回的空间列表截取前 limit 个
312
346
  if isinstance(data, dict) and 'result' in data:
@@ -330,14 +364,13 @@ class ICafeQueryClient:
330
364
 
331
365
  Raises:
332
366
  ValueError: 当 space_id 为空时
333
- requests.RequestException: 请求失败时
367
+ urllib.error.URLError: 请求失败时
334
368
  """
335
369
  if not space_id:
336
370
  raise ValueError("space_id 不能为空")
337
371
 
338
372
  url = f"{self.config.base_url}/api/v2/space/{space_id}/plans"
339
- response = self._get_with_retry(url, {})
340
- return response.json()
373
+ return self._get_with_retry(url, {})
341
374
 
342
375
  # ========================================
343
376
  # 5. 获取空间卡片类型列表
@@ -353,14 +386,13 @@ class ICafeQueryClient:
353
386
 
354
387
  Raises:
355
388
  ValueError: 当 space_prefix 为空时
356
- requests.RequestException: 请求失败时
389
+ urllib.error.URLError: 请求失败时
357
390
  """
358
391
  if not space_prefix:
359
392
  raise ValueError("space_prefix 不能为空")
360
393
 
361
394
  url = f"{self.config.base_url}/api/v2/space/{space_prefix}/issueTypes"
362
- response = self._get_with_retry(url, {})
363
- return response.json()
395
+ return self._get_with_retry(url, {})
364
396
 
365
397
  # ========================================
366
398
  # 6. 创建卡片
@@ -421,10 +453,7 @@ class ICafeQueryClient:
421
453
  'Content-Type': 'application/json'
422
454
  }
423
455
 
424
- # 使用 self.session.post 发送请求
425
- response = self.session.post(url, json=data, headers=headers, timeout=self.config.timeout)
426
- response.raise_for_status()
427
- result = response.json()
456
+ result = self._http_request(url, data=data, headers=headers)
428
457
 
429
458
  # 检查返回的状态
430
459
  if isinstance(result, dict):