@chenpengfei/daily-brief 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +21 -0
  3. package/README.md +28 -0
  4. package/config/sources.example.yaml +20 -0
  5. package/dist/src/adapters/fixture.js +70 -0
  6. package/dist/src/adapters/github-trending.js +183 -0
  7. package/dist/src/adapters/index.js +5 -0
  8. package/dist/src/adapters/rss.js +156 -0
  9. package/dist/src/adapters/types.js +1 -0
  10. package/dist/src/adapters/x.js +115 -0
  11. package/dist/src/agent/daily-brief-agent.js +350 -0
  12. package/dist/src/agent/index.js +10 -0
  13. package/dist/src/agent/model-runtime-config.js +221 -0
  14. package/dist/src/agent/model-stage-runtime.js +63 -0
  15. package/dist/src/agent/signal-narrative.js +247 -0
  16. package/dist/src/agent/signal-selection-ranking.js +276 -0
  17. package/dist/src/agent/source-grounding-audit.js +148 -0
  18. package/dist/src/agent/source-grounding-repair.js +159 -0
  19. package/dist/src/agent/source-item-understanding.js +206 -0
  20. package/dist/src/agent/stage-contracts.js +205 -0
  21. package/dist/src/agent/stage-runner.js +66 -0
  22. package/dist/src/brief/daily-brief.js +234 -0
  23. package/dist/src/brief/index.js +1 -0
  24. package/dist/src/cli.js +531 -0
  25. package/dist/src/collection/collect.js +67 -0
  26. package/dist/src/collection/index.js +1 -0
  27. package/dist/src/config/credential-store.js +169 -0
  28. package/dist/src/config/date-key.js +25 -0
  29. package/dist/src/config/index.js +5 -0
  30. package/dist/src/config/model-config.js +123 -0
  31. package/dist/src/config/paths.js +20 -0
  32. package/dist/src/config/source-registry.js +48 -0
  33. package/dist/src/discord/delivery.js +84 -0
  34. package/dist/src/discord/index.js +1 -0
  35. package/dist/src/domain/index.js +2 -0
  36. package/dist/src/domain/source-item.js +21 -0
  37. package/dist/src/domain/source.js +93 -0
  38. package/dist/src/storage/agent-run-artifact.js +44 -0
  39. package/dist/src/storage/brief-archive.js +17 -0
  40. package/dist/src/storage/index.js +3 -0
  41. package/dist/src/storage/source-item-store.js +63 -0
  42. package/dist/src/workflow/index.js +1 -0
  43. package/dist/src/workflow/status.js +95 -0
  44. package/docs/operations.md +74 -0
  45. package/docs/release-workflow.md +220 -0
  46. package/docs/user-manual.md +146 -0
  47. package/package.json +65 -0
  48. package/templates/daily-brief.md +9 -0
  49. package/templates/discord-notification.md +7 -0
@@ -0,0 +1,234 @@
1
+ import { formatDateKey } from "../config/index.js";
2
+ export function generateLowSignalDailyBrief(input) {
3
+ const date = input.date.toISOString().slice(0, 10);
4
+ const enabledSources = input.sources.filter((source) => source.enabled);
5
+ const disabledSources = input.sources.length - enabledSources.length;
6
+ return [
7
+ `# Daily Brief - ${date}`,
8
+ "",
9
+ "## Executive Summary",
10
+ "",
11
+ "今天是 low-signal day:当前 Collection Window 没有可用于生成 Top Signals 的 Source Items。系统仍然生成 Brief,以确认每日链路可运行,并避免用弱信号填充内容。",
12
+ "",
13
+ "## Top Signals",
14
+ "",
15
+ "暂无可引用的 Signals。没有 Source Item 引用支撑的判断不会进入 Daily Brief。",
16
+ "",
17
+ "## Source Coverage",
18
+ "",
19
+ input.sources.length === 0
20
+ ? "Source Registry 当前为空;本次运行没有可采集的 Sources。"
21
+ : `读取到 ${input.sources.length} 个 Sources,其中 ${enabledSources.length} 个启用,${disabledSources} 个停用。本次基础链路尚未接入真实 Fetch Adapter,因此没有产生 Source Items。`,
22
+ "",
23
+ "## Sources",
24
+ "",
25
+ input.sources.length === 0
26
+ ? "- None configured."
27
+ : input.sources
28
+ .map((source) => {
29
+ const state = source.enabled ? "enabled" : "disabled";
30
+ return `- ${source.id} (${source.platform}, ${source.adapter}, ${state}) - ${source.target}`;
31
+ })
32
+ .join("\n"),
33
+ ""
34
+ ].join("\n");
35
+ }
36
+ export function generateDailyBrief(input) {
37
+ const relevantItems = input.sourceItems.filter((item) => isBriefEligibleSourceItem(item) && isRelevantSourceItem(item));
38
+ const signals = buildSignals(relevantItems);
39
+ const sourceIds = new Set(input.sourceItems.map((item) => item.sourceId));
40
+ return {
41
+ date: input.date,
42
+ ...(input.dateKey ? { dateKey: input.dateKey } : {}),
43
+ executiveSummary: signals.length === 0
44
+ ? "今天是 low-signal day:没有足够 Source-grounded 的 Agent Architecture 或 AI Coding Signals。"
45
+ : `今天有 ${signals.length} 个 Source-grounded Signals,均保留 Source Item citation 以便回溯。`,
46
+ signals,
47
+ sourceCoverage: {
48
+ sourceItemCount: input.sourceItems.length,
49
+ sourceCount: input.sourceCount ?? sourceIds.size,
50
+ partialFailures: input.partialFailures ?? []
51
+ }
52
+ };
53
+ }
54
+ function isBriefEligibleSourceItem(item) {
55
+ if (item.platform !== "github") {
56
+ return true;
57
+ }
58
+ return !item.url.includes("github.com/sponsors/");
59
+ }
60
+ export function renderDailyBriefMarkdown(brief) {
61
+ const date = brief.dateKey ?? formatDateKey(brief.date);
62
+ return [
63
+ `# Daily Brief - ${date}`,
64
+ "",
65
+ "## Executive Summary",
66
+ "",
67
+ brief.executiveSummary,
68
+ "",
69
+ "## Top Signals",
70
+ "",
71
+ brief.signals.length === 0
72
+ ? "暂无可引用的 Signals。没有 Source Item 引用支撑的判断不会进入 Daily Brief。"
73
+ : brief.signals.map(renderSignal).join("\n\n"),
74
+ "",
75
+ "## Source Coverage",
76
+ "",
77
+ renderSourceCoverage(brief.sourceCoverage),
78
+ "",
79
+ "## Sources",
80
+ "",
81
+ renderSources(brief.signals),
82
+ ""
83
+ ].join("\n");
84
+ }
85
+ function buildSignals(items) {
86
+ const groups = new Map();
87
+ for (const item of items) {
88
+ const key = normalizeSignalKey(item);
89
+ groups.set(key, [...(groups.get(key) ?? []), item]);
90
+ }
91
+ return [...groups.entries()].map(([key, group]) => {
92
+ const primary = group[0];
93
+ if (!primary) {
94
+ throw new Error(`Cannot build Signal for empty group: ${key}`);
95
+ }
96
+ return {
97
+ id: `signal:${key}`,
98
+ type: classifySignal(primary),
99
+ title: primary.title,
100
+ summary: summarizeSignal(primary),
101
+ whyItMatters: explainWhyItMatters(primary),
102
+ citations: group.map((item) => ({
103
+ sourceItemId: item.id,
104
+ sourceId: item.sourceId,
105
+ title: item.title,
106
+ url: item.url
107
+ }))
108
+ };
109
+ });
110
+ }
111
+ function isRelevantSourceItem(item) {
112
+ const text = `${item.title} ${item.analyzableText}`.toLowerCase();
113
+ const terms = [
114
+ "agent architecture",
115
+ "agent runtime",
116
+ "agentic coding",
117
+ "coding agent",
118
+ "ai coding",
119
+ "tool execution",
120
+ "eval",
121
+ "memory",
122
+ "workflow",
123
+ "source-grounded",
124
+ "mcp"
125
+ ];
126
+ return terms.some((term) => text.includes(term));
127
+ }
128
+ function classifySignal(item) {
129
+ const text = `${item.title} ${item.analyzableText}`.toLowerCase();
130
+ if (text.includes("risk") || text.includes("failure") || text.includes("security")) {
131
+ return "risk";
132
+ }
133
+ if (text.includes("coding agent") || text.includes("ai coding")) {
134
+ return "ai-coding";
135
+ }
136
+ if (item.platform === "github" || text.includes("repo") || text.includes("tool repo")) {
137
+ return "tool-repo";
138
+ }
139
+ return "architecture";
140
+ }
141
+ function explainWhyItMatters(item) {
142
+ const type = classifySignal(item);
143
+ const reasonByType = {
144
+ architecture: "它提供了 Agent Architecture 的具体实现或设计线索,值得进一步阅读原文。",
145
+ "ai-coding": "它影响工程团队使用 Coding Agents 构建和维护软件的实践方式。",
146
+ "tool-repo": "它指向一个可能改变 Agent 工具链或实现选择的项目/工具信号。",
147
+ risk: "它提示了构建或运行 Agent 系统时需要显式管理的风险。"
148
+ };
149
+ return reasonByType[type];
150
+ }
151
+ function summarizeSignal(item) {
152
+ const type = classifySignal(item);
153
+ const description = sourceGroundedDescription(item);
154
+ const whatItIs = item.platform === "github"
155
+ ? `它是一个 GitHub repository:${description}`
156
+ : `它是一个 Source-grounded Signal:${description}`;
157
+ return {
158
+ whatItIs,
159
+ whatItIsNot: explainWhatItIsNot(item, type),
160
+ minimalExample: explainMinimalExample(item, type)
161
+ };
162
+ }
163
+ function sourceGroundedDescription(item) {
164
+ const metadataDescription = readMetadataString(item.metadata, "description");
165
+ return cleanupDescription(metadataDescription ?? item.analyzableText);
166
+ }
167
+ function readMetadataString(metadata, key) {
168
+ const value = metadata?.[key];
169
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
170
+ }
171
+ function cleanupDescription(value) {
172
+ const withoutMomentum = value
173
+ .replace(/\s+Momentum:.*$/i, "")
174
+ .replace(/\s+Ordinary commits are not treated as Source Items by this adapter\.$/i, "");
175
+ const withoutTrendingPrefix = withoutMomentum.replace(/^(Sponsor\s+)?Star\s+[\w.-]+\s+\/\s+[\w.-]+\s+/i, "");
176
+ const trimmed = withoutTrendingPrefix.replace(/\s+/g, " ").trim();
177
+ return trimmed.replace(/[。.!?]+$/u, "");
178
+ }
179
+ function explainWhatItIsNot(item, type) {
180
+ return `不是${unsupportedClaimBoundary(item, type)};当前只代表它在本次 Source Items 中形成了 ${type} Signal。`;
181
+ }
182
+ function unsupportedClaimBoundary(item, type) {
183
+ if (item.platform === "github" || type === "tool-repo") {
184
+ return "对项目成熟度或适用性的背书";
185
+ }
186
+ return "未引用来源支撑的通用观点";
187
+ }
188
+ function explainMinimalExample(item, type) {
189
+ if (type === "tool-repo") {
190
+ return `最小地看,先阅读 ${item.title} 的 README 或最小使用路径,再判断它是否适合当前工具链。`;
191
+ }
192
+ if (type === "risk") {
193
+ return "最小地看,把它转成一条检查项,确认当前 Agent workflow 是否显式处理同类风险。";
194
+ }
195
+ if (type === "ai-coding") {
196
+ return "最小地看,用一个小型 repo 或单个 review workflow 验证它对 AI Coding 实践的影响。";
197
+ }
198
+ return "最小地看,用它对照一个 Agent runtime 的 state、tool execution 或 workflow 边界。";
199
+ }
200
+ function normalizeSignalKey(item) {
201
+ return item.url.trim().toLowerCase();
202
+ }
203
+ function renderSignal(signal) {
204
+ return [
205
+ `### ${signal.title}`,
206
+ "",
207
+ `- 领域: ${renderLensValues(signal.focusAreas)}`,
208
+ `- 方向: ${renderLensValues(signal.directions)}`,
209
+ `- 是什么: ${signal.summary.whatItIs}`,
210
+ `- 不是什么: ${signal.summary.whatItIsNot}`,
211
+ `- 最小例子: ${signal.summary.minimalExample}`,
212
+ `- 为什么重要: ${signal.whyItMatters}`,
213
+ `- 引用: ${signal.citations.map((citation) => citation.sourceItemId).join(", ")}`
214
+ ].join("\n");
215
+ }
216
+ function renderLensValues(values) {
217
+ return values && values.length > 0 ? values.join(" / ") : "未标注";
218
+ }
219
+ function renderSourceCoverage(coverage) {
220
+ const base = `Processed ${coverage.sourceItemCount} Source Items from ${coverage.sourceCount} Sources.`;
221
+ if (coverage.partialFailures.length === 0) {
222
+ return base;
223
+ }
224
+ return `${base}\nPartial failures: ${coverage.partialFailures.join("; ")}`;
225
+ }
226
+ function renderSources(signals) {
227
+ const citations = signals.flatMap((signal) => signal.citations);
228
+ if (citations.length === 0) {
229
+ return "- None cited.";
230
+ }
231
+ return citations
232
+ .map((citation) => `- ${citation.sourceItemId}: [${citation.title}](${citation.url})`)
233
+ .join("\n");
234
+ }
@@ -0,0 +1 @@
1
+ export * from "./daily-brief.js";