@morehao/dsh-github-trending 0.4.5 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +26 -2
- package/client.js +493 -19
- package/lib/{chunk-XLIFTAVL.js → chunk-R7BK7SJK.js} +5 -1
- package/lib/{chunk-GBXP2NGW.js → chunk-R7EUBUTS.js} +289 -9
- package/lib/{exec-33EQXGUA.js → exec-VMDINNX5.js} +1 -1
- package/lib/index.js +2 -2
- package/lib/internal.d.ts +196 -8
- package/lib/internal.js +4 -2
- package/package.json +3 -3
|
@@ -67,9 +67,13 @@ async function execCapture(file, args, options = {}) {
|
|
|
67
67
|
const child = spawn(file, args, {
|
|
68
68
|
cwd: options.cwd,
|
|
69
69
|
env: options.env ?? process.env,
|
|
70
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
70
|
+
stdio: [options.input === void 0 ? "ignore" : "pipe", "pipe", "pipe"],
|
|
71
71
|
windowsHide: true
|
|
72
72
|
});
|
|
73
|
+
if (options.input !== void 0) {
|
|
74
|
+
child.stdin?.on("error", () => void 0);
|
|
75
|
+
child.stdin?.end(options.input);
|
|
76
|
+
}
|
|
73
77
|
let stdout = "";
|
|
74
78
|
let stderr = "";
|
|
75
79
|
let timedOut = false;
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
__export,
|
|
3
3
|
execCapture,
|
|
4
4
|
sanitizedEnv
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-R7BK7SJK.js";
|
|
6
6
|
|
|
7
7
|
// src/config.ts
|
|
8
8
|
var config_exports = {};
|
|
@@ -13,6 +13,7 @@ __export(config_exports, {
|
|
|
13
13
|
PROVIDER_BASE_URLS: () => PROVIDER_BASE_URLS,
|
|
14
14
|
SETTINGS_SECTIONS: () => SETTINGS_SECTIONS,
|
|
15
15
|
effectiveBaseURL: () => effectiveBaseURL,
|
|
16
|
+
isEnrich: () => isEnrich,
|
|
16
17
|
isPeriod: () => isPeriod,
|
|
17
18
|
isValidTimezone: () => isValidTimezone,
|
|
18
19
|
mergeSettingsSection: () => mergeSettingsSection,
|
|
@@ -27,6 +28,9 @@ var PERIODS = ["daily", "weekly", "monthly"];
|
|
|
27
28
|
function isPeriod(value) {
|
|
28
29
|
return value === "daily" || value === "weekly" || value === "monthly";
|
|
29
30
|
}
|
|
31
|
+
function isEnrich(value) {
|
|
32
|
+
return value === "none" || value === "repo" || value === "readme";
|
|
33
|
+
}
|
|
30
34
|
var DEFAULT_SETTINGS = {
|
|
31
35
|
model: {
|
|
32
36
|
provider: "deepseek",
|
|
@@ -55,6 +59,25 @@ var DEFAULT_SETTINGS = {
|
|
|
55
59
|
},
|
|
56
60
|
github: { authMode: "gh", tokenRef: "GITHUB_TOKEN" },
|
|
57
61
|
trending: { since: "daily", languages: ["all", "typescript", "python", "go", "rust"], topN: 25 },
|
|
62
|
+
summarize: {
|
|
63
|
+
batchSize: 10,
|
|
64
|
+
maxRetries: 1,
|
|
65
|
+
enrich: "none",
|
|
66
|
+
readmeChars: 800,
|
|
67
|
+
enrichCacheTTLHours: 168,
|
|
68
|
+
enrichConcurrency: 4,
|
|
69
|
+
enrichTimeoutSeconds: 5,
|
|
70
|
+
enrichBudgetSeconds: 8
|
|
71
|
+
},
|
|
72
|
+
releases: {
|
|
73
|
+
includePrerelease: false,
|
|
74
|
+
includeDrafts: false,
|
|
75
|
+
fallbackToTags: true,
|
|
76
|
+
baselineOnFirstRun: true,
|
|
77
|
+
perRepoLimit: 5,
|
|
78
|
+
maxNotesChars: 4e3,
|
|
79
|
+
period: "daily"
|
|
80
|
+
},
|
|
58
81
|
output: { dir: "trending" },
|
|
59
82
|
schedule: { enabled: true, time: "08:30:00", timezone: "Asia/Shanghai", periods: ["daily", "weekly", "monthly"] },
|
|
60
83
|
corePath: "",
|
|
@@ -66,12 +89,14 @@ var PROVIDER_BASE_URLS = {
|
|
|
66
89
|
anthropic: ""
|
|
67
90
|
};
|
|
68
91
|
var CORE_PROVIDERS = ["deepseek", "openai-compatible"];
|
|
69
|
-
var SETTINGS_SECTIONS = ["source", "model", "repo", "auth", "scope", "schedule"];
|
|
92
|
+
var SETTINGS_SECTIONS = ["source", "model", "repo", "auth", "scope", "summarize", "releases", "schedule"];
|
|
70
93
|
function sectionOfField(field) {
|
|
71
94
|
if (field.startsWith("model.")) return "model";
|
|
72
95
|
if (field.startsWith("repo.") || field.startsWith("output.") || field.startsWith("pr.")) return "repo";
|
|
73
96
|
if (field.startsWith("github.")) return "auth";
|
|
74
97
|
if (field.startsWith("trending.")) return "scope";
|
|
98
|
+
if (field.startsWith("summarize.")) return "summarize";
|
|
99
|
+
if (field.startsWith("releases.")) return "releases";
|
|
75
100
|
if (field.startsWith("schedule.")) return "schedule";
|
|
76
101
|
if (field === "corePath" || field === "coreAutoDownload") return "source";
|
|
77
102
|
return void 0;
|
|
@@ -97,6 +122,12 @@ function mergeSettingsSection(stored, incoming, section) {
|
|
|
97
122
|
case "scope":
|
|
98
123
|
next.trending = incoming.trending;
|
|
99
124
|
break;
|
|
125
|
+
case "summarize":
|
|
126
|
+
next.summarize = incoming.summarize;
|
|
127
|
+
break;
|
|
128
|
+
case "releases":
|
|
129
|
+
next.releases = incoming.releases;
|
|
130
|
+
break;
|
|
100
131
|
case "schedule":
|
|
101
132
|
next.schedule = incoming.schedule;
|
|
102
133
|
break;
|
|
@@ -127,11 +158,15 @@ function normalizeSettings(input) {
|
|
|
127
158
|
const pr = raw.pr ?? {};
|
|
128
159
|
const github = raw.github ?? {};
|
|
129
160
|
const trending = raw.trending ?? {};
|
|
161
|
+
const summarize = raw.summarize ?? {};
|
|
162
|
+
const releases = raw.releases ?? {};
|
|
130
163
|
const output = raw.output ?? {};
|
|
131
164
|
const schedule = raw.schedule ?? {};
|
|
132
165
|
const commitMode = str(repo.commitMode, DEFAULT_SETTINGS.repo.commitMode);
|
|
133
166
|
const authMode = str(github.authMode, DEFAULT_SETTINGS.github.authMode);
|
|
134
167
|
const since = str(trending.since, DEFAULT_SETTINGS.trending.since);
|
|
168
|
+
const enrich = str(summarize.enrich, DEFAULT_SETTINGS.summarize.enrich);
|
|
169
|
+
const releasesPeriod = str(releases.period, DEFAULT_SETTINGS.releases.period);
|
|
135
170
|
return {
|
|
136
171
|
model: {
|
|
137
172
|
provider: str(model.provider, DEFAULT_SETTINGS.model.provider),
|
|
@@ -168,6 +203,25 @@ function normalizeSettings(input) {
|
|
|
168
203
|
languages: strArray(trending.languages, DEFAULT_SETTINGS.trending.languages),
|
|
169
204
|
topN: Math.round(num(trending.topN, DEFAULT_SETTINGS.trending.topN))
|
|
170
205
|
},
|
|
206
|
+
summarize: {
|
|
207
|
+
batchSize: Math.round(num(summarize.batchSize, DEFAULT_SETTINGS.summarize.batchSize)),
|
|
208
|
+
maxRetries: Math.round(num(summarize.maxRetries, DEFAULT_SETTINGS.summarize.maxRetries)),
|
|
209
|
+
enrich: isEnrich(enrich) ? enrich : DEFAULT_SETTINGS.summarize.enrich,
|
|
210
|
+
readmeChars: Math.round(num(summarize.readmeChars, DEFAULT_SETTINGS.summarize.readmeChars)),
|
|
211
|
+
enrichCacheTTLHours: Math.round(num(summarize.enrichCacheTTLHours, DEFAULT_SETTINGS.summarize.enrichCacheTTLHours)),
|
|
212
|
+
enrichConcurrency: Math.round(num(summarize.enrichConcurrency, DEFAULT_SETTINGS.summarize.enrichConcurrency)),
|
|
213
|
+
enrichTimeoutSeconds: Math.round(num(summarize.enrichTimeoutSeconds, DEFAULT_SETTINGS.summarize.enrichTimeoutSeconds)),
|
|
214
|
+
enrichBudgetSeconds: Math.round(num(summarize.enrichBudgetSeconds, DEFAULT_SETTINGS.summarize.enrichBudgetSeconds))
|
|
215
|
+
},
|
|
216
|
+
releases: {
|
|
217
|
+
includePrerelease: bool(releases.includePrerelease, DEFAULT_SETTINGS.releases.includePrerelease),
|
|
218
|
+
includeDrafts: bool(releases.includeDrafts, DEFAULT_SETTINGS.releases.includeDrafts),
|
|
219
|
+
fallbackToTags: bool(releases.fallbackToTags, DEFAULT_SETTINGS.releases.fallbackToTags),
|
|
220
|
+
baselineOnFirstRun: bool(releases.baselineOnFirstRun, DEFAULT_SETTINGS.releases.baselineOnFirstRun),
|
|
221
|
+
perRepoLimit: Math.round(num(releases.perRepoLimit, DEFAULT_SETTINGS.releases.perRepoLimit)),
|
|
222
|
+
maxNotesChars: Math.round(num(releases.maxNotesChars, DEFAULT_SETTINGS.releases.maxNotesChars)),
|
|
223
|
+
period: isPeriod(releasesPeriod) ? releasesPeriod : DEFAULT_SETTINGS.releases.period
|
|
224
|
+
},
|
|
171
225
|
output: {
|
|
172
226
|
dir: str(output.dir, DEFAULT_SETTINGS.output.dir).trim() || DEFAULT_SETTINGS.output.dir
|
|
173
227
|
},
|
|
@@ -193,7 +247,7 @@ function isValidTimezone(timezone) {
|
|
|
193
247
|
}
|
|
194
248
|
function validateSettings(settings, providers = CORE_PROVIDERS) {
|
|
195
249
|
const problems = [];
|
|
196
|
-
const { model, repo, trending, output, schedule } = settings;
|
|
250
|
+
const { model, repo, trending, summarize, releases, output, schedule } = settings;
|
|
197
251
|
if (model.provider.trim() === "") {
|
|
198
252
|
problems.push({ field: "model.provider", code: "CONFIG_INVALID", message: "\u7F3A\u5C11 provider" });
|
|
199
253
|
} else if (!providers.includes(model.provider)) {
|
|
@@ -232,6 +286,27 @@ function validateSettings(settings, providers = CORE_PROVIDERS) {
|
|
|
232
286
|
if (!Number.isInteger(trending.topN) || trending.topN <= 0) {
|
|
233
287
|
problems.push({ field: "trending.topN", code: "CONFIG_INVALID", message: "\u6BCF\u8BED\u8A00\u6761\u6570\u5FC5\u987B\u662F\u6B63\u6574\u6570" });
|
|
234
288
|
}
|
|
289
|
+
if (!isEnrich(summarize.enrich)) {
|
|
290
|
+
problems.push({ field: "summarize.enrich", code: "CONFIG_INVALID", message: "enrich \u5FC5\u987B\u662F none / repo / readme" });
|
|
291
|
+
}
|
|
292
|
+
if (!Number.isInteger(summarize.batchSize) || summarize.batchSize <= 0) {
|
|
293
|
+
problems.push({ field: "summarize.batchSize", code: "CONFIG_INVALID", message: "batchSize \u5FC5\u987B\u662F\u6B63\u6574\u6570" });
|
|
294
|
+
}
|
|
295
|
+
if (!Number.isInteger(summarize.maxRetries) || summarize.maxRetries < 0) {
|
|
296
|
+
problems.push({ field: "summarize.maxRetries", code: "CONFIG_INVALID", message: "maxRetries \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570" });
|
|
297
|
+
}
|
|
298
|
+
if (!Number.isInteger(summarize.readmeChars) || summarize.readmeChars <= 0) {
|
|
299
|
+
problems.push({ field: "summarize.readmeChars", code: "CONFIG_INVALID", message: "readmeChars \u5FC5\u987B\u662F\u6B63\u6574\u6570" });
|
|
300
|
+
}
|
|
301
|
+
if (!isPeriod(releases.period)) {
|
|
302
|
+
problems.push({ field: "releases.period", code: "CONFIG_INVALID", message: "releases.period \u5FC5\u987B\u662F daily / weekly / monthly" });
|
|
303
|
+
}
|
|
304
|
+
if (!Number.isInteger(releases.perRepoLimit) || releases.perRepoLimit < 1 || releases.perRepoLimit > 20) {
|
|
305
|
+
problems.push({ field: "releases.perRepoLimit", code: "CONFIG_INVALID", message: "perRepoLimit \u5FC5\u987B\u662F 1\u201320 \u7684\u6574\u6570" });
|
|
306
|
+
}
|
|
307
|
+
if (!Number.isInteger(releases.maxNotesChars) || releases.maxNotesChars < 500 || releases.maxNotesChars > 2e4) {
|
|
308
|
+
problems.push({ field: "releases.maxNotesChars", code: "CONFIG_INVALID", message: "maxNotesChars \u5FC5\u987B\u662F 500\u201320000 \u7684\u6574\u6570" });
|
|
309
|
+
}
|
|
235
310
|
if (output.dir.trim() === "" || path.isAbsolute(output.dir) || output.dir.split(/[\\/]/).includes("..")) {
|
|
236
311
|
problems.push({ field: "output.dir", code: "CONFIG_INVALID", message: "\u8F93\u51FA\u76EE\u5F55\u5FC5\u987B\u662F\u4ED3\u5E93\u5185\u7684\u76F8\u5BF9\u8DEF\u5F84\uFF0C\u4E14\u4E0D\u542B .." });
|
|
237
312
|
}
|
|
@@ -275,6 +350,27 @@ function toCoreConfig(settings, apiKey, baseURLOverride, period) {
|
|
|
275
350
|
since: period ?? settings.trending.since,
|
|
276
351
|
perLanguage: settings.trending.topN
|
|
277
352
|
},
|
|
353
|
+
summarize: {
|
|
354
|
+
batchSize: settings.summarize.batchSize,
|
|
355
|
+
maxRetries: settings.summarize.maxRetries,
|
|
356
|
+
enrich: settings.summarize.enrich,
|
|
357
|
+
readmeChars: settings.summarize.readmeChars,
|
|
358
|
+
enrichCacheTTLHours: settings.summarize.enrichCacheTTLHours,
|
|
359
|
+
enrichConcurrency: settings.summarize.enrichConcurrency,
|
|
360
|
+
enrichTimeoutSeconds: settings.summarize.enrichTimeoutSeconds,
|
|
361
|
+
enrichBudgetSeconds: settings.summarize.enrichBudgetSeconds
|
|
362
|
+
},
|
|
363
|
+
releases: {
|
|
364
|
+
// 发版订阅常开:插件侧不再提供开关,是否产出由订阅列表决定。
|
|
365
|
+
enabled: true,
|
|
366
|
+
includePrerelease: settings.releases.includePrerelease,
|
|
367
|
+
includeDrafts: settings.releases.includeDrafts,
|
|
368
|
+
fallbackToTags: settings.releases.fallbackToTags,
|
|
369
|
+
baselineOnFirstRun: settings.releases.baselineOnFirstRun,
|
|
370
|
+
perRepoLimit: settings.releases.perRepoLimit,
|
|
371
|
+
maxNotesChars: settings.releases.maxNotesChars,
|
|
372
|
+
period: settings.releases.period
|
|
373
|
+
},
|
|
278
374
|
output: {
|
|
279
375
|
dir: settings.output.dir,
|
|
280
376
|
branchPrefix: "trending/",
|
|
@@ -354,6 +450,7 @@ __export(state_exports, {
|
|
|
354
450
|
PREVIEW_MAX_BYTES: () => PREVIEW_MAX_BYTES,
|
|
355
451
|
Store: () => Store,
|
|
356
452
|
newRunId: () => newRunId,
|
|
453
|
+
sumTokens: () => sumTokens,
|
|
357
454
|
writeJsonAtomic: () => writeJsonAtomic
|
|
358
455
|
});
|
|
359
456
|
import { mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync, appendFileSync, existsSync } from "fs";
|
|
@@ -566,6 +663,17 @@ function newRunId(now = /* @__PURE__ */ new Date()) {
|
|
|
566
663
|
const random = Math.random().toString(36).slice(2, 8);
|
|
567
664
|
return `${stamp}-${random}`;
|
|
568
665
|
}
|
|
666
|
+
function sumTokens(records) {
|
|
667
|
+
let total = 0;
|
|
668
|
+
let seen = false;
|
|
669
|
+
for (const record of records) {
|
|
670
|
+
if (typeof record.tokens === "number" && Number.isFinite(record.tokens)) {
|
|
671
|
+
total += record.tokens;
|
|
672
|
+
seen = true;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return seen ? total : void 0;
|
|
676
|
+
}
|
|
569
677
|
|
|
570
678
|
// src/errors.ts
|
|
571
679
|
var errors_exports = {};
|
|
@@ -593,7 +701,8 @@ var PLUGIN_CODES = [
|
|
|
593
701
|
"MODEL_PROVIDER_UNSUPPORTED",
|
|
594
702
|
"GITHUB_AUTH",
|
|
595
703
|
"PUSH_FAILED",
|
|
596
|
-
"REPO_DIRTY"
|
|
704
|
+
"REPO_DIRTY",
|
|
705
|
+
"SUBSCRIBE_FAILED"
|
|
597
706
|
];
|
|
598
707
|
var RETRIABLE = {
|
|
599
708
|
INTERNAL: true,
|
|
@@ -626,7 +735,8 @@ var RETRIABLE = {
|
|
|
626
735
|
MODEL_NOT_FOUND: false,
|
|
627
736
|
MODEL_PROVIDER_UNSUPPORTED: false,
|
|
628
737
|
GITHUB_AUTH: false,
|
|
629
|
-
PUSH_FAILED: true
|
|
738
|
+
PUSH_FAILED: true,
|
|
739
|
+
SUBSCRIBE_FAILED: true
|
|
630
740
|
};
|
|
631
741
|
function isRetriable(code) {
|
|
632
742
|
return RETRIABLE[code] === true;
|
|
@@ -709,6 +819,8 @@ function hintOf(code, message, reason) {
|
|
|
709
819
|
return "PR \u65E0\u6CD5\u81EA\u52A8\u5408\u5E76\uFF08\u5E38\u89C1\u4E8E\u5206\u652F\u4FDD\u62A4\uFF09\uFF1APR \u5DF2\u4FDD\u7559\uFF0C\u9700\u4EBA\u5DE5\u5904\u7406\u3002";
|
|
710
820
|
case "PUSH_FAILED":
|
|
711
821
|
return "\u63A8\u9001\u5931\u8D25\uFF1A\u672C\u5730 commit \u5DF2\u4FDD\u7559\uFF0C\u4FEE\u590D\u6743\u9650/\u7F51\u7EDC\u540E\u91CD\u8BD5\u5373\u53EF\u590D\u7528\u3002";
|
|
822
|
+
case "SUBSCRIBE_FAILED":
|
|
823
|
+
return "\u8BA2\u9605\u547D\u4EE4\u5931\u8D25\uFF1A\u6838\u5BF9 owner/repo \u5F62\u6001\uFF08\u5982 vercel/next.js\uFF09\uFF0C\u786E\u8BA4\u4ED3\u5E93\u6709\u5199\u6743\u9650\u540E\u91CD\u8BD5\uFF1B\u8BA2\u9605\u5217\u8868\u968F\u4E0B\u6B21\u8FD0\u884C\u843D\u76D8\u63D0\u4EA4\u3002";
|
|
712
824
|
case "PR_FAILED":
|
|
713
825
|
return "\u521B\u5EFA PR \u5931\u8D25\uFF1A\u672C\u5730 commit \u4E0E\u5206\u652F\u5DF2\u4FDD\u7559\u3002";
|
|
714
826
|
case "FETCH_FAILED":
|
|
@@ -802,6 +914,7 @@ __export(ipc_exports, {
|
|
|
802
914
|
isVersionInfo: () => isVersionInfo,
|
|
803
915
|
parseJsonObject: () => parseJsonObject,
|
|
804
916
|
parseRunResult: () => parseRunResult,
|
|
917
|
+
parseSubscribeResult: () => parseSubscribeResult,
|
|
805
918
|
parseVersionInfo: () => parseVersionInfo
|
|
806
919
|
});
|
|
807
920
|
import { validators } from "@morehao/trendradar-contract";
|
|
@@ -871,6 +984,8 @@ function parseRunResult(text, options) {
|
|
|
871
984
|
commit: typeof result.commit === "string" ? result.commit : void 0,
|
|
872
985
|
prUrl: typeof result.prUrl === "string" ? result.prUrl : void 0,
|
|
873
986
|
skipReason: typeof skipReason === "string" && skipReason !== "" ? skipReason : void 0,
|
|
987
|
+
...result.usage === void 0 ? {} : { usage: result.usage },
|
|
988
|
+
...result.releases === void 0 ? {} : { releases: result.releases },
|
|
874
989
|
error,
|
|
875
990
|
warnings: Array.isArray(result.warnings) ? result.warnings.filter((item) => typeof item === "string") : [],
|
|
876
991
|
...timing(options),
|
|
@@ -880,6 +995,35 @@ function parseRunResult(text, options) {
|
|
|
880
995
|
function timing(options) {
|
|
881
996
|
return { startedAt: options.startedAt, finishedAt: options.finishedAt, durationMs: options.durationMs };
|
|
882
997
|
}
|
|
998
|
+
var REPO_PATTERN = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
999
|
+
function parseSubscribeResult(text) {
|
|
1000
|
+
const trimmed = text.trim();
|
|
1001
|
+
if (trimmed === "") throw new IpcError("IPC_INVALID", "\u6838\u5FC3 subscribe \u8F93\u51FA\u4E3A\u7A7A");
|
|
1002
|
+
const lines = trimmed.split("\n");
|
|
1003
|
+
const lastLine = (lines[lines.length - 1] ?? "").trim();
|
|
1004
|
+
let envelope;
|
|
1005
|
+
try {
|
|
1006
|
+
envelope = JSON.parse(lastLine);
|
|
1007
|
+
} catch (error2) {
|
|
1008
|
+
const detail = error2 instanceof Error ? error2.message : String(error2);
|
|
1009
|
+
throw new IpcError("IPC_INVALID", `\u6838\u5FC3 subscribe \u672A\u4EE5\u7ED3\u679C\u4FE1\u5C01\u7ED3\u5C3E\uFF1A${detail}`);
|
|
1010
|
+
}
|
|
1011
|
+
if (!isRecord(envelope) || envelope.ipcSchema !== IPC_SCHEMA_VERSION || typeof envelope.ok !== "boolean") {
|
|
1012
|
+
throw new IpcError("IPC_INVALID", "\u6838\u5FC3 subscribe --json \u4E0D\u662F\u5951\u7EA6\u4FE1\u5C01\uFF08ipcSchema=2 / ok\uFF09");
|
|
1013
|
+
}
|
|
1014
|
+
const error = normalizeError(envelope.error);
|
|
1015
|
+
const repos = [];
|
|
1016
|
+
for (const line of lines.slice(0, -1)) {
|
|
1017
|
+
const value = line.trim();
|
|
1018
|
+
if (value === "") continue;
|
|
1019
|
+
if (REPO_PATTERN.test(value)) repos.push(value);
|
|
1020
|
+
}
|
|
1021
|
+
return {
|
|
1022
|
+
ok: envelope.ok === true,
|
|
1023
|
+
repos,
|
|
1024
|
+
...error === void 0 ? {} : { error }
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
883
1027
|
|
|
884
1028
|
// src/core/handshake.ts
|
|
885
1029
|
var handshake_exports = {};
|
|
@@ -1698,7 +1842,7 @@ async function defaultGhToken(fresh = false) {
|
|
|
1698
1842
|
if (!fresh && ghTokenCache !== void 0 && Date.now() - ghTokenCache.at < GH_TOKEN_TTL_MS) {
|
|
1699
1843
|
return ghTokenCache.value;
|
|
1700
1844
|
}
|
|
1701
|
-
const { execCapture: execCapture2 } = await import("./exec-
|
|
1845
|
+
const { execCapture: execCapture2 } = await import("./exec-VMDINNX5.js");
|
|
1702
1846
|
const result = await execCapture2("gh", ["auth", "token"], { timeoutMs: 2e3 });
|
|
1703
1847
|
const token = result.code === 0 ? result.stdout.trim() : "";
|
|
1704
1848
|
const value = token === "" ? void 0 : token;
|
|
@@ -2244,7 +2388,8 @@ var runner_exports = {};
|
|
|
2244
2388
|
__export(runner_exports, {
|
|
2245
2389
|
Runner: () => Runner,
|
|
2246
2390
|
isoWeekName: () => isoWeekName,
|
|
2247
|
-
periodFileBase: () => periodFileBase
|
|
2391
|
+
periodFileBase: () => periodFileBase,
|
|
2392
|
+
projectUsage: () => projectUsage
|
|
2248
2393
|
});
|
|
2249
2394
|
import { createHash as createHash2 } from "crypto";
|
|
2250
2395
|
import { existsSync as existsSync4, readFileSync as readFileSync3, realpathSync, statSync as statSync5 } from "fs";
|
|
@@ -2297,6 +2442,27 @@ function periodFileBase(period, date) {
|
|
|
2297
2442
|
if (period === "weekly") return isoWeekName(date);
|
|
2298
2443
|
return date;
|
|
2299
2444
|
}
|
|
2445
|
+
function projectUsage(outcome) {
|
|
2446
|
+
const usageTokens = outcome.usage?.totalTokens;
|
|
2447
|
+
const releasesTokens = outcome.releases?.usage?.totalTokens;
|
|
2448
|
+
let tokens;
|
|
2449
|
+
if (typeof usageTokens === "number" || typeof releasesTokens === "number") {
|
|
2450
|
+
tokens = (typeof usageTokens === "number" ? usageTokens : 0) + (typeof releasesTokens === "number" ? releasesTokens : 0);
|
|
2451
|
+
}
|
|
2452
|
+
const releases = outcome.releases === void 0 ? void 0 : {
|
|
2453
|
+
enabled: outcome.releases.enabled,
|
|
2454
|
+
repos: outcome.releases.repos,
|
|
2455
|
+
newReleases: outcome.releases.newReleases,
|
|
2456
|
+
...outcome.releases.summarized === void 0 ? {} : { summarized: outcome.releases.summarized },
|
|
2457
|
+
...outcome.releases.degraded === void 0 ? {} : { degraded: outcome.releases.degraded },
|
|
2458
|
+
...outcome.releases.failed === void 0 ? {} : { failed: outcome.releases.failed },
|
|
2459
|
+
...outcome.releases.skipped === void 0 ? {} : { skipped: outcome.releases.skipped }
|
|
2460
|
+
};
|
|
2461
|
+
return {
|
|
2462
|
+
...tokens === void 0 ? {} : { tokens },
|
|
2463
|
+
...releases === void 0 ? {} : { releases }
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2300
2466
|
var Runner = class {
|
|
2301
2467
|
active;
|
|
2302
2468
|
/** 批量运行(一次触发跑多个周期)期间为 true,挡住外部并发触发。 */
|
|
@@ -2494,6 +2660,7 @@ var Runner = class {
|
|
|
2494
2660
|
...outcome.prUrl === void 0 ? {} : { prUrl: outcome.prUrl },
|
|
2495
2661
|
...outcome.skipReason === void 0 ? {} : { skipReason: outcome.skipReason },
|
|
2496
2662
|
...error === void 0 ? {} : { error },
|
|
2663
|
+
...projectUsage(outcome),
|
|
2497
2664
|
warnings: outcome.warnings,
|
|
2498
2665
|
logFile: input.logFile,
|
|
2499
2666
|
...input.channel === void 0 ? {} : { channel: input.channel },
|
|
@@ -2538,7 +2705,9 @@ var Runner = class {
|
|
|
2538
2705
|
const markdown = outcome.files.filter((file) => {
|
|
2539
2706
|
const ext = path8.extname(file.path).toLowerCase();
|
|
2540
2707
|
const base = path8.basename(file.path).toLowerCase();
|
|
2541
|
-
|
|
2708
|
+
const normalized = file.path.replace(/\\/g, "/");
|
|
2709
|
+
const inReleases = normalized === "releases" || normalized.startsWith("releases/");
|
|
2710
|
+
return ext === ".md" && base !== "readme.md" && base !== "index.md" && !inReleases;
|
|
2542
2711
|
});
|
|
2543
2712
|
if (markdown.length === 0) return skip("no-markdown");
|
|
2544
2713
|
const expected = period === void 0 ? `${date}.md` : `${periodFileBase(period, date)}.md`;
|
|
@@ -2608,6 +2777,8 @@ var Runner = class {
|
|
|
2608
2777
|
...summary.commit === void 0 ? {} : { commit: summary.commit },
|
|
2609
2778
|
...summary.prUrl === void 0 ? {} : { prUrl: summary.prUrl },
|
|
2610
2779
|
...summary.preview === void 0 ? {} : { preview: summary.preview },
|
|
2780
|
+
...summary.tokens === void 0 ? {} : { tokens: summary.tokens },
|
|
2781
|
+
...summary.releases === void 0 ? {} : { releases: summary.releases },
|
|
2611
2782
|
coreVersion: summary.coreVersion,
|
|
2612
2783
|
model: { provider: settings.model.provider, model: settings.model.model },
|
|
2613
2784
|
languages: settings.trending.languages,
|
|
@@ -3228,6 +3399,74 @@ async function readDefaultBranch(repoPath, options = {}) {
|
|
|
3228
3399
|
return { source: "none", message: "\u672A\u8BFB\u53D6\u5230\u9ED8\u8BA4\u5206\u652F\uFF08\u53EF\u80FD\u662F\u7A7A\u4ED3\u5E93\u6216\u6CA1\u6709 origin\uFF09" };
|
|
3229
3400
|
}
|
|
3230
3401
|
|
|
3402
|
+
// src/host/subscribe.ts
|
|
3403
|
+
var subscribe_exports = {};
|
|
3404
|
+
__export(subscribe_exports, {
|
|
3405
|
+
SUBSCRIBE_TIMEOUT_MS: () => SUBSCRIBE_TIMEOUT_MS,
|
|
3406
|
+
isValidRepo: () => isValidRepo,
|
|
3407
|
+
runSubscribe: () => runSubscribe
|
|
3408
|
+
});
|
|
3409
|
+
import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync2, rmSync as rmSync2 } from "fs";
|
|
3410
|
+
import os4 from "os";
|
|
3411
|
+
import path11 from "path";
|
|
3412
|
+
var SUBSCRIBE_TIMEOUT_MS = 8e3;
|
|
3413
|
+
var REPO_PATTERN2 = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
3414
|
+
function isValidRepo(repo) {
|
|
3415
|
+
return REPO_PATTERN2.test(repo.trim());
|
|
3416
|
+
}
|
|
3417
|
+
function writeTempConfig(settings) {
|
|
3418
|
+
const dir = mkdtempSync2(path11.join(os4.tmpdir(), "dsh-subscribe-"));
|
|
3419
|
+
const file = path11.join(dir, "config.yml");
|
|
3420
|
+
const yaml = `${toYaml(toCoreConfig(settings, ""))}
|
|
3421
|
+
`;
|
|
3422
|
+
writeFileSync2(file, yaml, { mode: 384 });
|
|
3423
|
+
return { file, dir };
|
|
3424
|
+
}
|
|
3425
|
+
function requireUsableConfig(settings) {
|
|
3426
|
+
const problems = validateSettings(settings);
|
|
3427
|
+
if (problems.length > 0) {
|
|
3428
|
+
const first = problems[0];
|
|
3429
|
+
throw new IpcError("CONFIG_INVALID", `\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF0C\u65E0\u6CD5\u7BA1\u7406\u8BA2\u9605\uFF1A${first?.message ?? "\u672A\u77E5\u95EE\u9898"}`);
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
async function runSubscribe(input, deps) {
|
|
3433
|
+
const env = deps.env ?? process.env;
|
|
3434
|
+
const settings = deps.store.readSettings();
|
|
3435
|
+
requireUsableConfig(settings);
|
|
3436
|
+
if (input.action !== "list") {
|
|
3437
|
+
const repo = (input.repo ?? "").trim();
|
|
3438
|
+
if (!isValidRepo(repo)) {
|
|
3439
|
+
throw new IpcError("CONFIG_INVALID", `\u4ED3\u5E93\u5FC5\u987B\u662F owner/repo \u5F62\u6001\uFF1A${repo || "(\u7A7A)"}`);
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3442
|
+
const corePath = deps.corePath !== void 0 ? deps.corePath : (await locateCore({ settings, env, allowDownload: settings.coreAutoDownload })).path;
|
|
3443
|
+
const { file, dir } = writeTempConfig(settings);
|
|
3444
|
+
try {
|
|
3445
|
+
const request = {
|
|
3446
|
+
ipcSchema: 2,
|
|
3447
|
+
command: "subscribe",
|
|
3448
|
+
action: input.action,
|
|
3449
|
+
...input.action === "list" ? {} : { repo: (input.repo ?? "").trim() },
|
|
3450
|
+
configPath: file
|
|
3451
|
+
};
|
|
3452
|
+
const result = await execCapture(corePath, ["subscribe", "--json"], {
|
|
3453
|
+
env: sanitizedEnv(env),
|
|
3454
|
+
input: JSON.stringify(request),
|
|
3455
|
+
timeoutMs: SUBSCRIBE_TIMEOUT_MS
|
|
3456
|
+
});
|
|
3457
|
+
if (result.timedOut) {
|
|
3458
|
+
throw new IpcError("SUBSCRIBE_FAILED", `\u8BA2\u9605\u547D\u4EE4\u8D85\u65F6\uFF08${Math.round(SUBSCRIBE_TIMEOUT_MS / 1e3)} s\uFF09`);
|
|
3459
|
+
}
|
|
3460
|
+
if (result.stdout.trim() === "") {
|
|
3461
|
+
const detail = result.stderr.trim();
|
|
3462
|
+
throw new IpcError("SUBSCRIBE_FAILED", `\u8BA2\u9605\u547D\u4EE4\u65E0\u8F93\u51FA${detail === "" ? "" : `\uFF1A${detail}`}`);
|
|
3463
|
+
}
|
|
3464
|
+
return parseSubscribeResult(result.stdout);
|
|
3465
|
+
} finally {
|
|
3466
|
+
rmSync2(dir, { recursive: true, force: true });
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3469
|
+
|
|
3231
3470
|
// src/host/routes.ts
|
|
3232
3471
|
var routes_exports = {};
|
|
3233
3472
|
__export(routes_exports, {
|
|
@@ -3379,6 +3618,28 @@ async function dispatch(method, pathname, url, request, deps) {
|
|
|
3379
3618
|
const repoPath = url.searchParams.get("path") ?? settings.repo.path;
|
|
3380
3619
|
return { repo: await readDefaultBranch(repoPath, { env }) };
|
|
3381
3620
|
}
|
|
3621
|
+
if (method === "GET" && pathname === "/subscriptions") {
|
|
3622
|
+
const result = await runSubscribe({ action: "list" }, { store: deps.store, env });
|
|
3623
|
+
if (!result.ok) {
|
|
3624
|
+
throw new IpcError("SUBSCRIBE_FAILED", result.error?.message ?? "\u8BFB\u53D6\u8BA2\u9605\u5217\u8868\u5931\u8D25");
|
|
3625
|
+
}
|
|
3626
|
+
return { repos: result.repos };
|
|
3627
|
+
}
|
|
3628
|
+
if (method === "POST" && pathname === "/subscriptions") {
|
|
3629
|
+
const body = await readBody2(request);
|
|
3630
|
+
const action = body.action === "add" || body.action === "remove" ? body.action : void 0;
|
|
3631
|
+
if (action === void 0) throw new IpcError("CONFIG_INVALID", "action \u5FC5\u987B\u662F add \u6216 remove");
|
|
3632
|
+
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()] : [];
|
|
3633
|
+
if (repos.length === 0) throw new IpcError("CONFIG_INVALID", "\u5FC5\u987B\u63D0\u4F9B\u8981\u64CD\u4F5C\u7684 owner/repo");
|
|
3634
|
+
for (const repo of repos) {
|
|
3635
|
+
const result = await runSubscribe({ action, repo }, { store: deps.store, env });
|
|
3636
|
+
if (!result.ok) {
|
|
3637
|
+
throw new IpcError("SUBSCRIBE_FAILED", result.error?.message ?? `${action} ${repo} \u5931\u8D25`);
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3640
|
+
const latest = await runSubscribe({ action: "list" }, { store: deps.store, env });
|
|
3641
|
+
return { repos: latest.ok ? latest.repos : [] };
|
|
3642
|
+
}
|
|
3382
3643
|
if (method === "POST" && pathname === "/github/test") {
|
|
3383
3644
|
const body = await readBody2(request);
|
|
3384
3645
|
const candidate = body.settings === void 0 ? settings : normalizeSettings(body.settings);
|
|
@@ -3495,7 +3756,12 @@ async function statePayload(deps, settings) {
|
|
|
3495
3756
|
lastResult: state.lastResult ?? null,
|
|
3496
3757
|
pendingPr,
|
|
3497
3758
|
...pendingPrState === void 0 ? {} : { pendingPrState },
|
|
3498
|
-
history
|
|
3759
|
+
history,
|
|
3760
|
+
/** 历史里全部运行的 token 累计(读时求和,不落盘);全无数据则省略。 */
|
|
3761
|
+
...(() => {
|
|
3762
|
+
const totalTokens = sumTokens(history);
|
|
3763
|
+
return totalTokens === void 0 ? {} : { totalTokens };
|
|
3764
|
+
})()
|
|
3499
3765
|
},
|
|
3500
3766
|
model: {
|
|
3501
3767
|
mode: settings.model.mode,
|
|
@@ -3664,6 +3930,13 @@ function createTrendingRunTool(runner) {
|
|
|
3664
3930
|
const head = summary.ok ? summary.skipped ? "\u65E0\u53D8\u66F4\uFF08skipped\uFF09" : summary.dryRun ? "\u8BD5\u8DD1\u5B8C\u6210" : "\u8FD0\u884C\u6210\u529F" : `\u8FD0\u884C\u5931\u8D25\uFF1A${summary.error?.code ?? "INTERNAL"}`;
|
|
3665
3931
|
lines.push(`${summary.ok ? "\u2713" : "\u2717"} [${periodLabel}] ${head}`);
|
|
3666
3932
|
lines.push(`\xB7 \u6838\u5FC3 ${summary.coreVersion || "(\u672A\u77E5)"} \xB7 ${formatDuration(summary.durationMs)} \xB7 ${summary.files} \u4E2A\u6587\u4EF6`);
|
|
3933
|
+
if (summary.tokens !== void 0) {
|
|
3934
|
+
const parts = [`\u672C\u6B21 tokens ${summary.tokens.toLocaleString("en-US")}`];
|
|
3935
|
+
if (summary.releases !== void 0 && summary.releases.enabled) {
|
|
3936
|
+
parts.push(`\u53D1\u7248 ${summary.releases.newReleases} \u4E2A\u65B0\u7248\u672C / ${summary.releases.repos} \u4E2A\u4ED3\u5E93`);
|
|
3937
|
+
}
|
|
3938
|
+
lines.push(`\xB7 ${parts.join(" \xB7 ")}`);
|
|
3939
|
+
}
|
|
3667
3940
|
if (summary.contentHash !== void 0) lines.push(`\xB7 contentHash ${summary.contentHash.slice(0, 12)}`);
|
|
3668
3941
|
if (summary.branch !== void 0) lines.push(`\xB7 \u5206\u652F ${summary.branch}`);
|
|
3669
3942
|
if (summary.prUrl !== void 0) lines.push(`\xB7 PR ${summary.prUrl}`);
|
|
@@ -3686,6 +3959,8 @@ function createTrendingRunTool(runner) {
|
|
|
3686
3959
|
dryRun: summary.dryRun,
|
|
3687
3960
|
durationMs: summary.durationMs,
|
|
3688
3961
|
files: summary.files,
|
|
3962
|
+
...summary.tokens === void 0 ? {} : { tokens: summary.tokens },
|
|
3963
|
+
...summary.releases === void 0 ? {} : { releases: summary.releases },
|
|
3689
3964
|
...summary.branch === void 0 ? {} : { branch: summary.branch },
|
|
3690
3965
|
...summary.prUrl === void 0 ? {} : { prUrl: summary.prUrl },
|
|
3691
3966
|
...summary.error === void 0 ? {} : { errorCode: summary.error.code, errorMessage: summary.error.message }
|
|
@@ -3695,6 +3970,10 @@ function createTrendingRunTool(runner) {
|
|
|
3695
3970
|
dryRun: base.dryRun,
|
|
3696
3971
|
durationMs: summaries.reduce((sum, summary) => sum + summary.durationMs, 0),
|
|
3697
3972
|
files: summaries.reduce((sum, summary) => sum + summary.files, 0),
|
|
3973
|
+
...(() => {
|
|
3974
|
+
const total = summaries.reduce((sum, summary) => sum + (summary.tokens ?? 0), 0);
|
|
3975
|
+
return summaries.some((summary) => summary.tokens !== void 0) ? { tokens: total } : {};
|
|
3976
|
+
})(),
|
|
3698
3977
|
warnings: summaries.flatMap((summary) => summary.warnings),
|
|
3699
3978
|
...primary?.error === void 0 ? {} : { errorCode: primary.error.code, errorMessage: primary.error.message, errorHint: primary.error.hint },
|
|
3700
3979
|
markdown: lines.join("\n")
|
|
@@ -3772,6 +4051,7 @@ export {
|
|
|
3772
4051
|
pending_pr_exports,
|
|
3773
4052
|
preflight_exports,
|
|
3774
4053
|
repo_exports,
|
|
4054
|
+
subscribe_exports,
|
|
3775
4055
|
ROUTE_PREFIX,
|
|
3776
4056
|
createRoutes,
|
|
3777
4057
|
routes_exports,
|
package/lib/index.js
CHANGED
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
createTrendingRunTool,
|
|
9
9
|
createUpdateService,
|
|
10
10
|
readPluginInfo
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-R7EUBUTS.js";
|
|
12
|
+
import "./chunk-R7BK7SJK.js";
|
|
13
13
|
|
|
14
14
|
// src/index.ts
|
|
15
15
|
var name = "dsh-github-trending";
|