dsh-github-flow 0.4.0 → 0.6.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 (82) hide show
  1. package/README.en.md +91 -12
  2. package/README.md +91 -12
  3. package/docs/UPGRADE-NOTES.md +9 -12
  4. package/docs/architecture.md +63 -29
  5. package/docs/images/1.png +0 -0
  6. package/lib/api/routes-actions.js +268 -5
  7. package/lib/api/routes-overview.js +147 -29
  8. package/lib/cache.d.ts +77 -4
  9. package/lib/cache.js +114 -7
  10. package/lib/client.d.ts +9 -4
  11. package/lib/client.js +5293 -942
  12. package/lib/commands/gh.d.ts +6 -1
  13. package/lib/commands/gh.js +144 -71
  14. package/lib/executor/error-classifier.d.ts +55 -0
  15. package/lib/executor/error-classifier.js +199 -0
  16. package/lib/executor/git-parser.d.ts +157 -1
  17. package/lib/executor/git-parser.js +513 -4
  18. package/lib/executor.d.ts +147 -4
  19. package/lib/executor.js +866 -77
  20. package/lib/main.js +28 -4
  21. package/lib/renderers/agent-task.d.ts +16 -0
  22. package/lib/renderers/agent-task.js +107 -0
  23. package/lib/renderers/codespace.d.ts +16 -0
  24. package/lib/renderers/codespace.js +103 -0
  25. package/lib/renderers/discussion.d.ts +16 -0
  26. package/lib/renderers/discussion.js +101 -0
  27. package/lib/renderers/markdown.d.ts +4 -0
  28. package/lib/renderers/markdown.js +4 -0
  29. package/lib/renderers/project.d.ts +20 -0
  30. package/lib/renderers/project.js +128 -0
  31. package/lib/renderers/skill.d.ts +30 -0
  32. package/lib/renderers/skill.js +180 -0
  33. package/lib/renderers/status.d.ts +5 -0
  34. package/lib/renderers/status.js +52 -0
  35. package/lib/telemetry.d.ts +70 -0
  36. package/lib/telemetry.js +161 -0
  37. package/lib/tools/agent-task.d.ts +54 -0
  38. package/lib/tools/agent-task.js +135 -0
  39. package/lib/tools/codespace.d.ts +51 -0
  40. package/lib/tools/codespace.js +154 -0
  41. package/lib/tools/discussion.d.ts +70 -0
  42. package/lib/tools/discussion.js +195 -0
  43. package/lib/tools/help.js +129 -14
  44. package/lib/tools/image-utils.d.ts +27 -0
  45. package/lib/tools/image-utils.js +73 -3
  46. package/lib/tools/project.d.ts +80 -0
  47. package/lib/tools/project.js +241 -0
  48. package/lib/tools/repo.js +13 -1
  49. package/lib/tools/skill.d.ts +24 -1
  50. package/lib/tools/skill.js +115 -5
  51. package/lib/tools/status.d.ts +3 -2
  52. package/lib/tools/status.js +9 -4
  53. package/lib/types.d.ts +336 -0
  54. package/lib/ui/commit-modal.js +144 -14
  55. package/lib/ui/help-modal.d.ts +21 -0
  56. package/lib/ui/help-modal.js +300 -0
  57. package/lib/ui/issue-modal.d.ts +14 -0
  58. package/lib/ui/issue-modal.js +366 -0
  59. package/lib/ui/markdown-lite.d.ts +66 -0
  60. package/lib/ui/markdown-lite.js +312 -0
  61. package/lib/ui/network-banner.d.ts +12 -0
  62. package/lib/ui/network-banner.js +35 -0
  63. package/lib/ui/pr-modal.d.ts +17 -0
  64. package/lib/ui/pr-modal.js +516 -0
  65. package/lib/ui/repo-badges.d.ts +43 -0
  66. package/lib/ui/repo-badges.js +82 -0
  67. package/lib/ui/repo-selector.d.ts +14 -0
  68. package/lib/ui/repo-selector.js +112 -0
  69. package/lib/ui/storage.d.ts +56 -0
  70. package/lib/ui/storage.js +163 -0
  71. package/lib/ui/styles.d.ts +1 -1
  72. package/lib/ui/styles.js +1219 -0
  73. package/lib/ui/sync-settings-modal.js +1 -1
  74. package/lib/ui/upgrade-card.js +39 -14
  75. package/lib/ui/utils.d.ts +35 -0
  76. package/lib/ui/utils.js +172 -0
  77. package/lib/ui/workspace-panel.js +198 -31
  78. package/lib/upgrade-manager.d.ts +5 -1
  79. package/lib/upgrade-manager.js +24 -1
  80. package/lib/version.d.ts +1 -1
  81. package/lib/version.js +1 -1
  82. package/package.json +2 -2
package/lib/tools/help.js CHANGED
@@ -12,15 +12,22 @@ const KNOWLEDGE_BASE = {
12
12
  | \`github_api\` | 原生 GitHub REST/GraphQL 逃生门 | 调用任意端点、获取原始文件字节 (raw)、支持自动翻页 (paginate) |
13
13
  | \`github_release\` | 版本发布与构建资产交付 | 查看发版历史、自动生成 Release Notes、上传 .tgz 等构建产物 |
14
14
  | \`github_secret\` | CI/CD 密钥与变量管理 | 查看 NPM_TOKEN 等密钥清单、经 stdin 安全写入密文、删除密钥;kind:'variable' 管理明文变量(set/get/delete) |
15
- | \`github_skill\` | 跨 Agent 开源 Skills 生态发现 | 检索/预览/安装 GitHub 上的 Agent Skills (gh preview 特性) |
15
+ | \`github_skill\` | 跨 Agent 开源 Skills 生态发现与维护 | 检索/预览/安装 GitHub 上的 Agent Skills(gh preview 特性);\`publish\` 规范自检与发布、\`update\` 检查并同步更新已安装技能 |
16
16
  | \`github_label\` | 标签体系管理与跨仓库克隆 | 查看标签列表、创建/编辑标签、从源仓库一键 clone 标签体系、删除标签(需 confirm) |
17
17
  | \`github_ruleset\` | 分支保护规则与策略诊断 | 检查分支适用的合并策略规则 (check)、查看规则集列表与详情,权威回答“PR 为何无法合并” |
18
18
  | \`github_cache\` | Actions 构建缓存盘点与安全清理 | 查看缓存列表与体积占用、按 ID/Key 删除指定缓存、全量清空缓存(需 confirm) |
19
19
  | \`github_gist\` | 代码片段与调试日志分享治理 | 查看 Gist 列表与代码正文、创建 Secret/Public 代码片段、编辑与物理删除(需 confirm) |
20
20
  | \`github_status\` | 跨仓库待办与动态聚合看板 | 账号维度汇总指派给我的 Issue/PR、等待评审、被 @提及 以及订阅仓库近期动态 |
21
+ | \`github_agent_task\` | 云端智能体编码任务会话治理 | 查阅已分派任务列表、检视任务状态与会话日志、向云端 Agent 发起新编码重构任务 |
22
+ | \`github_discussion\` | 团队技术讨论与开源社区 RFC 闭环 | 浏览讨论列表、检视正文与评论楼层、发起新讨论、编辑正文与追加回复 |
23
+ | \`github_project\` | Projects v2 项目看板与任务规划 | 查阅项目列表/详情、浏览看板条目 (Items)、添加 Issue/PR 到看板、创建草稿任务与删除条目 |
24
+ | \`github_codespace\` | 云端远程开发环境管控 (MVP) | 查阅运行中实例、检视机器规格配置、停机防计费 (stop)、安全销毁环境 (delete,需 confirm) |
21
25
  | \`github_help\` | 路由导航、官方语法速查与故障自愈 | 遇到不确定的操作、搜索语法或接口报错时查询用法与诊断配方 |
22
26
 
23
27
  💡 **使用准则**:优先调用高层语义工具(pr / issue / run / repo / release / secret);当高层工具无法满足特殊接口需求时,再降级使用 \`github_api\`。
28
+ 📊 **规模口径**:18 个工具 / 103 个业务 action(不含 \`github_help\` 的 21 个查询主题与 \`github_api\` 的 4 个 HTTP method——它们不是业务动作)。
29
+ 💬 **人类指令**:聊天框支持 \`/gh status\`(大盘看板)、\`/gh upgrade\`(一键升级插件)、\`/gh help\`(快捷帮助)。
30
+ 🖥️ **可视化工作台**:最左侧 Octocat 图标打开全景驾驶舱(4 标签:本地工作区 / 我的仓库 / Pull Requests / 待办 Issues);每个会话右侧栏有 5 个 Tab(Git / 未提交 / PR / Issues / Actions)。点击任一 PR 或 Issue 卡片可在线查看详情与评论,无需跳浏览器。
24
31
  🗺️ **命令对照**:不确定某 gh 命令对应哪个工具?\`github_help(topic: 'mapping')\` 查询完整映射表(含未覆盖域的 API 引导)。`,
25
32
  pr: `### 🔀 github_pr 详细操作指南
26
33
 
@@ -42,7 +49,9 @@ const KNOWLEDGE_BASE = {
42
49
  - **分支落后自愈**: \`github_pr(action: 'update_branch', pr_number: 123)\`
43
50
  - 将基准分支最新提交同步进 PR 分支,解决「分支落后需更新」的 CI 门禁失败。
44
51
  - **上传本地附件/图片**: \`github_pr(action: 'create', title: 'UI 重构', body: '对比图如下', attach_images: ['./before.png', './after.png'])\`
45
- - 需 gh ≥ 2.99;支持 create/edit/comment 动作,单批上限 50 个文件,禁止网络 URL,与 view_images 对称闭环。`,
52
+ - 需 gh ≥ 2.99;支持 create/edit/comment 动作,单批上限 50 个文件,禁止网络 URL,与 view_images 对称闭环。
53
+ - **追加评论与编辑**: \`github_pr(action: 'comment', pr_number: 123, body: 'LGTM'); github_pr(action: 'edit', pr_number: 123, body: '更新后的描述')\`
54
+ - 两者同样支持 \`attach_images\` 附件通道。`,
46
55
  issue: `### 🎯 github_issue 详细操作指南
47
56
 
48
57
  - **筛选 Issue**: \`github_issue(action: 'list', state: 'open' | 'closed' | 'all', labels: ['bug'], assignees: ['octocat'], limit: 20)\`
@@ -155,7 +164,17 @@ const KNOWLEDGE_BASE = {
155
164
  - install 会写本地磁盘,必须 \`confirm: true\`;scope 默认 project(当前 git 仓库)。
156
165
  - 支持的 agent 值:claude-code / cursor / github-copilot / codex / gemini-cli 等。
157
166
  - **查看已安装**: \`github_skill(action: 'list')\`
158
- - ⚠️ 若报「unknown command」,说明宿主机 gh 版本过低,需升级到 2.9x 以上。`,
167
+ - **规范自检与发布**:
168
+ - \`github_skill(action: 'publish')\` —— 默认 \`--dry-run\` 模式,对本地技能目录进行 agentskills.io 合规性检查(命名规范、目录匹配、必需 frontmatter 字段等),零副作用安全自检。
169
+ - \`github_skill(action: 'publish', fix: true)\` —— 自动清洗并剥离残留的安装元数据(\`metadata.github-*\`),修改本地文件但不发布。
170
+ - \`github_skill(action: 'publish', tag: 'v1.0.0', dry_run: false, confirm: true)\` —— 正式发布,强制要求指定 \`tag\` 并附带 \`confirm: true\`(防无头挂起与误发布),自动创建 GitHub Release。
171
+ - ⚠️ 若报「unknown command」,说明宿主机 gh 版本过低,需升级到 2.9x 以上。
172
+
173
+ - **检查并同步更新已安装技能**:
174
+ - \`github_skill(action: 'update')\` —— **默认 dry-run**,只检查哪些技能有新版本,零副作用。
175
+ - \`github_skill(action: 'update', dry_run: false)\` —— 真正执行同步更新。
176
+ - \`github_skill(action: 'update', all: true)\` —— 更新全部已安装技能(否则只处理 \`skill_names\` 指定项)。
177
+ - \`github_skill(action: 'update', skill_names: ['code-review', 'devops'])\` —— 定向更新指定技能。`,
159
178
  label: `### 🏷️ github_label 详细操作指南
160
179
 
161
180
  - **查看标签列表**: \`github_label(action: 'list', limit: 30, search: 'bug')\`
@@ -210,15 +229,61 @@ const KNOWLEDGE_BASE = {
210
229
  - **限定组织**: \`github_status(org: 'my-org')\`
211
230
  - 仅汇报指定组织内部的待办事项与动态。
212
231
  - **排除噪音仓库**: \`github_status(exclude: ['owner/noisy-repo'])\`
213
- - 过滤高频刷屏但无需关注的仓库活动。`,
232
+ - 过滤高频刷屏但无需关注的仓库活动。
233
+ - **查看工具链运行时健康度**: \`github_status(action: 'health')\`
234
+ - 审计当前会话 18 大工具矩阵的综合健康分、API 降级率、安全防线拦截频次与针对性自愈建议。`,
235
+ agent_task: `### 🤖 github_agent_task 智能体任务指南
236
+
237
+ 管理与调度 GitHub Copilot Coding Agent 云端智能体会话:
238
+ - **查看任务列表**: \`github_agent_task(action: 'list', limit: 30)\`
239
+ - 账号全局任务全景列表(注:上游 gh CLI 原生不接收 -R/--repo 限制,默认列出当前用户所有活跃会话)。
240
+ - **检视任务会话与日志**: \`github_agent_task(action: 'view', task_id: 'e2fa49d2-...', log: true)\`
241
+ - 必须提供 \`task_id\`(支持 Session ID、PR 编号或 URL),支持 \`repo: 'owner/repo'\`,附加 \`log: true\` 可完整拉取任务执行过程日志。
242
+ - **派发新编码任务**: \`github_agent_task(action: 'create', prompt: '为用户模块补全单元测试', base_branch: 'main', repo: 'owner/repo')\`
243
+ - 支持附加 \`custom_agent: 'my-agent'\` 指定仓库预设的智能体定义,支持 \`repo\` 定向派发。`,
244
+ discussion: `### 💬 github_discussion 讨论区操作指南
245
+
246
+ 基于 GitHub CLI 的 \`gh discussion\` preview 特性,支持团队架构探讨、RFC 与社区互动:
247
+ - **查看讨论列表**: \`github_discussion(action: 'list', category: 'General', state: 'open', limit: 30)\`
248
+ - 支持按 \`category\`(分类)、\`state\`(open/closed/all)、\`labels\` 以及 \`search\`(关键词)过滤;状态自动结构化映射为 OPEN / CLOSED / ANSWERED。
249
+ - **检视讨论正文与回复楼层**: \`github_discussion(action: 'view', discussion_number: 123, comments: true)\`
250
+ - **发起新讨论**: \`github_discussion(action: 'create', title: 'RFC: 架构演进方案', category: 'Ideas', body: '详细方案...')\`
251
+ - \`title\`、\`category\` 与 \`body\` 均为必填项。
252
+ - **编辑讨论**: \`github_discussion(action: 'edit', discussion_number: 123, title: '新标题', body: '修正后的正文')\`
253
+ - **发表讨论回复**: \`github_discussion(action: 'comment', discussion_number: 123, body: '赞同该方案!')\`
254
+ - 💡 **提示**:若报错「discussions disabled」,说明目标仓库未在 GitHub 仓库「Settings -> General -> Features」中启用 Discussions 社区功能。`,
255
+ project: `### 📋 github_project 项目看板与规划指南
256
+
257
+ 基于 GitHub Projects v2,支持项目看板与任务全生命周期管理:
258
+ - **查看项目列表**: \`github_project(action: 'list', owner: '@me', closed: false)\`
259
+ - 缺省 owner 为 \`@me\`(当前用户),可指定组织或用户名称。
260
+ - **查看项目详情**: \`github_project(action: 'view', project_number: 1)\`
261
+ - **浏览看板条目 (Items)**: \`github_project(action: 'item-list', project_number: 1, query: 'is:open')\`
262
+ - **添加现有 Issue/PR 到看板**: \`github_project(action: 'item-add', project_number: 1, url: 'https://github.com/owner/repo/issues/10')\`
263
+ - **创建草稿条目**: \`github_project(action: 'item-create', project_number: 1, title: '待调研技术方案', body: '方案说明...')\`
264
+ - **删除看板条目**: \`github_project(action: 'item-delete', item_id: 'PVTI_...', confirm: true)\`
265
+ - 必须附加 \`confirm: true\`;仅解除条目与看板的关联,不删除 Issue/PR 原型。
266
+ - 🔑 若报缺少权限,在终端执行单行自愈授权命令:\`gh auth refresh -s read:project\``,
267
+ codespace: `### ☁️ github_codespace 云端开发环境指南
268
+
269
+ 管理 GitHub Codespaces 云端远程工作区(精选高频实用 MVP):
270
+ - **查看云端环境列表**: \`github_codespace(action: 'list', limit: 30)\`
271
+ - **检视实例配置与状态**: \`github_codespace(action: 'view', codespace: 'fuzzy-spoon-69vj')\`
272
+ - 必须显式提供 \`codespace\` 名称,杜绝交互式挂起。
273
+ - **停止运行环境 (防计费)**: \`github_codespace(action: 'stop', codespace: 'fuzzy-spoon-69vj')\`
274
+ - 立即向云端实例发送停机信号,防止持续扣除计算核时配额。
275
+ - **安全销毁实例**: \`github_codespace(action: 'delete', codespace: 'fuzzy-spoon-69vj', confirm: true)\`
276
+ - 物理销毁不可逆,必须附加 \`confirm: true\`。
277
+ - 🔑 若报缺少权限,在终端执行单行自愈授权命令:\`gh auth refresh -h github.com -s codespace\``,
214
278
  mapping: `### 🗺️ gh 命令 ↔ 插件工具映射总表
215
279
 
216
280
  #### 一、已覆盖域映射(语义化 action 精确对照)
217
281
 
218
- **PR(github_pr,13 action)**
282
+ **PR(github_pr,15 action)**
219
283
  | gh 命令 | 插件调用 | 备注 |
220
284
  | :--- | :--- | :--- |
221
- | \`gh pr list/view/create/diff/edit/comment\` | \`github_pr(action:'list'/'view'/'create'/'diff'/'edit'/'comment')\` | 高频基础操作 |
285
+ | \`gh pr list/view/create/diff/edit/comment\` | \`github_pr(action:'list'/'view'/'create'/'diff'/'edit'/'comment')\` | 高频基础操作;edit/comment 支持 attach_images |
286
+ | (PR 图片查看,gh 无对应命令) | \`github_pr(action:'view_images', pr_number:n)\` | 插件独有:正文+评论图片下载并转为可读图像块 |
222
287
  | \`gh pr close\` | 暂无专用 action——用 \`github_pr(action:'edit')\` 或 \`github_api(endpoint:'repos/{o}/{r}/pulls/{n}', method:'PATCH', fields:{state:'closed'})\` | 插件侧未覆盖 |
223
288
  | \`gh pr checks\` | \`github_pr(action:'checks', pr_number:n)\` | CI 状态药丸 |
224
289
  | \`gh pr review\` | \`github_pr(action:'review', review_decision:'APPROVE'…)\` | |
@@ -233,6 +298,7 @@ const KNOWLEDGE_BASE = {
233
298
  | gh 命令 | 插件调用 | 备注 |
234
299
  | :--- | :--- | :--- |
235
300
  | \`gh issue list/view/create/comment/close/reopen/edit\` | \`github_issue(action:…)\` | 基础操作 |
301
+ | (Issue 图片查看,gh 无对应命令) | \`github_issue(action:'view_images', issue_number:n)\` | 插件独有:报障截图转图像块 |
236
302
  | \`gh issue develop\` | \`github_issue(action:'develop', branch_name:…)\` | 关联开发分支 |
237
303
  | \`gh issue delete\` | \`github_issue(action:'delete', confirm:true)\` | 物理删除(非 close) |
238
304
  | \`gh issue transfer\` | \`github_issue(action:'transfer', target_repo:…, confirm:true)\` | 跨仓库迁移 |
@@ -271,8 +337,11 @@ const KNOWLEDGE_BASE = {
271
337
  | \`gh variable list/set/get/delete\` | \`github_secret(action:…, kind:'variable')\` | CI 明文:-b 直传、get 可回显 |
272
338
  | (gh secret get 不存在) | — | GitHub 侧加密存储,物理不可读取 |
273
339
 
274
- **Skill(github_skill,4 action)**
275
- \`gh skill search/preview/install/list\` → \`github_skill(action:…)\`;install 需 confirm(写磁盘)。
340
+ **Skill(github_skill,6 action)**
341
+ | gh 命令 | 插件调用 | 备注 |
342
+ | :--- | :--- | :--- |
343
+ | \`gh skill search/preview/install/list/publish\` | \`github_skill(action:…)\` | install 需 confirm(写磁盘);publish 默认 dry-run 安全自检,正式发布需 tag 与 confirm |
344
+ | \`gh skill update\` | \`github_skill(action:'update')\` | 默认 dry-run 检查;\`all:true\` 或 \`skill_names\` 定向;\`dry_run:false\` 才真正更新 |
276
345
 
277
346
  **Label(github_label,5 action)**
278
347
  | gh 命令 | 插件调用 | 备注 |
@@ -304,10 +373,45 @@ const KNOWLEDGE_BASE = {
304
373
  | \`gh gist edit\` | \`github_gist(action:'edit', gist_id:…)\` | 描述与文件修改 |
305
374
  | \`gh gist delete\` | \`github_gist(action:'delete', gist_id:…, confirm:true)\` | 物理删除,需 confirm |
306
375
 
307
- **Status(github_status,账号维度聚合面板)**
376
+ **Status(github_status,2 action)**
308
377
  | gh 命令 | 插件调用 | 备注 |
309
378
  | :--- | :--- | :--- |
310
379
  | \`gh status\` | \`github_status(action:'view')\` | 跨仓待办大盘与动态 |
380
+ | — | \`github_status(action:'health')\` | 工具链健康度与降级率审计 |
381
+
382
+ **Agent Task(github_agent_task,3 action)**
383
+ | gh 命令 | 插件调用 | 备注 |
384
+ | :--- | :--- | :--- |
385
+ | \`gh agent-task list\` | \`github_agent_task(action:'list')\` | 智能体编码任务列表 |
386
+ | \`gh agent-task view\` | \`github_agent_task(action:'view', task_id:…)\` | 任务状态与日志,ID 必填 |
387
+ | \`gh agent-task create\` | \`github_agent_task(action:'create', prompt:…)\` | 向云端 Agent 派发任务 |
388
+
389
+ **Discussion(github_discussion,5 action)**
390
+ | gh 命令 | 插件调用 | 备注 |
391
+ | :--- | :--- | :--- |
392
+ | \`gh discussion list\` | \`github_discussion(action:'list')\` | 社区与团队讨论列表 |
393
+ | \`gh discussion view\` | \`github_discussion(action:'view', discussion_number:…)\` | 讨论正文与回复楼层 |
394
+ | \`gh discussion create\` | \`github_discussion(action:'create', title:…, category:…, body:…)\` | 发起新讨论,三项必填 |
395
+ | \`gh discussion edit\` | \`github_discussion(action:'edit', discussion_number:…)\` | 修改讨论标题或正文 |
396
+ | \`gh discussion comment\` | \`github_discussion(action:'comment', discussion_number:…, body:…)\` | 追加讨论评论 |
397
+
398
+ **Project(github_project,6 action)**
399
+ | gh 命令 | 插件调用 | 备注 |
400
+ | :--- | :--- | :--- |
401
+ | \`gh project list\` | \`github_project(action:'list')\` | 项目看板列表,默认 @me |
402
+ | \`gh project view\` | \`github_project(action:'view', project_number:…)\` | 项目元数据与描述 |
403
+ | \`gh project item-list\` | \`github_project(action:'item-list', project_number:…)\` | 任务条目看板 |
404
+ | \`gh project item-add\` | \`github_project(action:'item-add', project_number:…, url:…)\` | 关联 Issue/PR 到看板 |
405
+ | \`gh project item-create\` | \`github_project(action:'item-create', project_number:…, title:…)\` | 创建草稿条目 |
406
+ | \`gh project item-delete\` | \`github_project(action:'item-delete', item_id:…, confirm:true)\` | 移除条目,需 confirm |
407
+
408
+ **Codespace(github_codespace,4 action)**
409
+ | gh 命令 | 插件调用 | 备注 |
410
+ | :--- | :--- | :--- |
411
+ | \`gh codespace list\` | \`github_codespace(action:'list')\` | 云端开发环境列表 |
412
+ | \`gh codespace view\` | \`github_codespace(action:'view', codespace:…)\` | 实例详情,名称必填 |
413
+ | \`gh codespace stop\` | \`github_codespace(action:'stop', codespace:…)\` | 关机防计费 |
414
+ | \`gh codespace delete\` | \`github_codespace(action:'delete', codespace:…, confirm:true)\` | 销毁实例,需 confirm |
311
415
 
312
416
  #### 二、归属提示(命令域与工具名不同构)
313
417
 
@@ -320,14 +424,10 @@ const KNOWLEDGE_BASE = {
320
424
 
321
425
  | gh 域 | 用途 | 推荐 REST 端点 |
322
426
  | :--- | :--- | :--- |
323
- | \`gh project\` | Projects v2 | \`graphql\`(Projects API 仅 GraphQL) |
324
- | \`gh discussion\` | 讨论 | \`graphql\`(需仓库开启 discussions) |
325
- | \`gh codespace\` | 云端开发环境 | \`user/codespaces\` |
326
427
  | \`gh org\` | 组织信息 | \`orgs/{org}\` |
327
428
  | \`gh auth/config/extension/alias\` | 本机配置类 | 多数无需 API(本机文件/命令) |
328
429
  | \`gh browse\` | 打开浏览器 | 直接给用户 URL 即可 |
329
430
  | \`gh attestation/gpg-key/ssh-key\` | 签名与密钥 | \`repos/{o}/{r}/attestations\` 等 |
330
- | \`gh agent-task\` | Copilot 会话 | \`graphql\`(需 Copilot 授权) |
331
431
 
332
432
  > 用法示例:\`github_api(endpoint: 'repos/owner/repo/pulls')\`(原有 \`repos/{o}/{r}/labels\` 端点已由原生 \`github_label\` 工具接管)`,
333
433
  search_syntax: `### 🔍 GitHub 官方高级检索语法速查手册
@@ -361,7 +461,18 @@ const KNOWLEDGE_BASE = {
361
461
  - *解法*:宿主机尚未安装 gh。Windows 运行 \`winget install GitHub.cli\`,macOS 运行 \`brew install gh\`,然后执行 \`gh auth login\` 登录。
362
462
  5. **报 \`unknown command "skill" for "gh"\`**:
363
463
  - *原因*:\`gh skill\` 是 GitHub CLI 2.9x 引入的 preview 特性,宿主机版本过低。
364
- - *解法*:升级 gh(Windows: \`winget upgrade GitHub.cli\`;macOS: \`brew upgrade gh\`)后重试;升级前可改用 \`github_api\` 检索 \`SKILL.md\` 文件路径作为替代。`
464
+ - *解法*:升级 gh(Windows: \`winget upgrade GitHub.cli\`;macOS: \`brew upgrade gh\`)后重试;升级前可改用 \`github_api\` 检索 \`SKILL.md\` 文件路径作为替代。
465
+ 6. **报 \`the token ... needs the '<scope>' scope\` (缺少权限)**:
466
+ - *原因*:GitHub Token 缺少对应操作的最小 Scope 权限(如 Codespaces 需要 \`codespace\` 权限,Projects v2 需要 \`read:project\` 权限)。
467
+ - *解法*:在系统终端执行单行自愈命令完成授权刷新(无需重启插件,即刻生效):
468
+ - Codespace: \`gh auth refresh -h github.com -s codespace\`
469
+ - Project: \`gh auth refresh -s read:project\`
470
+ 7. **报 \`the '...' repository has discussions disabled\`**:
471
+ - *原因*:目标 GitHub 仓库未开启 Discussions 社区功能。
472
+ - *解法*:需管理员前往 GitHub 网页端 \`Settings -> General -> Features\` 勾选开启 \`Discussions\`。
473
+ 8. **操作被拦截提示 \`Awaiting confirmation\`**:
474
+ - *原因*:对于高危破坏性操作(如合并 PR、删除分支、物理删除 Issue、清空构建缓存、删除密钥、销毁 Codespace),插件设置了强制安全确认防线,未确认时绝对不触发底层 CLI。
475
+ - *解法*:审阅影响评估报告后,在参数中显式传入 \`confirm: true\` 即可放行。`
365
476
  };
366
477
  export function createHelpTool(executor) {
367
478
  return {
@@ -387,6 +498,10 @@ export function createHelpTool(executor) {
387
498
  'cache',
388
499
  'gist',
389
500
  'status',
501
+ 'agent_task',
502
+ 'discussion',
503
+ 'project',
504
+ 'codespace',
390
505
  'mapping',
391
506
  'search_syntax',
392
507
  'troubleshooting',
@@ -37,6 +37,33 @@ export declare function sniffImageMime(buf: Buffer): string | null;
37
37
  /** 图片下载护栏:按真实资源消耗计算——单图字节与目录总量,无张数截断 */
38
38
  export declare const IMG_MAX_BYTES: number;
39
39
  export declare const IMG_DIR_MAX_BYTES: number;
40
+ export declare const IMG_DIR_LOW_WATERMARK: number;
41
+ /**
42
+ * 图片落盘目录(按内容寻址命名,重复下载天然去重)。
43
+ *
44
+ * 为什么支持 DSH_IMAGE_DIR 覆盖:目录里有 LRU 淘汰,按 mtime 删最旧文件。
45
+ * 若测试把 13MB 假数据写进真实用户目录,淘汰就会优先命中用户更早下载的
46
+ * 真图(用户图 mtime 更老,排序更靠前),造成静默数据丢失。
47
+ * 测试必须能把目录重定向到临时区——这与 upgrade-manager 的 DSH_CLI_BIN /
48
+ * DSH_PROFILE_DIR 覆盖是同一套思路。
49
+ */
50
+ export declare function imageStoreDir(): string;
51
+ /** 粗略统计图片目录现有总量(遍历一次,文件数有护栏上限不会失控) */
52
+ export declare function imageDirSize(dir: string): number;
53
+ export interface LruEvictionResult {
54
+ freedBytes: number;
55
+ evictedCount: number;
56
+ evictedFiles: string[];
57
+ }
58
+ /**
59
+ * LRU 图片缓存淘汰:当目录空间不足以容纳新图片时,按最后修改时间(mtime)淘汰最旧的历史文件。
60
+ *
61
+ * 护栏纪律:
62
+ * 1. 保护当前批次已写入的文件(protectFiles):避免同一批次内前一张图被后一张图立即顶替;
63
+ * 2. 仅淘汰历史文件:按 mtime 升序排列(最旧优先),逐一清理直到目录大小降至目标低水位;
64
+ * 3. 容错防御:单文件删除失败(如文件被锁定)静默跳过继续尝试下一个,绝不崩溃中断。
65
+ */
66
+ export declare function evictLruImages(dir: string, neededBytes: number, protectFiles?: Set<string>, maxDirBytes?: number, targetBytes?: number): LruEvictionResult;
40
67
  export interface DownloadedImage {
41
68
  file: string;
42
69
  mimeType: string;
@@ -132,12 +132,24 @@ export function sniffImageMime(buf) {
132
132
  /** 图片下载护栏:按真实资源消耗计算——单图字节与目录总量,无张数截断 */
133
133
  export const IMG_MAX_BYTES = 5 * 1024 * 1024; // 单图 5MB
134
134
  export const IMG_DIR_MAX_BYTES = 15 * 1024 * 1024; // 图片缓存目录总量 15MB
135
- /** 图片落盘目录(按内容寻址命名,重复下载天然去重) */
136
- function imageStoreDir() {
135
+ export const IMG_DIR_LOW_WATERMARK = 10 * 1024 * 1024; // LRU 淘汰低水位目标 10MB
136
+ /**
137
+ * 图片落盘目录(按内容寻址命名,重复下载天然去重)。
138
+ *
139
+ * 为什么支持 DSH_IMAGE_DIR 覆盖:目录里有 LRU 淘汰,按 mtime 删最旧文件。
140
+ * 若测试把 13MB 假数据写进真实用户目录,淘汰就会优先命中用户更早下载的
141
+ * 真图(用户图 mtime 更老,排序更靠前),造成静默数据丢失。
142
+ * 测试必须能把目录重定向到临时区——这与 upgrade-manager 的 DSH_CLI_BIN /
143
+ * DSH_PROFILE_DIR 覆盖是同一套思路。
144
+ */
145
+ export function imageStoreDir() {
146
+ const override = (process.env.DSH_IMAGE_DIR || '').trim();
147
+ if (override)
148
+ return path.resolve(override);
137
149
  return path.join(os.homedir(), '.dsh', 'data', 'dsh-github-flow', 'images');
138
150
  }
139
151
  /** 粗略统计图片目录现有总量(遍历一次,文件数有护栏上限不会失控) */
140
- function imageDirSize(dir) {
152
+ export function imageDirSize(dir) {
141
153
  let total = 0;
142
154
  try {
143
155
  for (const f of fs.readdirSync(dir)) {
@@ -150,6 +162,57 @@ function imageDirSize(dir) {
150
162
  catch { }
151
163
  return total;
152
164
  }
165
+ /**
166
+ * LRU 图片缓存淘汰:当目录空间不足以容纳新图片时,按最后修改时间(mtime)淘汰最旧的历史文件。
167
+ *
168
+ * 护栏纪律:
169
+ * 1. 保护当前批次已写入的文件(protectFiles):避免同一批次内前一张图被后一张图立即顶替;
170
+ * 2. 仅淘汰历史文件:按 mtime 升序排列(最旧优先),逐一清理直到目录大小降至目标低水位;
171
+ * 3. 容错防御:单文件删除失败(如文件被锁定)静默跳过继续尝试下一个,绝不崩溃中断。
172
+ */
173
+ export function evictLruImages(dir, neededBytes, protectFiles = new Set(), maxDirBytes = IMG_DIR_MAX_BYTES, targetBytes = IMG_DIR_LOW_WATERMARK) {
174
+ const result = { freedBytes: 0, evictedCount: 0, evictedFiles: [] };
175
+ if (!fs.existsSync(dir))
176
+ return result;
177
+ let currentSize = imageDirSize(dir);
178
+ if (currentSize + neededBytes <= maxDirBytes) {
179
+ return result;
180
+ }
181
+ const candidates = [];
182
+ try {
183
+ const entries = fs.readdirSync(dir);
184
+ for (const name of entries) {
185
+ const fullPath = path.join(dir, name);
186
+ if (protectFiles.has(fullPath))
187
+ continue;
188
+ try {
189
+ const stat = fs.statSync(fullPath);
190
+ if (stat.isFile()) {
191
+ candidates.push({ path: fullPath, size: stat.size, mtime: stat.mtimeMs });
192
+ }
193
+ }
194
+ catch { }
195
+ }
196
+ }
197
+ catch {
198
+ return result;
199
+ }
200
+ candidates.sort((a, b) => a.mtime - b.mtime);
201
+ for (const item of candidates) {
202
+ if (currentSize + neededBytes <= maxDirBytes && currentSize <= targetBytes) {
203
+ break;
204
+ }
205
+ try {
206
+ fs.unlinkSync(item.path);
207
+ currentSize -= item.size;
208
+ result.freedBytes += item.size;
209
+ result.evictedCount++;
210
+ result.evictedFiles.push(item.path);
211
+ }
212
+ catch { }
213
+ }
214
+ return result;
215
+ }
153
216
  /**
154
217
  * 交集过滤:把调用方请求的 URL 硬约束在正文实际提取的合法清单内。
155
218
  * 为什么必须交集而非直接信任传入:image_urls 来自模型生成参数,存在幻觉或
@@ -190,6 +253,7 @@ export async function downloadImages(urls, run) {
190
253
  const images = [];
191
254
  const failures = [];
192
255
  const remaining = [];
256
+ const currentBatchFiles = new Set();
193
257
  let budgetExhausted = false;
194
258
  // 无张数截断:字节护栏按真实资源消耗逐张判定。触顶后仍继续遍历——
195
259
  // 剩余 URL 全部收进 remaining 供 Agent 分批续传,而非静默丢弃。
@@ -213,6 +277,11 @@ export async function downloadImages(urls, run) {
213
277
  failures.push(`${url.slice(-24)}: 内容不是图片(魔数校验失败)`);
214
278
  continue;
215
279
  }
280
+ // 空间护栏检查:若超出目录上限,优先触发 LRU 淘汰历史文件以腾出预算
281
+ if (dirSize + buf.length > IMG_DIR_MAX_BYTES) {
282
+ const { freedBytes } = evictLruImages(dir, buf.length, currentBatchFiles);
283
+ dirSize = Math.max(0, dirSize - freedBytes);
284
+ }
216
285
  if (dirSize + buf.length > IMG_DIR_MAX_BYTES) {
217
286
  budgetExhausted = true;
218
287
  remaining.push(url);
@@ -222,6 +291,7 @@ export async function downloadImages(urls, run) {
222
291
  const ext = mime.includes('svg') ? 'svg' : mime.split('/')[1].replace('jpeg', 'jpg');
223
292
  const file = path.join(dir, `${crypto.createHash('sha256').update(buf).digest('hex').slice(0, 16)}.${ext}`);
224
293
  fs.writeFileSync(file, buf);
294
+ currentBatchFiles.add(file);
225
295
  // 累计已写入量:下张图的总量护栏判定必须基于最新值(否则多图可突破上限)
226
296
  dirSize += buf.length;
227
297
  images.push({ file, mimeType: mime, url, bytes: buf.length });
@@ -0,0 +1,80 @@
1
+ import type { GhExecutor } from '../executor.js';
2
+ /**
3
+ * 检测错误信息是否属于 Scope 权限不足,并返回标准自愈对象
4
+ */
5
+ export declare function checkScopeRequired(errorMsg: string, scope: string, command: string, tool: string): {
6
+ status: string;
7
+ scope: string;
8
+ command: string;
9
+ tool: string;
10
+ } | null;
11
+ export declare function createProjectTool(executor: GhExecutor): {
12
+ name: string;
13
+ description: string;
14
+ parameters: {
15
+ type: string;
16
+ properties: {
17
+ action: {
18
+ type: string;
19
+ enum: string[];
20
+ description: string;
21
+ };
22
+ owner: {
23
+ type: string;
24
+ description: string;
25
+ };
26
+ project_number: {
27
+ type: string;
28
+ description: string;
29
+ };
30
+ item_id: {
31
+ type: string;
32
+ description: string;
33
+ };
34
+ url: {
35
+ type: string;
36
+ description: string;
37
+ };
38
+ title: {
39
+ type: string;
40
+ description: string;
41
+ };
42
+ body: {
43
+ type: string;
44
+ description: string;
45
+ };
46
+ query: {
47
+ type: string;
48
+ description: string;
49
+ };
50
+ closed: {
51
+ type: string;
52
+ description: string;
53
+ };
54
+ limit: {
55
+ type: string;
56
+ description: string;
57
+ };
58
+ confirm: {
59
+ type: string;
60
+ description: string;
61
+ };
62
+ };
63
+ required: string[];
64
+ };
65
+ output: {
66
+ schema: {
67
+ type: string;
68
+ };
69
+ render(args: any, value: any): {
70
+ type: string;
71
+ text: string;
72
+ }[];
73
+ };
74
+ execute(args: any, execContext: any): Promise<Record<string, any> | {
75
+ status: string;
76
+ scope: string;
77
+ command: string;
78
+ tool: string;
79
+ }>;
80
+ };