@morehao/dsh-github-trending 0.7.8 → 0.7.9
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 +11 -0
- package/lib/{chunk-HYVMRVGP.js → chunk-YJ5GF3MW.js} +64 -115
- package/lib/index.js +1 -2
- package/lib/internal.d.ts +18 -37
- package/lib/internal.js +5 -5
- package/package.json +2 -2
- package/lib/chunk-R7BK7SJK.js +0 -121
- package/lib/exec-VMDINNX5.js +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [v0.7.9] - 2026-11-01
|
|
4
|
+
|
|
5
|
+
> 内部重构:把重复的通用实现收敛到共享底座 `@morehao/dsh-plugin-kit@^0.3.1`。对外接口与业务语义保持不变。
|
|
6
|
+
|
|
7
|
+
### 改进 — 迁移到 dsh-plugin-kit 0.3.1
|
|
8
|
+
|
|
9
|
+
- **子进程执行**:`src/core/exec.ts` 收敛到 kit `./exec` 的 `spawnCollect` / `sanitizedEnv`,删除本地实现;握手阶段改为判 `result.error` 抛 `CORE_SPAWN_FAILED`(kit 的 `spawnCollect` 永不 reject)。
|
|
10
|
+
- **插件身份**:`plugin-info.ts` 的仓库地址规范化与读包改用 kit `./github` + `./meta`(`createPluginMeta`),保留 `readPluginInfo` / `normalizeRepositoryUrl` 导出面与返回形状。
|
|
11
|
+
- **HTTP 路由**:`routes.ts` 的 `sendJson` / `readBody` / 头校验改用 kit `./http` 的 `createRouteHandler`;业务 `dispatch`、`IpcError` 错误码与 `PluginUpdateError→409` 映射保持不变,错误码翻译仍留在插件侧。
|
|
12
|
+
- 对外路由响应形状、读包字段、错误码/映射均无变化(行为等价)。
|
|
13
|
+
|
|
3
14
|
## [v0.7.8] - 2026-11-01
|
|
4
15
|
|
|
5
16
|
> 统一「订阅」口径:这个功能不再叫「发版」,运行记录、概览、设置、订阅页与提示文案一致;顺带修好运行记录里的类型胶囊样式。
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
6
|
|
|
7
7
|
// src/config.ts
|
|
8
8
|
var config_exports = {};
|
|
@@ -1148,16 +1148,15 @@ __export(handshake_exports, {
|
|
|
1148
1148
|
DEFAULT_PROVIDERS: () => DEFAULT_PROVIDERS,
|
|
1149
1149
|
handshake: () => handshake
|
|
1150
1150
|
});
|
|
1151
|
+
import { spawnCollect as execCapture } from "@morehao/dsh-plugin-kit/exec";
|
|
1151
1152
|
var DEFAULT_PROVIDERS = ["deepseek", "openai-compatible"];
|
|
1152
1153
|
async function handshake(core, options = {}) {
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
} catch (error) {
|
|
1160
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
1154
|
+
const result = await execCapture(core.path, ["version", "--json"], {
|
|
1155
|
+
timeoutMs: options.timeoutMs ?? 5e3,
|
|
1156
|
+
signal: options.signal
|
|
1157
|
+
});
|
|
1158
|
+
if (result.error !== void 0) {
|
|
1159
|
+
const detail = result.error.message;
|
|
1161
1160
|
throw new IpcError("CORE_SPAWN_FAILED", `\u65E0\u6CD5\u6267\u884C\u6838\u5FC3 ${core.path}\uFF1A${detail}`);
|
|
1162
1161
|
}
|
|
1163
1162
|
if (result.aborted || options.signal?.aborted === true) {
|
|
@@ -1590,6 +1589,7 @@ __export(run_exports, {
|
|
|
1590
1589
|
runCore: () => runCore
|
|
1591
1590
|
});
|
|
1592
1591
|
import { spawn as spawn2 } from "child_process";
|
|
1592
|
+
import { sanitizedEnv } from "@morehao/dsh-plugin-kit/exec";
|
|
1593
1593
|
var DEFAULT_RUN_TIMEOUT_MS = 12e4;
|
|
1594
1594
|
var MAX_STDOUT = 16 * 1024 * 1024;
|
|
1595
1595
|
var MAX_STDERR = 2 * 1024 * 1024;
|
|
@@ -1772,6 +1772,7 @@ __export(core_exports, {
|
|
|
1772
1772
|
});
|
|
1773
1773
|
import { accessSync as accessSync2, constants as constants3, statSync as statSync4 } from "fs";
|
|
1774
1774
|
import path7 from "path";
|
|
1775
|
+
import { spawnCollect as execCapture2 } from "@morehao/dsh-plugin-kit/exec";
|
|
1775
1776
|
function coreRepoFromSource(repo) {
|
|
1776
1777
|
let ownerRepo = repo;
|
|
1777
1778
|
if (ownerRepo === void 0) {
|
|
@@ -1876,7 +1877,7 @@ async function detectCoexistence(ownPath, options = {}) {
|
|
|
1876
1877
|
}
|
|
1877
1878
|
let status;
|
|
1878
1879
|
try {
|
|
1879
|
-
const result = await
|
|
1880
|
+
const result = await execCapture2(found, ["version", "--json"], { timeoutMs: 3e3 });
|
|
1880
1881
|
if (result.code !== 0) {
|
|
1881
1882
|
status = {
|
|
1882
1883
|
found: true,
|
|
@@ -1970,8 +1971,8 @@ async function defaultGhToken(fresh = false) {
|
|
|
1970
1971
|
if (!fresh && ghTokenCache !== void 0 && Date.now() - ghTokenCache.at < GH_TOKEN_TTL_MS) {
|
|
1971
1972
|
return ghTokenCache.value;
|
|
1972
1973
|
}
|
|
1973
|
-
const {
|
|
1974
|
-
const result = await
|
|
1974
|
+
const { spawnCollect: execCapture6 } = await import("@morehao/dsh-plugin-kit/exec");
|
|
1975
|
+
const result = await execCapture6("gh", ["auth", "token"], { timeoutMs: 2e3 });
|
|
1975
1976
|
const token = result.code === 0 ? result.stdout.trim() : "";
|
|
1976
1977
|
const value = token === "" ? void 0 : token;
|
|
1977
1978
|
ghTokenCache = { value, at: Date.now() };
|
|
@@ -2660,6 +2661,7 @@ __export(subscribe_exports, {
|
|
|
2660
2661
|
import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync2, rmSync as rmSync2 } from "fs";
|
|
2661
2662
|
import os3 from "os";
|
|
2662
2663
|
import path8 from "path";
|
|
2664
|
+
import { spawnCollect as execCapture3, sanitizedEnv as sanitizedEnv2 } from "@morehao/dsh-plugin-kit/exec";
|
|
2663
2665
|
var SUBSCRIBE_TIMEOUT_MS = 8e3;
|
|
2664
2666
|
var RELEASES_TIMEOUT_MS = 3e4;
|
|
2665
2667
|
var REPO_PATTERN2 = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
@@ -2709,8 +2711,8 @@ async function runSubscribe(input, deps) {
|
|
|
2709
2711
|
configPath: file
|
|
2710
2712
|
};
|
|
2711
2713
|
const timeoutMs = input.action === "releases" ? RELEASES_TIMEOUT_MS : SUBSCRIBE_TIMEOUT_MS;
|
|
2712
|
-
const result = await
|
|
2713
|
-
env:
|
|
2714
|
+
const result = await execCapture3(corePath, ["subscribe", "--json"], {
|
|
2715
|
+
env: sanitizedEnv2(env),
|
|
2714
2716
|
input: JSON.stringify(request),
|
|
2715
2717
|
timeoutMs
|
|
2716
2718
|
});
|
|
@@ -3411,40 +3413,17 @@ __export(plugin_info_exports, {
|
|
|
3411
3413
|
normalizeRepositoryUrl: () => normalizeRepositoryUrl,
|
|
3412
3414
|
readPluginInfo: () => readPluginInfo
|
|
3413
3415
|
});
|
|
3414
|
-
import {
|
|
3416
|
+
import { normalizeRepositoryUrl } from "@morehao/dsh-plugin-kit/github";
|
|
3417
|
+
import { createPluginMeta } from "@morehao/dsh-plugin-kit/meta";
|
|
3415
3418
|
var DEFAULT_NAME = "@morehao/dsh-github-trending";
|
|
3416
|
-
|
|
3417
|
-
if (typeof value !== "string") return void 0;
|
|
3418
|
-
let url = value.trim();
|
|
3419
|
-
if (url === "") return void 0;
|
|
3420
|
-
url = url.replace(/^git\+/i, "");
|
|
3421
|
-
const ssh = /^git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/i.exec(url);
|
|
3422
|
-
if (ssh !== null) url = `https://github.com/${ssh[1]}/${ssh[2]}`;
|
|
3423
|
-
url = url.replace(/\.git$/i, "");
|
|
3424
|
-
try {
|
|
3425
|
-
const parsed = new URL(url);
|
|
3426
|
-
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return void 0;
|
|
3427
|
-
if (parsed.hostname.toLowerCase() !== "github.com") return void 0;
|
|
3428
|
-
const pathname = parsed.pathname.replace(/\/+$/, "");
|
|
3429
|
-
if (pathname === "") return void 0;
|
|
3430
|
-
return `https://github.com${pathname}`;
|
|
3431
|
-
} catch {
|
|
3432
|
-
return void 0;
|
|
3433
|
-
}
|
|
3434
|
-
}
|
|
3419
|
+
var PKG_URL = new URL("../package.json", import.meta.url);
|
|
3435
3420
|
function readPluginInfo() {
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
version: typeof pkg.version === "string" ? pkg.version : "0.0.0",
|
|
3443
|
-
...repository === void 0 ? {} : { repository }
|
|
3444
|
-
};
|
|
3445
|
-
} catch {
|
|
3446
|
-
return { name: DEFAULT_NAME, version: "0.0.0" };
|
|
3447
|
-
}
|
|
3421
|
+
const meta = createPluginMeta({ pkgUrl: PKG_URL, defaultName: DEFAULT_NAME });
|
|
3422
|
+
return {
|
|
3423
|
+
name: meta.name,
|
|
3424
|
+
version: meta.version,
|
|
3425
|
+
...meta.repository === void 0 ? {} : { repository: meta.repository }
|
|
3426
|
+
};
|
|
3448
3427
|
}
|
|
3449
3428
|
|
|
3450
3429
|
// src/host/github.ts
|
|
@@ -3958,6 +3937,7 @@ __export(repo_exports, {
|
|
|
3958
3937
|
});
|
|
3959
3938
|
import { statSync as statSync6 } from "fs";
|
|
3960
3939
|
import path11 from "path";
|
|
3940
|
+
import { spawnCollect as execCapture4 } from "@morehao/dsh-plugin-kit/exec";
|
|
3961
3941
|
function isDirectory(dir) {
|
|
3962
3942
|
try {
|
|
3963
3943
|
return statSync6(dir).isDirectory();
|
|
@@ -3967,7 +3947,7 @@ function isDirectory(dir) {
|
|
|
3967
3947
|
}
|
|
3968
3948
|
async function git(dir, args, env) {
|
|
3969
3949
|
try {
|
|
3970
|
-
const result = await
|
|
3950
|
+
const result = await execCapture4("git", ["-C", dir, ...args], { env, timeoutMs: 5e3 });
|
|
3971
3951
|
return result.code === 0 ? result.stdout.trim() : void 0;
|
|
3972
3952
|
} catch {
|
|
3973
3953
|
return void 0;
|
|
@@ -3998,77 +3978,53 @@ __export(routes_exports, {
|
|
|
3998
3978
|
ROUTE_PREFIX: () => ROUTE_PREFIX,
|
|
3999
3979
|
createRoutes: () => createRoutes
|
|
4000
3980
|
});
|
|
3981
|
+
import { createRouteHandler, HttpError } from "@morehao/dsh-plugin-kit/http";
|
|
4001
3982
|
import { PluginUpdateError } from "@morehao/dsh-plugin-kit/update";
|
|
4002
3983
|
var ROUTE_PREFIX = "/api/morehao/github-trending";
|
|
4003
3984
|
var HEADER = "x-dsh-github-trending";
|
|
4004
3985
|
var MAX_BODY2 = 512 * 1024;
|
|
4005
|
-
function sendJson2(response, status, payload) {
|
|
4006
|
-
const body = JSON.stringify(payload);
|
|
4007
|
-
response.writeHead(status, {
|
|
4008
|
-
"content-type": "application/json; charset=utf-8",
|
|
4009
|
-
"cache-control": "no-store",
|
|
4010
|
-
"content-length": Buffer.byteLength(body)
|
|
4011
|
-
});
|
|
4012
|
-
response.end(body);
|
|
4013
|
-
}
|
|
4014
|
-
async function readBody2(request) {
|
|
4015
|
-
const chunks = [];
|
|
4016
|
-
let size = 0;
|
|
4017
|
-
for await (const chunk of request) {
|
|
4018
|
-
size += chunk.length;
|
|
4019
|
-
if (size > MAX_BODY2) throw new IpcError("PAYLOAD_TOO_LARGE", "\u8BF7\u6C42\u4F53\u8FC7\u5927");
|
|
4020
|
-
chunks.push(chunk);
|
|
4021
|
-
}
|
|
4022
|
-
if (chunks.length === 0) return {};
|
|
4023
|
-
const text = Buffer.concat(chunks).toString("utf8").trim();
|
|
4024
|
-
if (text === "") return {};
|
|
4025
|
-
try {
|
|
4026
|
-
const value = JSON.parse(text);
|
|
4027
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
4028
|
-
throw new Error("body must be a JSON object");
|
|
4029
|
-
}
|
|
4030
|
-
return value;
|
|
4031
|
-
} catch (error) {
|
|
4032
|
-
throw new IpcError("CONFIG_INVALID", `\u8BF7\u6C42\u4F53\u4E0D\u662F JSON \u5BF9\u8C61\uFF1A${error instanceof Error ? error.message : String(error)}`);
|
|
4033
|
-
}
|
|
4034
|
-
}
|
|
4035
3986
|
function createRoutes(deps) {
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
if (response.writableEnded) return;
|
|
3987
|
+
const logger = deps.logger;
|
|
3988
|
+
let current = { method: "GET", pathname: "/" };
|
|
3989
|
+
const handler = createRouteHandler({
|
|
3990
|
+
prefix: ROUTE_PREFIX,
|
|
3991
|
+
header: HEADER,
|
|
3992
|
+
maxBodyBytes: MAX_BODY2,
|
|
3993
|
+
dispatch: async ({ method, pathname, url, body }) => {
|
|
3994
|
+
current = { method, pathname };
|
|
3995
|
+
return dispatch(method, pathname, url, body, deps);
|
|
3996
|
+
},
|
|
3997
|
+
// 错误码翻译留在插件侧(dispatcher 不做映射):保持与原实现的响应形状逐字一致。
|
|
3998
|
+
onError: (error) => {
|
|
4049
3999
|
if (error instanceof PluginUpdateError) {
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4000
|
+
logger?.("update.failed", { code: error.code, message: error.message });
|
|
4001
|
+
return {
|
|
4002
|
+
status: 409,
|
|
4053
4003
|
code: "UPDATE_FAILED",
|
|
4054
|
-
updateCode: error.code,
|
|
4055
4004
|
message: redact(error.message),
|
|
4056
|
-
update: deps.update?.view() ?? null
|
|
4057
|
-
}
|
|
4058
|
-
|
|
4005
|
+
extra: { updateCode: error.code, update: deps.update?.view() ?? null }
|
|
4006
|
+
};
|
|
4007
|
+
}
|
|
4008
|
+
if (error instanceof HttpError) {
|
|
4009
|
+
const code2 = error.code === "PAYLOAD_TOO_LARGE" ? "PAYLOAD_TOO_LARGE" : "CONFIG_INVALID";
|
|
4010
|
+
return { status: 400, code: code2, message: redact(error.message) };
|
|
4059
4011
|
}
|
|
4060
4012
|
const code = error instanceof IpcError ? error.code : "INTERNAL";
|
|
4061
4013
|
const message = redact(error instanceof Error ? error.message : String(error));
|
|
4062
|
-
|
|
4014
|
+
logger?.("route.error", { pathname: current.pathname, method: current.method, code, message });
|
|
4063
4015
|
const status = code === "CONFIG_INVALID" ? (
|
|
4064
4016
|
// 「已有一次运行在进行中」是并发冲突而非参数错误:用 409,前端据此禁用按钮并提示。
|
|
4065
4017
|
message.includes("\u8FD0\u884C\u5728\u8FDB\u884C\u4E2D") ? 409 : 400
|
|
4066
4018
|
) : code === "NOT_FOUND" ? 404 : 500;
|
|
4067
|
-
|
|
4068
|
-
}
|
|
4019
|
+
return { status, code, message };
|
|
4020
|
+
},
|
|
4021
|
+
logger
|
|
4022
|
+
});
|
|
4023
|
+
return async function routeHandler(request, response) {
|
|
4024
|
+
await handler(request, response);
|
|
4069
4025
|
};
|
|
4070
4026
|
}
|
|
4071
|
-
async function dispatch(method, pathname, url,
|
|
4027
|
+
async function dispatch(method, pathname, url, body, deps) {
|
|
4072
4028
|
const env = deps.env ?? process.env;
|
|
4073
4029
|
const settings = deps.store.readSettings();
|
|
4074
4030
|
if (method === "GET" && pathname === "/state") return statePayload(deps, settings);
|
|
@@ -4079,7 +4035,6 @@ async function dispatch(method, pathname, url, request, deps) {
|
|
|
4079
4035
|
}
|
|
4080
4036
|
if (method === "POST" && pathname === "/update") {
|
|
4081
4037
|
if (deps.update === void 0) throw new IpcError("NOT_FOUND", "\u81EA\u66F4\u65B0\u670D\u52A1\u4E0D\u53EF\u7528");
|
|
4082
|
-
const body = await readBody2(request);
|
|
4083
4038
|
const version = typeof body.version === "string" && body.version.trim() !== "" ? body.version.trim() : void 0;
|
|
4084
4039
|
const result = await deps.update.apply(version === void 0 ? {} : { version });
|
|
4085
4040
|
return { result, update: deps.update.view() };
|
|
@@ -4095,7 +4050,6 @@ async function dispatch(method, pathname, url, request, deps) {
|
|
|
4095
4050
|
return { downloaded: true, path: core.path, tag: core.tag ?? null, core: status };
|
|
4096
4051
|
}
|
|
4097
4052
|
if (method === "POST" && pathname === "/config") {
|
|
4098
|
-
const body = await readBody2(request);
|
|
4099
4053
|
const incoming = normalizeSettings(body.settings ?? body);
|
|
4100
4054
|
const section = typeof body.section === "string" && SETTINGS_SECTIONS.includes(body.section) ? body.section : void 0;
|
|
4101
4055
|
let next = section === void 0 ? incoming : mergeSettingsSection(settings, incoming, section);
|
|
@@ -4114,7 +4068,6 @@ async function dispatch(method, pathname, url, request, deps) {
|
|
|
4114
4068
|
return { saved: true, settings: next, problems: [] };
|
|
4115
4069
|
}
|
|
4116
4070
|
if (method === "POST" && pathname === "/preflight") {
|
|
4117
|
-
const body = await readBody2(request);
|
|
4118
4071
|
const candidate = body.settings === void 0 ? settings : normalizeSettings(body.settings);
|
|
4119
4072
|
const result = await preflightModel({
|
|
4120
4073
|
settings: candidate,
|
|
@@ -4125,7 +4078,6 @@ async function dispatch(method, pathname, url, request, deps) {
|
|
|
4125
4078
|
return { preflight: result };
|
|
4126
4079
|
}
|
|
4127
4080
|
if (method === "POST" && pathname === "/run") {
|
|
4128
|
-
const body = await readBody2(request);
|
|
4129
4081
|
const base = {
|
|
4130
4082
|
dryRun: body.dryRun === true,
|
|
4131
4083
|
...typeof body.date === "string" && body.date !== "" ? { date: body.date } : {},
|
|
@@ -4143,7 +4095,6 @@ async function dispatch(method, pathname, url, request, deps) {
|
|
|
4143
4095
|
return { cancelled: deps.runner.cancel() };
|
|
4144
4096
|
}
|
|
4145
4097
|
if (method === "POST" && pathname === "/releases/run") {
|
|
4146
|
-
const body = await readBody2(request);
|
|
4147
4098
|
let repo;
|
|
4148
4099
|
if (body.repo !== void 0) {
|
|
4149
4100
|
if (typeof body.repo !== "string" || !isValidRepo(body.repo.trim())) {
|
|
@@ -4191,7 +4142,6 @@ async function dispatch(method, pathname, url, request, deps) {
|
|
|
4191
4142
|
return { ...result.doc };
|
|
4192
4143
|
}
|
|
4193
4144
|
if (method === "POST" && pathname === "/subscriptions") {
|
|
4194
|
-
const body = await readBody2(request);
|
|
4195
4145
|
const action = body.action === "add" || body.action === "remove" ? body.action : void 0;
|
|
4196
4146
|
if (action === void 0) throw new IpcError("CONFIG_INVALID", "action \u5FC5\u987B\u662F add \u6216 remove");
|
|
4197
4147
|
const repos = Array.isArray(body.repos) ? body.repos.filter((item) => typeof item === "string" && item.trim() !== "").map((item) => item.trim()) : typeof body.repo === "string" && body.repo.trim() !== "" ? [body.repo.trim()] : [];
|
|
@@ -4206,7 +4156,6 @@ async function dispatch(method, pathname, url, request, deps) {
|
|
|
4206
4156
|
return { repos: latest.ok ? latest.repos : [], items: latest.ok ? latest.items ?? [] : [] };
|
|
4207
4157
|
}
|
|
4208
4158
|
if (method === "POST" && pathname === "/github/test") {
|
|
4209
|
-
const body = await readBody2(request);
|
|
4210
4159
|
const candidate = body.settings === void 0 ? settings : normalizeSettings(body.settings);
|
|
4211
4160
|
const probe = await probeGithubAuth({
|
|
4212
4161
|
credentials: credentialServices(deps.get),
|
|
@@ -4225,7 +4174,6 @@ async function dispatch(method, pathname, url, request, deps) {
|
|
|
4225
4174
|
return { providers: candidates, defaultSelection: readDefaultSelection(deps.get) ?? null };
|
|
4226
4175
|
}
|
|
4227
4176
|
if (method === "POST" && pathname === "/quickfill") {
|
|
4228
|
-
const body = await readBody2(request);
|
|
4229
4177
|
const candidates = await listProviderCandidates({
|
|
4230
4178
|
llm: llmServices(deps.get),
|
|
4231
4179
|
credentials: credentialServices(deps.get),
|
|
@@ -4357,6 +4305,7 @@ __export(update_exports, {
|
|
|
4357
4305
|
});
|
|
4358
4306
|
import { normalizeProfile } from "@morehao/dsh-plugin-kit";
|
|
4359
4307
|
import { createPluginUpdater } from "@morehao/dsh-plugin-kit/update";
|
|
4308
|
+
import { spawnCollect as execCapture5, sanitizedEnv as sanitizedEnv3 } from "@morehao/dsh-plugin-kit/exec";
|
|
4360
4309
|
function pnpmViewRunner(get, env, exec) {
|
|
4361
4310
|
return async (spec) => {
|
|
4362
4311
|
const profile = normalizeProfile(get("profileContext"));
|
|
@@ -4367,7 +4316,7 @@ function pnpmViewRunner(get, env, exec) {
|
|
|
4367
4316
|
try {
|
|
4368
4317
|
result = await exec(command, [...prefix, "view", spec, "version", "--json"], {
|
|
4369
4318
|
cwd: profile.dir,
|
|
4370
|
-
env:
|
|
4319
|
+
env: sanitizedEnv3(env),
|
|
4371
4320
|
timeoutMs: 8e3,
|
|
4372
4321
|
maxStdout: 64 * 1024,
|
|
4373
4322
|
maxStderr: 16 * 1024
|
|
@@ -4389,7 +4338,7 @@ function pnpmViewRunner(get, env, exec) {
|
|
|
4389
4338
|
};
|
|
4390
4339
|
}
|
|
4391
4340
|
function createUpdateService(deps) {
|
|
4392
|
-
const exec = deps.exec ??
|
|
4341
|
+
const exec = deps.exec ?? execCapture5;
|
|
4393
4342
|
return createPluginUpdater({
|
|
4394
4343
|
meta: deps.meta,
|
|
4395
4344
|
getPluginManager: () => deps.get("pluginManager"),
|
package/lib/index.js
CHANGED
package/lib/internal.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { ErrorCode, FileArtifact, Usage, ReleasesReport, SubscriptionItem, SubscriptionDoc, SubscriptionStatus, ErrorInfo, RunRequest, RunResult, State, StateRun, SubscriptionList, SubscriptionVolume } from '@morehao/trendradar-contract';
|
|
2
|
+
import { ExecOptions, ExecResult } from '@morehao/dsh-plugin-kit/exec';
|
|
3
|
+
import * as exec from '@morehao/dsh-plugin-kit/exec';
|
|
4
|
+
export { exec };
|
|
5
|
+
import { normalizeRepositoryUrl } from '@morehao/dsh-plugin-kit/github';
|
|
2
6
|
import http from 'node:http';
|
|
3
7
|
import { Updater, PluginMeta, Logger } from '@morehao/dsh-plugin-kit/update';
|
|
4
8
|
|
|
@@ -930,40 +934,6 @@ declare namespace channel {
|
|
|
930
934
|
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 };
|
|
931
935
|
}
|
|
932
936
|
|
|
933
|
-
interface ExecResult {
|
|
934
|
-
code: number | null;
|
|
935
|
-
signal: NodeJS.Signals | null;
|
|
936
|
-
stdout: string;
|
|
937
|
-
stderr: string;
|
|
938
|
-
timedOut: boolean;
|
|
939
|
-
aborted: boolean;
|
|
940
|
-
durationMs: number;
|
|
941
|
-
}
|
|
942
|
-
declare function sanitizedEnv(source?: NodeJS.ProcessEnv, extra?: Record<string, string | undefined>): Record<string, string>;
|
|
943
|
-
interface ExecOptions {
|
|
944
|
-
env?: NodeJS.ProcessEnv;
|
|
945
|
-
cwd?: string;
|
|
946
|
-
timeoutMs?: number;
|
|
947
|
-
signal?: AbortSignal;
|
|
948
|
-
maxStdout?: number;
|
|
949
|
-
maxStderr?: number;
|
|
950
|
-
/** 写入子进程 stdin 的内容(写完即关闭);省略则 stdin 为 ignore。 */
|
|
951
|
-
input?: string;
|
|
952
|
-
}
|
|
953
|
-
/**
|
|
954
|
-
* 执行一次短命令并收集输出(握手、共存探测都走这里)。
|
|
955
|
-
* 超时与取消都先 SIGTERM、3 s 后 SIGKILL——核心是单进程,不需要 process group。
|
|
956
|
-
*/
|
|
957
|
-
declare function execCapture(file: string, args: string[], options?: ExecOptions): Promise<ExecResult>;
|
|
958
|
-
|
|
959
|
-
type exec_ExecOptions = ExecOptions;
|
|
960
|
-
type exec_ExecResult = ExecResult;
|
|
961
|
-
declare const exec_execCapture: typeof execCapture;
|
|
962
|
-
declare const exec_sanitizedEnv: typeof sanitizedEnv;
|
|
963
|
-
declare namespace exec {
|
|
964
|
-
export { type exec_ExecOptions as ExecOptions, type exec_ExecResult as ExecResult, exec_execCapture as execCapture, exec_sanitizedEnv as sanitizedEnv };
|
|
965
|
-
}
|
|
966
|
-
|
|
967
937
|
declare const DEFAULT_RUN_TIMEOUT_MS = 120000;
|
|
968
938
|
interface RunCoreOptions {
|
|
969
939
|
core: CoreLocation;
|
|
@@ -1654,13 +1624,24 @@ declare namespace subscribe {
|
|
|
1654
1624
|
export { subscribe_RELEASES_TIMEOUT_MS as RELEASES_TIMEOUT_MS, subscribe_SUBSCRIBE_TIMEOUT_MS as SUBSCRIBE_TIMEOUT_MS, type subscribe_SubscribeDeps as SubscribeDeps, subscribe_isValidRepo as isValidRepo, subscribe_runSubscribe as runSubscribe };
|
|
1655
1625
|
}
|
|
1656
1626
|
|
|
1627
|
+
/**
|
|
1628
|
+
* 插件自身元数据:包名、版本、仓库地址。
|
|
1629
|
+
*
|
|
1630
|
+
* `/state.plugin` 是界面上「关于」的唯一来源:版本不能硬编码在客户端,仓库地址
|
|
1631
|
+
* 也不能从客户端猜。`package.json.repository.url` 常见形态是
|
|
1632
|
+
* `git+https://github.com/o/r.git` 或 `git@github.com:o/r.git`,统一规范化成
|
|
1633
|
+
* `https://github.com/o/r`;解析不了就返回 undefined,界面隐藏外链而不是猜。
|
|
1634
|
+
*
|
|
1635
|
+
* 读包与规范化仓库地址都交给 `@morehao/dsh-plugin-kit` 的 `./meta` + `./github`;
|
|
1636
|
+
* 这里保留 `readPluginInfo()` / `normalizeRepositoryUrl()` 两个对内部(测试与 index)
|
|
1637
|
+
* 的既有导出面,形状不变。
|
|
1638
|
+
*/
|
|
1639
|
+
|
|
1657
1640
|
interface PluginInfo {
|
|
1658
1641
|
name: string;
|
|
1659
1642
|
version: string;
|
|
1660
1643
|
repository?: string;
|
|
1661
1644
|
}
|
|
1662
|
-
/** 只放行 GitHub 的 http(s) 地址;ssh / git+ 前缀先归一化。 */
|
|
1663
|
-
declare function normalizeRepositoryUrl(value: unknown): string | undefined;
|
|
1664
1645
|
declare function readPluginInfo(): PluginInfo;
|
|
1665
1646
|
|
|
1666
1647
|
type pluginInfo_PluginInfo = PluginInfo;
|
|
@@ -2164,4 +2145,4 @@ declare namespace tools {
|
|
|
2164
2145
|
export { tools_createTrendingHistoryTool as createTrendingHistoryTool, tools_createTrendingRunTool as createTrendingRunTool };
|
|
2165
2146
|
}
|
|
2166
2147
|
|
|
2167
|
-
export { channel, config, core, credentials, errors,
|
|
2148
|
+
export { channel, config, core, credentials, errors, github, handshake$1 as handshake, importCli, ipc, locate, paths, pendingPr, pluginInfo, preflight, proxy, quickfill, release, repo, routes, run, runner, schedule, state, subscribe, tools, update as updateService, version };
|
package/lib/internal.js
CHANGED
|
@@ -26,17 +26,17 @@ import {
|
|
|
26
26
|
tools_exports,
|
|
27
27
|
update_exports,
|
|
28
28
|
version_exports
|
|
29
|
-
} from "./chunk-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
} from "./chunk-YJ5GF3MW.js";
|
|
30
|
+
|
|
31
|
+
// src/internal.ts
|
|
32
|
+
import * as exec from "@morehao/dsh-plugin-kit/exec";
|
|
33
33
|
export {
|
|
34
34
|
channel_exports as channel,
|
|
35
35
|
config_exports as config,
|
|
36
36
|
core_exports as core,
|
|
37
37
|
credentials_exports as credentials,
|
|
38
38
|
errors_exports as errors,
|
|
39
|
-
|
|
39
|
+
exec,
|
|
40
40
|
github_exports as github,
|
|
41
41
|
handshake_exports as handshake,
|
|
42
42
|
import_cli_exports as importCli,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morehao/dsh-github-trending",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.9",
|
|
4
4
|
"description": "GitHub 趋势日报插件:每天定时 spawn 本地 trendradar 核心,抓取 Trending、生成中文简介与总结,提交到你的仓库并自动合并 PR。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
}
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@morehao/dsh-plugin-kit": "0.
|
|
53
|
+
"@morehao/dsh-plugin-kit": "^0.3.1",
|
|
54
54
|
"@morehao/trendradar-contract": "0.5.0"
|
|
55
55
|
},
|
|
56
56
|
"dsh": {
|
package/lib/chunk-R7BK7SJK.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __export = (target, all) => {
|
|
3
|
-
for (var name in all)
|
|
4
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
// src/core/exec.ts
|
|
8
|
-
var exec_exports = {};
|
|
9
|
-
__export(exec_exports, {
|
|
10
|
-
execCapture: () => execCapture,
|
|
11
|
-
sanitizedEnv: () => sanitizedEnv
|
|
12
|
-
});
|
|
13
|
-
import { spawn } from "child_process";
|
|
14
|
-
var ENV_KEYS = [
|
|
15
|
-
"PATH",
|
|
16
|
-
"HOME",
|
|
17
|
-
"USER",
|
|
18
|
-
"LOGNAME",
|
|
19
|
-
"SHELL",
|
|
20
|
-
"TMPDIR",
|
|
21
|
-
"TMP",
|
|
22
|
-
"TEMP",
|
|
23
|
-
"LANG",
|
|
24
|
-
"LC_ALL",
|
|
25
|
-
"LC_CTYPE",
|
|
26
|
-
"SSL_CERT_FILE",
|
|
27
|
-
"SSL_CERT_DIR",
|
|
28
|
-
"GIT_AUTHOR_NAME",
|
|
29
|
-
"GIT_AUTHOR_EMAIL",
|
|
30
|
-
"GIT_COMMITTER_NAME",
|
|
31
|
-
"GIT_COMMITTER_EMAIL",
|
|
32
|
-
"GIT_CONFIG_GLOBAL",
|
|
33
|
-
"GIT_SSH_COMMAND"
|
|
34
|
-
];
|
|
35
|
-
var PROXY_KEYS = [
|
|
36
|
-
"HTTP_PROXY",
|
|
37
|
-
"HTTPS_PROXY",
|
|
38
|
-
"NO_PROXY",
|
|
39
|
-
"ALL_PROXY",
|
|
40
|
-
"http_proxy",
|
|
41
|
-
"https_proxy",
|
|
42
|
-
"no_proxy",
|
|
43
|
-
"all_proxy"
|
|
44
|
-
];
|
|
45
|
-
function sanitizedEnv(source = process.env, extra = {}) {
|
|
46
|
-
const env = {};
|
|
47
|
-
for (const key of [...ENV_KEYS, ...PROXY_KEYS]) {
|
|
48
|
-
const value = source[key];
|
|
49
|
-
if (typeof value === "string" && value !== "") env[key] = value;
|
|
50
|
-
}
|
|
51
|
-
for (const [key, value] of Object.entries(extra)) {
|
|
52
|
-
if (typeof value === "string" && value !== "") env[key] = value;
|
|
53
|
-
}
|
|
54
|
-
return env;
|
|
55
|
-
}
|
|
56
|
-
function killTree(child, signal) {
|
|
57
|
-
try {
|
|
58
|
-
child.kill(signal);
|
|
59
|
-
} catch {
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
async function execCapture(file, args, options = {}) {
|
|
63
|
-
const started = Date.now();
|
|
64
|
-
const timeoutMs = options.timeoutMs ?? 1e4;
|
|
65
|
-
const maxStdout = options.maxStdout ?? 1024 * 1024;
|
|
66
|
-
const maxStderr = options.maxStderr ?? 1024 * 1024;
|
|
67
|
-
const child = spawn(file, args, {
|
|
68
|
-
cwd: options.cwd,
|
|
69
|
-
env: options.env ?? process.env,
|
|
70
|
-
stdio: [options.input === void 0 ? "ignore" : "pipe", "pipe", "pipe"],
|
|
71
|
-
windowsHide: true
|
|
72
|
-
});
|
|
73
|
-
if (options.input !== void 0) {
|
|
74
|
-
child.stdin?.on("error", () => void 0);
|
|
75
|
-
child.stdin?.end(options.input);
|
|
76
|
-
}
|
|
77
|
-
let stdout = "";
|
|
78
|
-
let stderr = "";
|
|
79
|
-
let timedOut = false;
|
|
80
|
-
let aborted = false;
|
|
81
|
-
const hardKill = setTimeout(() => killTree(child, "SIGKILL"), timeoutMs + 3e3);
|
|
82
|
-
const timer = setTimeout(() => {
|
|
83
|
-
timedOut = true;
|
|
84
|
-
killTree(child, "SIGTERM");
|
|
85
|
-
}, timeoutMs);
|
|
86
|
-
const onAbort = () => {
|
|
87
|
-
aborted = true;
|
|
88
|
-
killTree(child, "SIGTERM");
|
|
89
|
-
};
|
|
90
|
-
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
91
|
-
child.stdout?.setEncoding("utf8");
|
|
92
|
-
child.stdout?.on("data", (chunk) => {
|
|
93
|
-
if (stdout.length < maxStdout) stdout += chunk;
|
|
94
|
-
});
|
|
95
|
-
child.stderr?.setEncoding("utf8");
|
|
96
|
-
child.stderr?.on("data", (chunk) => {
|
|
97
|
-
if (stderr.length < maxStderr) stderr += chunk;
|
|
98
|
-
});
|
|
99
|
-
const result = await new Promise((resolve, reject) => {
|
|
100
|
-
child.on("error", (error) => reject(error));
|
|
101
|
-
child.on("close", (code, signal) => resolve({ code, signal }));
|
|
102
|
-
});
|
|
103
|
-
clearTimeout(timer);
|
|
104
|
-
clearTimeout(hardKill);
|
|
105
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
106
|
-
return {
|
|
107
|
-
...result,
|
|
108
|
-
stdout,
|
|
109
|
-
stderr,
|
|
110
|
-
timedOut,
|
|
111
|
-
aborted,
|
|
112
|
-
durationMs: Date.now() - started
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export {
|
|
117
|
-
__export,
|
|
118
|
-
sanitizedEnv,
|
|
119
|
-
execCapture,
|
|
120
|
-
exec_exports
|
|
121
|
-
};
|