dsh-github-flow 0.2.0 → 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 +68 -22
- package/README.md +69 -23
- package/docs/UPGRADE-NOTES.md +93 -0
- package/docs/architecture.md +76 -31
- package/docs/images/1.png +0 -0
- package/docs/images/2.png +0 -0
- package/docs/images/3.png +0 -0
- package/docs/images/4.png +0 -0
- package/docs/npm-publish-guide.md +27 -5
- package/lib/api/routes-actions.d.ts +18 -4
- package/lib/api/routes-actions.js +143 -19
- package/lib/api/routes-lifecycle.d.ts +1 -1
- package/lib/api/routes-lifecycle.js +53 -2
- package/lib/api/routes-overview.js +104 -1
- package/lib/client.js +991 -55
- package/lib/commands/gh.js +11 -2
- package/lib/executor.d.ts +118 -1
- package/lib/executor.js +479 -12
- package/lib/main.js +10 -0
- package/lib/renderers/markdown.d.ts +12 -1
- package/lib/renderers/markdown.js +150 -16
- package/lib/tools/help.js +144 -11
- package/lib/tools/image-utils.d.ts +79 -0
- package/lib/tools/image-utils.js +247 -0
- package/lib/tools/issue.d.ts +18 -4
- package/lib/tools/issue.js +161 -6
- package/lib/tools/pr.d.ts +12 -4
- package/lib/tools/pr.js +128 -7
- package/lib/tools/repo.d.ts +20 -4
- package/lib/tools/repo.js +196 -4
- 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 +85 -1
- package/lib/update-settings.d.ts +18 -0
- package/lib/update-settings.js +60 -0
- package/lib/updater.d.ts +32 -1
- package/lib/updater.js +117 -9
- package/lib/upgrade-manager.d.ts +70 -1
- package/lib/upgrade-manager.js +346 -46
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/lib/commands/gh.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CURRENT_PLUGIN_VERSION, PLUGIN_PACKAGE_NAME, NPM_PACKAGE_URL } from '../version.js';
|
|
2
|
+
import { loadUpdateSettings, describeUpdateMode } from '../update-settings.js';
|
|
2
3
|
export function registerGhCommand(commandsService, executor, updateChecker) {
|
|
3
4
|
if (!commandsService || typeof commandsService.register !== 'function')
|
|
4
5
|
return;
|
|
@@ -53,12 +54,20 @@ export function registerGhCommand(commandsService, executor, updateChecker) {
|
|
|
53
54
|
const platformName = isMac ? 'macOS' : isWin ? 'Windows' : 'Linux';
|
|
54
55
|
let md = `### 🚀 ${PLUGIN_PACKAGE_NAME} 插件升级指南\n\n`;
|
|
55
56
|
md += `- **当前运行版本**: \`v${curVer}\`\n`;
|
|
57
|
+
// 当前更新源:排查「查不到新版」时(镜像同步滞后)用户需可见自己在用哪个源。
|
|
58
|
+
// 优先读 checker 内存态(store 写盘失败时磁盘是旧值,活实例才是事实源),
|
|
59
|
+
// 无 checker 或未初始化(sourceMode=null 的 legacy 路径)回落磁盘 store。
|
|
60
|
+
const liveMode = updateChecker?.getSourceMode?.() ?? null;
|
|
61
|
+
const effectiveMode = liveMode ?? loadUpdateSettings();
|
|
62
|
+
md += `- **当前更新源**: ${describeUpdateMode(effectiveMode)}\n`;
|
|
56
63
|
md += `- **官方最新版本**: \`v${latestVer}\` ${hasUpdate ? '🔥 (有可用更新)' : '✅ (已是最新)'}\n`;
|
|
57
64
|
md += `- **操作系统环境**: \`${platformName} (${process.platform})\`\n`;
|
|
58
65
|
md += `- **npm 仓库地址**: [${NPM_PACKAGE_URL}](${NPM_PACKAGE_URL})\n\n`;
|
|
59
66
|
md += `#### 请根据你的 DSH 安装环境选择适用的升级方式:\n\n`;
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
// 官方 CLI 语义:--profile 为必填参数(dsh plugin --profile <name> add <pkg>),
|
|
68
|
+
// 任何不带 --profile 的形态(含 pnpm dsh plugin add)都会直接报 required option 错误。
|
|
69
|
+
md += `1. **DSH 桌面版 Profile 环境升级(推荐)**:\n\`\`\`bash\ndsh plugin --profile desktop add ${PLUGIN_PACKAGE_NAME}@latest\n\`\`\`\n\n`;
|
|
70
|
+
md += `2. **DSH Web / CLI 环境**(profile 名按实际环境填写):\n\`\`\`bash\ndsh plugin --profile web add ${PLUGIN_PACKAGE_NAME}@latest\n\`\`\`\n`;
|
|
62
71
|
if (isMac) {
|
|
63
72
|
md += `> 💡 *macOS 提示*:若在终端找不到 \`dsh\` 命令,可直接在桌面端目录更新:\n\`\`\`bash\ncd ~/.dsh/profiles/desktop && npm install ${PLUGIN_PACKAGE_NAME}@latest --save\n\`\`\`\n\n`;
|
|
64
73
|
}
|
package/lib/executor.d.ts
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
|
-
import type { GhExecutionOptions, GhResult, AuthStatus, RepoMetadata, PluginConfig } from './types.js';
|
|
1
|
+
import type { GhExecutionOptions, GhResult, AuthStatus, RepoMetadata, PluginConfig, GitLocalStatus, GitCommitLog, GitCommitEntry } from './types.js';
|
|
2
2
|
import type { ProxyManager } from './proxy.js';
|
|
3
|
+
/**
|
|
4
|
+
* 从 `gh --version` 输出中解析语义化版本号。
|
|
5
|
+
* 抽成导出纯函数的原因与 truncateOutput 相同:解析逻辑是「看似简单实则易错」的边界区,
|
|
6
|
+
* 必须能用单元测试钉死(不匹配输入返回 null 而非抛错,调用方据此走 fail-open)。
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseGhVersion(output: string): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* 数值分段比较两个 gh 版本:a>b 返回 1、a<b 返回 -1、相等返回 0。
|
|
11
|
+
* 为什么不能用字符串比较:`'2.96.0' < '2.100.0'` 在字典序下为 false('1'<'9'),
|
|
12
|
+
* 这会把 2.100 误判为低于 2.96,导致可用命令被错误降级。逐段 Number 比较是唯一正确姿势。
|
|
13
|
+
*/
|
|
14
|
+
export declare function compareGhVersions(a: string, b: string): number;
|
|
15
|
+
/**
|
|
16
|
+
* 解析 `git status -sb --porcelain` 输出为结构化状态。
|
|
17
|
+
* 抽导出纯函数(parseGhVersion 同理):三形态解析是易错边界区,单测钉死。
|
|
18
|
+
*
|
|
19
|
+
* 输出形态(实测):
|
|
20
|
+
* `## master...origin/master [ahead 2, behind 1]` 有 ahead/behind
|
|
21
|
+
* `## master...origin/master` 与远程同步
|
|
22
|
+
* `## master` / `## HEAD (no branch)` 无 upstream(ahead/behind 未知=-1)
|
|
23
|
+
* 后续每行 `<XY> <path>` 为 porcelain 变更项(XY 两字符状态码,?? = untracked)。
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseGitStatusOutput(output: string): GitLocalStatus | null;
|
|
26
|
+
/**
|
|
27
|
+
* 解析 `git log` 输出为提交条目数组。
|
|
28
|
+
* 支持两种形态:
|
|
29
|
+
* 1. 结构化带详情:%x1e 为 commit 间分隔符,%x1f 为字段间分隔符(含 fullSha/email/date/body/stat);
|
|
30
|
+
* 2. 简易管道符:%h|%an|%ar|%s 行格式(兼容旧单测输入)。
|
|
31
|
+
* 空输出返回 []。
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseGitLogLines(output: string): GitCommitEntry[];
|
|
3
34
|
/**
|
|
4
35
|
* 按「字符数 + UTF-8 字节数」双口径截断输出。
|
|
5
36
|
* 抽成纯函数是刻意的:截断逻辑是崩溃高发区(切碎多字节字符、误伤 JSON、把二进制流截成垃圾),
|
|
@@ -22,6 +53,12 @@ export declare class GhExecutor {
|
|
|
22
53
|
* 且热更新路径 updateConfig 能同步刷新。工具内以 `?? 20` 兜底保证旧配置兼容。
|
|
23
54
|
*/
|
|
24
55
|
defaultListLimit: number;
|
|
56
|
+
/**
|
|
57
|
+
* 是否注入 AI_AGENT='dsh'(gh 官方 agent 识别信号,默认 true)。
|
|
58
|
+
* 挂在 executor 而非工具参数:注入点是「每次 gh 子进程拉起」这一全局咽喉,
|
|
59
|
+
* 与 GH_NO_UPDATE_NOTIFIER/NO_COLOR 同级,语义上属于执行层默认值。
|
|
60
|
+
*/
|
|
61
|
+
agentEnvInjection: boolean;
|
|
25
62
|
/**
|
|
26
63
|
* 代理管理器引用(可选依赖)。
|
|
27
64
|
* 注入后每次 gh 子进程拉起都会合并代理环境变量——这是「工具调用 + Web 页面数据
|
|
@@ -31,6 +68,11 @@ export declare class GhExecutor {
|
|
|
31
68
|
private proxyManager?;
|
|
32
69
|
/** 认证状态缓存。`gh auth status` 实测 5.4 秒,而它位于全局驾驶舱关键路径的最前面 */
|
|
33
70
|
private authCache;
|
|
71
|
+
/**
|
|
72
|
+
* gh 版本号缓存。只缓存成功解析值(authCache 哲学:不确定结果不缓存)——
|
|
73
|
+
* 探测失败/未安装时不落缓存,用户装好 gh 后下一次探测立即生效。
|
|
74
|
+
*/
|
|
75
|
+
private ghVersionCache;
|
|
34
76
|
constructor(config?: PluginConfig);
|
|
35
77
|
updateConfig(config?: PluginConfig): void;
|
|
36
78
|
/** 注入代理管理器(main.ts 装配时调用一次;测试可注入 mock) */
|
|
@@ -57,6 +99,81 @@ export declare class GhExecutor {
|
|
|
57
99
|
* 而 Web 面板每次挂载都会来问一次,重复执行实测要 5.4 秒,属于纯浪费。
|
|
58
100
|
*/
|
|
59
101
|
checkAuth(cwd?: string, bypassCache?: boolean): Promise<AuthStatus>;
|
|
102
|
+
/**
|
|
103
|
+
* 获取当前 gh 版本号(带 30s TTL 缓存),失败返回 null。
|
|
104
|
+
* 底层直连 execFileAsync 而不走 this.run():run() 会先解析工作区(可能读
|
|
105
|
+
* workspace.json 与目录扫描)再做截断/JSON 解析,对一次 10ms 的版本字符串
|
|
106
|
+
* 查询是纯开销;直连也彻底规避 runGuarded → 探测 → run 的递归风险。
|
|
107
|
+
*/
|
|
108
|
+
getGhVersion(): Promise<string | null>;
|
|
109
|
+
/**
|
|
110
|
+
* 底层版本探测(独立方法而非内联:测试需要在不触发真实子进程的前提下
|
|
111
|
+
* 验证 getGhVersion 的缓存分支——覆写此方法即注入确定输出)。
|
|
112
|
+
* 直连 execFileAsync 而不走 this.run():run() 会先解析工作区(可能读
|
|
113
|
+
* workspace.json 与目录扫描)再做截断/JSON 解析,对一次 10ms 的版本字符串
|
|
114
|
+
* 查询是纯开销;直连也彻底规避 runGuarded → 探测 → run 的递归风险。
|
|
115
|
+
*/
|
|
116
|
+
protected probeGhVersionRaw(): Promise<string>;
|
|
117
|
+
/**
|
|
118
|
+
* 守卫执行器:按 gh 版本门槛路由「主命令 → 降级链路 → 升级指引」三态。
|
|
119
|
+
*
|
|
120
|
+
* 为什么是「检查+执行」一体的方法而非纯探测接口:检查与执行分离会在两者之间
|
|
121
|
+
* 留下竞隙(版本可能在间隙变化),且降级标注逻辑会被迫散落到每个工具的 if/else。
|
|
122
|
+
*
|
|
123
|
+
* fail-open 纪律:版本探测自身失败(null)时直接执行主命令——守卫是路由优化
|
|
124
|
+
* 不是安全边界,探测故障不应拦截业务;gh 未安装场景由主命令产出既有 ENOENT
|
|
125
|
+
* 安装引导,这里不重复造错误路径。
|
|
126
|
+
*/
|
|
127
|
+
runGuarded<T = unknown>(args: string[], options?: GhExecutionOptions & {
|
|
128
|
+
/** 该能力要求的最低 gh 版本,如 '2.95.0';缺省时等价于直接 run(渐进采用) */
|
|
129
|
+
minVersion?: string;
|
|
130
|
+
/** 人类可读能力名,用于错误信息,如 'gh repo read-file' */
|
|
131
|
+
capability?: string;
|
|
132
|
+
/** 版本不足时的降级链路(如 github_api contents 端点封装);无则报错带升级指引 */
|
|
133
|
+
fallback?: () => Promise<GhResult<T>>;
|
|
134
|
+
}): Promise<GhResult<T> & {
|
|
135
|
+
degraded?: boolean;
|
|
136
|
+
degradedReason?: string;
|
|
137
|
+
}>;
|
|
138
|
+
/** gh 升级命令按平台提示(复用三态状态机的平台判断口径) */
|
|
139
|
+
private getGhUpgradeHint;
|
|
140
|
+
/**
|
|
141
|
+
* 本地 Git 状态只读探测(白名单通道)。
|
|
142
|
+
*
|
|
143
|
+
* 这是本插件首次执行 git(此前仅 gh)——git 存在大量写命令,风险等级高于 gh,
|
|
144
|
+
* 因此白名单不落在「命令名过滤」而落在「命令形态常量」:spawn 参数是下方
|
|
145
|
+
* 硬编码的数组字面量,无任何动态拼接路径,写操作物理不可达(cwd 之外零输入,
|
|
146
|
+
* 而 cwd 本身也是插件解析的工作区路径)。
|
|
147
|
+
*
|
|
148
|
+
* 零网络:status 基于 remote-tracking ref(上次 fetch 的快照),毫秒级本地读取,
|
|
149
|
+
* 符合 global-overview 端点「工作区探测不发网络」的性能红线。
|
|
150
|
+
*/
|
|
151
|
+
getLocalGitStatus(cwd?: string): Promise<GitLocalStatus | null>;
|
|
152
|
+
/**
|
|
153
|
+
* 本地 Git 提交记录(三段一次返回:本地领先 / 远程领先 / 最近提交)。
|
|
154
|
+
*
|
|
155
|
+
* 白名单纪律与 getLocalGitStatus 同源:下方两个命令形态常量硬编码
|
|
156
|
+
* (log + 修订范围语法,range 段由 hasUpstream 守卫后才拼接且仅两个
|
|
157
|
+
* 固定形态 @{u}..HEAD / HEAD..@{u}——不含任何用户输入路径)。
|
|
158
|
+
* 领先/落后列表基于 remote-tracking ref(上次 fetch 快照),与 status
|
|
159
|
+
* 的 ahead/behind 计数同一数据口径;格式 %h|%an|%ar|%s 实测可结构化解析。
|
|
160
|
+
*/
|
|
161
|
+
getGitCommitLog(cwd?: string, hasUpstream?: boolean, limit?: number): Promise<GitCommitLog | null>;
|
|
162
|
+
/**
|
|
163
|
+
* 分页获取最近提交记录(用于 Git 面板下滑触底继续加载)。
|
|
164
|
+
*/
|
|
165
|
+
getGitRecentLog(cwd?: string, limit?: number, skip?: number): Promise<{
|
|
166
|
+
commits: GitCommitEntry[];
|
|
167
|
+
totalCount?: number;
|
|
168
|
+
}>;
|
|
169
|
+
/**
|
|
170
|
+
* 单条提交详情(点击提交行弹窗的数据源)。
|
|
171
|
+
* 白名单纪律延续:show 命令形态常量硬编码;sha 参数经 ^[0-9a-f]{4,40}$
|
|
172
|
+
* 十六进制校验后才拼接——这是 git 白名单通道首次接受「外部传入的单值」,
|
|
173
|
+
* 正则把值域锁死在纯十六进制(注入面为零:任何 shell 元字符/子命令
|
|
174
|
+
* 语法都不可能通过校验)。输出为 git show --stat 原文(含文件变更统计)。
|
|
175
|
+
*/
|
|
176
|
+
getGitCommitDetail(cwd: string | undefined, sha: string): Promise<string | null>;
|
|
60
177
|
/** 生成当前操作系统平台的推荐安装引导与命令 */
|
|
61
178
|
private getPlatformInstallGuide;
|
|
62
179
|
/** 实际执行 `gh auth status` 并解析结果,不含缓存逻辑 */
|