dsh-github-flow 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +38 -11
- package/README.md +37 -10
- package/docs/UPGRADE-NOTES.md +9 -9
- package/docs/architecture.md +53 -23
- package/docs/images/2.png +0 -0
- package/docs/npm-publish-guide.md +12 -1
- package/lib/api/routes-overview.js +104 -1
- package/lib/client.js +583 -14
- package/lib/executor.d.ts +118 -1
- package/lib/executor.js +357 -0
- package/lib/main.js +1 -0
- package/lib/renderers/markdown.d.ts +6 -0
- package/lib/renderers/markdown.js +109 -2
- package/lib/tools/help.js +132 -11
- package/lib/tools/issue.d.ts +9 -0
- package/lib/tools/issue.js +88 -4
- package/lib/tools/pr.d.ts +4 -0
- package/lib/tools/pr.js +50 -3
- package/lib/tools/repo.d.ts +8 -0
- package/lib/tools/repo.js +127 -3
- 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/types.d.ts +73 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -72,7 +72,7 @@ dsh plugin --profile web add dsh-github-flow
|
|
|
72
72
|
|
|
73
73
|
## 🤖 Core Agent Tools: Equipping Agents with Native GitHub Powers
|
|
74
74
|
|
|
75
|
-
Consolidates scattered GitHub endpoints into **9 core domain tools**, featuring **Token Budget Protection (default 24KB intelligent truncation)**, **High-density Native Markdown Rendering (70%+ list output token reduction)** and **Zero-argument CWD auto-binding**.
|
|
75
|
+
Consolidates scattered GitHub endpoints into **9 core domain tools (76+ actions covering PR/Issue/Actions workflow governance/clone-free file reads/secrets & variables)**, featuring **Token Budget Protection (default 24KB intelligent truncation)**, **High-density Native Markdown Rendering (70%+ list output token reduction)** and **Zero-argument CWD auto-binding**.
|
|
76
76
|
|
|
77
77
|
### 1. `github_pr`: Pull Request Lifecycle & Automated Code Review
|
|
78
78
|
> **Example Agent Prompts**:
|
|
@@ -91,6 +91,9 @@ Consolidates scattered GitHub endpoints into **9 core domain tools**, featuring
|
|
|
91
91
|
* `status`: 🆕 Inspect merge conflict status (`CLEAN` / `CONFLICT`) for the current branch's PR;
|
|
92
92
|
* `review`: Submit code reviews (`APPROVE`, `REQUEST_CHANGES`, `COMMENT`);
|
|
93
93
|
* `merge`: Merge pull requests (`squash` / `merge` / `rebase`, optional `delete_branch`; requires `confirm: true`);
|
|
94
|
+
* `ready`: 🆕 Toggle Draft ↔ Ready (`undo: true` converts back to Draft — fully reversible);
|
|
95
|
+
* `revert`: 🆕 Create a revert commit (generates a new revert PR on the remote; requires `confirm: true`);
|
|
96
|
+
* `update_branch`: 🆕 Sync the latest base-branch commits into the PR branch — the self-healing action for "branch is out-of-date" CI gate failures;
|
|
94
97
|
* `view_images`: 🆕 Download PR discussion screenshots (body + comments; `image_urls` targeting with budget-overflow resume list).
|
|
95
98
|
|
|
96
99
|
---
|
|
@@ -106,6 +109,10 @@ Consolidates scattered GitHub endpoints into **9 core domain tools**, featuring
|
|
|
106
109
|
* `list`: View recent workflow runs and conclusions (`branch` / `status: failure` filters to pin down broken builds);
|
|
107
110
|
* `view`: Inspect jobs and steps for a specific run ID;
|
|
108
111
|
* `trigger`: 🆕 Manually dispatch `workflow_dispatch` workflows to verify fixes immediately;
|
|
112
|
+
* `workflow_list`: 🆕 List workflows (active only by default; `all: true` includes disabled — when diagnosing "why didn't my workflow run", the disabled state itself is the answer);
|
|
113
|
+
* `workflow_view`: 🆕 Workflow details (locate by name/ID/filename, with recent runs);
|
|
114
|
+
* `workflow_enable` / `workflow_disable`: 🆕 Toggle workflows (disable explicitly warns "the next trigger will fail silently");
|
|
115
|
+
* `download`: 🆕 Download build artifacts to a plugin-managed directory (isolated per repo and run, returns file manifest; older gh versions get a security upgrade note);
|
|
109
116
|
* `rerun`: Re-trigger failed CI runs;
|
|
110
117
|
* `cancel`: Cancel in-progress workflows.
|
|
111
118
|
|
|
@@ -126,6 +133,11 @@ Consolidates scattered GitHub endpoints into **9 core domain tools**, featuring
|
|
|
126
133
|
* `develop`: 🆕 Create a linked development branch from an issue and check it out locally;
|
|
127
134
|
* `comment`: Append debugging updates or notes;
|
|
128
135
|
* `close` (requires `confirm: true`) / `reopen`: Manage issue lifecycle states;
|
|
136
|
+
* `delete`: 🆕 **Permanently delete** an issue (requires `confirm: true`; the number is gone forever and comments are destroyed — fundamentally different from close, which can be reopened);
|
|
137
|
+
* `transfer`: 🆕 Transfer an issue to another repository (requires `confirm: true`; original URL 301-redirects, ownership cannot be silently reverted);
|
|
138
|
+
* `pin` / `unpin`: 🆕 Toggle issue pinning (reversible state flag);
|
|
139
|
+
* `lock` / `unlock`: 🆕 Lock/unlock conversation (`lock_reason` supports off_topic/resolved/spam/too_heated);
|
|
140
|
+
* `status`: 🆕 Account-level assigned-issues panel (Assigned / Mentioning sections);
|
|
129
141
|
* `view_images`: 🆕 Download issue attachment screenshots (body + comments; `image_urls` targeting with resume list).
|
|
130
142
|
|
|
131
143
|
---
|
|
@@ -141,7 +153,10 @@ Consolidates scattered GitHub endpoints into **9 core domain tools**, featuring
|
|
|
141
153
|
* `readme`: 🆕 Read repository README raw content (branch-selectable; relative-path screenshots auto-resolved and downloaded);
|
|
142
154
|
* `sync`: 🆕 One-click fork sync with upstream to fix stale-fork CI gate failures;
|
|
143
155
|
* `search_code`: Search code symbols in current or specified repositories;
|
|
144
|
-
* `search_repos`: Search open-source GitHub repositories globally
|
|
156
|
+
* `search_repos`: Search open-source GitHub repositories globally;
|
|
157
|
+
* `search_issues` / `search_prs` / `search_commits`: 🆕 Global search over issues / PRs / commits (qualifiers go inline in the query, e.g. `repo:o/r state:open`; commits require search text);
|
|
158
|
+
* `read_file`: 🆕 **Clone-free single-file read at any path** (native on gh ≥2.95; older versions auto-degrade to the contents API with an explicit degraded-path note; binary files are rejected with `github_api` guidance);
|
|
159
|
+
* `read_dir`: 🆕 Clone-free directory listing (dirs first + file sizes, same degradation path).
|
|
145
160
|
|
|
146
161
|
---
|
|
147
162
|
|
|
@@ -166,15 +181,17 @@ Consolidates scattered GitHub endpoints into **9 core domain tools**, featuring
|
|
|
166
181
|
|
|
167
182
|
---
|
|
168
183
|
|
|
169
|
-
### 7. `github_secret`: CI/CD Secrets Management 🆕
|
|
184
|
+
### 7. `github_secret`: CI/CD Secrets & Variables Management 🆕
|
|
170
185
|
> **Example Agent Prompts**:
|
|
171
186
|
> - *"Update the NPM_TOKEN secret for this repository."*
|
|
172
187
|
> - *"Show which secrets are configured for this repo."*
|
|
188
|
+
> - *"Set the DEPLOY_ENV variable to staging and read it back to confirm."*
|
|
173
189
|
|
|
174
190
|
* **Supported Actions**:
|
|
175
|
-
* `list`: Show secret names and update times (the GitHub API never exposes secret values);
|
|
191
|
+
* `list`: Show secret/variable names and update times (the GitHub API never exposes secret values);
|
|
176
192
|
* `set`: Set/update secret values — **passed via subprocess stdin, never on the command line (ps-safe), never echoed in output**;
|
|
177
193
|
* `delete` (requires `confirm: true`): Remove a secret.
|
|
194
|
+
* Switch to **Actions plaintext variables** via `kind: 'variable'`: `set` passes the value directly as a flag and `get` can echo it back (that's the design difference from secrets — secrets are encrypted GitHub-side after write and physically unreadable); the two security semantics are physically isolated in the rendering layer.
|
|
178
195
|
* Supports repository / organization (`org`) / environment (`env`) scopes across `actions` / `codespaces` / `dependabot` / `agents` apps.
|
|
179
196
|
|
|
180
197
|
---
|
|
@@ -232,14 +249,23 @@ Access via the GitHub icon in the main left navigation:
|
|
|
232
249
|
</p>
|
|
233
250
|
|
|
234
251
|
### 2. Session Right Sidebar Panel (Workspace Drawer)
|
|
235
|
-
Located in the right drawer of every chat workspace:
|
|
236
|
-
* **Context Auto-Binding**: Automatically locks onto the active Git repository;
|
|
237
|
-
* **Freshness Pill Alignment**: Compact indicator `[📦 Local Snapshot (2m ago)]` with live `[🔄 Refresh]` button, 100% aligned with global rules;
|
|
238
|
-
* **PR Status Pills**: Live PR inspection with CI checks and review badges;
|
|
239
|
-
* **Workspace Open Issues List**: Direct issue task review with author badges and external links;
|
|
240
|
-
* **Latest Actions Pipeline**: Real-time CI workflow status tracking;
|
|
252
|
+
Located in the right drawer of every chat workspace, seamlessly bridging your local Git workspace with remote GitHub repositories:
|
|
253
|
+
* **Context Auto-Binding**: Automatically locks onto the active Git repository of the current session;
|
|
254
|
+
* **Freshness Pill Alignment**: Compact indicator `[📦 Local Snapshot (2m ago)]` with live `[🔄 Refresh]` button, 100% aligned with global rules for an instant 0ms first render;
|
|
241
255
|
* **Quick Action Grid**: Open repo in browser, jump to Issues/PRs, create PRs with one click;
|
|
242
|
-
*
|
|
256
|
+
* **Five Mutually Exclusive Tabs**: Compact tabbed navigation directly below the quick action grid, reducing vertical scrolling:
|
|
257
|
+
* **Git Records (`Git`)** (Default tab):
|
|
258
|
+
* Branch & Remote Sync: Real-time branch indicator (e.g. `master`) with tracking sync status (`✓ Up to date` or `↑N to push` / `↓N to pull`);
|
|
259
|
+
* Three-Section Commit View: Unpushed commits (ahead of remote), unpulled commits (behind remote), and recent commit history;
|
|
260
|
+
* 15 commits displayed by default, with **infinite scroll loading** when scrolling to the bottom (with live `15 / 74` progress counter and click trigger);
|
|
261
|
+
* Latest Release badge (`🏷️ v0.2.1`) anchored in the top right with hover details and direct release link;
|
|
262
|
+
* **Commit Detail Modal**: Click any commit row to open a clean modal dialog centered within the right sidebar (scoped inside drawer boundaries without overflowing full-screen), featuring smooth vertical scrolling, full 40-char SHA, author email, date, multi-line commit message body, and file diff stat table (`--stat`); pure local 0ms instant display, closable via `Esc`, close button, or backdrop click;
|
|
263
|
+
* **Uncommitted Changes (`📁 Uncommitted (N)`)**: Full-width list of uncommitted files with color-coded status codes (`??` untracked, `M` modified, `D` deleted, `R` renamed) and change counts;
|
|
264
|
+
* **Pull Requests (`🔀 PR (N)`)**: Open PR inspection with 3-state CI check rollup (`✅ CI Passed` / `❌ CI Failed` / `⏳ CI Pending`), merge conflict detection, review decisions (`✔ Approved` / `✋ Changes Requested` / `👀 Review Required`), Draft pills, and humanized relative timestamps;
|
|
265
|
+
* **Workspace Issues (`📋 Issues (N)`)**: Direct issue task review with assignees, labels, and category pills;
|
|
266
|
+
* **Actions Pipeline (`⚡ Actions (N)`)**: Real-time CI workflow status tracking with trigger event badges (`push`/`schedule`/`manual`/`PR`), relative time, and self-healing diagnostic notes for failed runs (embedding `run_id` for Agent one-click log inspection);
|
|
267
|
+
* **Official Git Vector Icon**: High-definition Git diamond vector icon (`#1296db` SVG) across all Git and branch labels;
|
|
268
|
+
* **⚙️ Full Settings Access**: Dedicated settings button reusing the same settings modal as the cockpit (all four sections: Sync / Proxy / Update Source / About) — no need to switch back to the main page.
|
|
243
269
|
|
|
244
270
|
<p align="center">
|
|
245
271
|
<img src="./docs/images/2.png" alt="Session Right Sidebar Panel" width="100%" />
|
|
@@ -348,6 +374,7 @@ Works out of the box, with optional tweaks in `cordis.patch.yml` or your profile
|
|
|
348
374
|
defaultListLimit: 20 # Default list size for pr/issue/run/release/skill queries
|
|
349
375
|
cacheTtlMs: 15000 # Repository overview cache TTL (default 15s)
|
|
350
376
|
checkUpdate: true # Enable automatic update checks (default true)
|
|
377
|
+
agentEnvInjection: true # Inject AI_AGENT=dsh identity into gh (auto agent-friendly output on gh ≥2.99; false restores native gh behavior)
|
|
351
378
|
updateCheckIntervalMs: 86400000 # Check interval in ms (default 24h)
|
|
352
379
|
registryUrl: '' # Custom private npm registry URL
|
|
353
380
|
proxyUrl: '' # Preset proxy default (e.g. 'http://127.0.0.1:7890'; only applies before the cockpit setting is saved — UI setting takes precedence)
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
12
|
<b>让 DeepSeek Harness Agent 拥有操作 GitHub 的原生手和脚,为人机协作打造沉浸式 GitHub 工作台。</b><br>
|
|
13
|
-
原生复用宿主机 <code>gh</code> CLI 安全登录凭据,告别 Personal Access Token 泄露;深度打通本地 Git 工作区与云端仓库协作,兼具 <b>9 大领域 Agent
|
|
13
|
+
原生复用宿主机 <code>gh</code> CLI 安全登录凭据,告别 Personal Access Token 泄露;深度打通本地 Git 工作区与云端仓库协作,兼具 <b>9 大领域 Agent 核心工具(76+ action,覆盖 PR/Issue/Actions 工作流治理/免 clone 读取任意文件/密钥与变量管理)</b>、<b>人类 Slash 快捷指令</b>、<b>Web UI 全景工作台</b> 与 <b>一键自动跨平台无缝升级</b>。
|
|
14
14
|
</p>
|
|
15
15
|
|
|
16
16
|
<p align="center">
|
|
@@ -91,6 +91,9 @@ dsh plugin --profile web add dsh-github-flow
|
|
|
91
91
|
* `status`:🆕 查看当前分支关联 PR 的合并冲突状态(`CLEAN` / `CONFLICT`);
|
|
92
92
|
* `review`:提交代码审查意见(`APPROVE`, `REQUEST_CHANGES`, `COMMENT`);
|
|
93
93
|
* `merge`:自动执行合并(支持 `squash` / `merge` / `rebase`,可指定 `delete_branch`;需 `confirm: true` 二次确认);
|
|
94
|
+
* `ready`:🆕 Draft ↔ Ready 切换(附 `undo: true` 可转回 Draft,完整可逆);
|
|
95
|
+
* `revert`:🆕 创建反向提交(远端生成新 revert PR,需 `confirm: true`);
|
|
96
|
+
* `update_branch`:🆕 将基准分支最新提交同步进 PR 分支——「分支落后需更新」CI 门禁失败的自愈动作;
|
|
94
97
|
* `view_images`:🆕 下载 PR 讨论截图(正文+评论,支持 `image_urls` 精准提取与触顶续传清单)。
|
|
95
98
|
|
|
96
99
|
---
|
|
@@ -106,6 +109,10 @@ dsh plugin --profile web add dsh-github-flow
|
|
|
106
109
|
* `list`:查看当前仓库的 Workflow 运行历史与结论(支持 `branch` / `status: failure` 快速锁定失败构建);
|
|
107
110
|
* `view`:查看指定 run_id 的详细阶段(Jobs & Steps);
|
|
108
111
|
* `trigger`:🆕 主动触发 `workflow_dispatch` 工作流(提交修复后立即验证远端 CI);
|
|
112
|
+
* `workflow_list`:🆕 工作流清单查询(默认仅 active;`all: true` 含 disabled——排查「工作流为何不跑」时 disabled 状态本身就是答案);
|
|
113
|
+
* `workflow_view`:🆕 工作流详情(名称/ID/文件名定位,含最近运行记录);
|
|
114
|
+
* `workflow_enable` / `workflow_disable`:🆕 启停工作流(disable 会显式警告「下次 trigger 将静默失败」);
|
|
115
|
+
* `download`:🆕 下载构建产物到插件管理目录(按仓库与 run 隔离,返回文件清单;低版本 gh 附安全升级提示);
|
|
109
116
|
* `rerun`:重新触发失败的 CI 运行;
|
|
110
117
|
* `cancel`:取消在途的工作流。
|
|
111
118
|
|
|
@@ -126,6 +133,11 @@ dsh plugin --profile web add dsh-github-flow
|
|
|
126
133
|
* `develop`:🆕 从 Issue 一键切出关联开发分支并本地检出,打通「读需求 → 写代码」闭环;
|
|
127
134
|
* `comment`:在指定 Issue 中追加排查进展或评论;
|
|
128
135
|
* `close`(需 `confirm: true`)/ `reopen`:开启或关闭 Issue;
|
|
136
|
+
* `delete`:🆕 **物理删除** Issue(需 `confirm: true`;编号永久消失、评论湮灭不可恢复——与 close 可 reopen 有本质区别,拦截级别更高);
|
|
137
|
+
* `transfer`:🆕 跨仓库迁移 Issue(需 `confirm: true`;原 URL 301 重定向,归属不可静默撤回);
|
|
138
|
+
* `pin` / `unpin`:🆕 置顶/取消置顶(可逆状态位);
|
|
139
|
+
* `lock` / `unlock`:🆕 锁定/解锁对话(`lock_reason` 支持 off_topic/resolved/spam/too_heated);
|
|
140
|
+
* `status`:🆕 账号维度的分配议题面板(Assigned / Mentioning 分段);
|
|
129
141
|
* `view_images`:🆕 下载 Issue 报障截图(正文+评论全量提取,支持 `image_urls` 按 URL 精准提取,触顶自动返回续传清单)。
|
|
130
142
|
|
|
131
143
|
---
|
|
@@ -141,7 +153,10 @@ dsh plugin --profile web add dsh-github-flow
|
|
|
141
153
|
* `readme`:🆕 读取仓库 README 原文(支持指定分支,相对路径截图自动解析下载);
|
|
142
154
|
* `sync`:🆕 一键拉平 Fork 仓库与上游主干,解决贡献开源项目时 Fork 落后导致 CI 门禁失败;
|
|
143
155
|
* `search_code`:跨仓库或当前仓库检索特定代码符号;
|
|
144
|
-
* `search_repos`:跨全站检索 GitHub
|
|
156
|
+
* `search_repos`:跨全站检索 GitHub 开源仓库;
|
|
157
|
+
* `search_issues` / `search_prs` / `search_commits`:🆕 全站检索 Issue / PR / 提交记录(限定符直接写进 query,如 `repo:o/r state:open`;commits 必须含搜索文本);
|
|
158
|
+
* `read_file`:🆕 **免 clone 读取任意路径单文件**(gh ≥2.95 直连,低版本自动降级 contents API 并显式标注降级链路;二进制文件拒绝并引导 `github_api`);
|
|
159
|
+
* `read_dir`:🆕 免 clone 列出目录清单(dir 置顶 + 文件大小,降级链路同上)。
|
|
145
160
|
|
|
146
161
|
---
|
|
147
162
|
|
|
@@ -166,15 +181,17 @@ dsh plugin --profile web add dsh-github-flow
|
|
|
166
181
|
|
|
167
182
|
---
|
|
168
183
|
|
|
169
|
-
### 7. `github_secret`:CI/CD
|
|
184
|
+
### 7. `github_secret`:CI/CD 密钥与变量管理 🆕
|
|
170
185
|
> **典型对话指令**:
|
|
171
186
|
> - *"帮我把新的 NPM_TOKEN 更新到当前仓库的 Secrets 里"*
|
|
172
187
|
> - *"看一下这个仓库配了哪些密钥"*
|
|
188
|
+
> - *"把 DEPLOY_ENV 变量设为 staging,并回读确认"*
|
|
173
189
|
|
|
174
190
|
* **支持操作 (`action`)**:
|
|
175
|
-
* `list
|
|
191
|
+
* `list`:查看密钥/变量名称清单(仅名称与更新时间,GitHub API 设计上不允许读取密文);
|
|
176
192
|
* `set`:设置/更新密钥值——**密文经子进程标准输入传递,绝不出现在命令行参数(防 `ps` 窃取),输出永不回显**;
|
|
177
193
|
* `delete`(需 `confirm: true`):删除密钥。
|
|
194
|
+
* 支持 `kind: 'variable'` 切换到 **Actions 明文变量**:`set` 走参数直传、`get` 可回显值(这正是变量与密钥的设计区别——secret 写入后 GitHub 侧加密,物理不可读取);两类对象的安全语义在渲染层物理隔离。
|
|
178
195
|
* 支持仓库 / 组织 (`org`) / 环境 (`env`) 三级作用域与 `actions` / `codespaces` / `dependabot` / `agents` 应用归属。
|
|
179
196
|
|
|
180
197
|
---
|
|
@@ -231,14 +248,23 @@ dsh plugin --profile web add dsh-github-flow
|
|
|
231
248
|
</p>
|
|
232
249
|
|
|
233
250
|
### 2. 会话右侧栏工作区面板 (Session Workspace Panel)
|
|
234
|
-
|
|
235
|
-
*
|
|
251
|
+
位于每个对话工作区的右侧抽屉栏,深度联动本地 Git 状态与远程 GitHub 仓库:
|
|
252
|
+
* **当前仓库上下文绑定**:自动锁定当前会话的物理 Git 仓库,展示远程关联与认证账号;
|
|
236
253
|
* **数据新鲜度胶囊对齐**:标题旁紧凑呈现 `[📦 本地快照 (2分钟前)]` 与 `[🔄 刷新]` 按钮,与主页规则 100% 保持一致,首屏 0ms 瞬间直出;
|
|
237
|
-
* **PR 门禁状态药丸**:展示当前开放 PR,悬停查看 Checks 结果与审核意见;
|
|
238
|
-
* **当前仓库 Open Issues 列表**:直接在侧边栏审查待办任务并提供直达链接;
|
|
239
|
-
* **最新 Actions 构建流水线**:实时关注 CI 状态;
|
|
240
254
|
* **快捷操作网格**:一键在浏览器打开仓库、直达 Issues/PRs、一键创建 PR;
|
|
241
|
-
*
|
|
255
|
+
* **五大 Tab 布局响应式互斥切换**:快捷操作下方采用紧凑 Tab 架构,内容区互斥展示、大幅降低纵向滚动需求:
|
|
256
|
+
* **Git 记录 (`Git`)**(默认首屏):
|
|
257
|
+
* 分支与同步状态:展示当前分支(如 `master`)与远程同步快照(`✓ 与远程同步` 或 `↑N 待 push` / `↓N 待 pull`);
|
|
258
|
+
* 三段式提交视图:待推送提交(本地领先)、待拉取提交(远程领先)及最近提交列表;
|
|
259
|
+
* 默认展示 15 条,支持**向下滑动触底自动分页加载**(伴随 `15 / 74` 实时进度提示与点击后备);
|
|
260
|
+
* 右上角锚定最新发布 Release 徽章(`🏷️ v0.2.1`),悬停查看发布时间与预发布标示,点击直达;
|
|
261
|
+
* **提交详情模态弹窗**:点击任意提交记录行,在右侧栏内局部居中弹出(与设置弹窗同构,不全屏越界),内置上下滑动区域,完整展示 40 位 SHA、提交者姓名邮箱、日期、多行详细正文说明与文件变更统计(`--stat`),纯本地 0ms 秒开,支持按 `Esc` 或点击遮罩随时关闭;
|
|
262
|
+
* **未提交清单 (`📁 未提交 (N)`)**:展示工作区未提交的文件清单,状态码色彩区分(`??` 新增、`M` 修改、`D` 删除、`R` 重命名)与变更总数;
|
|
263
|
+
* **拉取请求 (`🔀 PR (N)`)**:展示当前开放 PR,带有三态 CI 门禁(`✅ CI 通过` / `❌ CI 失败` / `⏳ CI 运行中`)、冲突检测、审核判定(`✔ 已批准` / `✋ 需修改` / `👀 待审查`)、Draft 草稿标示与人性化相对时间;
|
|
264
|
+
* **仓库议题 (`📋 Issues (N)`)**:直接在侧边栏审查待办任务,支持指派者、标签与多维状态药丸;
|
|
265
|
+
* **构建流水线 (`⚡ Actions (N)`)**:实时关注工作流 CI 状态,展示触发方式(`push`/`定时`/`手动`/`PR`)、相对时间与失败构建的 Agent 自愈诊断指引(嵌入 run_id);
|
|
266
|
+
* **全库统一 Git 官方矢量图标**:采用标准 Git 菱形分支官方矢量组件(`#1296db` SVG),全面统一各处 Git 标识;
|
|
267
|
+
* **⚙️ 完整设置入口**:右侧栏提供设置按钮,与主页复用同一设置弹窗(数据同步 / 网络代理 / 更新设置 / 关于 四分区完整可用),无需切回主页调整。
|
|
242
268
|
|
|
243
269
|
<p align="center">
|
|
244
270
|
<img src="./docs/images/2.png" alt="右侧栏工作区面板" width="100%" />
|
|
@@ -347,6 +373,7 @@ dsh plugin --profile web add dsh-github-flow
|
|
|
347
373
|
defaultListLimit: 20 # 列表类查询默认返回条数(pr/issue/run/release/skill 通用)
|
|
348
374
|
cacheTtlMs: 15000 # 单仓库概览缓存时长(毫秒,默认 15 秒)
|
|
349
375
|
checkUpdate: true # 是否开启新版本自动检查提示(默认开启;false 时熔断自动探测,显式升级不受限)
|
|
376
|
+
agentEnvInjection: true # 向 gh 注入 AI_AGENT=dsh 识别信号(gh ≥2.99 自动适配 Agent 输出;false 恢复 gh 原生行为)
|
|
350
377
|
updateCheckIntervalMs: 86400000 # 检查更新间隔(毫秒,默认 24 小时)
|
|
351
378
|
registryUrl: '' # 自定义私有 npm 镜像地址(留空走「更新设置」所选源,界面设置优先)
|
|
352
379
|
proxyUrl: '' # 代理地址预置默认值(如 'http://127.0.0.1:7890';仅未在驾驶舱设置过时生效,界面设置优先)
|
package/docs/UPGRADE-NOTES.md
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
| # | 文件 | 位置 | 当前值 | 说明 |
|
|
12
12
|
|---|---|---|---|---|
|
|
13
|
-
| 1 | [package.json](../package.json) | 第 3 行 `"version": "0.
|
|
14
|
-
| 2 | [src/version.ts](../src/version.ts) | 第 9 行 `CURRENT_PLUGIN_VERSION = '0.
|
|
13
|
+
| 1 | [package.json](../package.json) | 第 3 行 `"version": "0.3.0"` | `0.3.0` | npm 发布版本、CI 取版来源 |
|
|
14
|
+
| 2 | [src/version.ts](../src/version.ts) | 第 9 行 `CURRENT_PLUGIN_VERSION = '0.3.0'` | `'0.3.0'` | 运行时版本比较基准(假横幅的教训来源) |
|
|
15
15
|
|
|
16
16
|
**两处必须同值**。`pnpm run build` 会硬校验([scripts/build.mjs](../scripts/build.mjs) 的
|
|
17
17
|
`assertVersionConsistency`),不一致直接构建失败——但不要依赖拦截,发版前手动核对。
|
|
@@ -41,28 +41,28 @@
|
|
|
41
41
|
| # | 机制 | 说明 |
|
|
42
42
|
|---|---|---|
|
|
43
43
|
| 9 | CI 取版(.github/workflows/npm-publish.yml:62) | `VERSION=$(node -p "require('./package.json').version")`——从 package.json 读,无硬编码 |
|
|
44
|
-
| 10 | Git tag | `git tag v0.
|
|
44
|
+
| 10 | Git tag | `git tag v0.3.0` 手动打,值必须 = package.json 版本(tag 与 package.json 不一致时:CI 发布的 npm 版本以 package.json 为准,GitHub Release 标题以 tag 为准,出现两者错位) |
|
|
45
45
|
|
|
46
46
|
## 五、发版完整流程(含版本修改)
|
|
47
47
|
|
|
48
48
|
```powershell
|
|
49
49
|
# 1. 改版本(两处同值)
|
|
50
|
-
# package.json → "version": "0.
|
|
51
|
-
# src/version.ts → CURRENT_PLUGIN_VERSION = '0.
|
|
50
|
+
# package.json → "version": "0.3.0"
|
|
51
|
+
# src/version.ts → CURRENT_PLUGIN_VERSION = '0.3.0'
|
|
52
52
|
|
|
53
53
|
# 2. 文档已用占位符(npm-publish-guide 示例、README 安装命令),发版无需改文档版本号
|
|
54
54
|
|
|
55
55
|
# 3. 构建(版本一致性校验在此拦截漏改)+ 全量测试
|
|
56
56
|
pnpm run build
|
|
57
|
-
pnpm test #
|
|
57
|
+
pnpm test # 11 阶段全绿
|
|
58
58
|
|
|
59
59
|
# 4. 本机 e2e(必须先重启 DSH 桌面进程——Node 模块缓存,软链重建不注入运行中进程)
|
|
60
|
-
# 重启后验证:GET /api/github/check-update 的 currentVersion = 0.
|
|
60
|
+
# 重启后验证:GET /api/github/check-update 的 currentVersion = 0.3.0
|
|
61
61
|
|
|
62
62
|
# 5. 提交 + 打 tag + 推送(tag 值 = package.json 版本)
|
|
63
63
|
git add -A
|
|
64
|
-
git commit -m "chore(release): v0.
|
|
65
|
-
git tag v0.
|
|
64
|
+
git commit -m "chore(release): v0.3.0"
|
|
65
|
+
git tag v0.3.0
|
|
66
66
|
git push origin master --tags
|
|
67
67
|
# CI(npm-publish.yml)自动:构建→发布 npm→创建 GitHub Release
|
|
68
68
|
|
package/docs/architecture.md
CHANGED
|
@@ -20,8 +20,10 @@
|
|
|
20
20
|
│ │ GitHubService (ctx.github 原生服务) │ │
|
|
21
21
|
│ │ - checkAuth(cwd) - getRepoMetadata(cwd) │ │
|
|
22
22
|
│ │ - run<T>(args, opts) [execFile 数组隔离 + 24KB 智能截断] │ │
|
|
23
|
-
│ │
|
|
24
|
-
│ │ -
|
|
23
|
+
│ │ - runGuarded({minVersion,fallback}) [gh 版本守卫降级链] │ │
|
|
24
|
+
│ │ - getGhVersion() [30s TTL 缓存·只存成功值] │ │
|
|
25
|
+
│ │ - AI_AGENT=dsh 注入 [gh 官方 agent 识别·可配置开关] │ │
|
|
26
|
+
│ │ - UpdateChecker (源可选探测 + 24h 缓存 + Fail-Safe) │ │
|
|
25
27
|
│ │ - UpgradeManager (跨平台自适应 + 互斥锁 + macOS PATH 补全) │ │
|
|
26
28
|
│ │ - spawnWithStdin (密文通道: spawn+stdin.end + kill 超时) │ │
|
|
27
29
|
│ └──────┬───────────────────────┬────────────────────────┬──────┘ │
|
|
@@ -30,15 +32,22 @@
|
|
|
30
32
|
│ ┌──────────────────┐ ┌──────────────────┐ ┌───────────────────────┐ │
|
|
31
33
|
│ │ 9 大 Agent 工具 │ │ 人类 Slash 指令 │ │ Host HTTP WebServer │ │
|
|
32
34
|
│ │ (defineTool DSL)│ │ /gh status │ │ (Effect Disposer 清理)│ │
|
|
33
|
-
│ │ - pr
|
|
34
|
-
│ │
|
|
35
|
-
│ │ -
|
|
36
|
-
│ │
|
|
37
|
-
│ │
|
|
38
|
-
│ │ -
|
|
39
|
-
│ │
|
|
40
|
-
│ │ -
|
|
41
|
-
│ │
|
|
35
|
+
│ │ - pr (+ready· │ │ /gh upgrade │ │ - /api/github/overview│ │
|
|
36
|
+
│ │ revert·update)│ │ /gh help │ │ - /api/github/action │ │
|
|
37
|
+
│ │ - issue (+delete│ └──────────────────┘ │ - /api/github/refresh │ │
|
|
38
|
+
│ │ ·transfer·pin·│ │ - /check-update (并行)│ │
|
|
39
|
+
│ │ lock·status) │ │ - /upgrade (一键自动) │ │
|
|
40
|
+
│ │ - run (+workflow│ │ - /update-settings │ │
|
|
41
|
+
│ │ 系列·download)│ (workflow_enable/disable │ │ - /proxy (全局代理) │ │
|
|
42
|
+
│ │ - repo (+search │ 启停·list/view·download) │ - /auth (轻量探针) │ │
|
|
43
|
+
│ │ 三域+read_ │ └──────────┬────────────┘ │
|
|
44
|
+
│ │ file &read_dir)│ │ │
|
|
45
|
+
│ │ - api (逃生门) │ (search 三域=issues/prs/commits; │ │
|
|
46
|
+
│ │ - release │ read_file/read_dir 免clone读取) │ │
|
|
47
|
+
│ │ - secret (stdin │ │ │
|
|
48
|
+
│ │ +variable 域) │ │ │
|
|
49
|
+
│ │ - skill │ │ │
|
|
50
|
+
│ │ - help (元指南) │ │ │
|
|
42
51
|
│ └────────┬─────────┘ │ │
|
|
43
52
|
│ │ │ │
|
|
44
53
|
│ ▼ │ │
|
|
@@ -55,15 +64,15 @@
|
|
|
55
64
|
│ │
|
|
56
65
|
│ ┌──────────────────────────────────┐ ┌─────────────────────────────┐ │
|
|
57
66
|
│ │ 全局驾驶舱 (Main Slot) │ │ 右侧栏面板 (Right Sidebar) │ │
|
|
58
|
-
│ │ - 账号全局所有 GitHub 仓库 │ │ -
|
|
59
|
-
│ │ - 本地工作区矩阵透视 │ │
|
|
60
|
-
│ │ - 三维待办 Issues (药丸筛选) │ │ -
|
|
61
|
-
│ │ - 用户提单 / 分配待办 / 我发起 │ │ -
|
|
62
|
-
│ │ - 顶部升级通知横幅 (Banner) │ │ -
|
|
63
|
-
│ │ - 动态数据新鲜度胶囊与 SWR 缓存│ │ -
|
|
64
|
-
│ │ - 四分区设置弹窗 (同步/代理/ │ │ -
|
|
65
|
-
│ │ 更新源/关于) │ │
|
|
66
|
-
│ │ - 「插件」身份徽章 (关于直达) │ │
|
|
67
|
+
│ │ - 账号全局所有 GitHub 仓库 │ │ - 五 Tab 互斥 (Git/未提交/ │ │
|
|
68
|
+
│ │ - 本地工作区矩阵透视 │ │ PR/Issues/Actions) │ │
|
|
69
|
+
│ │ - 三维待办 Issues (药丸筛选) │ │ - Git 记录与分支同步全景 │ │
|
|
70
|
+
│ │ - 用户提单 / 分配待办 / 我发起 │ │ - 提交详情居中弹窗 (可滑动)│ │
|
|
71
|
+
│ │ - 顶部升级通知横幅 (Banner) │ │ - 下滑自动分页加载更多 │ │
|
|
72
|
+
│ │ - 动态数据新鲜度胶囊与 SWR 缓存│ │ - 快捷操作网格与设置入口 │ │
|
|
73
|
+
│ │ - 四分区设置弹窗 (同步/代理/ │ │ - 官方标准 Git 矢量图标 │ │
|
|
74
|
+
│ │ 更新源/关于) │ │ - 「插件」身份徽章 (直达) │ │
|
|
75
|
+
│ │ - 「插件」身份徽章 (关于直达) │ │ │ │
|
|
67
76
|
│ └──────────────────────────────────┘ └─────────────────────────────┘ │
|
|
68
77
|
└─────────────────────────────────────────────────────────────────────────────┘
|
|
69
78
|
```
|
|
@@ -86,11 +95,19 @@
|
|
|
86
95
|
- 所有的 `gh` 查询原生采用 `--json <fields>` 结构化投影;
|
|
87
96
|
- 对长文本输出(如大型 PR 的完整 `diff`、CI 失败步骤日志)设置安全截断阈值(默认 24KB),采用码点安全切割与二分查找字节截断,保留头尾关键上下文并添加显式截断标记,杜绝撑爆模型上下文;
|
|
88
97
|
- 列表与详情输出经独立 Markdown 渲染引擎(`src/renderers/markdown.ts`)转化为高密度表格与卡片(带状态徽章、可点击超链接与竖线转义防护),实测 20 条 PR 列表输出压缩 70%+ Token;
|
|
89
|
-
- 所有 Agent 工具的输出统一经过归一化,列表自动打包为 `{ items, count }`,标量打包为 `{ result }`,100% 严丝合缝契合 DSH
|
|
98
|
+
- 所有 Agent 工具的输出统一经过归一化,列表自动打包为 `{ items, count }`,标量打包为 `{ result }`,100% 严丝合缝契合 DSH 工具网关模式约束;
|
|
99
|
+
- **gh 版本守卫降级链(runGuarded)**:preview 命令与新特性按 `minVersion` 门槛路由——版本达标直通主命令、不足走 `fallback` 降级链路(结果携带 `degraded/degradedReason` 结构化标注,**降级不是静默的**,渲染层对 degraded 结果显式追加链路说明)、无降级时报错附平台升级指引;版本探测自身失败 fail-open 直通(守卫是路由优化不是安全边界)。版本比较采用数值分段(杜绝 `'2.96.0' > '2.100.0'` 字典序陷阱),探测结果 30s TTL 缓存且只缓存成功值;
|
|
100
|
+
- **AI_AGENT 识别信号注入**:每次 gh 子进程启动注入 `AI_AGENT=dsh`(gh detect.go 最高优先级通用信号)——gh ≥2.99 自动切换 text-only spinner、≥2.100 命令误用时打印完整 help(模型可据此自我纠正)、telemetry 归因到 dsh;旧版 gh 忽略该变量零副作用。经 `agentEnvInjection` 配置开关(默认开启)可恢复 gh 原生行为。
|
|
90
101
|
|
|
91
102
|
### 2.3.1 高危操作确认与敏感值安全通道 (Safety Confirmation & Secret stdin Channel)
|
|
92
|
-
- 不可逆写操作(`merge` / `close` / `release delete` / clobber 覆盖上传 / `secret delete` / `skill install`)强制要求 `confirm: true` 显式参数,未确认时仅返回影响评估卡片,不产生任何远端或本地副作用;
|
|
93
|
-
- 密钥明文仅经子进程标准输入传递(`spawnWithStdin` 通道:`spawn` + `stdin.end(data)` 半关闭写入——`execFile` 的 `input` 选项在实测环境从不真正写入管道,密文通道此前从未生效过),全程不出现在命令行参数、进程列表与工具输出中;渲染层对 secret 输出采用独立实现,从结构上隔离「绝不渲染 value 字段」这条安全红线。
|
|
103
|
+
- 不可逆写操作(`merge` / `close` / `issue delete`(物理删除)/ `issue transfer`(跨仓库迁移)/ `pr revert`(远端创建反向 PR)/ `release delete` / clobber 覆盖上传 / `secret delete` / `skill install`)强制要求 `confirm: true` 显式参数,未确认时仅返回影响评估卡片,不产生任何远端或本地副作用;
|
|
104
|
+
- 密钥明文仅经子进程标准输入传递(`spawnWithStdin` 通道:`spawn` + `stdin.end(data)` 半关闭写入——`execFile` 的 `input` 选项在实测环境从不真正写入管道,密文通道此前从未生效过),全程不出现在命令行参数、进程列表与工具输出中;渲染层对 secret 输出采用独立实现,从结构上隔离「绝不渲染 value 字段」这条安全红线。secret 与 variable(CI 明文,get 可回显)的渲染走**两个物理独立的函数**——安全语义靠函数边界而非同一函数的分支隔离,防未来重构互相污染。
|
|
105
|
+
|
|
106
|
+
### 2.3.2 产物落盘纪律 (Artifact Download Discipline)
|
|
107
|
+
- **目录固定派生,永不暴露路径参数**:构建产物下载(`run download` 等)的落盘目录由插件从 `~/.dsh/data/dsh-github-flow/artifacts/<owner>/<repo>/<run_id>/` 三级固定派生,不向调用方暴露任何目录参数——这是 GHSA-39wj-f2f4-978v(gh <2.102 符号链接路径穿越)的核心防线:用户无法注入 `../` 或符号链接目标,攻击面收敛到唯一一个 `mkdirSync(recursive)` 调用点,且目录天然按仓库与 run 隔离、可整体清理;
|
|
108
|
+
- **低版本安全提示而非硬拒绝**:gh <2.102 时下载仍可执行(受控仓库场景是合理需求),但返回值携带 `securityNote` 升级指引;需要自定义落盘位置的场景显式引导经 `github_api` 手动拉取;
|
|
109
|
+
- **下载后零本地符号化操作**:插件对落盘产物仅做递归枚举(相对路径 + 大小清单),不执行链接、移动或执行类操作。
|
|
110
|
+
未来任何新增下载类能力(如 gist 资产)必须引用本节纪律,而非各自重述。
|
|
94
111
|
|
|
95
112
|
### 2.4 原生浅色/深色主题自适应与快捷操作网格
|
|
96
113
|
- 全面对齐 DSH 官方 DSW 语义设计变量,基于 `body[data-ds-dark-theme]` 驱动无闪烁双模式切换;
|
|
@@ -160,3 +177,16 @@
|
|
|
160
177
|
- 全部前端数据链路 fetch 绑定 `AbortController`(45s 兜底;登录探测 10s)——代理劫持回环地址等极端场景下用户得到明确超时出口,绝不永久转圈(未安装 gh 用户的刷新卡死修复);
|
|
161
178
|
- 后端 `gh` 探测毫秒级返回 ENOENT/安装引导,前端安装引导卡(AuthGuideCard)承载唤起终端(stdio ignore,无 profile)等自愈出口。
|
|
162
179
|
|
|
180
|
+
### 2.10 右侧栏五 Tab 互斥与本地 Git 状态全景架构 (Right Sidebar Tabs & Local Git Engine)
|
|
181
|
+
- **五 Tab 响应式互斥布局**:
|
|
182
|
+
- 将右侧栏原本纵向堆叠的 PR / Issues / Actions / Git 状态与未提交清单彻底重构成水平紧凑 Tab(Git / 未提交 / PR / Issues / Actions),默认激活 Git 记录页,首屏高度收敛 60% 以上;
|
|
183
|
+
- 纯函数渲染约束与 DOM 级状态:`renderGithubRepoView` 坚守零 React Hooks 约束,激活态通过 `data-active-tab` 挂载在 DOM 容器上;根组件通过 `useEffect([data])` 与 `applyTabState` 联动,在 SWR 后台拉新完成触发重渲染时,自动重置回用户选择的 Tab,彻底解决后台数据刷新拽回默认 Tab 的缺陷。
|
|
184
|
+
- **三段式提交日志与本地 0ms 秒开**:
|
|
185
|
+
- 本地领先(待 push)、远程领先(待 pull,快照口径)与最近提交历史;
|
|
186
|
+
- 采用 ASCII 单元/记录控制符(`%x1e` / `%x1f`)结构化解析 `git log`,一次性提取 fullSha、author、email、date、多行 body 说明与 `--stat` 文件改动统计,首屏 0ms 纯本地呈现,零网络失败风险;
|
|
187
|
+
- 默认展示 15 条,通过右侧栏容器 `onScroll` 触底(<80px)与点击双重触发向后分页拉取,伴随实时进度计数(如 `15 / 74`)。
|
|
188
|
+
- **内嵌模态弹窗 (CommitDetailModal)**:
|
|
189
|
+
- 复用设置弹窗架构(`.dsh-github-modal-overlay` + `.dsh-github-modal-dialog`),挂载在右侧栏容器内部,天然受限于右侧栏边界居中,彻底消除传统 `<dialog>` 顶层穿透全屏居中的越界问题;
|
|
190
|
+
- 弹窗外框限制 `max-height: 84vh; overflow: hidden;`,正文区域 `flex: 1; min-height: 0; overflow-y: auto;`,完美支持上下滑动浏览数十行详细正文与修改文件统计,支持 Esc 键与点击遮罩随手退出。
|
|
191
|
+
- **全库统一 Git 官方矢量图标**:全量替换各处的植物/字符符号为标准 Git 菱形分支官方矢量组件(`#1296db` SVG)。
|
|
192
|
+
|
package/docs/images/2.png
CHANGED
|
Binary file
|
|
@@ -66,9 +66,20 @@ git push origin master --tags
|
|
|
66
66
|
**推送完成后**:
|
|
67
67
|
- GitHub Actions 会在 5 秒内自动感知到 `v0.1.1` 标签被创建;
|
|
68
68
|
- 启动 Ubuntu runner,全自动执行:
|
|
69
|
-
`检出代码 ➔ 安装 pnpm ➔ 安装依赖 ➔ pnpm run build (编译 + 清理) ➔ 产物完整性校验 ➔ 带 Provenance 签名发布到 npm ➔ 自动创建并发布对应 GitHub Release
|
|
69
|
+
`检出代码 ➔ 安装 pnpm ➔ 安装依赖 ➔ pnpm run build (编译 + 清理) ➔ 产物完整性校验 ➔ pnpm pack 打离线包 ➔ 带 Provenance 签名发布到 npm ➔ 自动创建并发布对应 GitHub Release(含离线安装包资产)`;
|
|
70
70
|
- 约 1 分钟后,npm 官网版本与 GitHub 仓库 Releases 页面同步更新!
|
|
71
71
|
|
|
72
|
+
### Release 离线安装包资产
|
|
73
|
+
|
|
74
|
+
每个 Release 会附带两个资产文件(与 npm 发布包**内容同源**:同一份 lib/ 构建产物,按 package.json `files` 字段打包):
|
|
75
|
+
|
|
76
|
+
| 资产 | 用途 |
|
|
77
|
+
| :--- | :--- |
|
|
78
|
+
| `dsh-github-flow-<版本>.tgz` | **离线/免构建安装包**:下载后执行 `dsh plugin --profile <名称> add ./dsh-github-flow-<版本>.tgz` 直接安装,无需网络与本地构建。适用场景:pnpm ≥ 10 从 Git 安装的构建授权拦截、npm 镜像同步滞后 24h(Q3 场景的零等待替代)、内网/离线环境分发 |
|
|
79
|
+
| `dsh-github-flow-<版本>.tgz.sha256` | 下载完整性校验(`sha256sum -c` / `Get-FileHash` 比对),供应链信任基线 |
|
|
80
|
+
|
|
81
|
+
> 注:Release 页 GitHub 自动生成的 `Source code (zip/tar.gz)` 是**源码快照**(TypeScript 源码,不可直接安装);`.tgz` 资产才是**编译产物包**(lib/ 已构建),两者用途不同。
|
|
82
|
+
|
|
72
83
|
---
|
|
73
84
|
|
|
74
85
|
## 2. 安全机制与 Provenance 产物溯源
|
|
@@ -43,6 +43,9 @@ export function registerOverviewRoutes(deps, executor, cacheMap, globalCache, ch
|
|
|
43
43
|
let pullRequests = [];
|
|
44
44
|
let issues = [];
|
|
45
45
|
let runs = [];
|
|
46
|
+
// 面板增强信息载体(git 状态/Release 锚定/分支 PR——全部可选字段,
|
|
47
|
+
// 进缓存与快照时旧消费方零破坏,渲染层 ?. 兜底)
|
|
48
|
+
const freshExtras = {};
|
|
46
49
|
if (repo && auth.loggedIn) {
|
|
47
50
|
// 并发拉取当前文件夹仓库的 PRs、Issues 和 Runs
|
|
48
51
|
const [prsRes, issuesRes, runsRes] = await Promise.all([
|
|
@@ -65,6 +68,34 @@ export function registerOverviewRoutes(deps, executor, cacheMap, globalCache, ch
|
|
|
65
68
|
}
|
|
66
69
|
if (runsRes.ok && Array.isArray(runsRes.data))
|
|
67
70
|
runs = runsRes.data;
|
|
71
|
+
// 面板信息增强(三路并行,全部失败静默——可选装饰信息不阻塞主流程):
|
|
72
|
+
// 1. git 本地状态:纯本地毫秒级(remote-tracking 快照),零网络
|
|
73
|
+
// 2. Release 锚定:gh release view,无 Release 仓库是常态非错误
|
|
74
|
+
// 3. 当前分支↔PR 关联:pr status -c,无 PR 分支同样静默
|
|
75
|
+
const [gitStatus, releaseInfo, branchPr] = await Promise.all([
|
|
76
|
+
executor.getLocalGitStatus(cwd).catch(() => null),
|
|
77
|
+
executor.run(['release', 'view', '--json', 'tagName,isPrerelease,isDraft,publishedAt,url', '-R', repo.nameWithOwner], { cwd, timeoutMs: 8_000 }).then((r) => (r.ok && r.data && !r.data.isDraft ? r.data : null)).catch(() => null),
|
|
78
|
+
executor.run(['pr', 'status', '-c', '--json', 'number,title,state,url,isDraft', '-R', repo.nameWithOwner], { cwd, timeoutMs: 8_000 }).then((r) => {
|
|
79
|
+
// 实测键集:{ createdBy: [...], needsReview: [...] }——「当前分支
|
|
80
|
+
// 关联 PR」按优先级取 createdBy(自己发起)→ needsReview(待审)。
|
|
81
|
+
// 不传 rawText:executor 对含 --json 的命令自动解析出 data——
|
|
82
|
+
// rawText 模式 data 恒 undefined 会让本功能静默失效(审查抓到的真实 Bug)
|
|
83
|
+
if (!r.ok || !r.data)
|
|
84
|
+
return null;
|
|
85
|
+
const createdBy = Array.isArray(r.data?.createdBy) ? r.data.createdBy : [];
|
|
86
|
+
const needsReview = Array.isArray(r.data?.needsReview) ? r.data.needsReview : [];
|
|
87
|
+
return createdBy[0] || needsReview[0] || null;
|
|
88
|
+
}).catch(() => null),
|
|
89
|
+
]);
|
|
90
|
+
freshExtras.gitStatus = gitStatus;
|
|
91
|
+
freshExtras.releaseInfo = releaseInfo;
|
|
92
|
+
freshExtras.branchPr = branchPr;
|
|
93
|
+
// 4. git 提交记录三段(领先/落后/最近):依赖 gitStatus.hasUpstream 守卫,
|
|
94
|
+
// 在并行波次之后串行补(本地毫秒级,无感知延迟)——放进第一波会因
|
|
95
|
+
// Promise.all 参数在调用时求值而引用未解构的 gitStatus(恒 undefined)
|
|
96
|
+
freshExtras.commitLog = await executor
|
|
97
|
+
.getGitCommitLog(cwd, gitStatus ? gitStatus.hasUpstream : false)
|
|
98
|
+
.catch(() => null);
|
|
68
99
|
}
|
|
69
100
|
const issueStats = calculateIssueStats(issues);
|
|
70
101
|
const freshData = {
|
|
@@ -76,6 +107,7 @@ export function registerOverviewRoutes(deps, executor, cacheMap, globalCache, ch
|
|
|
76
107
|
runs,
|
|
77
108
|
lastUpdated: new Date().toISOString(),
|
|
78
109
|
updateInfo: checker.getQuickStatus(),
|
|
110
|
+
...freshExtras,
|
|
79
111
|
};
|
|
80
112
|
cacheMap.set(cwd, freshData, now);
|
|
81
113
|
sendJson(res, 200, { ok: true, data: freshData, fromCache: false, cwd });
|
|
@@ -124,7 +156,7 @@ export function registerOverviewRoutes(deps, executor, cacheMap, globalCache, ch
|
|
|
124
156
|
const issueFields = 'number,title,repository,author,assignees,labels,url,updatedAt';
|
|
125
157
|
const queryResults = await Promise.allSettled([
|
|
126
158
|
executor.run(['repo', 'list', '--limit', '20', '--json', 'name,nameWithOwner,description,defaultBranchRef,isPrivate,stargazerCount,updatedAt,url'], { timeoutMs: 8_000 }),
|
|
127
|
-
executor.run(['search', 'prs', '--author=@me', '--state=open', '--limit', '10', '--json', 'number,title,repository,url,updatedAt'], { timeoutMs: 8_000 }),
|
|
159
|
+
executor.run(['search', 'prs', '--author=@me', '--state=open', '--limit', '10', '--json', 'number,title,repository,url,updatedAt,isDraft'], { timeoutMs: 8_000 }),
|
|
128
160
|
executor.run(['search', 'issues', '--owner=@me', '--state=open', '--sort=updated', '--limit', '15', '--json', issueFields], { timeoutMs: 8_000 }),
|
|
129
161
|
executor.run(['search', 'issues', '--assignee=@me', '--state=open', '--sort=updated', '--limit', '15', '--json', issueFields], { timeoutMs: 8_000 }),
|
|
130
162
|
executor.run(['search', 'issues', '--author=@me', '--state=open', '--sort=updated', '--limit', '15', '--json', issueFields], { timeoutMs: 8_000 }),
|
|
@@ -195,6 +227,9 @@ export function registerOverviewRoutes(deps, executor, cacheMap, globalCache, ch
|
|
|
195
227
|
// 每次网络往返都要秒级,5 个工作区就足以把该端点拖到 20 秒。
|
|
196
228
|
workspaceMatrix = await mapLimit(wsEntries, WORKSPACE_PROBE_CONCURRENCY, async (ws) => {
|
|
197
229
|
const hasGit = hasGitDir(ws.path);
|
|
230
|
+
// git 状态与身份识别同为纯本地探测(remote-tracking 快照零网络),
|
|
231
|
+
// 挂进同一 mapLimit 有界并发——不新增并发维度,不碰性能红线
|
|
232
|
+
const gitStatus = hasGit ? await executor.getLocalGitStatus(ws.path).catch(() => null) : null;
|
|
198
233
|
return {
|
|
199
234
|
id: ws.id,
|
|
200
235
|
title: ws.title || basenameSafe(ws.path),
|
|
@@ -202,6 +237,7 @@ export function registerOverviewRoutes(deps, executor, cacheMap, globalCache, ch
|
|
|
202
237
|
hasGit,
|
|
203
238
|
repo: hasGit ? executor.getRepoIdentityFromLocal(ws.path) || undefined : undefined,
|
|
204
239
|
sessionCount: ws.sessionIds.length,
|
|
240
|
+
...(gitStatus ? { gitStatus } : {}),
|
|
205
241
|
};
|
|
206
242
|
});
|
|
207
243
|
}
|
|
@@ -224,4 +260,71 @@ export function registerOverviewRoutes(deps, executor, cacheMap, globalCache, ch
|
|
|
224
260
|
}
|
|
225
261
|
},
|
|
226
262
|
});
|
|
263
|
+
// 3. 单条提交详情(Git 记录页点击行的惰性查询——弹窗打开时才发起,
|
|
264
|
+
// 不进 overview 缓存:低频单查 + git show 本地毫秒级,无缓存必要)
|
|
265
|
+
bindRoute({
|
|
266
|
+
kind: 'exact',
|
|
267
|
+
path: '/api/github/commit-detail',
|
|
268
|
+
handler: async (req, res) => {
|
|
269
|
+
if (req.method !== 'GET') {
|
|
270
|
+
sendJson(res, 405, { ok: false, message: '仅支持 GET 请求' });
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
try {
|
|
274
|
+
const url = new URL(req.url || '', 'http://127.0.0.1');
|
|
275
|
+
let cwd = url.searchParams.get('cwd') || undefined;
|
|
276
|
+
const sessionId = url.searchParams.get('sessionId');
|
|
277
|
+
if (!cwd && sessionId) {
|
|
278
|
+
cwd = findWorkspacePathBySession(sessionId) || undefined;
|
|
279
|
+
}
|
|
280
|
+
if (!cwd) {
|
|
281
|
+
cwd = findMostRecentWorkspacePath() || undefined;
|
|
282
|
+
}
|
|
283
|
+
const sha = url.searchParams.get('sha') || '';
|
|
284
|
+
// sha 形态校验双保险(executor 内还有一道):路由层先拦明显恶意值
|
|
285
|
+
if (!/^[0-9a-f]{4,40}$/i.test(sha)) {
|
|
286
|
+
sendJson(res, 400, { ok: false, error: '非法 sha(仅接受 4-40 位十六进制)' });
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const detail = await executor.getGitCommitDetail(cwd, sha);
|
|
290
|
+
if (detail === null) {
|
|
291
|
+
sendJson(res, 404, { ok: false, error: '未找到该提交(可能不在当前仓库)' });
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
sendJson(res, 200, { ok: true, detail });
|
|
295
|
+
}
|
|
296
|
+
catch (err) {
|
|
297
|
+
sendJson(res, 500, { ok: false, error: err.message || '查询提交详情失败' });
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
// 4. 分页获取最近提交记录(Git 记录页下滑触底自动加载或点击加载更多)
|
|
302
|
+
bindRoute({
|
|
303
|
+
kind: 'exact',
|
|
304
|
+
path: '/api/github/git-log',
|
|
305
|
+
handler: async (req, res) => {
|
|
306
|
+
if (req.method !== 'GET') {
|
|
307
|
+
sendJson(res, 405, { ok: false, message: '仅支持 GET 请求' });
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
const url = new URL(req.url || '', 'http://127.0.0.1');
|
|
312
|
+
let cwd = url.searchParams.get('cwd') || undefined;
|
|
313
|
+
const sessionId = url.searchParams.get('sessionId');
|
|
314
|
+
if (!cwd && sessionId) {
|
|
315
|
+
cwd = findWorkspacePathBySession(sessionId) || undefined;
|
|
316
|
+
}
|
|
317
|
+
if (!cwd) {
|
|
318
|
+
cwd = findMostRecentWorkspacePath() || undefined;
|
|
319
|
+
}
|
|
320
|
+
const limit = Math.min(Math.max(1, Number(url.searchParams.get('limit')) || 15), 50);
|
|
321
|
+
const skip = Math.max(0, Number(url.searchParams.get('skip')) || 0);
|
|
322
|
+
const result = await executor.getGitRecentLog(cwd, limit, skip);
|
|
323
|
+
sendJson(res, 200, { ok: true, data: result });
|
|
324
|
+
}
|
|
325
|
+
catch (err) {
|
|
326
|
+
sendJson(res, 500, { ok: false, error: err.message || '获取提交记录失败' });
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
});
|
|
227
330
|
}
|