@comate/zulu 1.1.0 → 1.2.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.
- package/README.md +8 -0
- package/comate-engine/assets/skills/auto-commit/SKILL.md +386 -0
- package/comate-engine/assets/skills/auto-commit/references/issue_type_mapping.json +19 -0
- package/comate-engine/assets/skills/auto-commit/references/new_version_instruction.md +196 -0
- package/comate-engine/assets/skills/auto-commit/references/old_version_instruction.md +189 -0
- package/comate-engine/assets/skills/auto-commit/references/query_reference.md +176 -0
- package/comate-engine/assets/skills/auto-commit/scripts/compat.py +86 -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 +195 -0
- package/comate-engine/assets/skills/auto-commit/scripts/git_utils.py +225 -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 +444 -0
- package/comate-engine/assets/skills/auto-commit/scripts/icafe/farseer.py +53 -0
- package/comate-engine/assets/skills/auto-commit/scripts/icafe/matching.py +778 -0
- package/comate-engine/assets/skills/auto-commit/scripts/logger.py +32 -0
- package/comate-engine/assets/skills/auto-commit/scripts/recognize_card_cli.py +63 -0
- package/comate-engine/assets/skills/automation-browser-comate/SKILL.md +193 -90
- package/comate-engine/assets/skills/figma2code-comate/SKILL.md +2 -2
- package/comate-engine/assets/skills/figma2code-comate/references/codeConnect.md +7 -10
- package/comate-engine/assets/skills/smart-commit/SKILL.md +646 -0
- package/comate-engine/assets/skills/smart-commit/references/issue_type_mapping.json +19 -0
- package/comate-engine/assets/skills/smart-commit/references/query_reference.md +176 -0
- package/comate-engine/assets/skills/smart-commit/scripts/compat.py +86 -0
- package/comate-engine/assets/skills/smart-commit/scripts/create_card_cli.py +67 -0
- package/comate-engine/assets/skills/smart-commit/scripts/git_utils.py +220 -0
- package/comate-engine/assets/skills/smart-commit/scripts/icafe/__init__.py +66 -0
- package/comate-engine/assets/skills/smart-commit/scripts/icafe/client.py +444 -0
- package/comate-engine/assets/skills/smart-commit/scripts/icafe/farseer.py +53 -0
- package/comate-engine/assets/skills/smart-commit/scripts/icafe/matching.py +728 -0
- package/comate-engine/assets/skills/smart-commit/scripts/logger.py +32 -0
- package/comate-engine/assets/skills/smart-commit/scripts/recognize_card_cli.py +63 -0
- package/comate-engine/node_modules/@comate/plugin-engine/dist/index.js +7 -7
- package/comate-engine/node_modules/@comate/plugin-host/dist/index.js +1 -1
- package/comate-engine/node_modules/@comate/plugin-host/dist/main.js +1 -1
- package/comate-engine/node_modules/@comate/plugin-shared-internals/dist/index.js +8 -8
- package/comate-engine/node_modules/@comate/preview-proxy/package.json +2 -2
- package/comate-engine/node_modules/better-sqlite3/build/Release/better_sqlite3.node +0 -0
- package/comate-engine/package.json +2 -2
- package/comate-engine/server.js +61 -44
- package/dist/bundle/index.js +8 -8
- package/package.json +1 -1
- package/comate-engine/node_modules/@comate/plugin-engine/dist/index.d.ts +0 -188
- package/comate-engine/node_modules/@comate/plugin-host/dist/main.d.ts +0 -14
- package/comate-engine/node_modules/@comate/plugin-shared-internals/dist/index.d.ts +0 -4817
- package/comate-engine/node_modules/better-sqlite3/README.md +0 -99
- package/comate-engine/node_modules/bindings/LICENSE.md +0 -22
- package/comate-engine/node_modules/bindings/README.md +0 -98
- package/comate-engine/node_modules/compare-versions/README.md +0 -133
- package/comate-engine/node_modules/compare-versions/lib/esm/compare.d.ts +0 -19
- package/comate-engine/node_modules/compare-versions/lib/esm/compareVersions.d.ts +0 -8
- package/comate-engine/node_modules/compare-versions/lib/esm/index.d.ts +0 -5
- package/comate-engine/node_modules/compare-versions/lib/esm/satisfies.d.ts +0 -14
- package/comate-engine/node_modules/compare-versions/lib/esm/utils.d.ts +0 -7
- package/comate-engine/node_modules/compare-versions/lib/esm/validate.d.ts +0 -28
- package/comate-engine/node_modules/file-uri-to-path/History.md +0 -21
- package/comate-engine/node_modules/file-uri-to-path/README.md +0 -74
- package/comate-engine/node_modules/file-uri-to-path/index.d.ts +0 -2
- package/comate-engine/node_modules/pkce-challenge/README.md +0 -55
- package/comate-engine/node_modules/pkce-challenge/dist/index.browser.d.ts +0 -19
- package/comate-engine/node_modules/pkce-challenge/dist/index.node.d.ts +0 -19
- package/comate-engine/node_modules/sqlite-vec/README.md +0 -1
- package/comate-engine/node_modules/sqlite-vec/index.d.ts +0 -17
- package/comate-engine/node_modules/sqlite-vec-darwin-arm64/README.md +0 -1
- package/comate-engine/node_modules/sqlite-vec-darwin-x64/README.md +0 -1
- package/comate-engine/node_modules/sqlite-vec-linux-arm64/README.md +0 -1
- package/comate-engine/node_modules/sqlite-vec-linux-x64/README.md +0 -1
- package/comate-engine/node_modules/sqlite-vec-windows-x64/README.md +0 -1
- package/comate-engine/node_modules/tree-sitter-bash/README.md +0 -44
- package/comate-engine/node_modules/tree-sitter-bash/bindings/node/binding_test.js +0 -9
- package/comate-engine/node_modules/tree-sitter-bash/bindings/node/index.d.ts +0 -28
- package/comate-engine/node_modules/tree-sitter-bash/bindings/node/index.js +0 -11
- package/comate-engine/node_modules/tree-sitter-bash/prebuilds/darwin-arm64/tree-sitter-bash.node +0 -0
- package/comate-engine/node_modules/tree-sitter-bash/prebuilds/darwin-x64/tree-sitter-bash.node +0 -0
- package/comate-engine/node_modules/tree-sitter-bash/prebuilds/linux-arm64/tree-sitter-bash.node +0 -0
- package/comate-engine/node_modules/tree-sitter-bash/prebuilds/linux-x64/tree-sitter-bash.node +0 -0
- package/comate-engine/node_modules/tree-sitter-bash/prebuilds/win32-arm64/tree-sitter-bash.node +0 -0
- package/comate-engine/node_modules/tree-sitter-bash/prebuilds/win32-x64/tree-sitter-bash.node +0 -0
- package/comate-engine/node_modules/tree-sitter-bash/src/grammar.json +0 -7145
- package/comate-engine/node_modules/tree-sitter-bash/src/node-types.json +0 -2894
- package/comate-engine/node_modules/web-streams-polyfill/README.md +0 -119
- package/comate-engine/node_modules/web-streams-polyfill/types/polyfill.d.ts +0 -28
- package/comate-engine/node_modules/web-streams-polyfill/types/ponyfill.d.ts +0 -809
- package/comate-engine/node_modules/web-tree-sitter/README.md +0 -269
- package/comate-engine/node_modules/web-tree-sitter/debug/tree-sitter.cjs +0 -4558
- package/comate-engine/node_modules/web-tree-sitter/debug/tree-sitter.js +0 -4516
- package/comate-engine/node_modules/web-tree-sitter/debug/tree-sitter.wasm +0 -0
- package/comate-engine/node_modules/web-tree-sitter/web-tree-sitter.d.ts +0 -1030
- package/comate-engine/node_modules/win-ca/README.md +0 -648
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# iCafe 卡片查询 IQL 完整参考
|
|
2
|
+
|
|
3
|
+
## API 端点
|
|
4
|
+
|
|
5
|
+
### 条件查询卡片
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
GET {base_url}/api/spaces/{space_id}/cards?iql={iql_expression}
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**请求参数:**
|
|
12
|
+
|
|
13
|
+
| 参数 | 位置 | 类型 | 必填 | 说明 |
|
|
14
|
+
|------|------|------|------|------|
|
|
15
|
+
| space_id | path | string | 是 | 空间 ID |
|
|
16
|
+
| iql | query | string | 是 | IQL 查询表达式 |
|
|
17
|
+
| page | query | int | 否 | 页码 |
|
|
18
|
+
| showDetail | query | flag | 否 | 显示详情(传空字符串即可) |
|
|
19
|
+
| showAssociations | query | flag | 否 | 显示关联信息 |
|
|
20
|
+
| isDesc | query | flag | 否 | 降序排列 |
|
|
21
|
+
| order | query | string | 否 | 排序字段 |
|
|
22
|
+
| showChildren | query | flag | 否 | 显示子卡片 |
|
|
23
|
+
| maxRecords | query | int | 否 | 最大返回数 |
|
|
24
|
+
| showOkr | query | flag | 否 | 显示 OKR |
|
|
25
|
+
| showAccumulate | query | flag | 否 | 显示累计信息 |
|
|
26
|
+
|
|
27
|
+
**响应示例:**
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"cards": [
|
|
32
|
+
{
|
|
33
|
+
"id": "12345",
|
|
34
|
+
"sequence": "628",
|
|
35
|
+
"title": "示例卡片",
|
|
36
|
+
"type": "Bug",
|
|
37
|
+
"status": "新建",
|
|
38
|
+
"assignee": "dongkexin01",
|
|
39
|
+
"priority": "P1-High",
|
|
40
|
+
"createdAt": "2025-01-15 10:30:00",
|
|
41
|
+
"updatedAt": "2025-01-16 14:20:00"
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"total": 1,
|
|
45
|
+
"page": 1,
|
|
46
|
+
"pageSize": 20
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 获取单张卡片
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
GET {base_url}/api/spaces/{space_id}/cards/{card_id}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 查询最近访问空间
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
GET {base_url}/api/v2/space/latest?currentUser={user_id}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 获取空间计划
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
GET {base_url}/api/v2/space/{space_id}/plans
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## IQL 查询语法完整参考
|
|
69
|
+
|
|
70
|
+
### 运算符
|
|
71
|
+
|
|
72
|
+
| 运算符 | 含义 | 适用类型 | 示例 |
|
|
73
|
+
|--------|------|----------|------|
|
|
74
|
+
| `=` | 等于 | 所有类型 | `类型 = Bug` |
|
|
75
|
+
| `!=` | 不等于 | 所有类型 | `状态 != 已完成` |
|
|
76
|
+
| `>` | 大于 | 日期、数字、流程状态 | `创建时间 > "2025-01-01"` |
|
|
77
|
+
| `<` | 小于 | 日期、数字、流程状态 | `优先级数值 < 3` |
|
|
78
|
+
| `>=` | 大于等于 | 流程状态、数字 | `流程状态 >= 开发中` |
|
|
79
|
+
| `<=` | 小于等于 | 流程状态、数字 | `流程状态 <= 开发中` |
|
|
80
|
+
| `in ()` | 在列表中 | 人员、类型、状态、标签等 | `类型 in (Bug, Story)` |
|
|
81
|
+
| `not in ()` | 不在列表中 | 人员、类型、状态、标签等 | `状态 not in (已完成, 已关闭)` |
|
|
82
|
+
| `is empty` | 为空 | 所有类型 | `负责人 is empty` |
|
|
83
|
+
| `is not empty` | 不为空 | 所有类型 | `截止日期 is not empty` |
|
|
84
|
+
| `~` | 包含(模糊匹配) | 标题、文本、关键字、URL | `标题 ~ 登录` |
|
|
85
|
+
| `!~` | 不包含 | 标题、文本 | `标题 !~ 测试` |
|
|
86
|
+
| `AND` | 逻辑与 | 连接多个条件 | `类型 = Bug AND 状态 = 新建` |
|
|
87
|
+
| `OR` | 逻辑或 | 连接多个条件 | `类型 = Bug OR 类型 = Story` |
|
|
88
|
+
| `()` | 分组 | 控制优先级 | `(类型 = Bug OR 类型 = Story) AND 负责人 = currentUser` |
|
|
89
|
+
|
|
90
|
+
### 字段参考
|
|
91
|
+
|
|
92
|
+
| 字段名 | 类型 | 说明 |
|
|
93
|
+
|--------|------|------|
|
|
94
|
+
| 类型 | 枚举 | Bug, Story, Task, Epic 等 |
|
|
95
|
+
| 负责人 | 人员 | 用户 ID,如 "dongkexin01" |
|
|
96
|
+
| 创建人 | 人员 | 用户 ID |
|
|
97
|
+
| 流程状态 | 状态枚举 | 新建, 待开发, 开发中, 进行中, 已完成 等 |
|
|
98
|
+
| 优先级 | 枚举 | P0-Urgent, P1-High, P2-Medium, P3-Low 等 |
|
|
99
|
+
| 创建时间 | 日期 | 格式 "YYYY-MM-DD" 或 "YYYY-MM-DD HH:mm:ss" |
|
|
100
|
+
| 更新时间 | 日期 | 格式同上 |
|
|
101
|
+
| 截止日期 | 日期 | 格式同上 |
|
|
102
|
+
| 标题 | 文本 | 卡片标题 |
|
|
103
|
+
| 关键字 | 文本 | 全文搜索关键字 |
|
|
104
|
+
| Label | 标签 | 卡片标签 |
|
|
105
|
+
| 所属计划 | 树 | 需要完整路径,如 "测试/测试1" |
|
|
106
|
+
|
|
107
|
+
### 常用查询模式
|
|
108
|
+
|
|
109
|
+
#### 按类型查询
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
类型 = Bug
|
|
113
|
+
类型 in (Bug, Story, Task)
|
|
114
|
+
类型 != Epic
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### 按人员查询
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
负责人 = currentUser
|
|
121
|
+
负责人 = dongkexin01
|
|
122
|
+
创建人 = v_liuxiang
|
|
123
|
+
负责人 in (user1, user2, user3)
|
|
124
|
+
负责人 is empty
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### 按状态查询
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
流程状态 = 新建
|
|
131
|
+
流程状态 in (新建, 开发中, 待开发, 进行中)
|
|
132
|
+
流程状态 <= 开发中
|
|
133
|
+
流程状态 != 已完成
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### 按时间查询
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
创建时间 > "2025-01-01"
|
|
140
|
+
创建时间 > "2025-01-01 00:00:00" AND 创建时间 < "2025-06-30 23:59:59"
|
|
141
|
+
更新时间 > "2025-03-01"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### 按内容查询
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
标题 ~ 登录
|
|
148
|
+
标题 !~ 测试
|
|
149
|
+
关键字 ~ 性能优化
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### 组合查询
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
类型 = Bug AND 负责人 = currentUser AND 流程状态 != 已完成
|
|
156
|
+
(类型 = Bug OR 类型 = Story) AND 优先级 = P1-High
|
|
157
|
+
创建人 = dongkexin01 AND 创建时间 > "2025-01-01" AND 流程状态 in (新建, 开发中)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## 认证说明
|
|
161
|
+
|
|
162
|
+
所有请求需要 `x-ac-Authorization` header。Token 获取优先级:
|
|
163
|
+
|
|
164
|
+
1. 环境变量 `COMATE_AUTH_TOKEN`
|
|
165
|
+
2. 文件 `~/.comate/login`
|
|
166
|
+
|
|
167
|
+
## 错误码
|
|
168
|
+
|
|
169
|
+
| HTTP 状态码 | 说明 |
|
|
170
|
+
|-------------|------|
|
|
171
|
+
| 200 | 成功 |
|
|
172
|
+
| 400 | 请求参数错误(如 IQL 语法错误) |
|
|
173
|
+
| 401 | 认证失败(token 无效或过期) |
|
|
174
|
+
| 403 | 无权限访问该空间 |
|
|
175
|
+
| 404 | 空间或卡片不存在 |
|
|
176
|
+
| 500 | 服务端错误 |
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
版本兼容性检测模块
|
|
3
|
+
|
|
4
|
+
用于检测当前 IDE 版本是否支持自定义交互式 UI
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# 支持自定义 UI 的最低版本
|
|
8
|
+
MIN_INTERACTIVE_VERSION = '1.2.0'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def parse_version(version_str: str) -> tuple:
|
|
12
|
+
"""
|
|
13
|
+
解析版本号字符串为可比较的元组
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
version_str: 版本号字符串,如 "1.2.3"
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
版本号元组,如 (1, 2, 3)
|
|
20
|
+
"""
|
|
21
|
+
try:
|
|
22
|
+
parts = version_str.split('.')
|
|
23
|
+
return tuple(int(p) for p in parts[:3])
|
|
24
|
+
except (ValueError, AttributeError):
|
|
25
|
+
return (0, 0, 0)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def is_interactive_ui_supported(ide_name: str, plugin_version: str) -> bool:
|
|
29
|
+
"""
|
|
30
|
+
检测当前 IDE 版本是否支持自定义交互式 UI
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
ide_name: 从 ${COMATE_IDE_NAME} 获取的值
|
|
34
|
+
plugin_version: 从 ${COMATE_PLUGIN_VERSION} 获取的值
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
True 如果支持自定义 UI,否则 False
|
|
38
|
+
"""
|
|
39
|
+
# 1. 检测占位符是否被替换
|
|
40
|
+
# 旧版本 CLI 不支持这些占位符,值仍为 "${...}" 原样
|
|
41
|
+
if not ide_name or ide_name.startswith('${'):
|
|
42
|
+
return False
|
|
43
|
+
if not plugin_version or plugin_version.startswith('${'):
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
# 2. 版本号比较
|
|
47
|
+
current = parse_version(plugin_version)
|
|
48
|
+
minimum = parse_version(MIN_INTERACTIVE_VERSION)
|
|
49
|
+
|
|
50
|
+
return current >= minimum
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def check_interactive_support(ide_name: str, plugin_version: str) -> str:
|
|
54
|
+
"""
|
|
55
|
+
检测并返回应使用的流程模式
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
ide_name: 从 ${COMATE_IDE_NAME} 获取的值
|
|
59
|
+
plugin_version: 从 ${COMATE_PLUGIN_VERSION} 获取的值
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
"INTERACTIVE_MODE" 或 "FALLBACK_MODE"
|
|
63
|
+
"""
|
|
64
|
+
if is_interactive_ui_supported(ide_name, plugin_version):
|
|
65
|
+
return "INTERACTIVE_MODE"
|
|
66
|
+
return "FALLBACK_MODE"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
# 测试用例
|
|
71
|
+
test_cases = [
|
|
72
|
+
("vscode", "1.2.0", "INTERACTIVE_MODE"),
|
|
73
|
+
("vscode", "1.3.5", "INTERACTIVE_MODE"),
|
|
74
|
+
("vscode", "1.1.9", "FALLBACK_MODE"),
|
|
75
|
+
("vscode", "0.9.0", "FALLBACK_MODE"),
|
|
76
|
+
("${COMATE_IDE_NAME}", "1.2.0", "FALLBACK_MODE"),
|
|
77
|
+
("vscode", "${COMATE_PLUGIN_VERSION}", "FALLBACK_MODE"),
|
|
78
|
+
("", "1.2.0", "FALLBACK_MODE"),
|
|
79
|
+
("vscode", "", "FALLBACK_MODE"),
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
print("Running compatibility check tests...")
|
|
83
|
+
for ide, version, expected in test_cases:
|
|
84
|
+
result = check_interactive_support(ide, version)
|
|
85
|
+
status = "PASS" if result == expected else "FAIL"
|
|
86
|
+
print(f"[{status}] ide={ide!r}, version={version!r} -> {result} (expected: {expected})")
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""命令行工具:创建 iCafe 卡片
|
|
2
|
+
|
|
3
|
+
用法:
|
|
4
|
+
python3 create_card_cli.py --title "标题" --space-prefix "dkx" --type-name "Bug" --username "dongkexin01"
|
|
5
|
+
|
|
6
|
+
输出:
|
|
7
|
+
JSON 格式的创建结果,包含 sequence、title、spacePrefix 等字段。
|
|
8
|
+
失败时输出 {"error": "错误信息"}。
|
|
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 icafe.client import ICafeQueryClient
|
|
19
|
+
from git_utils import get_current_user
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main():
|
|
23
|
+
"""解析命令行参数并调用 iCafe 接口创建卡片。"""
|
|
24
|
+
parser = argparse.ArgumentParser(description="创建 iCafe 卡片")
|
|
25
|
+
parser.add_argument("--title", required=True, help="卡片标题")
|
|
26
|
+
parser.add_argument("--space-prefix", required=True, help="空间前缀,如 dkx")
|
|
27
|
+
parser.add_argument("--type-name", required=True, help="卡片类型名称,如 Bug")
|
|
28
|
+
parser.add_argument("--description", default="", help="卡片描述")
|
|
29
|
+
parser.add_argument("--username", default=None, help="用户名,如 dongkexin01")
|
|
30
|
+
args = parser.parse_args()
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
client = ICafeQueryClient()
|
|
34
|
+
assignee = get_current_user(username=args.username)
|
|
35
|
+
|
|
36
|
+
created = client.create_card(
|
|
37
|
+
title=args.title,
|
|
38
|
+
space_id=args.space_prefix,
|
|
39
|
+
card_type=args.type_name,
|
|
40
|
+
description=args.description,
|
|
41
|
+
assignee_id=assignee,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
if created:
|
|
45
|
+
issues = created.get("issues", [])
|
|
46
|
+
if issues:
|
|
47
|
+
sequence = issues[0].get("sequence")
|
|
48
|
+
print(json.dumps({
|
|
49
|
+
"success": True,
|
|
50
|
+
"sequence": str(sequence),
|
|
51
|
+
"title": args.title,
|
|
52
|
+
"type": args.type_name,
|
|
53
|
+
"status": "新建",
|
|
54
|
+
"spacePrefix": args.space_prefix,
|
|
55
|
+
}))
|
|
56
|
+
else:
|
|
57
|
+
print(json.dumps({"error": "创建卡片成功但无法获取序列号"}))
|
|
58
|
+
else:
|
|
59
|
+
print(json.dumps({"error": "创建卡片失败,请重试"}))
|
|
60
|
+
except Exception as e:
|
|
61
|
+
err_name = type(e).__name__
|
|
62
|
+
print(json.dumps({"error": f"创建卡片异常: {err_name}: {e}"}))
|
|
63
|
+
sys.exit(1)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if __name__ == "__main__":
|
|
67
|
+
main()
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"""Git 工具函数"""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import re
|
|
6
|
+
from typing import Dict, List, Any, Optional
|
|
7
|
+
|
|
8
|
+
from icafe.client import (
|
|
9
|
+
DEFAULT_MAX_COMMITS,
|
|
10
|
+
DEFAULT_MAX_DIFF_LINES,
|
|
11
|
+
GIT_LOG_FALSE_POSITIVE_PREFIXES,
|
|
12
|
+
)
|
|
13
|
+
from logger import get_logger
|
|
14
|
+
|
|
15
|
+
logger = get_logger()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _get_username_from_arg_or_env(username: Optional[str] = None) -> Optional[str]:
|
|
19
|
+
"""从命令行参数或环境变量获取用户名
|
|
20
|
+
|
|
21
|
+
优先使用传入的 username 参数(来自命令行 --username),
|
|
22
|
+
回退到环境变量 COMATE_USERNAME。
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
username: 通过命令行参数传入的用户名
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
用户名字符串;未设置或未替换时返回 None
|
|
29
|
+
"""
|
|
30
|
+
# 优先使用命令行参数
|
|
31
|
+
if username and 'COMATE_USERNAME' not in username:
|
|
32
|
+
return username
|
|
33
|
+
# 回退到环境变量
|
|
34
|
+
value = os.environ.get('COMATE_USERNAME', '')
|
|
35
|
+
if value and 'COMATE_USERNAME' not in value:
|
|
36
|
+
return value
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_current_user(username: Optional[str] = None) -> Optional[str]:
|
|
41
|
+
"""获取当前用户 ID
|
|
42
|
+
|
|
43
|
+
优先级:
|
|
44
|
+
1. 通过参数传入的用户名(来自命令行 --username)
|
|
45
|
+
2. 环境变量 COMATE_USERNAME
|
|
46
|
+
3. git config user.email 提取 @ 前的用户名
|
|
47
|
+
4. git config user.name
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
username: 通过命令行参数传入的用户名
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
用户 ID 字符串,如 "dongkexin01";无法获取时返回 None
|
|
54
|
+
"""
|
|
55
|
+
# 1. 优先从参数或环境变量获取用户名
|
|
56
|
+
comate_username = _get_username_from_arg_or_env(username)
|
|
57
|
+
logger.info("skill.md username: %s", comate_username)
|
|
58
|
+
if comate_username:
|
|
59
|
+
logger.info("用户识别: source=arg_or_env, user=%s", comate_username)
|
|
60
|
+
return comate_username
|
|
61
|
+
|
|
62
|
+
# 2. 从 git config user.email 提取
|
|
63
|
+
try:
|
|
64
|
+
result = subprocess.run(
|
|
65
|
+
["git", "config", "user.email"],
|
|
66
|
+
capture_output=True, text=True, timeout=5
|
|
67
|
+
)
|
|
68
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
69
|
+
username = result.stdout.strip().split("@")[0]
|
|
70
|
+
if username:
|
|
71
|
+
logger.info("用户识别: source=email, user=%s", username)
|
|
72
|
+
return username
|
|
73
|
+
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
# 3. 回退到 git config user.name
|
|
77
|
+
try:
|
|
78
|
+
result = subprocess.run(
|
|
79
|
+
["git", "config", "user.name"],
|
|
80
|
+
capture_output=True, text=True, timeout=5
|
|
81
|
+
)
|
|
82
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
83
|
+
username = result.stdout.strip()
|
|
84
|
+
logger.info("用户识别: source=name, user=%s", username)
|
|
85
|
+
return username
|
|
86
|
+
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
logger.warning("无法获取用户 ID,所有来源均失败")
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_git_diff_summary(max_diff_lines: int = DEFAULT_MAX_DIFF_LINES) -> Optional[Dict[str, Any]]:
|
|
94
|
+
"""获取当前工作区的 git diff 摘要
|
|
95
|
+
|
|
96
|
+
执行 git diff HEAD 获取所有未提交的变更(包括暂存和未暂存),
|
|
97
|
+
并提取变更文件列表和 diff 内容摘要。
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
max_diff_lines: diff 输出的最大行数,超出部分截断。默认 500。
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
包含 diff 信息的字典:
|
|
104
|
+
{
|
|
105
|
+
"changed_files": ["path/to/file1.ts", ...],
|
|
106
|
+
"stat_summary": "git diff --stat 输出的摘要行",
|
|
107
|
+
"diff_content": "截断后的 diff 全文",
|
|
108
|
+
"truncated": bool
|
|
109
|
+
}
|
|
110
|
+
非 git 仓库或无变更时返回 None
|
|
111
|
+
"""
|
|
112
|
+
try:
|
|
113
|
+
stat_result = subprocess.run(
|
|
114
|
+
["git", "diff", "HEAD", "--stat"],
|
|
115
|
+
capture_output=True, text=True, timeout=10
|
|
116
|
+
)
|
|
117
|
+
if stat_result.returncode != 0 or not stat_result.stdout.strip():
|
|
118
|
+
logger.info("git diff 无变更")
|
|
119
|
+
return None
|
|
120
|
+
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
121
|
+
logger.info("git diff 无变更")
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
stat_lines = stat_result.stdout.strip().splitlines()
|
|
125
|
+
changed_files = []
|
|
126
|
+
for line in stat_lines[:-1]:
|
|
127
|
+
file_path = line.split("|")[0].strip()
|
|
128
|
+
if file_path:
|
|
129
|
+
changed_files.append(file_path)
|
|
130
|
+
stat_summary = stat_lines[-1].strip() if stat_lines else ""
|
|
131
|
+
|
|
132
|
+
if not changed_files:
|
|
133
|
+
logger.info("git diff 无变更")
|
|
134
|
+
return None
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
diff_result = subprocess.run(
|
|
138
|
+
["git", "diff", "HEAD"],
|
|
139
|
+
capture_output=True, text=True, timeout=30
|
|
140
|
+
)
|
|
141
|
+
diff_content = diff_result.stdout if diff_result.returncode == 0 else ""
|
|
142
|
+
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
143
|
+
diff_content = ""
|
|
144
|
+
|
|
145
|
+
lines = diff_content.splitlines()
|
|
146
|
+
truncated = len(lines) > max_diff_lines
|
|
147
|
+
if truncated:
|
|
148
|
+
diff_content = "\n".join(lines[:max_diff_lines]) + "\n... (truncated)"
|
|
149
|
+
|
|
150
|
+
logger.info("git diff: %d 个文件, %s, truncated=%s", len(changed_files), stat_summary, truncated)
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
"changed_files": changed_files,
|
|
154
|
+
"stat_summary": stat_summary,
|
|
155
|
+
"diff_content": diff_content,
|
|
156
|
+
"truncated": truncated,
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def extract_space_ids_from_git_log(
|
|
161
|
+
max_commits: int = DEFAULT_MAX_COMMITS,
|
|
162
|
+
known_prefixes: Optional[List[str]] = None,
|
|
163
|
+
) -> List[str]:
|
|
164
|
+
"""从 git commit message 中提取 iCafe 空间前缀
|
|
165
|
+
|
|
166
|
+
优先使用已知的空间前缀列表进行精确匹配(支持含连字符的前缀如 DevOps-iScan),
|
|
167
|
+
回退到正则启发式提取。
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
max_commits: 扫描的最大提交数量
|
|
171
|
+
known_prefixes: 已知的空间 prefixCode 列表(来自 API)。
|
|
172
|
+
提供时优先用精确匹配;未提供时用正则启发式。
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
去重后的空间前缀列表(保留原始大小写),按提交次数降序排列。
|
|
176
|
+
非 git 仓库或无匹配时返回空列表。
|
|
177
|
+
"""
|
|
178
|
+
try:
|
|
179
|
+
result = subprocess.run(
|
|
180
|
+
["git", "log", "--oneline", "-n", str(max_commits)],
|
|
181
|
+
capture_output=True, text=True, timeout=10
|
|
182
|
+
)
|
|
183
|
+
if result.returncode != 0:
|
|
184
|
+
return []
|
|
185
|
+
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
186
|
+
return []
|
|
187
|
+
|
|
188
|
+
log_text = result.stdout.strip()
|
|
189
|
+
if not log_text:
|
|
190
|
+
return []
|
|
191
|
+
|
|
192
|
+
# 策略 1:用已知前缀精确匹配 "前缀-数字"
|
|
193
|
+
if known_prefixes:
|
|
194
|
+
counter: Dict[str, int] = {}
|
|
195
|
+
for prefix in known_prefixes:
|
|
196
|
+
pat = re.compile(re.escape(prefix) + r'-\d+', re.IGNORECASE)
|
|
197
|
+
count = len(pat.findall(log_text))
|
|
198
|
+
if count > 0:
|
|
199
|
+
counter[prefix] = count
|
|
200
|
+
if counter:
|
|
201
|
+
sorted_prefixes = sorted(counter, key=counter.get, reverse=True)
|
|
202
|
+
logger.info("git log 提取前缀: %s, 策略=精确匹配", sorted_prefixes)
|
|
203
|
+
return sorted_prefixes
|
|
204
|
+
|
|
205
|
+
# 策略 2:正则启发式兜底(无已知前缀或精确匹配无结果)
|
|
206
|
+
pattern = re.compile(r'\b([a-zA-Z][a-zA-Z0-9_]*)-(\d+)\b')
|
|
207
|
+
counter_fallback: Dict[str, int] = {}
|
|
208
|
+
|
|
209
|
+
for line in log_text.splitlines():
|
|
210
|
+
for match in pattern.finditer(line):
|
|
211
|
+
prefix = match.group(1).lower()
|
|
212
|
+
if prefix in GIT_LOG_FALSE_POSITIVE_PREFIXES:
|
|
213
|
+
continue
|
|
214
|
+
if len(prefix) <= 1:
|
|
215
|
+
continue
|
|
216
|
+
counter_fallback[prefix] = counter_fallback.get(prefix, 0) + 1
|
|
217
|
+
|
|
218
|
+
sorted_prefixes = sorted(counter_fallback, key=counter_fallback.get, reverse=True)
|
|
219
|
+
logger.info("git log 提取前缀: %s, 策略=正则启发式", sorted_prefixes)
|
|
220
|
+
return sorted_prefixes
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""iCafe Card Query Client - 卡片条件查询助手
|
|
2
|
+
|
|
3
|
+
提供 iCafe 平台卡片条件查询相关的 API 接口封装,
|
|
4
|
+
支持通过 IQL 表达式、卡片 ID、空间等维度灵活查询卡片信息。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .client import (
|
|
8
|
+
ICafeQueryConfig,
|
|
9
|
+
ICafeQueryClient,
|
|
10
|
+
# 常量
|
|
11
|
+
ICAFE_BASE_URL,
|
|
12
|
+
FARSEER_BASE_URL,
|
|
13
|
+
DEFAULT_TIMEOUT,
|
|
14
|
+
DEFAULT_LOOKBACK_DAYS,
|
|
15
|
+
DEFAULT_MAX_RECORDS,
|
|
16
|
+
DEFAULT_MAX_COMMITS,
|
|
17
|
+
DEFAULT_MAX_DIFF_LINES,
|
|
18
|
+
GIT_LOG_FALSE_POSITIVE_PREFIXES,
|
|
19
|
+
ISSUE_TYPE_MAP,
|
|
20
|
+
ISSUE_TYPE_NAME_MAP,
|
|
21
|
+
)
|
|
22
|
+
from git_utils import (
|
|
23
|
+
get_current_user,
|
|
24
|
+
get_git_diff_summary,
|
|
25
|
+
extract_space_ids_from_git_log,
|
|
26
|
+
)
|
|
27
|
+
from .matching import (
|
|
28
|
+
auto_detect_space,
|
|
29
|
+
find_matching_card,
|
|
30
|
+
match_diff_to_cards,
|
|
31
|
+
build_type_filter_iql,
|
|
32
|
+
format_card_summary,
|
|
33
|
+
format_query_result,
|
|
34
|
+
)
|
|
35
|
+
from .farseer import get_binding_card_types
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
# 配置和客户端
|
|
39
|
+
'ICafeQueryConfig',
|
|
40
|
+
'ICafeQueryClient',
|
|
41
|
+
# 常量
|
|
42
|
+
'ICAFE_BASE_URL',
|
|
43
|
+
'FARSEER_BASE_URL',
|
|
44
|
+
'DEFAULT_TIMEOUT',
|
|
45
|
+
'DEFAULT_LOOKBACK_DAYS',
|
|
46
|
+
'DEFAULT_MAX_RECORDS',
|
|
47
|
+
'DEFAULT_MAX_COMMITS',
|
|
48
|
+
'DEFAULT_MAX_DIFF_LINES',
|
|
49
|
+
'GIT_LOG_FALSE_POSITIVE_PREFIXES',
|
|
50
|
+
'ISSUE_TYPE_MAP',
|
|
51
|
+
'ISSUE_TYPE_NAME_MAP',
|
|
52
|
+
# Git 工具
|
|
53
|
+
'get_current_user',
|
|
54
|
+
'get_git_diff_summary',
|
|
55
|
+
'extract_space_ids_from_git_log',
|
|
56
|
+
# 自动检测和匹配
|
|
57
|
+
'auto_detect_space',
|
|
58
|
+
'find_matching_card',
|
|
59
|
+
'match_diff_to_cards',
|
|
60
|
+
'build_type_filter_iql',
|
|
61
|
+
# 格式化
|
|
62
|
+
'format_card_summary',
|
|
63
|
+
'format_query_result',
|
|
64
|
+
# Farseer API
|
|
65
|
+
'get_binding_card_types',
|
|
66
|
+
]
|