dsh-github-flow 0.1.8 → 0.2.1
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 +162 -58
- package/README.md +167 -60
- package/docs/UPGRADE-NOTES.md +93 -0
- package/docs/architecture.md +47 -17
- 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 +26 -3
- package/lib/api/route-helpers.d.ts +47 -0
- package/lib/api/route-helpers.js +134 -0
- package/lib/api/routes-actions.d.ts +23 -0
- package/lib/api/routes-actions.js +239 -0
- package/lib/api/routes-lifecycle.d.ts +9 -0
- package/lib/api/routes-lifecycle.js +126 -0
- package/lib/api/routes-overview.d.ts +11 -0
- package/lib/api/routes-overview.js +227 -0
- package/lib/api/routes-proxy.d.ts +18 -0
- package/lib/api/routes-proxy.js +63 -0
- package/lib/api/routes.d.ts +16 -6
- package/lib/api/routes.js +14 -504
- package/lib/client.js +785 -90
- package/lib/commands/gh.js +11 -2
- package/lib/executor.d.ts +17 -0
- package/lib/executor.js +146 -8
- package/lib/main.d.ts +1 -0
- package/lib/main.js +49 -9
- package/lib/proxy.d.ts +87 -0
- package/lib/proxy.js +275 -0
- package/lib/renderers/markdown.d.ts +29 -0
- package/lib/renderers/markdown.js +520 -0
- package/lib/tools/api.d.ts +4 -0
- package/lib/tools/api.js +14 -4
- package/lib/tools/help.d.ts +31 -0
- package/lib/tools/help.js +224 -0
- package/lib/tools/image-utils.d.ts +79 -0
- package/lib/tools/image-utils.js +247 -0
- package/lib/tools/issue.d.ts +40 -4
- package/lib/tools/issue.js +167 -19
- package/lib/tools/pr.d.ts +29 -4
- package/lib/tools/pr.js +144 -18
- package/lib/tools/release.d.ts +89 -0
- package/lib/tools/release.js +219 -0
- package/lib/tools/repo.d.ts +24 -4
- package/lib/tools/repo.js +114 -14
- package/lib/tools/run.d.ts +22 -1
- package/lib/tools/run.js +74 -14
- package/lib/tools/secret.d.ts +60 -0
- package/lib/tools/secret.js +175 -0
- package/lib/tools/skill.d.ts +63 -0
- package/lib/tools/skill.js +146 -0
- package/lib/types.d.ts +24 -1
- package/lib/update-settings.d.ts +18 -0
- package/lib/update-settings.js +60 -0
- package/lib/updater.d.ts +40 -1
- package/lib/updater.js +126 -9
- package/lib/upgrade-manager.d.ts +74 -1
- package/lib/upgrade-manager.js +356 -46
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +3 -2
- package/lib/client/icons.d.ts +0 -13
- package/lib/client/icons.js +0 -41
- package/lib/client/index.d.ts +0 -3
- package/lib/client/index.js +0 -36
- package/lib/client/panel.d.ts +0 -1
- package/lib/client/panel.js +0 -102
- package/lib/client/style.d.ts +0 -1
- package/lib/client/style.js +0 -555
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { mapLimit, tryReadWorkspaces, findWorkspacePathBySession, findMostRecentWorkspacePath, hasGitDir } from '../workspace.js';
|
|
2
|
+
import { resolveIssueCategories, calculateIssueStats, basenameSafe, sendJson } from './route-helpers.js';
|
|
3
|
+
/** 探测单个工作区时在途的 gh 进程数上限;libuv 线程池默认 4,留出余量给其他请求 */
|
|
4
|
+
const WORKSPACE_PROBE_CONCURRENCY = 3;
|
|
5
|
+
export function registerOverviewRoutes(deps, executor, cacheMap, globalCache, checker) {
|
|
6
|
+
const { bindRoute } = deps;
|
|
7
|
+
// 1. 获取全局与当前仓库的 GitHub 概览
|
|
8
|
+
bindRoute({
|
|
9
|
+
kind: 'exact',
|
|
10
|
+
path: '/api/github/overview',
|
|
11
|
+
handler: async (req, res) => {
|
|
12
|
+
if (req.method !== 'GET') {
|
|
13
|
+
sendJson(res, 405, { ok: false, message: '仅支持 GET 请求' });
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const url = new URL(req.url || '', 'http://127.0.0.1');
|
|
18
|
+
let cwd = url.searchParams.get('cwd');
|
|
19
|
+
const sessionId = url.searchParams.get('sessionId');
|
|
20
|
+
// 会话 ID → 物理路径,以及「最近活跃工作区」兜底,统一由 workspace 模块提供
|
|
21
|
+
if (!cwd && sessionId) {
|
|
22
|
+
cwd = findWorkspacePathBySession(sessionId) || null;
|
|
23
|
+
}
|
|
24
|
+
if (!cwd) {
|
|
25
|
+
cwd = findMostRecentWorkspacePath() || null;
|
|
26
|
+
}
|
|
27
|
+
if (!cwd) {
|
|
28
|
+
cwd = process.cwd();
|
|
29
|
+
}
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
const cachedData = cacheMap.get(cwd, now);
|
|
32
|
+
if (cachedData) {
|
|
33
|
+
sendJson(res, 200, {
|
|
34
|
+
ok: true,
|
|
35
|
+
data: { ...cachedData, updateInfo: checker.getQuickStatus() },
|
|
36
|
+
fromCache: true,
|
|
37
|
+
cwd,
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const auth = await executor.checkAuth(cwd);
|
|
42
|
+
const repo = await executor.getRepoMetadata(cwd);
|
|
43
|
+
let pullRequests = [];
|
|
44
|
+
let issues = [];
|
|
45
|
+
let runs = [];
|
|
46
|
+
if (repo && auth.loggedIn) {
|
|
47
|
+
// 并发拉取当前文件夹仓库的 PRs、Issues 和 Runs
|
|
48
|
+
const [prsRes, issuesRes, runsRes] = await Promise.all([
|
|
49
|
+
executor.run(['pr', 'list', '--json', 'number,title,state,author,headRefName,baseRefName,isDraft,mergeable,reviewDecision,statusCheckRollup,url,updatedAt', '-L', '10'], { cwd, timeoutMs: 8_000 }),
|
|
50
|
+
executor.run(['issue', 'list', '--json', 'number,title,state,author,labels,assignees,url,updatedAt', '-L', '10'], { cwd, timeoutMs: 8_000 }),
|
|
51
|
+
executor.run(['run', 'list', '--json', 'databaseId,name,status,conclusion,event,headBranch,url,createdAt', '-L', '5'], { cwd, timeoutMs: 8_000 }),
|
|
52
|
+
]);
|
|
53
|
+
if (prsRes.ok && Array.isArray(prsRes.data))
|
|
54
|
+
pullRequests = prsRes.data;
|
|
55
|
+
if (issuesRes.ok && Array.isArray(issuesRes.data)) {
|
|
56
|
+
const currentUser = auth.user;
|
|
57
|
+
const repoOwner = repo?.owner || repo?.nameWithOwner?.split('/')[0];
|
|
58
|
+
issues = issuesRes.data.map((item) => {
|
|
59
|
+
const categories = resolveIssueCategories(item, currentUser, repoOwner);
|
|
60
|
+
return {
|
|
61
|
+
...item,
|
|
62
|
+
categories,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (runsRes.ok && Array.isArray(runsRes.data))
|
|
67
|
+
runs = runsRes.data;
|
|
68
|
+
}
|
|
69
|
+
const issueStats = calculateIssueStats(issues);
|
|
70
|
+
const freshData = {
|
|
71
|
+
auth,
|
|
72
|
+
repo: repo || undefined,
|
|
73
|
+
pullRequests,
|
|
74
|
+
issues,
|
|
75
|
+
issueStats,
|
|
76
|
+
runs,
|
|
77
|
+
lastUpdated: new Date().toISOString(),
|
|
78
|
+
updateInfo: checker.getQuickStatus(),
|
|
79
|
+
};
|
|
80
|
+
cacheMap.set(cwd, freshData, now);
|
|
81
|
+
sendJson(res, 200, { ok: true, data: freshData, fromCache: false, cwd });
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
sendJson(res, 500, { ok: false, error: err.message || '获取 GitHub 概览失败' });
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
// 2. 获取全局视角的驾驶舱概览数据 (不绑定单一项目)
|
|
89
|
+
bindRoute({
|
|
90
|
+
kind: 'exact',
|
|
91
|
+
path: '/api/github/global-overview',
|
|
92
|
+
handler: async (req, res) => {
|
|
93
|
+
if (req.method !== 'GET') {
|
|
94
|
+
sendJson(res, 405, { ok: false, message: '仅支持 GET 请求' });
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// 全局驾驶舱要 spawn 十几次 gh(认证 + 仓库 + PR + Issue + 每个工作区探测),
|
|
98
|
+
// 实测冷启动曾达 18.9 秒。缓存是这里唯一的解药:面板每次挂载都会来取一次。
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
const cachedGlobal = globalCache.get('global', now);
|
|
101
|
+
if (cachedGlobal) {
|
|
102
|
+
sendJson(res, 200, {
|
|
103
|
+
ok: true,
|
|
104
|
+
data: { ...cachedGlobal, updateInfo: checker.getQuickStatus() },
|
|
105
|
+
fromCache: true,
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const auth = await executor.checkAuth();
|
|
111
|
+
let userRepos = [];
|
|
112
|
+
let myPrs = [];
|
|
113
|
+
let myIssues = [];
|
|
114
|
+
let issueStats = { total: 0, reported: 0, assigned: 0, created: 0 };
|
|
115
|
+
let workspaceMatrix = [];
|
|
116
|
+
let workspaceError;
|
|
117
|
+
if (auth.loggedIn) {
|
|
118
|
+
// 并发执行:1. 账号下仓库列表 2. 个人 PRs 3. 三维 Issue 检索(名下仓库用户提单 + 指派待办 + 我创建的)
|
|
119
|
+
// 为什么三路并发搜索:
|
|
120
|
+
// - --owner=@me: 捕获用户/访客在当前用户所有仓库下提的 Issue (如反馈 Bug、Feature Request),解决外部提单看不见的问题
|
|
121
|
+
// - --assignee=@me: 捕获团队成员或自己指派给当前账号的待办任务 (含跨组织/第三方项目)
|
|
122
|
+
// - --author=@me: 捕获当前账号亲自发起的任务与向外部提起的议题
|
|
123
|
+
// 3 个轻量进程与 repo/prs 同步 spawn,经 OS 并发调度实测仅耗时 3 秒出头,完全满足 8 秒超时门限。
|
|
124
|
+
const issueFields = 'number,title,repository,author,assignees,labels,url,updatedAt';
|
|
125
|
+
const queryResults = await Promise.allSettled([
|
|
126
|
+
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 }),
|
|
128
|
+
executor.run(['search', 'issues', '--owner=@me', '--state=open', '--sort=updated', '--limit', '15', '--json', issueFields], { timeoutMs: 8_000 }),
|
|
129
|
+
executor.run(['search', 'issues', '--assignee=@me', '--state=open', '--sort=updated', '--limit', '15', '--json', issueFields], { timeoutMs: 8_000 }),
|
|
130
|
+
executor.run(['search', 'issues', '--author=@me', '--state=open', '--sort=updated', '--limit', '15', '--json', issueFields], { timeoutMs: 8_000 }),
|
|
131
|
+
]);
|
|
132
|
+
const reposRes = queryResults[0].status === 'fulfilled' ? queryResults[0].value : { ok: false };
|
|
133
|
+
const prsRes = queryResults[1].status === 'fulfilled' ? queryResults[1].value : { ok: false };
|
|
134
|
+
const ownerIssuesRes = queryResults[2].status === 'fulfilled' ? queryResults[2].value : { ok: false };
|
|
135
|
+
const assignedIssuesRes = queryResults[3].status === 'fulfilled' ? queryResults[3].value : { ok: false };
|
|
136
|
+
const authorIssuesRes = queryResults[4].status === 'fulfilled' ? queryResults[4].value : { ok: false };
|
|
137
|
+
if (reposRes.ok && Array.isArray(reposRes.data)) {
|
|
138
|
+
userRepos = reposRes.data.map((r) => ({
|
|
139
|
+
name: r.name || '',
|
|
140
|
+
nameWithOwner: r.nameWithOwner || '',
|
|
141
|
+
description: r.description || '',
|
|
142
|
+
defaultBranch: r.defaultBranchRef?.name || 'main',
|
|
143
|
+
isPrivate: Boolean(r.isPrivate),
|
|
144
|
+
stargazerCount: r.stargazerCount || 0,
|
|
145
|
+
updatedAt: r.updatedAt || '',
|
|
146
|
+
url: r.url || `https://github.com/${r.nameWithOwner}`,
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
if (prsRes.ok && Array.isArray(prsRes.data)) {
|
|
150
|
+
myPrs = prsRes.data;
|
|
151
|
+
}
|
|
152
|
+
// 多源 Issues 聚合、按 URL 唯一去重并排序
|
|
153
|
+
const issueMap = new Map();
|
|
154
|
+
const collectIssues = (res) => {
|
|
155
|
+
if (res.ok && Array.isArray(res.data)) {
|
|
156
|
+
for (const item of res.data) {
|
|
157
|
+
if (item.url && !issueMap.has(item.url)) {
|
|
158
|
+
issueMap.set(item.url, item);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
collectIssues(ownerIssuesRes);
|
|
164
|
+
collectIssues(assignedIssuesRes);
|
|
165
|
+
collectIssues(authorIssuesRes);
|
|
166
|
+
const rawList = Array.from(issueMap.values());
|
|
167
|
+
// 统一按最后更新时间降序排列
|
|
168
|
+
rawList.sort((a, b) => new Date(b.updatedAt || 0).getTime() - new Date(a.updatedAt || 0).getTime());
|
|
169
|
+
const currentUser = auth.user;
|
|
170
|
+
myIssues = rawList.map((raw) => {
|
|
171
|
+
const categories = resolveIssueCategories(raw, currentUser);
|
|
172
|
+
return {
|
|
173
|
+
number: raw.number,
|
|
174
|
+
title: raw.title || '',
|
|
175
|
+
repository: raw.repository || { nameWithOwner: '' },
|
|
176
|
+
author: raw.author ? { login: raw.author.login } : undefined,
|
|
177
|
+
assignees: Array.isArray(raw.assignees) ? raw.assignees.map((a) => ({ login: a.login })) : [],
|
|
178
|
+
labels: Array.isArray(raw.labels) ? raw.labels.map((l) => ({ name: l.name, color: l.color })) : [],
|
|
179
|
+
url: raw.url || '',
|
|
180
|
+
updatedAt: raw.updatedAt || '',
|
|
181
|
+
state: raw.state || 'OPEN',
|
|
182
|
+
categories,
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
issueStats = calculateIssueStats(myIssues);
|
|
186
|
+
}
|
|
187
|
+
// 解析本地所有工作区与 GitHub 关联矩阵
|
|
188
|
+
const wsRead = tryReadWorkspaces();
|
|
189
|
+
workspaceError = wsRead.error;
|
|
190
|
+
if (!workspaceError) {
|
|
191
|
+
const wsEntries = wsRead.workspaces.filter((ws) => ws.path);
|
|
192
|
+
// 有界并发探测:每个工作区最多 spawn 2 个 gh 进程,无上限并发会让它们全挤进
|
|
193
|
+
// libuv 默认 4 线程的队列里排队,延迟随工作区数量线性劣化。
|
|
194
|
+
// 这里刻意只用本地 .git/config 识别身份、不发网络请求——全局矩阵只需要「属于哪个仓库」,
|
|
195
|
+
// 每次网络往返都要秒级,5 个工作区就足以把该端点拖到 20 秒。
|
|
196
|
+
workspaceMatrix = await mapLimit(wsEntries, WORKSPACE_PROBE_CONCURRENCY, async (ws) => {
|
|
197
|
+
const hasGit = hasGitDir(ws.path);
|
|
198
|
+
return {
|
|
199
|
+
id: ws.id,
|
|
200
|
+
title: ws.title || basenameSafe(ws.path),
|
|
201
|
+
path: ws.path,
|
|
202
|
+
hasGit,
|
|
203
|
+
repo: hasGit ? executor.getRepoIdentityFromLocal(ws.path) || undefined : undefined,
|
|
204
|
+
sessionCount: ws.sessionIds.length,
|
|
205
|
+
};
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
const globalData = {
|
|
209
|
+
auth,
|
|
210
|
+
userRepos,
|
|
211
|
+
workspaceMatrix,
|
|
212
|
+
myPrs,
|
|
213
|
+
myIssues,
|
|
214
|
+
issueStats,
|
|
215
|
+
lastUpdated: new Date().toISOString(),
|
|
216
|
+
updateInfo: checker.getQuickStatus(),
|
|
217
|
+
...(workspaceError ? { workspaceError } : {}),
|
|
218
|
+
};
|
|
219
|
+
globalCache.set('global', globalData, now);
|
|
220
|
+
sendJson(res, 200, { ok: true, data: globalData, fromCache: false });
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
sendJson(res, 500, { ok: false, error: err.message || '获取全局驾驶舱数据失败' });
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 网络代理设置路由(驾驶舱「网络代理」设置分区的后端入口)。
|
|
3
|
+
* 为什么独立于 Cordis Config:代理设置变更若走 Loader 会触发插件全量 reload
|
|
4
|
+
* (工具注销重注册、面板断流),而代理是高频试错型设置,必须保存即生效。
|
|
5
|
+
*/
|
|
6
|
+
import type { UpdateChecker } from '../updater.js';
|
|
7
|
+
import { type RouteDeps } from './route-helpers.js';
|
|
8
|
+
/** ProxyManager 的路由侧最小接口:避免路由层直接依赖实现细节,测试可注入 mock */
|
|
9
|
+
export interface ProxyRouteManager {
|
|
10
|
+
save: (input: any) => {
|
|
11
|
+
ok: boolean;
|
|
12
|
+
error?: string;
|
|
13
|
+
state: any;
|
|
14
|
+
};
|
|
15
|
+
probe: () => Promise<any>;
|
|
16
|
+
snapshot: () => any;
|
|
17
|
+
}
|
|
18
|
+
export declare function registerProxyRoutes(deps: RouteDeps, checker: UpdateChecker, proxyManager?: ProxyRouteManager): void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { sendJson, readJsonBody } from './route-helpers.js';
|
|
2
|
+
export function registerProxyRoutes(deps, checker, proxyManager) {
|
|
3
|
+
const { bindRoute } = deps;
|
|
4
|
+
// 1. 代理配置:GET 读取状态 / POST 保存并立即生效(写 proxy.json + 重应用 dispatcher,零插件重载)
|
|
5
|
+
bindRoute({
|
|
6
|
+
kind: 'exact',
|
|
7
|
+
path: '/api/github/proxy',
|
|
8
|
+
handler: async (req, res) => {
|
|
9
|
+
if (req.method === 'GET') {
|
|
10
|
+
if (!proxyManager) {
|
|
11
|
+
sendJson(res, 200, { ok: true, state: null, message: '当前运行环境未启用代理管理器' });
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
sendJson(res, 200, { ok: true, state: proxyManager.snapshot() });
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (req.method !== 'POST') {
|
|
18
|
+
sendJson(res, 405, { ok: false, message: '仅支持 GET / POST 请求' });
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!proxyManager) {
|
|
22
|
+
sendJson(res, 503, { ok: false, message: '当前运行环境未启用代理管理器' });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const body = await readJsonBody(req);
|
|
27
|
+
const result = proxyManager.save(body || {});
|
|
28
|
+
if (!result.ok) {
|
|
29
|
+
sendJson(res, 400, { ok: false, message: result.error, state: result.state });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// 配置变更后同步刷新 updater 的 fetch dispatcher(npm 探测链路)
|
|
33
|
+
checker.applyProxy(proxyManager);
|
|
34
|
+
sendJson(res, 200, { ok: true, state: result.state });
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
sendJson(res, 500, { ok: false, message: err.message || '代理配置保存失败' });
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
// 2. 手动触发连通性探测(2.5s 超时,结果持久化到 lastProbe 供 UI 展示)
|
|
42
|
+
bindRoute({
|
|
43
|
+
kind: 'exact',
|
|
44
|
+
path: '/api/github/proxy/probe',
|
|
45
|
+
handler: async (req, res) => {
|
|
46
|
+
if (req.method !== 'POST') {
|
|
47
|
+
sendJson(res, 405, { ok: false, message: '仅支持 POST 请求' });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (!proxyManager) {
|
|
51
|
+
sendJson(res, 503, { ok: false, message: '当前运行环境未启用代理管理器' });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const probe = await proxyManager.probe();
|
|
56
|
+
sendJson(res, 200, { ok: true, probe, state: proxyManager.snapshot() });
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
sendJson(res, 500, { ok: false, message: err.message || '代理探测失败' });
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
}
|
package/lib/api/routes.d.ts
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API 路由注册器(纯装配骨架)。
|
|
3
|
+
*
|
|
4
|
+
* 架构说明:具体 handler 按领域拆分在 routes-overview / routes-actions /
|
|
5
|
+
* routes-lifecycle / routes-proxy 四个分组文件中,本文件只负责:
|
|
6
|
+
* 1. 解析 ctx/webServer 与可选依赖(缺省时给默认实现,保持向后兼容);
|
|
7
|
+
* 2. 构造共享闭包(缓存实例 + bindRoute 生命周期绑定);
|
|
8
|
+
* 3. 按固定顺序装配各分组。
|
|
9
|
+
*
|
|
10
|
+
* 为什么 bindRoute 必须在这里定义:它闭包引用 ctx(effect 纳管)与 webServer
|
|
11
|
+
* (自愈清理),分组文件只消费注入的 RouteDeps,不感知 Cordis 上下文。
|
|
12
|
+
*/
|
|
1
13
|
import type { GhExecutor } from '../executor.js';
|
|
2
14
|
import { UpdateChecker } from '../updater.js';
|
|
3
15
|
import { UpgradeManager } from '../upgrade-manager.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export declare function globalCacheTtlMs(cacheTtlMs: number): number;
|
|
9
|
-
export declare function registerApiRoutes(ctxOrWebServer: any, executor: GhExecutor, workspaceRegistry?: any, cacheTtlMs?: number, updateChecker?: UpdateChecker, upgradeManager?: UpgradeManager): void;
|
|
16
|
+
import { globalCacheTtlMs } from './route-helpers.js';
|
|
17
|
+
import { type ProxyRouteManager } from './routes-proxy.js';
|
|
18
|
+
export { globalCacheTtlMs };
|
|
19
|
+
export declare function registerApiRoutes(ctxOrWebServer: any, executor: GhExecutor, workspaceRegistry?: any, cacheTtlMs?: number, updateChecker?: UpdateChecker, upgradeManager?: UpgradeManager, proxyManager?: ProxyRouteManager): void;
|