dsh-github-flow 0.2.1 → 0.4.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.en.md +234 -130
- package/README.md +217 -112
- package/docs/UPGRADE-NOTES.md +15 -9
- package/docs/architecture.md +120 -108
- package/docs/images/2.png +0 -0
- package/docs/npm-publish-guide.md +12 -1
- package/lib/api/routes-actions.js +117 -0
- package/lib/api/routes-overview.js +198 -3
- package/lib/cache.d.ts +4 -0
- package/lib/cache.js +14 -0
- package/lib/client.d.ts +13 -1
- package/lib/client.js +3162 -2162
- package/lib/executor/git-parser.d.ts +25 -0
- package/lib/executor/git-parser.js +143 -0
- package/lib/executor/platform-guide.d.ts +14 -0
- package/lib/executor/platform-guide.js +40 -0
- package/lib/executor/process-utils.d.ts +51 -0
- package/lib/executor/process-utils.js +162 -0
- package/lib/executor/version-utils.d.ts +12 -0
- package/lib/executor/version-utils.js +27 -0
- package/lib/executor.d.ts +131 -17
- package/lib/executor.js +411 -223
- package/lib/git-watcher.d.ts +36 -0
- package/lib/git-watcher.js +91 -0
- package/lib/main.js +11 -0
- package/lib/renderers/cache.d.ts +8 -0
- package/lib/renderers/cache.js +66 -0
- package/lib/renderers/common.d.ts +24 -0
- package/lib/renderers/common.js +88 -0
- package/lib/renderers/gist.d.ts +15 -0
- package/lib/renderers/gist.js +99 -0
- package/lib/renderers/issue.d.ts +4 -0
- package/lib/renderers/issue.js +70 -0
- package/lib/renderers/label.d.ts +4 -0
- package/lib/renderers/label.js +48 -0
- package/lib/renderers/markdown.d.ts +15 -26
- package/lib/renderers/markdown.js +15 -517
- package/lib/renderers/pr.d.ts +4 -0
- package/lib/renderers/pr.js +107 -0
- package/lib/renderers/release.d.ts +4 -0
- package/lib/renderers/release.js +74 -0
- package/lib/renderers/repo.d.ts +4 -0
- package/lib/renderers/repo.js +149 -0
- package/lib/renderers/ruleset.d.ts +4 -0
- package/lib/renderers/ruleset.js +74 -0
- package/lib/renderers/run.d.ts +4 -0
- package/lib/renderers/run.js +79 -0
- package/lib/renderers/skill.d.ts +4 -0
- package/lib/renderers/skill.js +61 -0
- package/lib/renderers/status.d.ts +23 -0
- package/lib/renderers/status.js +124 -0
- package/lib/tools/cache.d.ts +64 -0
- package/lib/tools/cache.js +186 -0
- package/lib/tools/gist.d.ts +155 -0
- package/lib/tools/gist.js +190 -0
- package/lib/tools/help.js +233 -11
- package/lib/tools/image-utils.d.ts +8 -0
- package/lib/tools/image-utils.js +34 -0
- package/lib/tools/issue.d.ts +17 -1
- package/lib/tools/issue.js +114 -8
- package/lib/tools/label.d.ts +80 -0
- package/lib/tools/label.js +237 -0
- package/lib/tools/pr.d.ts +12 -0
- package/lib/tools/pr.js +96 -4
- package/lib/tools/repo.d.ts +8 -0
- package/lib/tools/repo.js +127 -3
- package/lib/tools/ruleset.d.ts +80 -0
- package/lib/tools/ruleset.js +177 -0
- package/lib/tools/run.d.ts +8 -0
- package/lib/tools/run.js +104 -3
- package/lib/tools/secret.d.ts +5 -0
- package/lib/tools/secret.js +108 -23
- package/lib/tools/status.d.ts +39 -0
- package/lib/tools/status.js +53 -0
- package/lib/types.d.ts +112 -0
- package/lib/ui/auth-guide-card.d.ts +4 -0
- package/lib/ui/auth-guide-card.js +161 -0
- package/lib/ui/branch-selector.d.ts +10 -0
- package/lib/ui/branch-selector.js +163 -0
- package/lib/ui/commit-modal.d.ts +8 -0
- package/lib/ui/commit-modal.js +89 -0
- package/lib/ui/icons.d.ts +7 -0
- package/lib/ui/icons.js +53 -0
- package/lib/ui/network-banner.d.ts +10 -0
- package/lib/ui/network-banner.js +54 -0
- package/lib/ui/storage.d.ts +26 -0
- package/lib/ui/storage.js +134 -0
- package/lib/ui/styles.d.ts +6 -0
- package/lib/ui/styles.js +1285 -0
- package/lib/ui/sync-settings-modal.d.ts +11 -0
- package/lib/ui/sync-settings-modal.js +350 -0
- package/lib/ui/sync-status-badge.d.ts +8 -0
- package/lib/ui/sync-status-badge.js +64 -0
- package/lib/ui/upgrade-card.d.ts +7 -0
- package/lib/ui/upgrade-card.js +197 -0
- package/lib/ui/utils.d.ts +10 -0
- package/lib/ui/utils.js +66 -0
- package/lib/ui/workspace-panel.d.ts +4 -0
- package/lib/ui/workspace-panel.js +464 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/lib/tools/help.js
CHANGED
|
@@ -7,15 +7,21 @@ const KNOWLEDGE_BASE = {
|
|
|
7
7
|
| :--- | :--- | :--- |
|
|
8
8
|
| \`github_pr\` | Pull Request 管理、审查与本地检出 | 查看 PR 列表/详情、比对 diff、本地检出代码验证、检查 CI 状态、执行带确认合并 |
|
|
9
9
|
| \`github_issue\` | Issue 任务追踪与分支开发关联 | 筛选待办议题、追加评论、编辑标题/标签、从 Issue 一键切出关联开发分支 |
|
|
10
|
-
| \`github_run\` |
|
|
11
|
-
| \`github_repo\` | 仓库元数据、Fork 同步与全局检索 | 查看仓库与 topics、一键拉平 Fork
|
|
10
|
+
| \`github_run\` | Actions 构建排查与工作流管理 | 查看构建列表、提取失败日志 (log_failed)、重新触发、手动触发 workflow_dispatch、启停工作流、下载构建产物 |
|
|
11
|
+
| \`github_repo\` | 仓库元数据、Fork 同步与全局检索 | 查看仓库与 topics、一键拉平 Fork (sync)、检索代码/仓库/Issue/PR/提交、免 clone 读取任意文件与目录 |
|
|
12
12
|
| \`github_api\` | 原生 GitHub REST/GraphQL 逃生门 | 调用任意端点、获取原始文件字节 (raw)、支持自动翻页 (paginate) |
|
|
13
13
|
| \`github_release\` | 版本发布与构建资产交付 | 查看发版历史、自动生成 Release Notes、上传 .tgz 等构建产物 |
|
|
14
|
-
| \`github_secret\` | CI/CD
|
|
14
|
+
| \`github_secret\` | CI/CD 密钥与变量管理 | 查看 NPM_TOKEN 等密钥清单、经 stdin 安全写入密文、删除密钥;kind:'variable' 管理明文变量(set/get/delete) |
|
|
15
15
|
| \`github_skill\` | 跨 Agent 开源 Skills 生态发现 | 检索/预览/安装 GitHub 上的 Agent Skills (gh preview 特性) |
|
|
16
|
+
| \`github_label\` | 标签体系管理与跨仓库克隆 | 查看标签列表、创建/编辑标签、从源仓库一键 clone 标签体系、删除标签(需 confirm) |
|
|
17
|
+
| \`github_ruleset\` | 分支保护规则与策略诊断 | 检查分支适用的合并策略规则 (check)、查看规则集列表与详情,权威回答“PR 为何无法合并” |
|
|
18
|
+
| \`github_cache\` | Actions 构建缓存盘点与安全清理 | 查看缓存列表与体积占用、按 ID/Key 删除指定缓存、全量清空缓存(需 confirm) |
|
|
19
|
+
| \`github_gist\` | 代码片段与调试日志分享治理 | 查看 Gist 列表与代码正文、创建 Secret/Public 代码片段、编辑与物理删除(需 confirm) |
|
|
20
|
+
| \`github_status\` | 跨仓库待办与动态聚合看板 | 账号维度汇总指派给我的 Issue/PR、等待评审、被 @提及 以及订阅仓库近期动态 |
|
|
16
21
|
| \`github_help\` | 路由导航、官方语法速查与故障自愈 | 遇到不确定的操作、搜索语法或接口报错时查询用法与诊断配方 |
|
|
17
22
|
|
|
18
|
-
💡 **使用准则**:优先调用高层语义工具(pr / issue / run / repo / release / secret);当高层工具无法满足特殊接口需求时,再降级使用 \`github_api
|
|
23
|
+
💡 **使用准则**:优先调用高层语义工具(pr / issue / run / repo / release / secret);当高层工具无法满足特殊接口需求时,再降级使用 \`github_api\`。
|
|
24
|
+
🗺️ **命令对照**:不确定某 gh 命令对应哪个工具?\`github_help(topic: 'mapping')\` 查询完整映射表(含未覆盖域的 API 引导)。`,
|
|
19
25
|
pr: `### 🔀 github_pr 详细操作指南
|
|
20
26
|
|
|
21
27
|
- **查看列表**: \`github_pr(action: 'list', state: 'open' | 'closed' | 'merged' | 'all', limit: 20, author: '@me')\`
|
|
@@ -29,7 +35,14 @@ const KNOWLEDGE_BASE = {
|
|
|
29
35
|
- **检查冲突状态**: \`github_pr(action: 'status')\`
|
|
30
36
|
- 查看当前分支关联 PR 的 merge conflict 状态。
|
|
31
37
|
- **安全合并**: \`github_pr(action: 'merge', pr_number: 123, confirm: true, merge_method: 'squash', delete_branch: false)\`
|
|
32
|
-
- 高危操作必须显式附带 \`confirm: true
|
|
38
|
+
- 高危操作必须显式附带 \`confirm: true\`;若未传将返回拦截警告与待合并影响报告。
|
|
39
|
+
- **Draft 切换**: \`github_pr(action: 'ready', pr_number: 123)\`;反向转回 Draft 附加 \`undo: true\`
|
|
40
|
+
- **反向提交**: \`github_pr(action: 'revert', pr_number: 123, confirm: true)\`
|
|
41
|
+
- 在远端创建反向提交与新 PR(非本地操作),需 confirm。
|
|
42
|
+
- **分支落后自愈**: \`github_pr(action: 'update_branch', pr_number: 123)\`
|
|
43
|
+
- 将基准分支最新提交同步进 PR 分支,解决「分支落后需更新」的 CI 门禁失败。
|
|
44
|
+
- **上传本地附件/图片**: \`github_pr(action: 'create', title: 'UI 重构', body: '对比图如下', attach_images: ['./before.png', './after.png'])\`
|
|
45
|
+
- 需 gh ≥ 2.99;支持 create/edit/comment 动作,单批上限 50 个文件,禁止网络 URL,与 view_images 对称闭环。`,
|
|
33
46
|
issue: `### 🎯 github_issue 详细操作指南
|
|
34
47
|
|
|
35
48
|
- **筛选 Issue**: \`github_issue(action: 'list', state: 'open' | 'closed' | 'all', labels: ['bug'], assignees: ['octocat'], limit: 20)\`
|
|
@@ -39,12 +52,22 @@ const KNOWLEDGE_BASE = {
|
|
|
39
52
|
- 经 gh api 下载正文+评论图片到本地(~/.dsh/data/dsh-github-flow/images/,内容寻址去重),以图片内容块返回,Agent 可直接查看用户报障截图;魔数校验 + 字节护栏(单图 5MB、目录 15MB)。
|
|
40
53
|
- **按 URL 精准获取**: 附加 \`image_urls: ['<view 返回清单中的 URL>']\` 只下载指定图片(可单张可批量);传入 URL 必须在清单内(防任意下载)。
|
|
41
54
|
- 触达目录上限时返回 \`remaining\` 结构化清单,直接作为下一批 image_urls 续传即可。
|
|
55
|
+
- **上传本地附件/图片**: \`github_issue(action: 'comment', issue_number: 42, body: '复现证据', attach_images: ['./bug.png'])\`
|
|
56
|
+
- 需 gh ≥ 2.99;支持 create/edit/comment 动作,单批上限 50 个本地文件(绝对路径或工作区相对路径,禁止网络 URL)。
|
|
42
57
|
- **关联开发分支**: \`github_issue(action: 'develop', issue_number: 42, branch_name: 'fix-login-bug')\`
|
|
43
58
|
- 自动在远端和本地创建带有官方关联关系的开发分支并切换过去,实现“读需求 -> 开分支写代码”的无缝衔接。
|
|
44
59
|
- **编辑 Issue**: \`github_issue(action: 'edit', issue_number: 42, title: '新标题', add_labels: ['p1'], remove_labels: ['triage'])\`
|
|
45
60
|
- **追加讨论**: \`github_issue(action: 'comment', issue_number: 42, body: '定位到问题原因...')\`
|
|
46
61
|
- **安全关闭**: \`github_issue(action: 'close', issue_number: 42, confirm: true)\`
|
|
47
|
-
- 关闭操作必须附带 \`confirm: true
|
|
62
|
+
- 关闭操作必须附带 \`confirm: true\`。
|
|
63
|
+
- **物理删除**: \`github_issue(action: 'delete', issue_number: 42, confirm: true)\`
|
|
64
|
+
- 与 close 有本质区别:编号永久消失、评论湮灭、GraphQL 层无法恢复——拦截级别高于 close。
|
|
65
|
+
- **跨仓库迁移**: \`github_issue(action: 'transfer', issue_number: 42, target_repo: 'other/repo', confirm: true)\`
|
|
66
|
+
- 原 URL 301 重定向,归属改变不可静默撤回。
|
|
67
|
+
- **置顶**: \`github_issue(action: 'pin'/'unpin', issue_number: 42)\`(可逆状态位)
|
|
68
|
+
- **锁定对话**: \`github_issue(action: 'lock', issue_number: 42, lock_reason: 'resolved')\`
|
|
69
|
+
- reason 合法值:off_topic / resolved / spam / too_heated;解锁用 \`action: 'unlock'\`(独立命令)。
|
|
70
|
+
- **我的分配议题**: \`github_issue(action: 'status')\`(账号维度面板)`,
|
|
48
71
|
run: `### 🚀 github_run 详细操作指南
|
|
49
72
|
|
|
50
73
|
- **过滤构建记录**: \`github_run(action: 'list', branch: 'main', status: 'failure', limit: 10)\`
|
|
@@ -53,7 +76,14 @@ const KNOWLEDGE_BASE = {
|
|
|
53
76
|
- 专为 Agent 优化的失败信息提取能力,直接定位报错位置;若无失败步骤则优雅提示。
|
|
54
77
|
- **主动触发工作流**: \`github_run(action: 'trigger', workflow: 'pr-check.yml', ref: 'main', inputs: { env: 'staging' })\`
|
|
55
78
|
- 提交代码修复后,主动触发远端 CI/CD 验证。
|
|
56
|
-
- **重新执行失败任务**: \`github_run(action: 'rerun', run_id: '12345678')
|
|
79
|
+
- **重新执行失败任务**: \`github_run(action: 'rerun', run_id: '12345678')\`
|
|
80
|
+
- **工作流查询**: \`github_run(action: 'workflow_list', all: true)\`
|
|
81
|
+
- 默认仅 active;\`all: true\` 含 disabled(排查「工作流为何不跑」时 disabled 本身就是答案)。
|
|
82
|
+
- **工作流详情**: \`github_run(action: 'workflow_view', workflow: 'npm-publish.yml')\`(名称/ID/文件名均可定位)
|
|
83
|
+
- **启停工作流**: \`github_run(action: 'workflow_enable'/'workflow_disable', workflow: '…')\`
|
|
84
|
+
- disable 后 trigger 将静默失败,直至重新 enable——输出会显式警告这一点。
|
|
85
|
+
- **下载构建产物**: \`github_run(action: 'download', run_id: '12345678', name: '构建产物名'?)\`
|
|
86
|
+
- 落盘目录由插件固定管理(\`~/.dsh/data/dsh-github-flow/artifacts/\` 下按仓库与 run 隔离),返回文件清单。`,
|
|
57
87
|
repo: `### 📦 github_repo 详细操作指南
|
|
58
88
|
|
|
59
89
|
- **查看元数据与标签**: \`github_repo(action: 'view')\`
|
|
@@ -63,7 +93,13 @@ const KNOWLEDGE_BASE = {
|
|
|
63
93
|
- **下载图片查看**: 附加 \`image_urls: [...]\` 精准下载指定图(留空下载全部截图);护栏与 Issue/PR 图片一致,触顶返回 remaining 可续传。
|
|
64
94
|
- **一键拉平 Fork 主干 (防止 Stale)**: \`github_repo(action: 'sync', branch: 'main')\`
|
|
65
95
|
- 解决开源项目贡献中因本地 Fork 落后导致上游 CI 门禁失败的顽疾。
|
|
66
|
-
- **代码检索**: \`github_repo(action: 'search_code', query: 'filename:package.json dsh.bundle')
|
|
96
|
+
- **代码检索**: \`github_repo(action: 'search_code', query: 'filename:package.json dsh.bundle')\`
|
|
97
|
+
- **Issue/PR/Commit 检索**: \`github_repo(action: 'search_issues'/'search_prs'/'search_commits', query: 'repo:o/r state:open')\`
|
|
98
|
+
- 限定符直接写进 query(gh 惯例);注意 commits 必须含搜索文本,纯限定符会被 gh 拒绝。
|
|
99
|
+
- **免 clone 读单文件**: \`github_repo(action: 'read_file', path: 'src/index.ts', ref: 'dev'?)\`
|
|
100
|
+
- gh ≥2.95 直连;低版本自动降级 contents API(输出带降级标注)。二进制文件会被拒绝并引导 github_api。
|
|
101
|
+
- **免 clone 列目录**: \`github_repo(action: 'read_dir', path: '.github/workflows'?)\`
|
|
102
|
+
- 返回目录清单(dir 置顶 + 大小),降级链路同上。`,
|
|
67
103
|
api: `### ⚡ github_api 底层逃生门指南
|
|
68
104
|
|
|
69
105
|
- **标准 GET 请求带参数**:
|
|
@@ -89,7 +125,9 @@ const KNOWLEDGE_BASE = {
|
|
|
89
125
|
- **下载资产**: \`github_release(action: 'download', tag: 'v0.1.9', pattern: '*.tgz', dir: './dist')\`
|
|
90
126
|
- **删除 Release**: \`github_release(action: 'delete', tag: 'v0.1.9', confirm: true)\`
|
|
91
127
|
- 高危不可逆操作,必须显式确认。`,
|
|
92
|
-
secret: `### 🔐 github_secret
|
|
128
|
+
secret: `### 🔐 github_secret 密钥与变量管理指南
|
|
129
|
+
|
|
130
|
+
支持两类对象(kind 分流):**Secret**(密文,默认)与 **Variable**(CI 明文变量)。
|
|
93
131
|
|
|
94
132
|
- **查看密钥清单**: \`github_secret(action: 'list')\`
|
|
95
133
|
- 仅返回名称、可见性与更新时间;GitHub API 设计上就不允许读取密文。
|
|
@@ -99,7 +137,11 @@ const KNOWLEDGE_BASE = {
|
|
|
99
137
|
- gh 在本地用仓库公钥加密后才上传,明文不落盘。
|
|
100
138
|
- **组织/环境级密钥**: 附加 \`org: 'my-org'\` 或 \`env: 'production'\` 参数切换作用域。
|
|
101
139
|
- **删除密钥**: \`github_secret(action: 'delete', name: 'NPM_TOKEN', confirm: true)\`
|
|
102
|
-
- 删除后引用该密钥的 CI
|
|
140
|
+
- 删除后引用该密钥的 CI 工作流会立即失败,务必先确认无工作流依赖。
|
|
141
|
+
- **变量操作(CI 明文)**: 附加 \`kind: 'variable'\`
|
|
142
|
+
- \`github_secret(action: 'set', kind: 'variable', name: 'DEPLOY_ENV', value: 'staging')\`——经 -b 直传(明文无 stdin 红线)。
|
|
143
|
+
- \`github_secret(action: 'get', kind: 'variable', name: 'DEPLOY_ENV')\`——可回显值(这正是变量与密钥的设计区别:secret 写入后 GitHub 侧加密,物理不可读取)。
|
|
144
|
+
- list/delete 与 secret 同形(delete 需 confirm)。`,
|
|
103
145
|
skill: `### 🧠 github_skill Agent Skills 生态指南
|
|
104
146
|
|
|
105
147
|
基于 GitHub CLI 的 \`gh skill\` preview 特性(需 gh >= 2.9x),跨仓库发现与安装开源 Agent Skills:
|
|
@@ -114,6 +156,180 @@ const KNOWLEDGE_BASE = {
|
|
|
114
156
|
- 支持的 agent 值:claude-code / cursor / github-copilot / codex / gemini-cli 等。
|
|
115
157
|
- **查看已安装**: \`github_skill(action: 'list')\`
|
|
116
158
|
- ⚠️ 若报「unknown command」,说明宿主机 gh 版本过低,需升级到 2.9x 以上。`,
|
|
159
|
+
label: `### 🏷️ github_label 详细操作指南
|
|
160
|
+
|
|
161
|
+
- **查看标签列表**: \`github_label(action: 'list', limit: 30, search: 'bug')\`
|
|
162
|
+
- 支持按名称或描述模糊检索,支持 \`sort: 'created' | 'name'\` 与 \`order: 'asc' | 'desc'\`。
|
|
163
|
+
- **创建标签**: \`github_label(action: 'create', name: 'priority/p0', color: 'd73a4a', description: '最高优先级缺陷')\`
|
|
164
|
+
- 颜色自动去除前导 \`#\` 并校验 6 位十六进制;已存在时可附加 \`force: true\` 强制覆盖更新。
|
|
165
|
+
- **编辑标签**: \`github_label(action: 'edit', name: 'old-name', new_name: 'new-name', color: '0075ca')\`
|
|
166
|
+
- 支持修改描述、色值以及重命名标签(\`new_name\`)。
|
|
167
|
+
- **删除标签**: \`github_label(action: 'delete', name: 'deprecated', confirm: true)\`
|
|
168
|
+
- 高危破坏性操作:会导致所有关联 Issue/PR 自动解绑该标记,必须显式附加 \`confirm: true\`;底层自动传 \`--yes\` 杜绝无头交互挂起。
|
|
169
|
+
- **跨仓库克隆标签**: \`github_label(action: 'clone', source_repo: 'cli/cli', force: true)\`
|
|
170
|
+
- 将源仓库的标准标签体系一键同步到当前仓库(或指定的 \`repo\`),新仓库初始化刚需。`,
|
|
171
|
+
ruleset: `### 🛡️ github_ruleset 详细操作指南
|
|
172
|
+
|
|
173
|
+
- **检查分支合并策略约束**: \`github_ruleset(action: 'check', branch: 'master')\`
|
|
174
|
+
- **PR 无法合并的策略视角权威答案**:输出指定分支匹配到的全部硬性规则约束(必审人数、指定 CI、禁止 force push 等)。
|
|
175
|
+
- 若无规则约束,输出排障引导,建议联动 \`github_pr(action: 'checks')\` 检查 CI 执行状态。
|
|
176
|
+
- 检查默认分支可附加 \`default_branch: true\`。
|
|
177
|
+
- **查看规则集列表**: \`github_ruleset(action: 'list', limit: 30)\`
|
|
178
|
+
- 默认包含上级组织继承规则;附加 \`no_parents: true\` 仅查看仓库自身规则集;支持 \`org: 'org-name'\` 查看组织级规则集(需 \`admin:org\` 权限)。
|
|
179
|
+
- **查看规则集详情**: \`github_ruleset(action: 'view', ruleset_id: '4898070')\`
|
|
180
|
+
- 查看具体 Ruleset 详细配置规则与适用范围,\`ruleset_id\` 必填。`,
|
|
181
|
+
cache: `### ⚡ github_cache 详细操作指南
|
|
182
|
+
|
|
183
|
+
- **查看缓存列表与体积**: \`github_cache(action: 'list', limit: 30, sort: 'size_in_bytes', order: 'desc')\`
|
|
184
|
+
- 返回仓库 Actions 构建缓存清单、占用体积(自动换算为 KB/MB/GB)、关联 Git Ref 以及最后访问时间。
|
|
185
|
+
- 可附加 \`key: 'npm-cache'\` 过滤特定前缀,或通过 \`ref: 'refs/heads/main'\` 限定分支。
|
|
186
|
+
- **精准删除单条缓存**:
|
|
187
|
+
- 按数字 ID 删除: \`github_cache(action: 'delete', cache_id: '12345678')\`
|
|
188
|
+
- 按 Key 键名删除: \`github_cache(action: 'delete', key: 'Linux-npm-18-abcd1234')\`
|
|
189
|
+
- **全量清空仓库缓存**:
|
|
190
|
+
\`github_cache(action: 'delete', all: true, confirm: true)\`
|
|
191
|
+
- 批量破坏性操作:会导致后续流水线构建重新拉取依赖,必须显式附加 \`confirm: true\`;底层自动注入 \`--succeed-on-no-caches\` 保证幂等执行。`,
|
|
192
|
+
gist: `### 📝 github_gist 详细操作指南
|
|
193
|
+
|
|
194
|
+
- **查看我的 Gist 列表**: \`github_gist(action: 'list', limit: 10)\`
|
|
195
|
+
- 默认查看全部;可附加 \`public: true\` 仅看公开、\`public: false\` 仅看私密;支持 \`filter: 'regex'\` 正则过滤。
|
|
196
|
+
- **检视代码片段正文**: \`github_gist(action: 'view', gist_id: '5b0e0062eb8e9654adad7bb1d81cc75f')\`
|
|
197
|
+
- 直接输出原始代码正文,\`gist_id\` 必填(防交互挂起);可选 \`filename: 'main.py'\` 限定文件。
|
|
198
|
+
- **创建 Gist 代码片段**:
|
|
199
|
+
- 直接传文本内容: \`github_gist(action: 'create', content: 'console.log("hello");', filename: 'demo.ts', description: '排错测试片段')\`
|
|
200
|
+
- 传本地文件列表: \`github_gist(action: 'create', files: ['./build.log', './error.txt'], description: 'CI 失败排错日志')\`
|
|
201
|
+
- 默认创建 Secret Gist(Unlisted 弱保密,拥有链接者可访问);若要公开需显式附加 \`public: true\`。
|
|
202
|
+
- ⚠️ **安全须知**: 切勿将敏感凭据、API Token 存入 Gist。
|
|
203
|
+
- **编辑 Gist**: \`github_gist(action: 'edit', gist_id: '...', description: '新描述', filename: 'patch.diff')\`
|
|
204
|
+
- **删除 Gist**: \`github_gist(action: 'delete', gist_id: '...', confirm: true)\`
|
|
205
|
+
- 物理删除不可逆,必须显式附加 \`confirm: true\`;底层自动注入 \`--yes\` 杜绝交互式卡死。`,
|
|
206
|
+
status: `### 🧭 github_status 详细操作指南
|
|
207
|
+
|
|
208
|
+
- **查看个人待办与动态大盘**: \`github_status()\` 或 \`github_status(action: 'view')\`
|
|
209
|
+
- 账号维度一站式汇总:指派给我的 Issues、指派给我的 PR、等待我评审的 PR、近期 @提及 以及订阅仓库最新动态。
|
|
210
|
+
- **限定组织**: \`github_status(org: 'my-org')\`
|
|
211
|
+
- 仅汇报指定组织内部的待办事项与动态。
|
|
212
|
+
- **排除噪音仓库**: \`github_status(exclude: ['owner/noisy-repo'])\`
|
|
213
|
+
- 过滤高频刷屏但无需关注的仓库活动。`,
|
|
214
|
+
mapping: `### 🗺️ gh 命令 ↔ 插件工具映射总表
|
|
215
|
+
|
|
216
|
+
#### 一、已覆盖域映射(语义化 action 精确对照)
|
|
217
|
+
|
|
218
|
+
**PR(github_pr,13 action)**
|
|
219
|
+
| gh 命令 | 插件调用 | 备注 |
|
|
220
|
+
| :--- | :--- | :--- |
|
|
221
|
+
| \`gh pr list/view/create/diff/edit/comment\` | \`github_pr(action:'list'/'view'/'create'/'diff'/'edit'/'comment')\` | 高频基础操作 |
|
|
222
|
+
| \`gh pr close\` | 暂无专用 action——用 \`github_pr(action:'edit')\` 或 \`github_api(endpoint:'repos/{o}/{r}/pulls/{n}', method:'PATCH', fields:{state:'closed'})\` | 插件侧未覆盖 |
|
|
223
|
+
| \`gh pr checks\` | \`github_pr(action:'checks', pr_number:n)\` | CI 状态药丸 |
|
|
224
|
+
| \`gh pr review\` | \`github_pr(action:'review', review_decision:'APPROVE'…)\` | |
|
|
225
|
+
| \`gh pr merge\` | \`github_pr(action:'merge', confirm:true)\` | 高危确认 |
|
|
226
|
+
| \`gh pr checkout\` | \`github_pr(action:'checkout')\` | 本地检出 |
|
|
227
|
+
| \`gh pr status\` | \`github_pr(action:'status')\` | 当前分支关联 PR |
|
|
228
|
+
| \`gh pr ready [--undo]\` | \`github_pr(action:'ready', undo:true?)\` | Draft↔Ready 可逆 |
|
|
229
|
+
| \`gh pr revert\` | \`github_pr(action:'revert', confirm:true)\` | 远端创建反向 PR |
|
|
230
|
+
| \`gh pr update-branch\` | \`github_pr(action:'update_branch')\` | 分支落后自愈 |
|
|
231
|
+
|
|
232
|
+
**Issue(github_issue,16 action)**
|
|
233
|
+
| gh 命令 | 插件调用 | 备注 |
|
|
234
|
+
| :--- | :--- | :--- |
|
|
235
|
+
| \`gh issue list/view/create/comment/close/reopen/edit\` | \`github_issue(action:…)\` | 基础操作 |
|
|
236
|
+
| \`gh issue develop\` | \`github_issue(action:'develop', branch_name:…)\` | 关联开发分支 |
|
|
237
|
+
| \`gh issue delete\` | \`github_issue(action:'delete', confirm:true)\` | 物理删除(非 close) |
|
|
238
|
+
| \`gh issue transfer\` | \`github_issue(action:'transfer', target_repo:…, confirm:true)\` | 跨仓库迁移 |
|
|
239
|
+
| \`gh issue pin/unpin\` | \`github_issue(action:'pin'/'unpin')\` | 置顶状态位 |
|
|
240
|
+
| \`gh issue lock/unlock\` | \`github_issue(action:'lock', lock_reason:'resolved'…)\` | reason 四枚举 |
|
|
241
|
+
| \`gh issue status\` | \`github_issue(action:'status')\` | 我的分配议题面板 |
|
|
242
|
+
|
|
243
|
+
**Actions(github_run,11 action)——注意 workflow 域也在此工具**
|
|
244
|
+
| gh 命令 | 插件调用 | 备注 |
|
|
245
|
+
| :--- | :--- | :--- |
|
|
246
|
+
| \`gh run list/view/rerun/cancel\` | \`github_run(action:…)\` | |
|
|
247
|
+
| \`gh run view --log-failed\` | \`github_run(action:'log_failed', run_id:…)\` | 失败日志提取 |
|
|
248
|
+
| \`gh run download\` | \`github_run(action:'download', run_id:…)\` | 落盘插件管理目录 |
|
|
249
|
+
| \`gh workflow run\` | \`github_run(action:'trigger', workflow:…)\` | workflow_dispatch |
|
|
250
|
+
| \`gh workflow list/view\` | \`github_run(action:'workflow_list'/'workflow_view')\` | all:true 含 disabled |
|
|
251
|
+
| \`gh workflow enable/disable\` | \`github_run(action:'workflow_enable'/'workflow_disable')\` | disable 后 trigger 静默失败 |
|
|
252
|
+
|
|
253
|
+
**Repo(github_repo,10 action)——注意 search 域也在此工具**
|
|
254
|
+
| gh 命令 | 插件调用 | 备注 |
|
|
255
|
+
| :--- | :--- | :--- |
|
|
256
|
+
| \`gh repo view\` | \`github_repo(action:'view')\` | 元数据 |
|
|
257
|
+
| (README 读取,gh 无专用命令) | \`github_repo(action:'readme', repo:…)\` | 原文 + 图片清单/下载(插件独有) |
|
|
258
|
+
| \`gh repo sync\` | \`github_repo(action:'sync', force:true?)\` | Fork 对齐 |
|
|
259
|
+
| \`gh repo read-file\` | \`github_repo(action:'read_file', path:…)\` | 免 clone 读文件,gh<2.95 自动降级 API |
|
|
260
|
+
| \`gh repo read-dir\` | \`github_repo(action:'read_dir', path:?)\` | 目录清单,同上降级 |
|
|
261
|
+
| \`gh search code/repos\` | \`github_repo(action:'search_code'/'search_repos')\` | |
|
|
262
|
+
| \`gh search issues/prs/commits\` | \`github_repo(action:'search_issues'/'search_prs'/'search_commits')\` | 限定符写进 query |
|
|
263
|
+
|
|
264
|
+
**Release(github_release,6 action)**
|
|
265
|
+
\`gh release list/view/create/upload/download/delete\` → \`github_release(action:…)\`;delete/clobber 需 confirm。
|
|
266
|
+
|
|
267
|
+
**Secret 与 Variable(github_secret,kind 分流)——注意 variable 域也在此工具**
|
|
268
|
+
| gh 命令 | 插件调用 | 备注 |
|
|
269
|
+
| :--- | :--- | :--- |
|
|
270
|
+
| \`gh secret list/set/delete\` | \`github_secret(action:…)\` | 密文走 stdin,永不回显 |
|
|
271
|
+
| \`gh variable list/set/get/delete\` | \`github_secret(action:…, kind:'variable')\` | CI 明文:-b 直传、get 可回显 |
|
|
272
|
+
| (gh secret get 不存在) | — | GitHub 侧加密存储,物理不可读取 |
|
|
273
|
+
|
|
274
|
+
**Skill(github_skill,4 action)**
|
|
275
|
+
\`gh skill search/preview/install/list\` → \`github_skill(action:…)\`;install 需 confirm(写磁盘)。
|
|
276
|
+
|
|
277
|
+
**Label(github_label,5 action)**
|
|
278
|
+
| gh 命令 | 插件调用 | 备注 |
|
|
279
|
+
| :--- | :--- | :--- |
|
|
280
|
+
| \`gh label list\` | \`github_label(action:'list')\` | 支持搜索与排序 |
|
|
281
|
+
| \`gh label create\` | \`github_label(action:'create', name:…, color:…)\` | 颜色十六进制校验 |
|
|
282
|
+
| \`gh label edit\` | \`github_label(action:'edit', name:…, new_name:…)\` | 支持重命名 |
|
|
283
|
+
| \`gh label delete\` | \`github_label(action:'delete', name:…, confirm:true)\` | 高危解绑,需 confirm |
|
|
284
|
+
| \`gh label clone\` | \`github_label(action:'clone', source_repo:…)\` | 跨仓库一键克隆 |
|
|
285
|
+
|
|
286
|
+
**Ruleset(github_ruleset,3 action)**
|
|
287
|
+
| gh 命令 | 插件调用 | 备注 |
|
|
288
|
+
| :--- | :--- | :--- |
|
|
289
|
+
| \`gh ruleset check\` | \`github_ruleset(action:'check', branch:…)\` | PR 策略排障核心 |
|
|
290
|
+
| \`gh ruleset list\` | \`github_ruleset(action:'list')\` | 规则集概览 |
|
|
291
|
+
| \`gh ruleset view\` | \`github_ruleset(action:'view', ruleset_id:…)\` | 规则详情,ID 必填 |
|
|
292
|
+
|
|
293
|
+
**Cache(github_cache,2 action)**
|
|
294
|
+
| gh 命令 | 插件调用 | 备注 |
|
|
295
|
+
| :--- | :--- | :--- |
|
|
296
|
+
| \`gh cache list\` | \`github_cache(action:'list')\` | 缓存盘点与过滤 |
|
|
297
|
+
| \`gh cache delete\` | \`github_cache(action:'delete', cache_id:…)\` | all:true 需 confirm |
|
|
298
|
+
|
|
299
|
+
**Gist(github_gist,5 action)**
|
|
300
|
+
| gh 命令 | 插件调用 | 备注 |
|
|
301
|
+
| :--- | :--- | :--- |
|
|
302
|
+
| \`gh gist list/view\` | \`github_gist(action:'list'/'view')\` | 代码正文检视 |
|
|
303
|
+
| \`gh gist create\` | \`github_gist(action:'create', content:…)\` | 默认 secret 弱保密 |
|
|
304
|
+
| \`gh gist edit\` | \`github_gist(action:'edit', gist_id:…)\` | 描述与文件修改 |
|
|
305
|
+
| \`gh gist delete\` | \`github_gist(action:'delete', gist_id:…, confirm:true)\` | 物理删除,需 confirm |
|
|
306
|
+
|
|
307
|
+
**Status(github_status,账号维度聚合面板)**
|
|
308
|
+
| gh 命令 | 插件调用 | 备注 |
|
|
309
|
+
| :--- | :--- | :--- |
|
|
310
|
+
| \`gh status\` | \`github_status(action:'view')\` | 跨仓待办大盘与动态 |
|
|
311
|
+
|
|
312
|
+
#### 二、归属提示(命令域与工具名不同构)
|
|
313
|
+
|
|
314
|
+
- \`gh workflow …\` / \`gh search …\` / \`gh variable …\` 分别归 **github_run / github_repo / github_secret**(不是独立工具)
|
|
315
|
+
- \`gh api\` 的等价物是 \`github_api\`(全端点逃生门,支持 raw/paginate/jq)
|
|
316
|
+
- 图片查看:\`github_issue\`/\`github_pr\` 的 \`view_images\`、\`github_repo\` 的 \`readme\` + image_urls(插件独有能力,gh 无对应命令)
|
|
317
|
+
- 附件上传:\`github_issue\`/\`github_pr\` 的 \`attach_images\` 映射 gh ≥2.99 原生可重复 \`--attach\` flag(支持 create/edit/comment)
|
|
318
|
+
|
|
319
|
+
#### 三、未覆盖域引导(经 github_api 调用)
|
|
320
|
+
|
|
321
|
+
| gh 域 | 用途 | 推荐 REST 端点 |
|
|
322
|
+
| :--- | :--- | :--- |
|
|
323
|
+
| \`gh project\` | Projects v2 | \`graphql\`(Projects API 仅 GraphQL) |
|
|
324
|
+
| \`gh discussion\` | 讨论 | \`graphql\`(需仓库开启 discussions) |
|
|
325
|
+
| \`gh codespace\` | 云端开发环境 | \`user/codespaces\` |
|
|
326
|
+
| \`gh org\` | 组织信息 | \`orgs/{org}\` |
|
|
327
|
+
| \`gh auth/config/extension/alias\` | 本机配置类 | 多数无需 API(本机文件/命令) |
|
|
328
|
+
| \`gh browse\` | 打开浏览器 | 直接给用户 URL 即可 |
|
|
329
|
+
| \`gh attestation/gpg-key/ssh-key\` | 签名与密钥 | \`repos/{o}/{r}/attestations\` 等 |
|
|
330
|
+
| \`gh agent-task\` | Copilot 会话 | \`graphql\`(需 Copilot 授权) |
|
|
331
|
+
|
|
332
|
+
> 用法示例:\`github_api(endpoint: 'repos/owner/repo/pulls')\`(原有 \`repos/{o}/{r}/labels\` 端点已由原生 \`github_label\` 工具接管)`,
|
|
117
333
|
search_syntax: `### 🔍 GitHub 官方高级检索语法速查手册
|
|
118
334
|
|
|
119
335
|
在 \`github_repo\`、\`github_api\` 或搜索场景中,请严格遵守 GitHub 官方搜索语法:
|
|
@@ -166,10 +382,16 @@ export function createHelpTool(executor) {
|
|
|
166
382
|
'release',
|
|
167
383
|
'secret',
|
|
168
384
|
'skill',
|
|
385
|
+
'label',
|
|
386
|
+
'ruleset',
|
|
387
|
+
'cache',
|
|
388
|
+
'gist',
|
|
389
|
+
'status',
|
|
390
|
+
'mapping',
|
|
169
391
|
'search_syntax',
|
|
170
392
|
'troubleshooting',
|
|
171
393
|
],
|
|
172
|
-
description: '
|
|
394
|
+
description: '帮助主题分类。mapping 提供 gh 命令与插件工具的完整对照表(不确定某 gh 命令对应哪个工具时查询)。留空则返回全局工具箱导航。',
|
|
173
395
|
},
|
|
174
396
|
gh_command: {
|
|
175
397
|
type: 'string',
|
|
@@ -77,3 +77,11 @@ export declare function downloadImages(urls: string[], run: (url: string) => Pro
|
|
|
77
77
|
}>): Promise<ImageBatchResult>;
|
|
78
78
|
/** render 的 image 内容块构造(text 块由调用方自行拼):仅双合法字段才产出块 */
|
|
79
79
|
export declare function buildImageBlocks(value: any): any[];
|
|
80
|
+
/**
|
|
81
|
+
* 校验并解析本地附件路径列表(Issue/PR --attach 专用)。
|
|
82
|
+
* - 仅接受本地绝对路径或工作区相对路径
|
|
83
|
+
* - 严格拒绝 URL(HTTP/HTTPS)
|
|
84
|
+
* - 单批限制最多 50 个文件(GitHub 限制)
|
|
85
|
+
* - 校验本地文件物理存在性
|
|
86
|
+
*/
|
|
87
|
+
export declare function validateAttachPaths(attachImages: unknown, cwd: string): string[];
|
package/lib/tools/image-utils.js
CHANGED
|
@@ -245,3 +245,37 @@ export function buildImageBlocks(value) {
|
|
|
245
245
|
}
|
|
246
246
|
return blocks;
|
|
247
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* 校验并解析本地附件路径列表(Issue/PR --attach 专用)。
|
|
250
|
+
* - 仅接受本地绝对路径或工作区相对路径
|
|
251
|
+
* - 严格拒绝 URL(HTTP/HTTPS)
|
|
252
|
+
* - 单批限制最多 50 个文件(GitHub 限制)
|
|
253
|
+
* - 校验本地文件物理存在性
|
|
254
|
+
*/
|
|
255
|
+
export function validateAttachPaths(attachImages, cwd) {
|
|
256
|
+
if (!attachImages)
|
|
257
|
+
return [];
|
|
258
|
+
if (!Array.isArray(attachImages)) {
|
|
259
|
+
throw new Error('`attach_images` 必须为本地文件路径数组(string[])。');
|
|
260
|
+
}
|
|
261
|
+
if (attachImages.length > 50) {
|
|
262
|
+
throw new Error(`单次上传附件数量超出 GitHub 限制(单批上限 50 个文件),当前提供: ${attachImages.length} 个。`);
|
|
263
|
+
}
|
|
264
|
+
const resolvedPaths = [];
|
|
265
|
+
for (const item of attachImages) {
|
|
266
|
+
if (typeof item !== 'string' || !item.trim()) {
|
|
267
|
+
throw new Error('`attach_images` 数组中的文件路径不能为空。');
|
|
268
|
+
}
|
|
269
|
+
const trimmed = item.trim();
|
|
270
|
+
// 严格禁止 URL
|
|
271
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
272
|
+
throw new Error(`\`attach_images\` 仅支持本地文件路径上传,不支持网络 URL: "${trimmed}"。\n若需引用网络图片,请直接在正文/评论中使用 Markdown 语法 \`\`,或先将其下载至本地再上传。`);
|
|
273
|
+
}
|
|
274
|
+
const absPath = path.isAbsolute(trimmed) ? trimmed : path.resolve(cwd, trimmed);
|
|
275
|
+
if (!fs.existsSync(absPath)) {
|
|
276
|
+
throw new Error(`指定的附件文件不存在: "${absPath}"(输入路径: "${trimmed}")。`);
|
|
277
|
+
}
|
|
278
|
+
resolvedPaths.push(absPath);
|
|
279
|
+
}
|
|
280
|
+
return resolvedPaths;
|
|
281
|
+
}
|
package/lib/tools/issue.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { GhExecutor } from '../executor.js';
|
|
2
|
-
export { extractImageUrls as extractIssueImageUrls } from './image-utils.js';
|
|
2
|
+
export { extractImageUrls as extractIssueImageUrls, validateAttachPaths } from './image-utils.js';
|
|
3
3
|
export declare function createIssueTool(executor: GhExecutor): {
|
|
4
4
|
name: string;
|
|
5
5
|
description: string;
|
|
@@ -15,6 +15,15 @@ export declare function createIssueTool(executor: GhExecutor): {
|
|
|
15
15
|
type: string;
|
|
16
16
|
description: string;
|
|
17
17
|
};
|
|
18
|
+
target_repo: {
|
|
19
|
+
type: string;
|
|
20
|
+
description: string;
|
|
21
|
+
};
|
|
22
|
+
lock_reason: {
|
|
23
|
+
type: string;
|
|
24
|
+
enum: string[];
|
|
25
|
+
description: string;
|
|
26
|
+
};
|
|
18
27
|
repo: {
|
|
19
28
|
type: string;
|
|
20
29
|
description: string;
|
|
@@ -79,6 +88,13 @@ export declare function createIssueTool(executor: GhExecutor): {
|
|
|
79
88
|
};
|
|
80
89
|
description: string;
|
|
81
90
|
};
|
|
91
|
+
attach_images: {
|
|
92
|
+
type: string;
|
|
93
|
+
items: {
|
|
94
|
+
type: string;
|
|
95
|
+
};
|
|
96
|
+
description: string;
|
|
97
|
+
};
|
|
82
98
|
};
|
|
83
99
|
required: string[];
|
|
84
100
|
};
|
package/lib/tools/issue.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { compareGhVersions } from '../executor.js';
|
|
1
2
|
import { renderIssueMarkdown } from '../renderers/markdown.js';
|
|
2
|
-
import { extractImageUrls, downloadImages, buildImageBlocks, filterRequestedUrls } from './image-utils.js';
|
|
3
|
+
import { extractImageUrls, downloadImages, buildImageBlocks, filterRequestedUrls, validateAttachPaths } from './image-utils.js';
|
|
3
4
|
function normalizeOutput(data) {
|
|
4
5
|
if (data && typeof data === 'object' && !Array.isArray(data)) {
|
|
5
6
|
return data;
|
|
@@ -9,8 +10,8 @@ function normalizeOutput(data) {
|
|
|
9
10
|
}
|
|
10
11
|
return { result: data !== undefined && data !== null ? data : '' };
|
|
11
12
|
}
|
|
12
|
-
//
|
|
13
|
-
export { extractImageUrls as extractIssueImageUrls } from './image-utils.js';
|
|
13
|
+
// 共享图片工具链的同名再导出:保持路径与单测稳定
|
|
14
|
+
export { extractImageUrls as extractIssueImageUrls, validateAttachPaths } from './image-utils.js';
|
|
14
15
|
export function createIssueTool(executor) {
|
|
15
16
|
return {
|
|
16
17
|
name: 'github_issue',
|
|
@@ -20,12 +21,21 @@ export function createIssueTool(executor) {
|
|
|
20
21
|
properties: {
|
|
21
22
|
action: {
|
|
22
23
|
type: 'string',
|
|
23
|
-
enum: ['list', 'view', 'create', 'comment', 'close', 'reopen', 'edit', 'develop', 'view_images'],
|
|
24
|
-
description: 'Issue 操作类型。view_images 下载正文内的图片到本地并返回可渲染的图片内容块(Agent 可直接"看"用户报障截图)。',
|
|
24
|
+
enum: ['list', 'view', 'create', 'comment', 'close', 'reopen', 'edit', 'develop', 'view_images', 'delete', 'transfer', 'pin', 'unpin', 'lock', 'unlock', 'status'],
|
|
25
|
+
description: 'Issue 操作类型。view_images 下载正文内的图片到本地并返回可渲染的图片内容块(Agent 可直接"看"用户报障截图)。delete 物理删除不可恢复、transfer 跨仓库迁移,两者均需 confirm: true。',
|
|
25
26
|
},
|
|
26
27
|
issue_number: {
|
|
27
28
|
type: 'number',
|
|
28
|
-
description: 'Issue 编号(view, comment, close, reopen, edit, develop 时使用)。',
|
|
29
|
+
description: 'Issue 编号(view, comment, close, reopen, edit, develop, delete, transfer, pin/unpin/lock/unlock 时使用)。',
|
|
30
|
+
},
|
|
31
|
+
target_repo: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
description: 'transfer 动作必填:迁移目标仓库 [owner/repo](迁移后原 URL 301 重定向,归属不可静默撤回)。',
|
|
34
|
+
},
|
|
35
|
+
lock_reason: {
|
|
36
|
+
type: 'string',
|
|
37
|
+
enum: ['off_topic', 'resolved', 'spam', 'too_heated'],
|
|
38
|
+
description: 'lock 动作可选:锁定原因(gh 实测四合法值)。',
|
|
29
39
|
},
|
|
30
40
|
repo: {
|
|
31
41
|
type: 'string',
|
|
@@ -74,13 +84,18 @@ export function createIssueTool(executor) {
|
|
|
74
84
|
},
|
|
75
85
|
confirm: {
|
|
76
86
|
type: 'boolean',
|
|
77
|
-
description: '高危破坏性操作确认标志(close
|
|
87
|
+
description: '高危破坏性操作确认标志(close/delete/transfer 动作必需)。delete 物理删除不可恢复、transfer 跨仓库迁移,拦截级别高于 close。',
|
|
78
88
|
},
|
|
79
89
|
image_urls: {
|
|
80
90
|
type: 'array',
|
|
81
91
|
items: { type: 'string' },
|
|
82
92
|
description: 'view_images 可选:仅下载指定 URL 的图片(从 view 返回的 images 清单中选取,不在清单内的会被拒绝)。留空下载全部(正文+评论)。',
|
|
83
93
|
},
|
|
94
|
+
attach_images: {
|
|
95
|
+
type: 'array',
|
|
96
|
+
items: { type: 'string' },
|
|
97
|
+
description: '本地图片/附件路径列表(create, edit, comment 动作使用,需 gh ≥ 2.99;禁止 URL,单批上限 50 个)。',
|
|
98
|
+
},
|
|
84
99
|
},
|
|
85
100
|
required: ['action'],
|
|
86
101
|
},
|
|
@@ -107,6 +122,18 @@ export function createIssueTool(executor) {
|
|
|
107
122
|
}
|
|
108
123
|
const repoArgs = ['-R', repoTarget];
|
|
109
124
|
const runOpts = { cwd, sessionId };
|
|
125
|
+
const appendAttachFlags = async (cmd, attachImages) => {
|
|
126
|
+
const attachPaths = validateAttachPaths(attachImages, cwd);
|
|
127
|
+
if (attachPaths.length > 0) {
|
|
128
|
+
const version = await executor.getGhVersion();
|
|
129
|
+
if (version && compareGhVersions(version, '2.99.0') < 0) {
|
|
130
|
+
throw new Error(`附件上传能力 (\`--attach\`) 需要 GitHub CLI 版本 ≥ 2.99.0,当前版本为: ${version}。\n请升级 gh(Windows: \`winget upgrade GitHub.cli\`,macOS: \`brew upgrade gh\`)后再试。`);
|
|
131
|
+
}
|
|
132
|
+
for (const p of attachPaths) {
|
|
133
|
+
cmd.push('--attach', p);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
110
137
|
switch (args.action) {
|
|
111
138
|
case 'list': {
|
|
112
139
|
const listCmd = ['issue', 'list', ...repoArgs, '--json', 'number,title,state,author,labels,updatedAt,url'];
|
|
@@ -207,6 +234,7 @@ export function createIssueTool(executor) {
|
|
|
207
234
|
if (args.assignees && Array.isArray(args.assignees) && args.assignees.length > 0) {
|
|
208
235
|
cmd.push('--assignee', args.assignees.join(','));
|
|
209
236
|
}
|
|
237
|
+
await appendAttachFlags(cmd, args.attach_images);
|
|
210
238
|
const res = await executor.run(cmd, runOpts);
|
|
211
239
|
if (!res.ok)
|
|
212
240
|
throw new Error(res.error);
|
|
@@ -228,6 +256,7 @@ export function createIssueTool(executor) {
|
|
|
228
256
|
for (const l of args.remove_labels)
|
|
229
257
|
editCmd.push('--remove-label', l);
|
|
230
258
|
}
|
|
259
|
+
await appendAttachFlags(editCmd, args.attach_images);
|
|
231
260
|
const res = await executor.run(editCmd, runOpts);
|
|
232
261
|
if (!res.ok)
|
|
233
262
|
throw new Error(res.error);
|
|
@@ -248,7 +277,9 @@ export function createIssueTool(executor) {
|
|
|
248
277
|
case 'comment': {
|
|
249
278
|
if (!args.issue_number || !args.body)
|
|
250
279
|
throw new Error('comment 必须提供 issue_number 和 body');
|
|
251
|
-
const
|
|
280
|
+
const commentCmd = ['issue', 'comment', String(args.issue_number), ...repoArgs, '--body', args.body];
|
|
281
|
+
await appendAttachFlags(commentCmd, args.attach_images);
|
|
282
|
+
const res = await executor.run(commentCmd, runOpts);
|
|
252
283
|
if (!res.ok)
|
|
253
284
|
throw new Error(res.error);
|
|
254
285
|
return { message: '评论发布成功', output: res.rawOutput };
|
|
@@ -277,6 +308,81 @@ export function createIssueTool(executor) {
|
|
|
277
308
|
throw new Error(res.error);
|
|
278
309
|
return { message: `Issue #${args.issue_number} 已重新开启` };
|
|
279
310
|
}
|
|
311
|
+
// ---- 变更面新增(S3)----
|
|
312
|
+
case 'pin':
|
|
313
|
+
case 'unpin': {
|
|
314
|
+
if (!args.issue_number)
|
|
315
|
+
throw new Error(`${args.action} 操作必须提供 issue_number`);
|
|
316
|
+
// 置顶状态位:可逆(pin↔unpin 互逆),按轻变更免 confirm
|
|
317
|
+
const res = await executor.run(['issue', args.action, String(args.issue_number), ...repoArgs], runOpts);
|
|
318
|
+
if (!res.ok)
|
|
319
|
+
throw new Error(res.error);
|
|
320
|
+
return { message: `Issue #${args.issue_number} 已${args.action === 'pin' ? '置顶' : '取消置顶'}` };
|
|
321
|
+
}
|
|
322
|
+
case 'lock':
|
|
323
|
+
case 'unlock': {
|
|
324
|
+
if (!args.issue_number)
|
|
325
|
+
throw new Error(`${args.action} 操作必须提供 issue_number`);
|
|
326
|
+
// unlock 是 gh 独立命令(非 lock 的 flag,实测 help 已钉);锁定对话可逆,免 confirm
|
|
327
|
+
const cmd = ['issue', args.action, String(args.issue_number), ...repoArgs];
|
|
328
|
+
if (args.action === 'lock' && args.lock_reason) {
|
|
329
|
+
cmd.push('--reason', args.lock_reason);
|
|
330
|
+
}
|
|
331
|
+
const res = await executor.run(cmd, runOpts);
|
|
332
|
+
if (!res.ok)
|
|
333
|
+
throw new Error(res.error);
|
|
334
|
+
return {
|
|
335
|
+
message: `Issue #${args.issue_number} 对话已${args.action === 'lock' ? '锁定' : '解锁'}`,
|
|
336
|
+
...(args.action === 'lock' && args.lock_reason ? { reason: args.lock_reason } : {}),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
case 'delete': {
|
|
340
|
+
if (!args.issue_number)
|
|
341
|
+
throw new Error('delete 操作必须提供 issue_number');
|
|
342
|
+
// 物理删除 > close 的拦截级别:issue 编号永久消失、评论湮灭、GraphQL 无法恢复
|
|
343
|
+
if (args.confirm !== true) {
|
|
344
|
+
return {
|
|
345
|
+
status: 'AWAITING_CONFIRMATION',
|
|
346
|
+
warning: `⚠️ 高危操作拦截:你即将**物理删除** Issue #${args.issue_number}(非 close,不可恢复)。`,
|
|
347
|
+
impact: 'Issue 编号将永久消失,全部评论与附件随之湮灭,GraphQL 层无法恢复——这与 close(可 reopen 逆转)有本质区别。',
|
|
348
|
+
requiredAction: '如确认删除,请与用户核实后附加 `confirm: true` 重新调用。',
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
// 非 TTY 下 gh issue delete 会挂起等待 prompt,--yes 是非交互执行的唯一途径
|
|
352
|
+
const res = await executor.run(['issue', 'delete', String(args.issue_number), ...repoArgs, '--yes'], runOpts);
|
|
353
|
+
if (!res.ok)
|
|
354
|
+
throw new Error(res.error);
|
|
355
|
+
return { message: `Issue #${args.issue_number} 已永久删除(不可恢复)` };
|
|
356
|
+
}
|
|
357
|
+
case 'transfer': {
|
|
358
|
+
if (!args.issue_number)
|
|
359
|
+
throw new Error('transfer 操作必须提供 issue_number');
|
|
360
|
+
if (!args.target_repo)
|
|
361
|
+
throw new Error('transfer 操作必须提供 target_repo [owner/repo]');
|
|
362
|
+
if (args.target_repo === repoTarget) {
|
|
363
|
+
throw new Error(`transfer 目标仓库 (${args.target_repo}) 与当前仓库相同,迁移无意义。`);
|
|
364
|
+
}
|
|
365
|
+
// 跨仓库迁移:原 URL 301 但归属改变,不可静默撤回——与 delete 同级 confirm
|
|
366
|
+
if (args.confirm !== true) {
|
|
367
|
+
return {
|
|
368
|
+
status: 'AWAITING_CONFIRMATION',
|
|
369
|
+
warning: `⚠️ 高危操作拦截:你即将把 Issue #${args.issue_number} 从 ${repoTarget} 迁移到 ${args.target_repo}。`,
|
|
370
|
+
impact: `迁移后 Issue 归属 ${args.target_repo}(原 URL 301 重定向),标签/里程碑不随迁,操作不可静默撤回。需要目标仓库的写权限。`,
|
|
371
|
+
requiredAction: '如确认迁移,请与用户核实后附加 `confirm: true` 重新调用。',
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
const res = await executor.run(['issue', 'transfer', String(args.issue_number), args.target_repo, ...repoArgs], runOpts);
|
|
375
|
+
if (!res.ok)
|
|
376
|
+
throw new Error(res.error);
|
|
377
|
+
return { message: `Issue #${args.issue_number} 已迁移至 ${args.target_repo}`, url: res.rawOutput };
|
|
378
|
+
}
|
|
379
|
+
case 'status': {
|
|
380
|
+
// 非 TTY 纯文本分段(Assigned/Mentioning/Pushed),gh 原生已是紧凑格式
|
|
381
|
+
const res = await executor.run(['issue', 'status', ...repoArgs], { ...runOpts, rawText: true, timeoutMs: 20_000 });
|
|
382
|
+
if (!res.ok)
|
|
383
|
+
throw new Error(res.error);
|
|
384
|
+
return { result: res.rawOutput || '无分配议题' };
|
|
385
|
+
}
|
|
280
386
|
default:
|
|
281
387
|
throw new Error(`未知的 Issue 操作: ${args.action}`);
|
|
282
388
|
}
|