@morehao/dsh-github-trending 0.0.1 → 0.1.2
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/CHANGELOG.md +61 -1
- package/README.md +115 -9
- package/client.js +1408 -0
- package/contract/CONTRACT.sha256 +10 -0
- package/contract/UPSTREAM.json +37 -0
- package/contract/fixtures/digest-degraded.json +39 -0
- package/contract/fixtures/digest-empty-lang.json +39 -0
- package/contract/fixtures/digest-normal.json +91 -0
- package/contract/schema/api.v1.yaml +70 -0
- package/contract/schema/digest.v1.json +24 -0
- package/contract/schema/ipc.v1.json +103 -0
- package/contract/schema/model.v1.json +46 -0
- package/cordis.patch.yml +3 -0
- package/lib/chunk-RXYA5WFW.js +2909 -0
- package/lib/chunk-XLIFTAVL.js +117 -0
- package/lib/exec-33EQXGUA.js +8 -0
- package/lib/index.d.ts +20 -9
- package/lib/index.js +82 -4
- package/lib/internal.d.ts +1443 -0
- package/lib/internal.js +48 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +46 -7
- package/lib/index.js.map +0 -1
|
@@ -0,0 +1,1443 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 由 scripts/gen-ipc-types.mjs 从 contract/schema/ipc.v1.json 生成,**不要手改**。
|
|
5
|
+
* 上游:https://github.com/morehao/trendradar.git@d3bf720a869732e7a2ee04fa39d32dd50868fd61
|
|
6
|
+
* aggregate:eb7f1ac9e117a709d15d87de89cf30e309c479e62dfa3d320cb8f154d3f1dc1e
|
|
7
|
+
* 重新生成:npm run gen:ipc
|
|
8
|
+
*/
|
|
9
|
+
type ErrorCode = "INTERNAL" | "CONFIG_INVALID" | "PAYLOAD_TOO_LARGE" | "FETCH_FAILED" | "FETCH_RATE_LIMITED" | "PARSE_FAILED" | "MODEL_UNAUTHORIZED" | "MODEL_RATE_LIMITED" | "MODEL_TIMEOUT" | "MODEL_FAILED" | "MODEL_BAD_OUTPUT" | "GIT_NOT_INSTALLED" | "REPO_NOT_GIT" | "REPO_DIRTY" | "GIT_OPERATION_FAILED" | "PR_FAILED" | "NOT_MERGEABLE";
|
|
10
|
+
interface ErrorInfo {
|
|
11
|
+
code: ErrorCode;
|
|
12
|
+
message: string;
|
|
13
|
+
retriable: boolean;
|
|
14
|
+
details?: Record<string, unknown>;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
interface FileArtifact {
|
|
18
|
+
path: string;
|
|
19
|
+
bytes: number;
|
|
20
|
+
sha256: string;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
interface RunRequest {
|
|
24
|
+
ipcSchema: 1;
|
|
25
|
+
command: "run" | "serve" | "config" | "version";
|
|
26
|
+
configPath?: string;
|
|
27
|
+
date?: string;
|
|
28
|
+
dryRun?: boolean;
|
|
29
|
+
outputDir?: string;
|
|
30
|
+
}
|
|
31
|
+
interface RunResult {
|
|
32
|
+
ipcSchema: 1;
|
|
33
|
+
ok: boolean;
|
|
34
|
+
command: "run" | "serve" | "config" | "version";
|
|
35
|
+
startedAt: string;
|
|
36
|
+
finishedAt: string;
|
|
37
|
+
skipped: boolean;
|
|
38
|
+
files: FileArtifact[];
|
|
39
|
+
error?: ErrorInfo;
|
|
40
|
+
warnings?: string[];
|
|
41
|
+
[key: string]: unknown;
|
|
42
|
+
}
|
|
43
|
+
interface StateRun {
|
|
44
|
+
date: string;
|
|
45
|
+
contentHash: string;
|
|
46
|
+
runAt: string;
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
}
|
|
49
|
+
interface State {
|
|
50
|
+
ipcSchema: 1;
|
|
51
|
+
lastRun?: StateRun;
|
|
52
|
+
[key: string]: unknown;
|
|
53
|
+
}
|
|
54
|
+
declare const IPC_SCHEMA_VERSION: 1;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 错误码:核心码(`ipc.v1` 的 17 个)+ 插件自己的码。
|
|
58
|
+
*
|
|
59
|
+
* 核心当前只在 stderr 打 `error: <CODE>: <message>`,模型/抓取的失败甚至没有码,
|
|
60
|
+
* 所以这里承担两件事:
|
|
61
|
+
* 1. 从 stderr 里**优先**取出核心自己的码(有码就用码,不改写);
|
|
62
|
+
* 2. 没有码时按稳定的文本特征归类,归类结果会标注 `inferred: true`,
|
|
63
|
+
* 让界面能区分「核心说的」与「插件猜的」。
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
/** 插件在核心之外新增的码。前缀统一避免与核心码冲突。 */
|
|
67
|
+
declare const PLUGIN_CODES: readonly ["CORE_UNAVAILABLE", "CORE_INCOMPATIBLE", "CORE_SPAWN_FAILED", "CORE_TIMEOUT", "CORE_CANCELLED", "CORE_CONFIG_CHANNEL_FAILED", "CORE_NOT_DOWNLOADED", "CORE_CHECKSUM_MISMATCH", "IPC_INVALID", "MODEL_KEY_MISSING", "MODEL_NOT_FOUND", "MODEL_PROVIDER_UNSUPPORTED", "GITHUB_AUTH", "PUSH_FAILED", "REPO_DIRTY"];
|
|
68
|
+
type PluginCode = (typeof PLUGIN_CODES)[number];
|
|
69
|
+
type AnyCode = ErrorCode | PluginCode;
|
|
70
|
+
interface ClassifiedError {
|
|
71
|
+
code: AnyCode;
|
|
72
|
+
message: string;
|
|
73
|
+
retriable: boolean;
|
|
74
|
+
/** true = 插件按文本推断出来的码,不是核心明确返回的。 */
|
|
75
|
+
inferred: boolean;
|
|
76
|
+
}
|
|
77
|
+
declare function isRetriable(code: string): boolean;
|
|
78
|
+
/** 错误码 → 界面落点。UI 用这个决定红字出现在哪个区块。 */
|
|
79
|
+
type ErrorArea = 'core' | 'model' | 'repo' | 'auth' | 'run';
|
|
80
|
+
declare function areaOf(code: string): ErrorArea;
|
|
81
|
+
/** 每种码一句「下一步怎么做」,避免界面只给码不给路。 */
|
|
82
|
+
declare function hintOf(code: string): string;
|
|
83
|
+
/**
|
|
84
|
+
* 从核心的 stderr 里解出一个结构化错误。
|
|
85
|
+
*
|
|
86
|
+
* 优先级:`error: <CODE>: ...` 的显式码 > 文本归类 > INTERNAL。
|
|
87
|
+
* message 只取最后一条非空行(核心把根因打在最外层,前面的行多是上下文)。
|
|
88
|
+
*/
|
|
89
|
+
declare function classifyStderr(stderr: string): ClassifiedError;
|
|
90
|
+
/**
|
|
91
|
+
* 脱敏:先把调用方已知的明文密钥逐个替换,再按形态兜一层。
|
|
92
|
+
* 所有进日志/返回给前端的 stderr 都必须过这里(AC-P-04 的第一道闸)。
|
|
93
|
+
*/
|
|
94
|
+
declare function redact(input: string, secrets?: Array<string | undefined>): string;
|
|
95
|
+
|
|
96
|
+
type errors_AnyCode = AnyCode;
|
|
97
|
+
type errors_ClassifiedError = ClassifiedError;
|
|
98
|
+
type errors_ErrorArea = ErrorArea;
|
|
99
|
+
declare const errors_PLUGIN_CODES: typeof PLUGIN_CODES;
|
|
100
|
+
type errors_PluginCode = PluginCode;
|
|
101
|
+
declare const errors_areaOf: typeof areaOf;
|
|
102
|
+
declare const errors_classifyStderr: typeof classifyStderr;
|
|
103
|
+
declare const errors_hintOf: typeof hintOf;
|
|
104
|
+
declare const errors_isRetriable: typeof isRetriable;
|
|
105
|
+
declare const errors_redact: typeof redact;
|
|
106
|
+
declare namespace errors {
|
|
107
|
+
export { type errors_AnyCode as AnyCode, type errors_ClassifiedError as ClassifiedError, type errors_ErrorArea as ErrorArea, errors_PLUGIN_CODES as PLUGIN_CODES, type errors_PluginCode as PluginCode, errors_areaOf as areaOf, errors_classifyStderr as classifyStderr, errors_hintOf as hintOf, errors_isRetriable as isRetriable, errors_redact as redact };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 契约类型与运行时守卫。
|
|
112
|
+
*
|
|
113
|
+
* 类型来自 `contract/schema/ipc.v1.json` 的生成物(`ipc.gen.ts`);本文件只放
|
|
114
|
+
* 契约没有、但插件必须理解的东西:核心 `version --json` 的握手形状、核心 `run --json`
|
|
115
|
+
* 的输出形状,以及把两种结果形状归一化成 `RunOutcome` 的解析器。
|
|
116
|
+
*
|
|
117
|
+
* 为什么同时接受两种形状:`contract/schema/ipc.v1.json` 定义的是 `RunResult`
|
|
118
|
+
* (`ok`/`startedAt`/`error.code`),而当前核心的 `run --json` 输出的是一份更小的
|
|
119
|
+
* `runOutput`(`files`/`skipped`/`branch`/`prUrl`/`digest.contentHash`),错误只走
|
|
120
|
+
* stderr 文本。核心补上信封后,`parseRunResult` 无需改动即可接住。
|
|
121
|
+
*/
|
|
122
|
+
|
|
123
|
+
/** 插件能接受的 digest 契约版本(与核心 `version --json` 的 digestSchema 比对)。 */
|
|
124
|
+
declare const SUPPORTED_DIGEST_SCHEMA = 1;
|
|
125
|
+
/** 核心 `version --json` 的输出。 */
|
|
126
|
+
interface VersionInfo {
|
|
127
|
+
version: string;
|
|
128
|
+
commit?: string;
|
|
129
|
+
ipcSchema: number;
|
|
130
|
+
digestSchema: number;
|
|
131
|
+
supportedProviders?: string[];
|
|
132
|
+
}
|
|
133
|
+
/** 插件侧的错误信息:`code` 可能是核心码,也可能是插件码(`CORE_*` 等)。 */
|
|
134
|
+
interface RunError {
|
|
135
|
+
code: AnyCode;
|
|
136
|
+
message: string;
|
|
137
|
+
retriable: boolean;
|
|
138
|
+
details?: Record<string, unknown>;
|
|
139
|
+
}
|
|
140
|
+
/** 归一化后的一次运行结果:状态、历史、工具返回值都用它。 */
|
|
141
|
+
interface RunOutcome {
|
|
142
|
+
ok: boolean;
|
|
143
|
+
skipped: boolean;
|
|
144
|
+
dryRun: boolean;
|
|
145
|
+
files: FileArtifact[];
|
|
146
|
+
contentHash?: string;
|
|
147
|
+
branch?: string;
|
|
148
|
+
commit?: string;
|
|
149
|
+
prUrl?: string;
|
|
150
|
+
error?: RunError;
|
|
151
|
+
warnings: string[];
|
|
152
|
+
startedAt: string;
|
|
153
|
+
finishedAt: string;
|
|
154
|
+
durationMs: number;
|
|
155
|
+
coreVersion: string;
|
|
156
|
+
}
|
|
157
|
+
declare class IpcError extends Error {
|
|
158
|
+
readonly code: string;
|
|
159
|
+
constructor(code: string, message: string);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* 解析「单个 JSON 对象」。核心的 stdout 纪律是只允许一个信封,因此:
|
|
163
|
+
* 空输出、多文档、非对象一律拒绝,不做「取第一段 JSON」这种猜测。
|
|
164
|
+
*/
|
|
165
|
+
declare function parseJsonObject(text: string): Record<string, unknown>;
|
|
166
|
+
declare function isVersionInfo(value: unknown): value is VersionInfo;
|
|
167
|
+
declare function parseVersionInfo(text: string): VersionInfo;
|
|
168
|
+
interface ParseRunOptions {
|
|
169
|
+
coreVersion: string;
|
|
170
|
+
startedAt: string;
|
|
171
|
+
finishedAt: string;
|
|
172
|
+
durationMs: number;
|
|
173
|
+
dryRun: boolean;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* 把核心 `run --json` 的 stdout 归一化成 `RunOutcome`。
|
|
177
|
+
*
|
|
178
|
+
* 两种形状的判别:有 `ipcSchema` 且 `command === 'run'` 就是契约 `RunResult`;
|
|
179
|
+
* 否则按当前核心的 `runOutput` 处理。两者都不像就直接 `IPC_INVALID`,
|
|
180
|
+
* 绝不「猜字段」——结果信封读错会把失败当成功写进状态。
|
|
181
|
+
*/
|
|
182
|
+
declare function parseRunResult(text: string, options: ParseRunOptions): RunOutcome;
|
|
183
|
+
|
|
184
|
+
type ipc_ErrorCode = ErrorCode;
|
|
185
|
+
type ipc_ErrorInfo = ErrorInfo;
|
|
186
|
+
type ipc_FileArtifact = FileArtifact;
|
|
187
|
+
declare const ipc_IPC_SCHEMA_VERSION: typeof IPC_SCHEMA_VERSION;
|
|
188
|
+
type ipc_IpcError = IpcError;
|
|
189
|
+
declare const ipc_IpcError: typeof IpcError;
|
|
190
|
+
type ipc_ParseRunOptions = ParseRunOptions;
|
|
191
|
+
type ipc_RunError = RunError;
|
|
192
|
+
type ipc_RunOutcome = RunOutcome;
|
|
193
|
+
type ipc_RunRequest = RunRequest;
|
|
194
|
+
type ipc_RunResult = RunResult;
|
|
195
|
+
declare const ipc_SUPPORTED_DIGEST_SCHEMA: typeof SUPPORTED_DIGEST_SCHEMA;
|
|
196
|
+
type ipc_State = State;
|
|
197
|
+
type ipc_StateRun = StateRun;
|
|
198
|
+
type ipc_VersionInfo = VersionInfo;
|
|
199
|
+
declare const ipc_isVersionInfo: typeof isVersionInfo;
|
|
200
|
+
declare const ipc_parseJsonObject: typeof parseJsonObject;
|
|
201
|
+
declare const ipc_parseRunResult: typeof parseRunResult;
|
|
202
|
+
declare const ipc_parseVersionInfo: typeof parseVersionInfo;
|
|
203
|
+
declare namespace ipc {
|
|
204
|
+
export { type ipc_ErrorCode as ErrorCode, type ipc_ErrorInfo as ErrorInfo, type ipc_FileArtifact as FileArtifact, ipc_IPC_SCHEMA_VERSION as IPC_SCHEMA_VERSION, ipc_IpcError as IpcError, type ipc_ParseRunOptions as ParseRunOptions, type ipc_RunError as RunError, type ipc_RunOutcome as RunOutcome, type ipc_RunRequest as RunRequest, type ipc_RunResult as RunResult, ipc_SUPPORTED_DIGEST_SCHEMA as SUPPORTED_DIGEST_SCHEMA, type ipc_State as State, type ipc_StateRun as StateRun, type ipc_VersionInfo as VersionInfo, ipc_isVersionInfo as isVersionInfo, ipc_parseJsonObject as parseJsonObject, ipc_parseRunResult as parseRunResult, ipc_parseVersionInfo as parseVersionInfo };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
type Provider = string;
|
|
208
|
+
type CommitMode = 'branch' | 'direct';
|
|
209
|
+
type AuthMode = 'device' | 'pat' | 'gh';
|
|
210
|
+
type Since = 'daily' | 'weekly';
|
|
211
|
+
interface ModelSettings {
|
|
212
|
+
provider: Provider;
|
|
213
|
+
/** `direct` = 密钥经配置通道直传核心;`proxy` = 宿主 provider 无可导出密钥,走回环代理。 */
|
|
214
|
+
mode: 'direct' | 'proxy';
|
|
215
|
+
/** `mode=proxy` 时转发给哪个宿主 provider 路由(核心不认这个值)。 */
|
|
216
|
+
hostProvider: string;
|
|
217
|
+
baseURL: string;
|
|
218
|
+
model: string;
|
|
219
|
+
/** `ctx.credentials` 的引用名;密钥本身不写进 settings.json。 */
|
|
220
|
+
apiKeyRef: string;
|
|
221
|
+
temperature: number;
|
|
222
|
+
maxTokens: number;
|
|
223
|
+
allowDegraded: boolean;
|
|
224
|
+
}
|
|
225
|
+
interface RepoSettings {
|
|
226
|
+
path: string;
|
|
227
|
+
baseBranch: string;
|
|
228
|
+
remote: string;
|
|
229
|
+
commitMode: CommitMode;
|
|
230
|
+
authorName: string;
|
|
231
|
+
authorEmail: string;
|
|
232
|
+
}
|
|
233
|
+
interface PRSettings {
|
|
234
|
+
enabled: boolean;
|
|
235
|
+
titleTemplate: string;
|
|
236
|
+
autoMerge: boolean;
|
|
237
|
+
labels: string[];
|
|
238
|
+
}
|
|
239
|
+
interface GithubSettings {
|
|
240
|
+
authMode: AuthMode;
|
|
241
|
+
tokenRef: string;
|
|
242
|
+
}
|
|
243
|
+
interface TrendingSettings {
|
|
244
|
+
since: Since;
|
|
245
|
+
languages: string[];
|
|
246
|
+
topN: number;
|
|
247
|
+
}
|
|
248
|
+
interface OutputSettings {
|
|
249
|
+
dir: string;
|
|
250
|
+
}
|
|
251
|
+
interface ScheduleSettings {
|
|
252
|
+
enabled: boolean;
|
|
253
|
+
/** `HH:MM:SS`(本地墙钟,按 timezone 解释)。 */
|
|
254
|
+
time: string;
|
|
255
|
+
timezone: string;
|
|
256
|
+
}
|
|
257
|
+
interface Settings {
|
|
258
|
+
model: ModelSettings;
|
|
259
|
+
repo: RepoSettings;
|
|
260
|
+
pr: PRSettings;
|
|
261
|
+
github: GithubSettings;
|
|
262
|
+
trending: TrendingSettings;
|
|
263
|
+
output: OutputSettings;
|
|
264
|
+
schedule: ScheduleSettings;
|
|
265
|
+
/** 核心二进制覆盖;只在开发/排障时用,对应 TRENDING_DIGEST_CORE。 */
|
|
266
|
+
corePath: string;
|
|
267
|
+
/** 缓存缺失时是否自动从 Release 下载核心(首次运行需要联网)。 */
|
|
268
|
+
coreAutoDownload: boolean;
|
|
269
|
+
}
|
|
270
|
+
declare const DEFAULT_SETTINGS: Settings;
|
|
271
|
+
/** 核心支持的 provider 默认端点(空字符串 = 必须由用户填)。 */
|
|
272
|
+
declare const PROVIDER_BASE_URLS: Record<string, string>;
|
|
273
|
+
declare const CORE_PROVIDERS: readonly ["deepseek", "openai-compatible"];
|
|
274
|
+
/**
|
|
275
|
+
* 把任意来源的对象(磁盘上的旧版本、HTTP 请求体、CLI 导入)收敛成完整设置。
|
|
276
|
+
* 未知字段一律丢弃:settings.json 只有以下形状,避免旧版本字段悄悄生效。
|
|
277
|
+
*/
|
|
278
|
+
declare function normalizeSettings(input: unknown): Settings;
|
|
279
|
+
interface Problem {
|
|
280
|
+
field: string;
|
|
281
|
+
code: string;
|
|
282
|
+
message: string;
|
|
283
|
+
}
|
|
284
|
+
declare function isValidTimezone(timezone: string): boolean;
|
|
285
|
+
/**
|
|
286
|
+
* 设置校验。`providers` 来自核心 `version --json` 的 `supportedProviders`
|
|
287
|
+
* (拿不到时按 CORE_PROVIDERS 兜底)——provider 不在核心能力里必须当场拦下,
|
|
288
|
+
* 否则会变成运行时一个莫名其妙的模型错误。
|
|
289
|
+
*/
|
|
290
|
+
declare function validateSettings(settings: Settings, providers?: readonly string[]): Problem[];
|
|
291
|
+
declare function effectiveBaseURL(model: ModelSettings): string;
|
|
292
|
+
/** 核心 `config.Config` 的对象形状(随后序列化成 YAML)。 */
|
|
293
|
+
interface CoreConfig {
|
|
294
|
+
model: {
|
|
295
|
+
provider: string;
|
|
296
|
+
name: string;
|
|
297
|
+
baseURL: string;
|
|
298
|
+
apiKey: string;
|
|
299
|
+
temperature: number;
|
|
300
|
+
maxTokens: number;
|
|
301
|
+
allowDegraded: boolean;
|
|
302
|
+
};
|
|
303
|
+
repo: {
|
|
304
|
+
path: string;
|
|
305
|
+
remote: string;
|
|
306
|
+
baseBranch: string;
|
|
307
|
+
authorName?: string;
|
|
308
|
+
authorEmail?: string;
|
|
309
|
+
};
|
|
310
|
+
pr: {
|
|
311
|
+
enabled: boolean;
|
|
312
|
+
titleTemplate: string;
|
|
313
|
+
labels: string[];
|
|
314
|
+
autoMerge: boolean;
|
|
315
|
+
};
|
|
316
|
+
trending: {
|
|
317
|
+
languages: string[];
|
|
318
|
+
since: string;
|
|
319
|
+
perLanguage: number;
|
|
320
|
+
};
|
|
321
|
+
output: {
|
|
322
|
+
dir: string;
|
|
323
|
+
branchPrefix: string;
|
|
324
|
+
retentionDays: number;
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* 生成核心配置。`apiKey` 单独传入:它只能来自宿主凭据或用户当次输入,
|
|
329
|
+
* 绝不来自 settings.json。
|
|
330
|
+
*/
|
|
331
|
+
declare function toCoreConfig(settings: Settings, apiKey: string, baseURLOverride?: string): CoreConfig;
|
|
332
|
+
/**
|
|
333
|
+
* 极简 YAML 序列化:只覆盖「对象/数组/字符串/数字/布尔」。
|
|
334
|
+
* 字符串一律用 JSON 双引号形式——JSON 字符串是合法 YAML 标量,且能避免
|
|
335
|
+
* `: `、`#`、`- ` 之类的歧义;密钥因此不需要额外转义规则。
|
|
336
|
+
*/
|
|
337
|
+
declare function toYaml(value: unknown, depth?: number): string;
|
|
338
|
+
|
|
339
|
+
type config_AuthMode = AuthMode;
|
|
340
|
+
declare const config_CORE_PROVIDERS: typeof CORE_PROVIDERS;
|
|
341
|
+
type config_CommitMode = CommitMode;
|
|
342
|
+
type config_CoreConfig = CoreConfig;
|
|
343
|
+
declare const config_DEFAULT_SETTINGS: typeof DEFAULT_SETTINGS;
|
|
344
|
+
type config_GithubSettings = GithubSettings;
|
|
345
|
+
type config_ModelSettings = ModelSettings;
|
|
346
|
+
type config_OutputSettings = OutputSettings;
|
|
347
|
+
declare const config_PROVIDER_BASE_URLS: typeof PROVIDER_BASE_URLS;
|
|
348
|
+
type config_PRSettings = PRSettings;
|
|
349
|
+
type config_Problem = Problem;
|
|
350
|
+
type config_Provider = Provider;
|
|
351
|
+
type config_RepoSettings = RepoSettings;
|
|
352
|
+
type config_ScheduleSettings = ScheduleSettings;
|
|
353
|
+
type config_Settings = Settings;
|
|
354
|
+
type config_Since = Since;
|
|
355
|
+
type config_TrendingSettings = TrendingSettings;
|
|
356
|
+
declare const config_effectiveBaseURL: typeof effectiveBaseURL;
|
|
357
|
+
declare const config_isValidTimezone: typeof isValidTimezone;
|
|
358
|
+
declare const config_normalizeSettings: typeof normalizeSettings;
|
|
359
|
+
declare const config_toCoreConfig: typeof toCoreConfig;
|
|
360
|
+
declare const config_toYaml: typeof toYaml;
|
|
361
|
+
declare const config_validateSettings: typeof validateSettings;
|
|
362
|
+
declare namespace config {
|
|
363
|
+
export { type config_AuthMode as AuthMode, config_CORE_PROVIDERS as CORE_PROVIDERS, type config_CommitMode as CommitMode, type config_CoreConfig as CoreConfig, config_DEFAULT_SETTINGS as DEFAULT_SETTINGS, type config_GithubSettings as GithubSettings, type config_ModelSettings as ModelSettings, type config_OutputSettings as OutputSettings, config_PROVIDER_BASE_URLS as PROVIDER_BASE_URLS, type config_PRSettings as PRSettings, type config_Problem as Problem, type config_Provider as Provider, type config_RepoSettings as RepoSettings, type config_ScheduleSettings as ScheduleSettings, type config_Settings as Settings, type config_Since as Since, type config_TrendingSettings as TrendingSettings, config_effectiveBaseURL as effectiveBaseURL, config_isValidTimezone as isValidTimezone, config_normalizeSettings as normalizeSettings, config_toCoreConfig as toCoreConfig, config_toYaml as toYaml, config_validateSettings as validateSettings };
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
declare const PLUGIN_DIR_NAME = "github-trending";
|
|
367
|
+
declare function homeDir(env?: NodeJS.ProcessEnv): string;
|
|
368
|
+
declare function dshHome(env?: NodeJS.ProcessEnv): string;
|
|
369
|
+
declare function dataDir(env?: NodeJS.ProcessEnv): string;
|
|
370
|
+
declare function runsDir(env?: NodeJS.ProcessEnv): string;
|
|
371
|
+
declare const SETTINGS_FILE = "settings.json";
|
|
372
|
+
declare const STATE_FILE = "state.json";
|
|
373
|
+
declare const HISTORY_FILE = "history.json";
|
|
374
|
+
|
|
375
|
+
declare const paths_HISTORY_FILE: typeof HISTORY_FILE;
|
|
376
|
+
declare const paths_PLUGIN_DIR_NAME: typeof PLUGIN_DIR_NAME;
|
|
377
|
+
declare const paths_SETTINGS_FILE: typeof SETTINGS_FILE;
|
|
378
|
+
declare const paths_STATE_FILE: typeof STATE_FILE;
|
|
379
|
+
declare const paths_dataDir: typeof dataDir;
|
|
380
|
+
declare const paths_dshHome: typeof dshHome;
|
|
381
|
+
declare const paths_homeDir: typeof homeDir;
|
|
382
|
+
declare const paths_runsDir: typeof runsDir;
|
|
383
|
+
declare namespace paths {
|
|
384
|
+
export { paths_HISTORY_FILE as HISTORY_FILE, paths_PLUGIN_DIR_NAME as PLUGIN_DIR_NAME, paths_SETTINGS_FILE as SETTINGS_FILE, paths_STATE_FILE as STATE_FILE, paths_dataDir as dataDir, paths_dshHome as dshHome, paths_homeDir as homeDir, paths_runsDir as runsDir };
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
declare const HISTORY_LIMIT = 30;
|
|
388
|
+
interface DigestIdentity {
|
|
389
|
+
date: string;
|
|
390
|
+
contentHash: string;
|
|
391
|
+
coreVersion: string;
|
|
392
|
+
}
|
|
393
|
+
interface RunRecord {
|
|
394
|
+
id: string;
|
|
395
|
+
at: string;
|
|
396
|
+
kind: 'run' | 'dry-run';
|
|
397
|
+
ok: boolean;
|
|
398
|
+
skipped: boolean;
|
|
399
|
+
/** `null` 表示没有错误。 */
|
|
400
|
+
errorCode?: string;
|
|
401
|
+
errorMessage?: string;
|
|
402
|
+
durationMs: number;
|
|
403
|
+
files: number;
|
|
404
|
+
contentHash?: string;
|
|
405
|
+
branch?: string;
|
|
406
|
+
commit?: string;
|
|
407
|
+
prUrl?: string;
|
|
408
|
+
coreVersion: string;
|
|
409
|
+
model: {
|
|
410
|
+
provider: string;
|
|
411
|
+
model: string;
|
|
412
|
+
};
|
|
413
|
+
languages: string[];
|
|
414
|
+
warnings: string[];
|
|
415
|
+
logFile?: string;
|
|
416
|
+
}
|
|
417
|
+
interface PendingPr {
|
|
418
|
+
url: string;
|
|
419
|
+
createdAt: string;
|
|
420
|
+
}
|
|
421
|
+
interface PluginState {
|
|
422
|
+
lastRunAt?: string;
|
|
423
|
+
lastDigest?: DigestIdentity;
|
|
424
|
+
lastResult?: RunRecord;
|
|
425
|
+
pendingPr?: PendingPr;
|
|
426
|
+
}
|
|
427
|
+
interface HistoryFile {
|
|
428
|
+
records: RunRecord[];
|
|
429
|
+
}
|
|
430
|
+
/** 原子写:同目录临时文件写完再 rename,权限 0600。 */
|
|
431
|
+
declare function writeJsonAtomic(file: string, value: unknown): void;
|
|
432
|
+
interface StoreOptions {
|
|
433
|
+
env?: NodeJS.ProcessEnv;
|
|
434
|
+
/** 直接指定目录,测试用。 */
|
|
435
|
+
dir?: string;
|
|
436
|
+
}
|
|
437
|
+
declare class Store {
|
|
438
|
+
readonly dir: string;
|
|
439
|
+
private readonly env;
|
|
440
|
+
constructor(options?: StoreOptions);
|
|
441
|
+
get settingsPath(): string;
|
|
442
|
+
get statePath(): string;
|
|
443
|
+
get historyPath(): string;
|
|
444
|
+
get logsPath(): string;
|
|
445
|
+
readSettings(): Settings;
|
|
446
|
+
writeSettings(settings: Settings): void;
|
|
447
|
+
readState(): PluginState;
|
|
448
|
+
writeState(state: PluginState): void;
|
|
449
|
+
readHistory(): RunRecord[];
|
|
450
|
+
/** 记录一次运行:历史裁剪到 30 条,state 同步更新。 */
|
|
451
|
+
recordRun(record: RunRecord, next?: Partial<PluginState>): void;
|
|
452
|
+
newLogPath(id: string): string;
|
|
453
|
+
appendLog(file: string, line: string): void;
|
|
454
|
+
hasLog(file: string): boolean;
|
|
455
|
+
readLog(file: string, maxBytes?: number): string;
|
|
456
|
+
}
|
|
457
|
+
/** 运行 id:时间前缀便于按时间排序,随机后缀避免同毫秒撞车。 */
|
|
458
|
+
declare function newRunId(now?: Date): string;
|
|
459
|
+
|
|
460
|
+
type state_DigestIdentity = DigestIdentity;
|
|
461
|
+
declare const state_HISTORY_LIMIT: typeof HISTORY_LIMIT;
|
|
462
|
+
type state_HistoryFile = HistoryFile;
|
|
463
|
+
type state_PendingPr = PendingPr;
|
|
464
|
+
type state_PluginState = PluginState;
|
|
465
|
+
type state_RunRecord = RunRecord;
|
|
466
|
+
type state_Store = Store;
|
|
467
|
+
declare const state_Store: typeof Store;
|
|
468
|
+
type state_StoreOptions = StoreOptions;
|
|
469
|
+
declare const state_newRunId: typeof newRunId;
|
|
470
|
+
declare const state_writeJsonAtomic: typeof writeJsonAtomic;
|
|
471
|
+
declare namespace state {
|
|
472
|
+
export { type state_DigestIdentity as DigestIdentity, state_HISTORY_LIMIT as HISTORY_LIMIT, type state_HistoryFile as HistoryFile, type state_PendingPr as PendingPr, type state_PluginState as PluginState, type state_RunRecord as RunRecord, state_Store as Store, type state_StoreOptions as StoreOptions, state_newRunId as newRunId, state_writeJsonAtomic as writeJsonAtomic };
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
interface CoreRelease {
|
|
476
|
+
/** `owner/repo`(GitHub)。 */
|
|
477
|
+
repo: string;
|
|
478
|
+
/** 不带 `v` 的版本号,例如 `0.1.0`;对应 tag `v0.1.0`。 */
|
|
479
|
+
version: string;
|
|
480
|
+
}
|
|
481
|
+
interface ReleaseDescriptor extends CoreRelease {
|
|
482
|
+
tag: string;
|
|
483
|
+
goos: string;
|
|
484
|
+
goarch: string;
|
|
485
|
+
asset: string;
|
|
486
|
+
url: string;
|
|
487
|
+
checksumsUrl: string;
|
|
488
|
+
cacheDir: string;
|
|
489
|
+
binaryPath: string;
|
|
490
|
+
cached: boolean;
|
|
491
|
+
}
|
|
492
|
+
/** 从本包的 package.json 读核心版本(`sync-contract --ref vX` 会同时更新它)。 */
|
|
493
|
+
declare function readCoreRelease(pkg?: {
|
|
494
|
+
dsh?: {
|
|
495
|
+
core?: {
|
|
496
|
+
repo?: unknown;
|
|
497
|
+
version?: unknown;
|
|
498
|
+
};
|
|
499
|
+
};
|
|
500
|
+
}): CoreRelease;
|
|
501
|
+
/** Node 的 platform/arch → Go 的 GOOS/GOARCH(两个生态词汇不同,映射必须显式)。 */
|
|
502
|
+
declare function goTarget(platform?: NodeJS.Platform, arch?: string): {
|
|
503
|
+
goos: string;
|
|
504
|
+
goarch: string;
|
|
505
|
+
};
|
|
506
|
+
declare function assetName(platform?: NodeJS.Platform, arch?: string): string;
|
|
507
|
+
declare function describeRelease(release: CoreRelease, options?: {
|
|
508
|
+
env?: NodeJS.ProcessEnv;
|
|
509
|
+
platform?: NodeJS.Platform;
|
|
510
|
+
arch?: string;
|
|
511
|
+
}): ReleaseDescriptor;
|
|
512
|
+
/** 缓存里的二进制是否可信:可执行 + 与下载时记录的哈希一致。 */
|
|
513
|
+
declare function verifyCached(binaryPath: string): {
|
|
514
|
+
ok: boolean;
|
|
515
|
+
reason?: string;
|
|
516
|
+
};
|
|
517
|
+
interface EnsureOptions {
|
|
518
|
+
release?: CoreRelease;
|
|
519
|
+
env?: NodeJS.ProcessEnv;
|
|
520
|
+
platform?: NodeJS.Platform;
|
|
521
|
+
arch?: string;
|
|
522
|
+
/** false 时只查缓存,不联网(设置页探测、离线诊断用)。 */
|
|
523
|
+
allowDownload?: boolean;
|
|
524
|
+
/** true 时忽略缓存重新下载(「重新下载核心」按钮)。 */
|
|
525
|
+
force?: boolean;
|
|
526
|
+
fetchImpl?: typeof fetch;
|
|
527
|
+
onProgress?: (event: {
|
|
528
|
+
phase: 'checksums' | 'download' | 'verify';
|
|
529
|
+
bytes?: number;
|
|
530
|
+
total?: number;
|
|
531
|
+
}) => void;
|
|
532
|
+
}
|
|
533
|
+
interface EnsureResult {
|
|
534
|
+
path: string;
|
|
535
|
+
source: 'cache' | 'download';
|
|
536
|
+
descriptor: ReleaseDescriptor;
|
|
537
|
+
sha256?: string;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* 确保本地有一份可用的核心二进制。
|
|
541
|
+
* 缓存命中就不联网;`allowDownload=false` 时缓存缺失直接报错(不带网络副作用)。
|
|
542
|
+
*/
|
|
543
|
+
declare function ensureCore(options?: EnsureOptions): Promise<EnsureResult>;
|
|
544
|
+
|
|
545
|
+
type release_CoreRelease = CoreRelease;
|
|
546
|
+
type release_EnsureOptions = EnsureOptions;
|
|
547
|
+
type release_EnsureResult = EnsureResult;
|
|
548
|
+
type release_ReleaseDescriptor = ReleaseDescriptor;
|
|
549
|
+
declare const release_assetName: typeof assetName;
|
|
550
|
+
declare const release_describeRelease: typeof describeRelease;
|
|
551
|
+
declare const release_ensureCore: typeof ensureCore;
|
|
552
|
+
declare const release_goTarget: typeof goTarget;
|
|
553
|
+
declare const release_readCoreRelease: typeof readCoreRelease;
|
|
554
|
+
declare const release_verifyCached: typeof verifyCached;
|
|
555
|
+
declare namespace release {
|
|
556
|
+
export { type release_CoreRelease as CoreRelease, type release_EnsureOptions as EnsureOptions, type release_EnsureResult as EnsureResult, type release_ReleaseDescriptor as ReleaseDescriptor, release_assetName as assetName, release_describeRelease as describeRelease, release_ensureCore as ensureCore, release_goTarget as goTarget, release_readCoreRelease as readCoreRelease, release_verifyCached as verifyCached };
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
interface CoreLocation {
|
|
560
|
+
path: string;
|
|
561
|
+
source: 'settings' | 'env' | 'cache' | 'download';
|
|
562
|
+
release?: CoreRelease;
|
|
563
|
+
tag?: string;
|
|
564
|
+
/** 本次调用是否真的下载了(用于日志与状态提示)。 */
|
|
565
|
+
downloaded?: boolean;
|
|
566
|
+
sha256?: string;
|
|
567
|
+
}
|
|
568
|
+
interface LocateOptions {
|
|
569
|
+
settings: Settings;
|
|
570
|
+
env?: NodeJS.ProcessEnv;
|
|
571
|
+
platform?: NodeJS.Platform;
|
|
572
|
+
arch?: string;
|
|
573
|
+
/** 默认 true;false 时只查缓存(设置页探测用)。 */
|
|
574
|
+
allowDownload?: boolean;
|
|
575
|
+
forceDownload?: boolean;
|
|
576
|
+
fetchImpl?: typeof fetch;
|
|
577
|
+
release?: CoreRelease;
|
|
578
|
+
}
|
|
579
|
+
declare function overridePath(settings: Settings, env?: NodeJS.ProcessEnv): {
|
|
580
|
+
path: string;
|
|
581
|
+
source: 'settings' | 'env';
|
|
582
|
+
} | undefined;
|
|
583
|
+
declare function locateCore(options: LocateOptions): Promise<CoreLocation>;
|
|
584
|
+
/** 只读的 Release 视图:不联网、不创建目录,供设置页展示「有没有、从哪来」。 */
|
|
585
|
+
declare function inspectRelease(settings: Settings, options?: {
|
|
586
|
+
env?: NodeJS.ProcessEnv;
|
|
587
|
+
platform?: NodeJS.Platform;
|
|
588
|
+
arch?: string;
|
|
589
|
+
release?: CoreRelease;
|
|
590
|
+
}): {
|
|
591
|
+
descriptor?: ReleaseDescriptor;
|
|
592
|
+
override?: {
|
|
593
|
+
path: string;
|
|
594
|
+
source: 'settings' | 'env';
|
|
595
|
+
};
|
|
596
|
+
error?: string;
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
type locate_CoreLocation = CoreLocation;
|
|
600
|
+
type locate_LocateOptions = LocateOptions;
|
|
601
|
+
declare const locate_inspectRelease: typeof inspectRelease;
|
|
602
|
+
declare const locate_locateCore: typeof locateCore;
|
|
603
|
+
declare const locate_overridePath: typeof overridePath;
|
|
604
|
+
declare namespace locate {
|
|
605
|
+
export { type locate_CoreLocation as CoreLocation, type locate_LocateOptions as LocateOptions, locate_inspectRelease as inspectRelease, locate_locateCore as locateCore, locate_overridePath as overridePath };
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
interface HandshakeResult {
|
|
609
|
+
version: VersionInfo;
|
|
610
|
+
corePath: string;
|
|
611
|
+
durationMs: number;
|
|
612
|
+
/** 核心声明的 provider 能力;设置页据此限制 provider 选择。 */
|
|
613
|
+
supportedProviders: string[];
|
|
614
|
+
}
|
|
615
|
+
declare const DEFAULT_PROVIDERS: readonly ["deepseek", "openai-compatible"];
|
|
616
|
+
declare function handshake(core: CoreLocation, options?: {
|
|
617
|
+
timeoutMs?: number;
|
|
618
|
+
signal?: AbortSignal;
|
|
619
|
+
}): Promise<HandshakeResult>;
|
|
620
|
+
|
|
621
|
+
declare const handshake$1_DEFAULT_PROVIDERS: typeof DEFAULT_PROVIDERS;
|
|
622
|
+
type handshake$1_HandshakeResult = HandshakeResult;
|
|
623
|
+
declare const handshake$1_handshake: typeof handshake;
|
|
624
|
+
declare namespace handshake$1 {
|
|
625
|
+
export { handshake$1_DEFAULT_PROVIDERS as DEFAULT_PROVIDERS, type handshake$1_HandshakeResult as HandshakeResult, handshake$1_handshake as handshake };
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
type ChannelKind = 'fifo' | 'tmpfile';
|
|
629
|
+
interface ConfigChannel {
|
|
630
|
+
kind: ChannelKind;
|
|
631
|
+
path: string;
|
|
632
|
+
/** spawn 之后调用:把内容送进通道。 */
|
|
633
|
+
publish(content: string): Promise<void>;
|
|
634
|
+
/** 无论成功失败都要调用;幂等。 */
|
|
635
|
+
dispose(): Promise<void>;
|
|
636
|
+
}
|
|
637
|
+
declare const WRITE_TIMEOUT_MS = 15000;
|
|
638
|
+
/**
|
|
639
|
+
* 建配置通道。`preferFifo=false` 或平台不是 POSIX 或 mkfifo 失败时走临时文件。
|
|
640
|
+
*/
|
|
641
|
+
declare function openConfigChannel(options?: {
|
|
642
|
+
preferFifo?: boolean;
|
|
643
|
+
writeTimeoutMs?: number;
|
|
644
|
+
}): Promise<ConfigChannel>;
|
|
645
|
+
/** 清理通道所在目录(dispose 之后调用)。 */
|
|
646
|
+
declare function removeChannelDir(channel: ConfigChannel): Promise<void>;
|
|
647
|
+
|
|
648
|
+
type channel_ChannelKind = ChannelKind;
|
|
649
|
+
type channel_ConfigChannel = ConfigChannel;
|
|
650
|
+
declare const channel_WRITE_TIMEOUT_MS: typeof WRITE_TIMEOUT_MS;
|
|
651
|
+
declare const channel_openConfigChannel: typeof openConfigChannel;
|
|
652
|
+
declare const channel_removeChannelDir: typeof removeChannelDir;
|
|
653
|
+
declare namespace channel {
|
|
654
|
+
export { type channel_ChannelKind as ChannelKind, type channel_ConfigChannel as ConfigChannel, channel_WRITE_TIMEOUT_MS as WRITE_TIMEOUT_MS, channel_openConfigChannel as openConfigChannel, channel_removeChannelDir as removeChannelDir };
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
interface ExecResult {
|
|
658
|
+
code: number | null;
|
|
659
|
+
signal: NodeJS.Signals | null;
|
|
660
|
+
stdout: string;
|
|
661
|
+
stderr: string;
|
|
662
|
+
timedOut: boolean;
|
|
663
|
+
aborted: boolean;
|
|
664
|
+
durationMs: number;
|
|
665
|
+
}
|
|
666
|
+
declare function sanitizedEnv(source?: NodeJS.ProcessEnv, extra?: Record<string, string | undefined>): Record<string, string>;
|
|
667
|
+
interface ExecOptions {
|
|
668
|
+
env?: NodeJS.ProcessEnv;
|
|
669
|
+
cwd?: string;
|
|
670
|
+
timeoutMs?: number;
|
|
671
|
+
signal?: AbortSignal;
|
|
672
|
+
maxStdout?: number;
|
|
673
|
+
maxStderr?: number;
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* 执行一次短命令并收集输出(握手、共存探测都走这里)。
|
|
677
|
+
* 超时与取消都先 SIGTERM、3 s 后 SIGKILL——核心是单进程,不需要 process group。
|
|
678
|
+
*/
|
|
679
|
+
declare function execCapture(file: string, args: string[], options?: ExecOptions): Promise<ExecResult>;
|
|
680
|
+
|
|
681
|
+
type exec_ExecOptions = ExecOptions;
|
|
682
|
+
type exec_ExecResult = ExecResult;
|
|
683
|
+
declare const exec_execCapture: typeof execCapture;
|
|
684
|
+
declare const exec_sanitizedEnv: typeof sanitizedEnv;
|
|
685
|
+
declare namespace exec {
|
|
686
|
+
export { type exec_ExecOptions as ExecOptions, type exec_ExecResult as ExecResult, exec_execCapture as execCapture, exec_sanitizedEnv as sanitizedEnv };
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
declare const DEFAULT_RUN_TIMEOUT_MS = 120000;
|
|
690
|
+
interface RunCoreOptions {
|
|
691
|
+
core: CoreLocation;
|
|
692
|
+
version: VersionInfo;
|
|
693
|
+
settings: Settings;
|
|
694
|
+
/** 模型密钥;只进配置通道,不进 argv/env/日志。 */
|
|
695
|
+
apiKey: string;
|
|
696
|
+
/** GitHub token;核心只从 env 读(GITHUB_TOKEN/GH_TOKEN)。 */
|
|
697
|
+
token?: string;
|
|
698
|
+
date?: string;
|
|
699
|
+
dryRun: boolean;
|
|
700
|
+
/** 回环代理地址:覆盖配置里的 model.baseURL(代理模式专用)。 */
|
|
701
|
+
baseURLOverride?: string;
|
|
702
|
+
signal?: AbortSignal;
|
|
703
|
+
timeoutMs?: number;
|
|
704
|
+
onStderr?: (line: string) => void;
|
|
705
|
+
/** 已知明文,用于日志脱敏。 */
|
|
706
|
+
secrets?: Array<string | undefined>;
|
|
707
|
+
}
|
|
708
|
+
interface RunCoreResult {
|
|
709
|
+
outcome: RunOutcome;
|
|
710
|
+
channelKind: ChannelKind;
|
|
711
|
+
stderr: string;
|
|
712
|
+
exitCode: number | null;
|
|
713
|
+
}
|
|
714
|
+
declare function buildCoreArgs(channelPath: string, options: {
|
|
715
|
+
dryRun: boolean;
|
|
716
|
+
date?: string;
|
|
717
|
+
}): string[];
|
|
718
|
+
declare function runCore(options: RunCoreOptions): Promise<RunCoreResult>;
|
|
719
|
+
|
|
720
|
+
declare const run_DEFAULT_RUN_TIMEOUT_MS: typeof DEFAULT_RUN_TIMEOUT_MS;
|
|
721
|
+
type run_RunCoreOptions = RunCoreOptions;
|
|
722
|
+
type run_RunCoreResult = RunCoreResult;
|
|
723
|
+
declare const run_buildCoreArgs: typeof buildCoreArgs;
|
|
724
|
+
declare const run_runCore: typeof runCore;
|
|
725
|
+
declare namespace run {
|
|
726
|
+
export { run_DEFAULT_RUN_TIMEOUT_MS as DEFAULT_RUN_TIMEOUT_MS, type run_RunCoreOptions as RunCoreOptions, type run_RunCoreResult as RunCoreResult, run_buildCoreArgs as buildCoreArgs, run_runCore as runCore };
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/** Release 分发下的核心视图:用户一眼能看出「版本、下没下、从哪来」。 */
|
|
730
|
+
interface ReleaseStatus {
|
|
731
|
+
repo: string;
|
|
732
|
+
tag: string;
|
|
733
|
+
asset: string;
|
|
734
|
+
url: string;
|
|
735
|
+
checksumsUrl: string;
|
|
736
|
+
cacheDir: string;
|
|
737
|
+
binaryPath: string;
|
|
738
|
+
cached: boolean;
|
|
739
|
+
}
|
|
740
|
+
interface CoreStatus {
|
|
741
|
+
state: 'ready' | 'unavailable' | 'incompatible';
|
|
742
|
+
path?: string;
|
|
743
|
+
source?: CoreLocation['source'];
|
|
744
|
+
/** Release 分发状态(有覆盖路径时只有 override,没有 release)。 */
|
|
745
|
+
release?: ReleaseStatus;
|
|
746
|
+
override?: {
|
|
747
|
+
path: string;
|
|
748
|
+
source: 'settings' | 'env';
|
|
749
|
+
};
|
|
750
|
+
download: {
|
|
751
|
+
state: 'cached' | 'missing' | 'override';
|
|
752
|
+
reason?: string;
|
|
753
|
+
};
|
|
754
|
+
version?: string;
|
|
755
|
+
commit?: string;
|
|
756
|
+
ipcSchema?: number;
|
|
757
|
+
digestSchema?: number;
|
|
758
|
+
supportedProviders: string[];
|
|
759
|
+
code?: string;
|
|
760
|
+
message?: string;
|
|
761
|
+
hint?: string;
|
|
762
|
+
checkedAt: string;
|
|
763
|
+
durationMs?: number;
|
|
764
|
+
}
|
|
765
|
+
interface CoexistenceStatus {
|
|
766
|
+
found: boolean;
|
|
767
|
+
path?: string;
|
|
768
|
+
version?: string;
|
|
769
|
+
ipcSchema?: number;
|
|
770
|
+
digestSchema?: number;
|
|
771
|
+
compatible?: boolean;
|
|
772
|
+
message?: string;
|
|
773
|
+
}
|
|
774
|
+
/** 在 PATH 里找同名 CLI(只用于共存提示,绝不用于运行)。 */
|
|
775
|
+
declare function findOnPath(command: string, env?: NodeJS.ProcessEnv): string | undefined;
|
|
776
|
+
declare function inspectCore(settings: Settings, options?: {
|
|
777
|
+
env?: NodeJS.ProcessEnv;
|
|
778
|
+
fresh?: boolean;
|
|
779
|
+
}): Promise<CoreStatus>;
|
|
780
|
+
/**
|
|
781
|
+
* 共存检测(FR-P-15 / AC-P-13):PATH 上有 `trendradar` 就读它的版本,只提示不切换。
|
|
782
|
+
* 若命中的正是本插件平台包里的二进制(比如用户把它加进了 PATH),不算共存。
|
|
783
|
+
*/
|
|
784
|
+
declare function detectCoexistence(ownPath: string | undefined, options?: {
|
|
785
|
+
env?: NodeJS.ProcessEnv;
|
|
786
|
+
fresh?: boolean;
|
|
787
|
+
}): Promise<CoexistenceStatus>;
|
|
788
|
+
|
|
789
|
+
type core_CoexistenceStatus = CoexistenceStatus;
|
|
790
|
+
type core_CoreStatus = CoreStatus;
|
|
791
|
+
type core_ReleaseStatus = ReleaseStatus;
|
|
792
|
+
declare const core_detectCoexistence: typeof detectCoexistence;
|
|
793
|
+
declare const core_findOnPath: typeof findOnPath;
|
|
794
|
+
declare const core_inspectCore: typeof inspectCore;
|
|
795
|
+
declare namespace core {
|
|
796
|
+
export { type core_CoexistenceStatus as CoexistenceStatus, type core_CoreStatus as CoreStatus, type core_ReleaseStatus as ReleaseStatus, core_detectCoexistence as detectCoexistence, core_findOnPath as findOnPath, core_inspectCore as inspectCore };
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* 凭据解析:一律「按操作解析」,不缓存明文(ADR D-04 约束 2)。
|
|
801
|
+
*
|
|
802
|
+
* 宿主的凭据服务只回答被问到的引用,**没有枚举**——所以这里的 ref 只来自两处:
|
|
803
|
+
* 设置里用户选定的 `model.apiKeyRef` / `github.tokenRef`,以及 provider 目录声明的
|
|
804
|
+
* `nativeAuth.env`。不存在「猜一个 ref 试试」。
|
|
805
|
+
*/
|
|
806
|
+
interface CredentialDescription {
|
|
807
|
+
configured: boolean;
|
|
808
|
+
source?: string;
|
|
809
|
+
writable: boolean;
|
|
810
|
+
}
|
|
811
|
+
interface ResolvedSecret {
|
|
812
|
+
value?: string;
|
|
813
|
+
source?: string;
|
|
814
|
+
}
|
|
815
|
+
interface CredentialServices {
|
|
816
|
+
describe?: (ref: string) => Promise<CredentialDescription> | CredentialDescription;
|
|
817
|
+
resolve?: (ref: string) => Promise<ResolvedSecret | undefined | null> | ResolvedSecret | undefined | null;
|
|
818
|
+
set?: (ref: string, value: string) => Promise<unknown> | unknown;
|
|
819
|
+
}
|
|
820
|
+
declare function credentialServices(get: (name: string) => unknown): CredentialServices | undefined;
|
|
821
|
+
declare function describeRef(services: CredentialServices | undefined, ref: string, env?: NodeJS.ProcessEnv): Promise<CredentialDescription>;
|
|
822
|
+
declare function resolveRef(services: CredentialServices | undefined, ref: string, env?: NodeJS.ProcessEnv): Promise<ResolvedSecret>;
|
|
823
|
+
/** GitHub token:按 authMode 取,`gh` 模式读本机 gh 的登录态。 */
|
|
824
|
+
declare function resolveGithubToken(services: CredentialServices | undefined, authMode: 'device' | 'pat' | 'gh', tokenRef: string, deps?: {
|
|
825
|
+
env?: NodeJS.ProcessEnv;
|
|
826
|
+
execGh?: () => Promise<string | undefined>;
|
|
827
|
+
}): Promise<{
|
|
828
|
+
token?: string;
|
|
829
|
+
source: string;
|
|
830
|
+
}>;
|
|
831
|
+
|
|
832
|
+
type credentials_CredentialDescription = CredentialDescription;
|
|
833
|
+
type credentials_CredentialServices = CredentialServices;
|
|
834
|
+
type credentials_ResolvedSecret = ResolvedSecret;
|
|
835
|
+
declare const credentials_credentialServices: typeof credentialServices;
|
|
836
|
+
declare const credentials_describeRef: typeof describeRef;
|
|
837
|
+
declare const credentials_resolveGithubToken: typeof resolveGithubToken;
|
|
838
|
+
declare const credentials_resolveRef: typeof resolveRef;
|
|
839
|
+
declare namespace credentials {
|
|
840
|
+
export { type credentials_CredentialDescription as CredentialDescription, type credentials_CredentialServices as CredentialServices, type credentials_ResolvedSecret as ResolvedSecret, credentials_credentialServices as credentialServices, credentials_describeRef as describeRef, credentials_resolveGithubToken as resolveGithubToken, credentials_resolveRef as resolveRef };
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* 从宿主的 provider 目录快速填充模型配置(FR-P-03 / AC-P-03)。
|
|
845
|
+
*
|
|
846
|
+
* 三种认证形态的判定,只用宿主公开的两个目录:
|
|
847
|
+
* - `listProviders()`:当前**活着**的路由(id + 名称);
|
|
848
|
+
* - `listConfigurableProviders()`:连**休眠**路由一起,带 `defaultBaseURL` 与 `nativeAuth`
|
|
849
|
+
* (认证读哪些环境变量、是否支持已存的 OAuth 登录)。
|
|
850
|
+
*
|
|
851
|
+
* 由此得到三种形态:
|
|
852
|
+
* 1. `nativeAuth.env` 里有已配置的引用 → `direct`(密钥可解析,经配置通道直传);
|
|
853
|
+
* 2. `nativeAuth.oauth === true` 且无可导出密钥 → `proxy`(回环代理转发 `ctx.llm`);
|
|
854
|
+
* 3. 都没有 → `missing`(界面要求用户手动填)。
|
|
855
|
+
*
|
|
856
|
+
* 这里**不写任何配置**:只产出候选,由用户确认后 `/config` 落盘(禁止静默复制)。
|
|
857
|
+
*/
|
|
858
|
+
|
|
859
|
+
interface LlmModelCandidate {
|
|
860
|
+
id: string;
|
|
861
|
+
name: string;
|
|
862
|
+
}
|
|
863
|
+
interface LlmProviderCandidate {
|
|
864
|
+
/** 宿主 provider 路由 id。 */
|
|
865
|
+
id: string;
|
|
866
|
+
name: string;
|
|
867
|
+
/** 该路由的默认端点(宿主声明,可能为空)。 */
|
|
868
|
+
baseURL: string;
|
|
869
|
+
models: LlmModelCandidate[];
|
|
870
|
+
credential: {
|
|
871
|
+
/** 选中的凭据引用名(`direct` 时非空)。 */
|
|
872
|
+
ref?: string;
|
|
873
|
+
/** 该路由声明的环境变量名。 */
|
|
874
|
+
env: string[];
|
|
875
|
+
configured: boolean;
|
|
876
|
+
oauth: boolean;
|
|
877
|
+
mode: 'direct' | 'proxy' | 'missing';
|
|
878
|
+
source?: string;
|
|
879
|
+
};
|
|
880
|
+
/** 映射到核心能接受的 provider 名。 */
|
|
881
|
+
coreProvider: string;
|
|
882
|
+
}
|
|
883
|
+
interface LlmProviderInfo {
|
|
884
|
+
id: string;
|
|
885
|
+
name: string;
|
|
886
|
+
}
|
|
887
|
+
interface LlmConfigurableProvider {
|
|
888
|
+
provider: string;
|
|
889
|
+
displayName?: string;
|
|
890
|
+
defaultBaseURL?: string;
|
|
891
|
+
nativeAuth?: {
|
|
892
|
+
env?: readonly string[];
|
|
893
|
+
oauth?: boolean;
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
interface LlmServices {
|
|
897
|
+
listProviders?: () => LlmProviderInfo[];
|
|
898
|
+
listModels?: (provider: string) => Promise<Array<{
|
|
899
|
+
id?: string;
|
|
900
|
+
name?: string;
|
|
901
|
+
}>>;
|
|
902
|
+
listConfigurableProviders?: () => LlmConfigurableProvider[];
|
|
903
|
+
}
|
|
904
|
+
declare function llmServices(get: (name: string) => unknown): LlmServices | undefined;
|
|
905
|
+
/** 宿主 provider → 核心 provider。核心只认 deepseek / openai-compatible。 */
|
|
906
|
+
declare function coreProviderFor(providerId: string): string;
|
|
907
|
+
interface CandidateOptions {
|
|
908
|
+
llm: LlmServices | undefined;
|
|
909
|
+
credentials: CredentialServices | undefined;
|
|
910
|
+
env?: NodeJS.ProcessEnv;
|
|
911
|
+
}
|
|
912
|
+
declare function listProviderCandidates(options: CandidateOptions): Promise<LlmProviderCandidate[]>;
|
|
913
|
+
/**
|
|
914
|
+
* 把候选落成模型设置。`mode: 'proxy'` 时清空 baseURL 与 apiKeyRef——
|
|
915
|
+
* 端点由插件在运行时注入回环代理地址,留存旧值只会误导。
|
|
916
|
+
*/
|
|
917
|
+
declare function applyCandidate(settings: Settings, candidate: LlmProviderCandidate, modelId: string): Settings;
|
|
918
|
+
/** 运行前解析模型密钥:`direct` 走凭据,`proxy` 不需要密钥。 */
|
|
919
|
+
declare function resolveModelKey(settings: Settings, credentials: CredentialServices | undefined, env?: NodeJS.ProcessEnv): Promise<{
|
|
920
|
+
apiKey?: string;
|
|
921
|
+
mode: 'direct' | 'proxy';
|
|
922
|
+
source?: string;
|
|
923
|
+
}>;
|
|
924
|
+
|
|
925
|
+
type quickfill_CandidateOptions = CandidateOptions;
|
|
926
|
+
type quickfill_LlmModelCandidate = LlmModelCandidate;
|
|
927
|
+
type quickfill_LlmProviderCandidate = LlmProviderCandidate;
|
|
928
|
+
type quickfill_LlmServices = LlmServices;
|
|
929
|
+
declare const quickfill_applyCandidate: typeof applyCandidate;
|
|
930
|
+
declare const quickfill_coreProviderFor: typeof coreProviderFor;
|
|
931
|
+
declare const quickfill_credentialServices: typeof credentialServices;
|
|
932
|
+
declare const quickfill_listProviderCandidates: typeof listProviderCandidates;
|
|
933
|
+
declare const quickfill_llmServices: typeof llmServices;
|
|
934
|
+
declare const quickfill_resolveModelKey: typeof resolveModelKey;
|
|
935
|
+
declare namespace quickfill {
|
|
936
|
+
export { type quickfill_CandidateOptions as CandidateOptions, type quickfill_LlmModelCandidate as LlmModelCandidate, type quickfill_LlmProviderCandidate as LlmProviderCandidate, type quickfill_LlmServices as LlmServices, quickfill_applyCandidate as applyCandidate, quickfill_coreProviderFor as coreProviderFor, quickfill_credentialServices as credentialServices, quickfill_listProviderCandidates as listProviderCandidates, quickfill_llmServices as llmServices, quickfill_resolveModelKey as resolveModelKey };
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
/**
|
|
940
|
+
* 模型连通性预检(FR-P-02 / §13 风险表:保存前预检)。
|
|
941
|
+
*
|
|
942
|
+
* 只做一次最小请求,把「能不能连、密钥对不对、模型在不在」区分开:
|
|
943
|
+
* - 401/403 → MODEL_UNAUTHORIZED
|
|
944
|
+
* - 404 / model not found → MODEL_NOT_FOUND
|
|
945
|
+
* - 429 → MODEL_RATE_LIMITED(算连通)
|
|
946
|
+
* - 超时 / 网络错误 → MODEL_FAILED
|
|
947
|
+
*
|
|
948
|
+
* 代理模式不走 HTTP,直接用 `ctx.llm.stream` 发一个 1 token 的请求。
|
|
949
|
+
*/
|
|
950
|
+
|
|
951
|
+
interface PreflightResult {
|
|
952
|
+
ok: boolean;
|
|
953
|
+
code?: string;
|
|
954
|
+
message?: string;
|
|
955
|
+
hint?: string;
|
|
956
|
+
area?: string;
|
|
957
|
+
durationMs: number;
|
|
958
|
+
endpoint?: string;
|
|
959
|
+
mode: 'direct' | 'proxy';
|
|
960
|
+
}
|
|
961
|
+
declare function preflightModel(options: {
|
|
962
|
+
settings: Settings;
|
|
963
|
+
credentials: CredentialServices | undefined;
|
|
964
|
+
llm: LlmServices | undefined;
|
|
965
|
+
env?: NodeJS.ProcessEnv;
|
|
966
|
+
fetchImpl?: typeof fetch;
|
|
967
|
+
}): Promise<PreflightResult>;
|
|
968
|
+
|
|
969
|
+
type preflight_PreflightResult = PreflightResult;
|
|
970
|
+
declare const preflight_preflightModel: typeof preflightModel;
|
|
971
|
+
declare namespace preflight {
|
|
972
|
+
export { type preflight_PreflightResult as PreflightResult, preflight_preflightModel as preflightModel };
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
interface StreamChunkLike {
|
|
976
|
+
type?: string;
|
|
977
|
+
text?: string;
|
|
978
|
+
reason?: {
|
|
979
|
+
kind?: string;
|
|
980
|
+
failure?: {
|
|
981
|
+
code?: string;
|
|
982
|
+
message?: string;
|
|
983
|
+
};
|
|
984
|
+
};
|
|
985
|
+
usage?: {
|
|
986
|
+
inputTokens?: number;
|
|
987
|
+
outputTokens?: number;
|
|
988
|
+
totalTokens?: number;
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
interface LlmLike {
|
|
992
|
+
stream(options: Record<string, unknown>): AsyncIterable<StreamChunkLike>;
|
|
993
|
+
}
|
|
994
|
+
interface ProxyOptions {
|
|
995
|
+
llm: LlmLike;
|
|
996
|
+
provider: string;
|
|
997
|
+
model: string;
|
|
998
|
+
temperature?: number;
|
|
999
|
+
maxTokens?: number;
|
|
1000
|
+
timeoutMs?: number;
|
|
1001
|
+
}
|
|
1002
|
+
interface ProxyHandle {
|
|
1003
|
+
url: string;
|
|
1004
|
+
token: string;
|
|
1005
|
+
port: number;
|
|
1006
|
+
requests: number;
|
|
1007
|
+
close(): Promise<void>;
|
|
1008
|
+
}
|
|
1009
|
+
interface ChatMessage {
|
|
1010
|
+
role?: string;
|
|
1011
|
+
content?: unknown;
|
|
1012
|
+
}
|
|
1013
|
+
/** 把 OpenAI 的 messages 折成「system + 单个 user」。核心只用单轮,超出部分并入 user。 */
|
|
1014
|
+
declare function foldMessages(messages: ChatMessage[]): {
|
|
1015
|
+
system: string;
|
|
1016
|
+
user: string;
|
|
1017
|
+
};
|
|
1018
|
+
declare function startProxy(options: ProxyOptions): Promise<ProxyHandle>;
|
|
1019
|
+
|
|
1020
|
+
type proxy_LlmLike = LlmLike;
|
|
1021
|
+
type proxy_ProxyHandle = ProxyHandle;
|
|
1022
|
+
type proxy_ProxyOptions = ProxyOptions;
|
|
1023
|
+
declare const proxy_foldMessages: typeof foldMessages;
|
|
1024
|
+
declare const proxy_startProxy: typeof startProxy;
|
|
1025
|
+
declare namespace proxy {
|
|
1026
|
+
export { type proxy_LlmLike as LlmLike, type proxy_ProxyHandle as ProxyHandle, type proxy_ProxyOptions as ProxyOptions, proxy_foldMessages as foldMessages, proxy_startProxy as startProxy };
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
interface RunSummary {
|
|
1030
|
+
id: string;
|
|
1031
|
+
ok: boolean;
|
|
1032
|
+
skipped: boolean;
|
|
1033
|
+
dryRun: boolean;
|
|
1034
|
+
date?: string;
|
|
1035
|
+
durationMs: number;
|
|
1036
|
+
coreVersion: string;
|
|
1037
|
+
files: number;
|
|
1038
|
+
contentHash?: string;
|
|
1039
|
+
branch?: string;
|
|
1040
|
+
prUrl?: string;
|
|
1041
|
+
error?: {
|
|
1042
|
+
code: string;
|
|
1043
|
+
message: string;
|
|
1044
|
+
hint: string;
|
|
1045
|
+
area: string;
|
|
1046
|
+
retriable: boolean;
|
|
1047
|
+
inferred?: boolean;
|
|
1048
|
+
};
|
|
1049
|
+
warnings: string[];
|
|
1050
|
+
logFile?: string;
|
|
1051
|
+
channel?: 'fifo' | 'tmpfile';
|
|
1052
|
+
proxy?: boolean;
|
|
1053
|
+
/** 核心从哪来:env/settings 覆盖、缓存、还是本次下载。 */
|
|
1054
|
+
coreSource?: 'settings' | 'env' | 'cache' | 'download';
|
|
1055
|
+
coreTag?: string;
|
|
1056
|
+
}
|
|
1057
|
+
interface RunRequestOptions {
|
|
1058
|
+
dryRun?: boolean;
|
|
1059
|
+
date?: string;
|
|
1060
|
+
trigger: 'manual' | 'schedule' | 'tool';
|
|
1061
|
+
}
|
|
1062
|
+
interface RunnerDeps {
|
|
1063
|
+
store: Store;
|
|
1064
|
+
get: (name: string) => unknown;
|
|
1065
|
+
env?: NodeJS.ProcessEnv;
|
|
1066
|
+
/** 运行结束(成功或失败)后回调,用于刷新调度/界面缓存。 */
|
|
1067
|
+
onFinished?: (summary: RunSummary) => void;
|
|
1068
|
+
}
|
|
1069
|
+
declare class Runner {
|
|
1070
|
+
private active;
|
|
1071
|
+
private readonly deps;
|
|
1072
|
+
constructor(deps: RunnerDeps);
|
|
1073
|
+
get running(): {
|
|
1074
|
+
id: string;
|
|
1075
|
+
startedAt: string;
|
|
1076
|
+
} | undefined;
|
|
1077
|
+
cancel(): boolean;
|
|
1078
|
+
run(options: RunRequestOptions): Promise<RunSummary>;
|
|
1079
|
+
private summarize;
|
|
1080
|
+
private failureSummary;
|
|
1081
|
+
/** 写历史与状态;同一天的 skipped 运行不覆盖 lastDigest。 */
|
|
1082
|
+
private record;
|
|
1083
|
+
/** 给设置页/工具用的「核心现在什么状态」。 */
|
|
1084
|
+
coreStatus(fresh?: boolean): Promise<CoreStatus>;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
type runner_RunRequestOptions = RunRequestOptions;
|
|
1088
|
+
type runner_RunSummary = RunSummary;
|
|
1089
|
+
type runner_Runner = Runner;
|
|
1090
|
+
declare const runner_Runner: typeof Runner;
|
|
1091
|
+
type runner_RunnerDeps = RunnerDeps;
|
|
1092
|
+
declare namespace runner {
|
|
1093
|
+
export { type runner_RunRequestOptions as RunRequestOptions, type runner_RunSummary as RunSummary, runner_Runner as Runner, type runner_RunnerDeps as RunnerDeps };
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* 调度(FR-P-08 / 规格 §9)。
|
|
1098
|
+
*
|
|
1099
|
+
* 规格原本设想「复用宿主 schedule 服务」,但实测:宿主的 `ctx.schedule` 是 **会话本地**
|
|
1100
|
+
* 的提醒(rc.5 才引入,create 需要 sessionId,冷会话不投递),而本插件的运行完全不依赖会话。
|
|
1101
|
+
* 因此这里实现规格 §9 已经写明的兜底:宿主 `timer` 服务(或 `setInterval`)60 s tick、
|
|
1102
|
+
* 按 IANA 时区判当日、6 h 内补跑、同日不重复。
|
|
1103
|
+
*
|
|
1104
|
+
* 「下一次运行」也由同一份时区算术给出,界面与工具都用它。
|
|
1105
|
+
*/
|
|
1106
|
+
|
|
1107
|
+
interface ScheduleConfig {
|
|
1108
|
+
enabled: boolean;
|
|
1109
|
+
time: string;
|
|
1110
|
+
timezone: string;
|
|
1111
|
+
}
|
|
1112
|
+
/** 目标时区的墙上时间 → UTC 时刻(按 DST 修正一次,够用且可测)。 */
|
|
1113
|
+
declare function zonedTimeToUtc(year: number, month: number, day: number, hour: number, minute: number, second: number, timezone: string): Date;
|
|
1114
|
+
declare function parseClock(time: string): {
|
|
1115
|
+
hour: number;
|
|
1116
|
+
minute: number;
|
|
1117
|
+
second: number;
|
|
1118
|
+
};
|
|
1119
|
+
/** 目标时区下的本地日期串(YYYY-MM-DD)。 */
|
|
1120
|
+
declare function zonedDateString(date: Date, timezone: string): string;
|
|
1121
|
+
/** 下一次应当运行的时刻(严格晚于 now)。 */
|
|
1122
|
+
declare function nextOccurrence(now: Date, schedule: ScheduleConfig): Date;
|
|
1123
|
+
/** 今天这一次是否已过点且在补跑窗口内。 */
|
|
1124
|
+
declare function isDue(now: Date, schedule: ScheduleConfig): boolean;
|
|
1125
|
+
interface SchedulerDeps {
|
|
1126
|
+
store: Store;
|
|
1127
|
+
run: (trigger: 'schedule') => Promise<unknown>;
|
|
1128
|
+
isRunning: () => boolean;
|
|
1129
|
+
getTimer: () => {
|
|
1130
|
+
interval?: (fn: () => void, ms: number) => unknown;
|
|
1131
|
+
timeout?: (fn: () => void, ms: number) => unknown;
|
|
1132
|
+
} | undefined;
|
|
1133
|
+
onError?: (error: unknown) => void;
|
|
1134
|
+
}
|
|
1135
|
+
declare class Scheduler {
|
|
1136
|
+
private readonly deps;
|
|
1137
|
+
private timerHandle;
|
|
1138
|
+
private stopped;
|
|
1139
|
+
private lastFiredFor;
|
|
1140
|
+
constructor(deps: SchedulerDeps);
|
|
1141
|
+
start(): void;
|
|
1142
|
+
stop(): void;
|
|
1143
|
+
/** 公开给测试:判断此刻是否该跑,并按需触发一次。 */
|
|
1144
|
+
tick(now?: Date): Promise<'skipped' | 'ran' | 'disabled' | 'busy'>;
|
|
1145
|
+
private readSchedule;
|
|
1146
|
+
/** 下一次运行(禁用时为 undefined)。 */
|
|
1147
|
+
next(): Date | undefined;
|
|
1148
|
+
describe(state: PluginState, now?: Date): {
|
|
1149
|
+
enabled: boolean;
|
|
1150
|
+
time: string;
|
|
1151
|
+
timezone: string;
|
|
1152
|
+
nextRunAt?: string;
|
|
1153
|
+
lastRunDate?: string;
|
|
1154
|
+
catchUpMinutes: number;
|
|
1155
|
+
source: 'timer';
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
type schedule_ScheduleConfig = ScheduleConfig;
|
|
1160
|
+
type schedule_Scheduler = Scheduler;
|
|
1161
|
+
declare const schedule_Scheduler: typeof Scheduler;
|
|
1162
|
+
type schedule_SchedulerDeps = SchedulerDeps;
|
|
1163
|
+
declare const schedule_isDue: typeof isDue;
|
|
1164
|
+
declare const schedule_nextOccurrence: typeof nextOccurrence;
|
|
1165
|
+
declare const schedule_parseClock: typeof parseClock;
|
|
1166
|
+
declare const schedule_zonedDateString: typeof zonedDateString;
|
|
1167
|
+
declare const schedule_zonedTimeToUtc: typeof zonedTimeToUtc;
|
|
1168
|
+
declare namespace schedule {
|
|
1169
|
+
export { type schedule_ScheduleConfig as ScheduleConfig, schedule_Scheduler as Scheduler, type schedule_SchedulerDeps as SchedulerDeps, schedule_isDue as isDue, schedule_nextOccurrence as nextOccurrence, schedule_parseClock as parseClock, schedule_zonedDateString as zonedDateString, schedule_zonedTimeToUtc as zonedTimeToUtc };
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* Host HTTP 面:`/api/morehao/github-trending/*`。
|
|
1174
|
+
*
|
|
1175
|
+
* 只有客户端 bundle 会调它。安全基线沿用宿主插件的通行做法:
|
|
1176
|
+
* - 一律要求自定义头 `x-dsh-github-trending: 1`(跨源请求会先触发预检,等于顺带挡 CSRF);
|
|
1177
|
+
* - 响应 `no-store`;
|
|
1178
|
+
* - 没有任何路由返回密钥明文:只返回「已配置/来源」。
|
|
1179
|
+
*/
|
|
1180
|
+
|
|
1181
|
+
declare const ROUTE_PREFIX = "/api/morehao/github-trending";
|
|
1182
|
+
declare const HEADER = "x-dsh-github-trending";
|
|
1183
|
+
interface RouteDeps {
|
|
1184
|
+
store: Store;
|
|
1185
|
+
runner: Runner;
|
|
1186
|
+
scheduler: Scheduler;
|
|
1187
|
+
get: (name: string) => unknown;
|
|
1188
|
+
env?: NodeJS.ProcessEnv;
|
|
1189
|
+
version: string;
|
|
1190
|
+
logger?: (event: string, data?: Record<string, unknown>) => void;
|
|
1191
|
+
}
|
|
1192
|
+
declare function createRoutes(deps: RouteDeps): (request: http.IncomingMessage, response: http.ServerResponse) => Promise<void>;
|
|
1193
|
+
|
|
1194
|
+
declare const routes_HEADER: typeof HEADER;
|
|
1195
|
+
declare const routes_ROUTE_PREFIX: typeof ROUTE_PREFIX;
|
|
1196
|
+
type routes_RouteDeps = RouteDeps;
|
|
1197
|
+
declare const routes_createRoutes: typeof createRoutes;
|
|
1198
|
+
declare namespace routes {
|
|
1199
|
+
export { routes_HEADER as HEADER, routes_ROUTE_PREFIX as ROUTE_PREFIX, type routes_RouteDeps as RouteDeps, routes_createRoutes as createRoutes };
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
interface ImportCandidate {
|
|
1203
|
+
path: string;
|
|
1204
|
+
exists: boolean;
|
|
1205
|
+
}
|
|
1206
|
+
interface ImportResult {
|
|
1207
|
+
ok: boolean;
|
|
1208
|
+
source?: string;
|
|
1209
|
+
settings?: Settings;
|
|
1210
|
+
imported: string[];
|
|
1211
|
+
skippedSecrets: string[];
|
|
1212
|
+
problems: string[];
|
|
1213
|
+
}
|
|
1214
|
+
/** 可能的 CLI 配置位置(按顺序取第一个存在的)。 */
|
|
1215
|
+
declare function cliConfigCandidates(env?: NodeJS.ProcessEnv, home?: string): string[];
|
|
1216
|
+
type YamlValue = string | number | boolean | string[] | YamlMap;
|
|
1217
|
+
interface YamlMap {
|
|
1218
|
+
[key: string]: YamlValue;
|
|
1219
|
+
}
|
|
1220
|
+
/** 只支持两层缩进 map + 标量/flow 数组;其它形状直接抛错。 */
|
|
1221
|
+
declare function parseSimpleYaml(text: string): YamlMap;
|
|
1222
|
+
declare function importFromCli(filePath: string, base?: Settings): ImportResult;
|
|
1223
|
+
/** 找到第一个存在的 CLI 配置并导入。 */
|
|
1224
|
+
declare function importFirstAvailable(env?: NodeJS.ProcessEnv, base?: Settings): ImportResult;
|
|
1225
|
+
|
|
1226
|
+
type importCli_ImportCandidate = ImportCandidate;
|
|
1227
|
+
type importCli_ImportResult = ImportResult;
|
|
1228
|
+
declare const importCli_cliConfigCandidates: typeof cliConfigCandidates;
|
|
1229
|
+
declare const importCli_importFirstAvailable: typeof importFirstAvailable;
|
|
1230
|
+
declare const importCli_importFromCli: typeof importFromCli;
|
|
1231
|
+
declare const importCli_parseSimpleYaml: typeof parseSimpleYaml;
|
|
1232
|
+
declare namespace importCli {
|
|
1233
|
+
export { type importCli_ImportCandidate as ImportCandidate, type importCli_ImportResult as ImportResult, importCli_cliConfigCandidates as cliConfigCandidates, importCli_importFirstAvailable as importFirstAvailable, importCli_importFromCli as importFromCli, importCli_parseSimpleYaml as parseSimpleYaml };
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
/**
|
|
1237
|
+
* 两个对外工具:`trending_run` / `trending_history`(规格 §8)。
|
|
1238
|
+
*
|
|
1239
|
+
* 工具名是**稳定对外接口**:一旦发布不再改名;需要新能力时新增工具。
|
|
1240
|
+
* 参数方言用宿主 `dsh-tools` 的「内联 required: true」,输出用标准 JSON Schema。
|
|
1241
|
+
*/
|
|
1242
|
+
|
|
1243
|
+
declare function createTrendingRunTool(runner: Runner): {
|
|
1244
|
+
name: string;
|
|
1245
|
+
description: string;
|
|
1246
|
+
parameters: {
|
|
1247
|
+
dryRun: {
|
|
1248
|
+
type: string;
|
|
1249
|
+
description: string;
|
|
1250
|
+
};
|
|
1251
|
+
date: {
|
|
1252
|
+
type: string;
|
|
1253
|
+
description: string;
|
|
1254
|
+
};
|
|
1255
|
+
};
|
|
1256
|
+
output: {
|
|
1257
|
+
schema: {
|
|
1258
|
+
readonly type: "object";
|
|
1259
|
+
readonly additionalProperties: true;
|
|
1260
|
+
readonly properties: {
|
|
1261
|
+
readonly id: {
|
|
1262
|
+
readonly type: "string";
|
|
1263
|
+
};
|
|
1264
|
+
readonly ok: {
|
|
1265
|
+
readonly type: "boolean";
|
|
1266
|
+
};
|
|
1267
|
+
readonly skipped: {
|
|
1268
|
+
readonly type: "boolean";
|
|
1269
|
+
};
|
|
1270
|
+
readonly dryRun: {
|
|
1271
|
+
readonly type: "boolean";
|
|
1272
|
+
};
|
|
1273
|
+
readonly durationMs: {
|
|
1274
|
+
readonly type: "number";
|
|
1275
|
+
};
|
|
1276
|
+
readonly coreVersion: {
|
|
1277
|
+
readonly type: "string";
|
|
1278
|
+
};
|
|
1279
|
+
readonly files: {
|
|
1280
|
+
readonly type: "number";
|
|
1281
|
+
};
|
|
1282
|
+
readonly contentHash: {
|
|
1283
|
+
readonly type: "string";
|
|
1284
|
+
};
|
|
1285
|
+
readonly branch: {
|
|
1286
|
+
readonly type: "string";
|
|
1287
|
+
};
|
|
1288
|
+
readonly prUrl: {
|
|
1289
|
+
readonly type: "string";
|
|
1290
|
+
};
|
|
1291
|
+
readonly errorCode: {
|
|
1292
|
+
readonly type: "string";
|
|
1293
|
+
};
|
|
1294
|
+
readonly errorMessage: {
|
|
1295
|
+
readonly type: "string";
|
|
1296
|
+
};
|
|
1297
|
+
readonly errorHint: {
|
|
1298
|
+
readonly type: "string";
|
|
1299
|
+
};
|
|
1300
|
+
readonly warnings: {
|
|
1301
|
+
readonly type: "array";
|
|
1302
|
+
readonly items: {
|
|
1303
|
+
readonly type: "string";
|
|
1304
|
+
};
|
|
1305
|
+
};
|
|
1306
|
+
readonly markdown: {
|
|
1307
|
+
readonly type: "string";
|
|
1308
|
+
};
|
|
1309
|
+
};
|
|
1310
|
+
readonly required: readonly ["ok", "markdown"];
|
|
1311
|
+
};
|
|
1312
|
+
render: (_args: unknown, value: {
|
|
1313
|
+
markdown?: string;
|
|
1314
|
+
}) => {
|
|
1315
|
+
type: string;
|
|
1316
|
+
text: string;
|
|
1317
|
+
}[];
|
|
1318
|
+
};
|
|
1319
|
+
execute(args?: {
|
|
1320
|
+
dryRun?: boolean;
|
|
1321
|
+
date?: string;
|
|
1322
|
+
}, exec?: {
|
|
1323
|
+
signal?: AbortSignal;
|
|
1324
|
+
}): Promise<{
|
|
1325
|
+
warnings: string[];
|
|
1326
|
+
markdown: string;
|
|
1327
|
+
errorCode?: string | undefined;
|
|
1328
|
+
errorMessage?: string | undefined;
|
|
1329
|
+
errorHint?: string | undefined;
|
|
1330
|
+
prUrl?: string | undefined;
|
|
1331
|
+
branch?: string | undefined;
|
|
1332
|
+
contentHash?: string | undefined;
|
|
1333
|
+
id: string;
|
|
1334
|
+
ok: boolean;
|
|
1335
|
+
skipped: boolean;
|
|
1336
|
+
dryRun: boolean;
|
|
1337
|
+
durationMs: number;
|
|
1338
|
+
coreVersion: string;
|
|
1339
|
+
files: number;
|
|
1340
|
+
}>;
|
|
1341
|
+
};
|
|
1342
|
+
declare function createTrendingHistoryTool(store: Store, scheduler: Scheduler): {
|
|
1343
|
+
name: string;
|
|
1344
|
+
description: string;
|
|
1345
|
+
parameters: {
|
|
1346
|
+
limit: {
|
|
1347
|
+
type: string;
|
|
1348
|
+
description: string;
|
|
1349
|
+
};
|
|
1350
|
+
};
|
|
1351
|
+
output: {
|
|
1352
|
+
schema: {
|
|
1353
|
+
readonly type: "object";
|
|
1354
|
+
readonly additionalProperties: true;
|
|
1355
|
+
readonly properties: {
|
|
1356
|
+
readonly lastRunAt: {
|
|
1357
|
+
readonly type: "string";
|
|
1358
|
+
};
|
|
1359
|
+
readonly nextRunAt: {
|
|
1360
|
+
readonly type: "string";
|
|
1361
|
+
};
|
|
1362
|
+
readonly coreVersion: {
|
|
1363
|
+
readonly type: "string";
|
|
1364
|
+
};
|
|
1365
|
+
readonly model: {
|
|
1366
|
+
readonly type: "string";
|
|
1367
|
+
};
|
|
1368
|
+
readonly provider: {
|
|
1369
|
+
readonly type: "string";
|
|
1370
|
+
};
|
|
1371
|
+
readonly pendingPr: {
|
|
1372
|
+
readonly type: "string";
|
|
1373
|
+
};
|
|
1374
|
+
readonly records: {
|
|
1375
|
+
readonly type: "array";
|
|
1376
|
+
readonly items: {
|
|
1377
|
+
readonly type: "object";
|
|
1378
|
+
readonly additionalProperties: true;
|
|
1379
|
+
readonly properties: {
|
|
1380
|
+
readonly at: {
|
|
1381
|
+
readonly type: "string";
|
|
1382
|
+
};
|
|
1383
|
+
readonly ok: {
|
|
1384
|
+
readonly type: "boolean";
|
|
1385
|
+
};
|
|
1386
|
+
readonly skipped: {
|
|
1387
|
+
readonly type: "boolean";
|
|
1388
|
+
};
|
|
1389
|
+
readonly errorCode: {
|
|
1390
|
+
readonly type: "string";
|
|
1391
|
+
};
|
|
1392
|
+
readonly durationMs: {
|
|
1393
|
+
readonly type: "number";
|
|
1394
|
+
};
|
|
1395
|
+
readonly files: {
|
|
1396
|
+
readonly type: "number";
|
|
1397
|
+
};
|
|
1398
|
+
readonly branch: {
|
|
1399
|
+
readonly type: "string";
|
|
1400
|
+
};
|
|
1401
|
+
readonly prUrl: {
|
|
1402
|
+
readonly type: "string";
|
|
1403
|
+
};
|
|
1404
|
+
readonly coreVersion: {
|
|
1405
|
+
readonly type: "string";
|
|
1406
|
+
};
|
|
1407
|
+
};
|
|
1408
|
+
};
|
|
1409
|
+
};
|
|
1410
|
+
readonly markdown: {
|
|
1411
|
+
readonly type: "string";
|
|
1412
|
+
};
|
|
1413
|
+
};
|
|
1414
|
+
readonly required: readonly ["markdown"];
|
|
1415
|
+
};
|
|
1416
|
+
render: (_args: unknown, value: {
|
|
1417
|
+
markdown?: string;
|
|
1418
|
+
}) => {
|
|
1419
|
+
type: string;
|
|
1420
|
+
text: string;
|
|
1421
|
+
}[];
|
|
1422
|
+
};
|
|
1423
|
+
execute(args?: {
|
|
1424
|
+
limit?: number;
|
|
1425
|
+
}): Promise<{
|
|
1426
|
+
records: RunRecord[];
|
|
1427
|
+
markdown: string;
|
|
1428
|
+
pendingPr?: string | undefined;
|
|
1429
|
+
coreVersion: string;
|
|
1430
|
+
model: string;
|
|
1431
|
+
provider: string;
|
|
1432
|
+
nextRunAt?: string | undefined;
|
|
1433
|
+
lastRunAt?: string | undefined;
|
|
1434
|
+
}>;
|
|
1435
|
+
};
|
|
1436
|
+
|
|
1437
|
+
declare const tools_createTrendingHistoryTool: typeof createTrendingHistoryTool;
|
|
1438
|
+
declare const tools_createTrendingRunTool: typeof createTrendingRunTool;
|
|
1439
|
+
declare namespace tools {
|
|
1440
|
+
export { tools_createTrendingHistoryTool as createTrendingHistoryTool, tools_createTrendingRunTool as createTrendingRunTool };
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
export { channel, config, core, credentials, errors, exec, handshake$1 as handshake, importCli, ipc, locate, paths, preflight, proxy, quickfill, release, routes, run, runner, schedule, state, tools };
|