github-weekly-reporter 0.1.0 → 0.2.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.
- package/README.md +86 -115
- package/dist/cli/commands/deploy.d.ts.map +1 -1
- package/dist/cli/commands/deploy.js +9 -3
- package/dist/cli/commands/deploy.js.map +1 -1
- package/dist/cli/commands/fetch.d.ts +3 -0
- package/dist/cli/commands/fetch.d.ts.map +1 -0
- package/dist/cli/commands/fetch.js +148 -0
- package/dist/cli/commands/fetch.js.map +1 -0
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +59 -80
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/render.d.ts +3 -0
- package/dist/cli/commands/render.d.ts.map +1 -0
- package/dist/cli/commands/render.js +172 -0
- package/dist/cli/commands/render.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +3 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +709 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/index.js +6 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/collector/clean-body.d.ts +2 -0
- package/dist/collector/clean-body.d.ts.map +1 -0
- package/dist/collector/clean-body.js +27 -0
- package/dist/collector/clean-body.js.map +1 -0
- package/dist/collector/date-range.d.ts +3 -2
- package/dist/collector/date-range.d.ts.map +1 -1
- package/dist/collector/date-range.js +125 -5
- package/dist/collector/date-range.js.map +1 -1
- package/dist/collector/fetch-contributions.d.ts +11 -1
- package/dist/collector/fetch-contributions.d.ts.map +1 -1
- package/dist/collector/fetch-contributions.js +15 -3
- package/dist/collector/fetch-contributions.js.map +1 -1
- package/dist/collector/fetch-events.d.ts +6 -0
- package/dist/collector/fetch-events.d.ts.map +1 -0
- package/dist/collector/fetch-events.js +106 -0
- package/dist/collector/fetch-events.js.map +1 -0
- package/dist/collector/fetch-repo-prs.d.ts +7 -0
- package/dist/collector/fetch-repo-prs.d.ts.map +1 -0
- package/dist/collector/fetch-repo-prs.js +62 -0
- package/dist/collector/fetch-repo-prs.js.map +1 -0
- package/dist/collector/queries.d.ts +1 -4
- package/dist/collector/queries.d.ts.map +1 -1
- package/dist/collector/queries.js +7 -59
- package/dist/collector/queries.js.map +1 -1
- package/dist/deployer/index-page.d.ts +22 -2
- package/dist/deployer/index-page.d.ts.map +1 -1
- package/dist/deployer/index-page.js +424 -33
- package/dist/deployer/index-page.js.map +1 -1
- package/dist/deployer/week.d.ts +1 -1
- package/dist/deployer/week.d.ts.map +1 -1
- package/dist/deployer/week.js +17 -6
- package/dist/deployer/week.js.map +1 -1
- package/dist/i18n/fonts.d.ts +8 -0
- package/dist/i18n/fonts.d.ts.map +1 -0
- package/dist/i18n/fonts.js +44 -0
- package/dist/i18n/fonts.js.map +1 -0
- package/dist/i18n/index.d.ts +28 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +259 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/llm/index.d.ts +2 -1
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +77 -5
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/preprocess.d.ts +3 -0
- package/dist/llm/preprocess.d.ts.map +1 -0
- package/dist/llm/preprocess.js +92 -0
- package/dist/llm/preprocess.js.map +1 -0
- package/dist/llm/prompt.d.ts.map +1 -1
- package/dist/llm/prompt.js +109 -29
- package/dist/llm/prompt.js.map +1 -1
- package/dist/llm/providers/anthropic.js +1 -1
- package/dist/llm/providers/anthropic.js.map +1 -1
- package/dist/llm/providers/grok.d.ts +3 -0
- package/dist/llm/providers/grok.d.ts.map +1 -0
- package/dist/llm/providers/grok.js +18 -0
- package/dist/llm/providers/grok.js.map +1 -0
- package/dist/llm/providers/groq.d.ts +3 -0
- package/dist/llm/providers/groq.d.ts.map +1 -0
- package/dist/llm/providers/groq.js +18 -0
- package/dist/llm/providers/groq.js.map +1 -0
- package/dist/llm/providers/openai.js +1 -1
- package/dist/llm/providers/openai.js.map +1 -1
- package/dist/llm/providers/openrouter.d.ts +3 -0
- package/dist/llm/providers/openrouter.d.ts.map +1 -0
- package/dist/llm/providers/openrouter.js +18 -0
- package/dist/llm/providers/openrouter.js.map +1 -0
- package/dist/llm/types.d.ts +5 -2
- package/dist/llm/types.d.ts.map +1 -1
- package/dist/renderer/helpers.d.ts +6 -1
- package/dist/renderer/helpers.d.ts.map +1 -1
- package/dist/renderer/helpers.js +54 -17
- package/dist/renderer/helpers.js.map +1 -1
- package/dist/renderer/index.d.ts +11 -2
- package/dist/renderer/index.d.ts.map +1 -1
- package/dist/renderer/index.js +41 -19
- package/dist/renderer/index.js.map +1 -1
- package/dist/renderer/og-image.d.ts +15 -0
- package/dist/renderer/og-image.d.ts.map +1 -0
- package/dist/renderer/og-image.js +152 -0
- package/dist/renderer/og-image.js.map +1 -0
- package/dist/renderer/themes.d.ts +2 -17
- package/dist/renderer/themes.d.ts.map +1 -1
- package/dist/renderer/themes.js +371 -147
- package/dist/renderer/themes.js.map +1 -1
- package/dist/types.d.ts +103 -11
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -2
- package/src/renderer/templates/partials/footer.hbs +3 -1
- package/src/renderer/templates/partials/header.hbs +10 -7
- package/src/renderer/templates/partials/highlights.hbs +24 -0
- package/src/renderer/templates/partials/overview.hbs +3 -0
- package/src/renderer/templates/partials/summaries.hbs +73 -0
- package/src/renderer/templates/report.hbs +100 -15
- package/dist/cli/config.d.ts +0 -11
- package/dist/cli/config.d.ts.map +0 -1
- package/dist/cli/config.js +0 -16
- package/dist/cli/config.js.map +0 -1
- package/dist/cli/config.test.d.ts +0 -2
- package/dist/cli/config.test.d.ts.map +0 -1
- package/dist/cli/config.test.js +0 -32
- package/dist/cli/config.test.js.map +0 -1
- package/dist/collector/aggregate.test.d.ts +0 -2
- package/dist/collector/aggregate.test.d.ts.map +0 -1
- package/dist/collector/aggregate.test.js +0 -88
- package/dist/collector/aggregate.test.js.map +0 -1
- package/dist/collector/date-range.test.d.ts +0 -2
- package/dist/collector/date-range.test.d.ts.map +0 -1
- package/dist/collector/date-range.test.js +0 -25
- package/dist/collector/date-range.test.js.map +0 -1
- package/dist/collector/fetch-issues.d.ts +0 -5
- package/dist/collector/fetch-issues.d.ts.map +0 -1
- package/dist/collector/fetch-issues.js +0 -31
- package/dist/collector/fetch-issues.js.map +0 -1
- package/dist/collector/fetch-languages.d.ts +0 -4
- package/dist/collector/fetch-languages.d.ts.map +0 -1
- package/dist/collector/fetch-languages.js +0 -42
- package/dist/collector/fetch-languages.js.map +0 -1
- package/dist/collector/fetch-pull-requests.d.ts +0 -5
- package/dist/collector/fetch-pull-requests.d.ts.map +0 -1
- package/dist/collector/fetch-pull-requests.js +0 -31
- package/dist/collector/fetch-pull-requests.js.map +0 -1
- package/dist/collector/index.d.ts +0 -3
- package/dist/collector/index.d.ts.map +0 -1
- package/dist/collector/index.js +0 -50
- package/dist/collector/index.js.map +0 -1
- package/dist/deployer/index-page.test.d.ts +0 -2
- package/dist/deployer/index-page.test.d.ts.map +0 -1
- package/dist/deployer/index-page.test.js +0 -29
- package/dist/deployer/index-page.test.js.map +0 -1
- package/dist/deployer/week.test.d.ts +0 -2
- package/dist/deployer/week.test.d.ts.map +0 -1
- package/dist/deployer/week.test.js +0 -21
- package/dist/deployer/week.test.js.map +0 -1
- package/dist/llm/llm.test.d.ts +0 -2
- package/dist/llm/llm.test.d.ts.map +0 -1
- package/dist/llm/llm.test.js +0 -24
- package/dist/llm/llm.test.js.map +0 -1
- package/dist/llm/prompt.test.d.ts +0 -2
- package/dist/llm/prompt.test.d.ts.map +0 -1
- package/dist/llm/prompt.test.js +0 -48
- package/dist/llm/prompt.test.js.map +0 -1
- package/dist/renderer/renderer.test.d.ts +0 -2
- package/dist/renderer/renderer.test.d.ts.map +0 -1
- package/dist/renderer/renderer.test.js +0 -111
- package/dist/renderer/renderer.test.js.map +0 -1
- package/src/renderer/templates/partials/heatmap.hbs +0 -11
- package/src/renderer/templates/partials/languages.hbs +0 -19
- package/src/renderer/templates/partials/narrative.hbs +0 -10
- package/src/renderer/templates/partials/repositories.hbs +0 -25
- package/src/renderer/templates/partials/stats.hbs +0 -8
package/dist/llm/prompt.js
CHANGED
|
@@ -1,31 +1,111 @@
|
|
|
1
|
-
// Build the prompt for AI
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
.
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
// Build the prompt for AI structured content generation
|
|
2
|
+
import { buildLLMContext } from "./preprocess.js";
|
|
3
|
+
import { llmLanguageInstruction } from "../i18n/index.js";
|
|
4
|
+
export const buildPrompt = (input) => {
|
|
5
|
+
const langInstruction = llmLanguageInstruction(input.language ?? "en");
|
|
6
|
+
const langBlock = langInstruction ? `\n${langInstruction}\n` : "";
|
|
7
|
+
return `
|
|
8
|
+
You are generating structured content for a developer's personal weekly report.
|
|
9
|
+
This is like a development diary: written from the developer's own perspective.
|
|
10
|
+
${langBlock}
|
|
11
|
+
Read the GitHub activity data and produce a YAML response matching the schema below.
|
|
12
|
+
|
|
13
|
+
Writing style:
|
|
14
|
+
- First person. This is the developer's own weekly log.
|
|
15
|
+
- Specific: reference actual PR titles, repo names, concrete numbers. No generic filler.
|
|
16
|
+
- Focus on WHAT was accomplished and WHY it matters, not just counting things.
|
|
17
|
+
- Natural and conversational, like a developer writing a blog post about their week.
|
|
18
|
+
- Notice patterns: focus shifts between projects, burst days, collaboration dynamics.
|
|
19
|
+
|
|
20
|
+
Section requirements:
|
|
21
|
+
- title: a specific one-line title that could ONLY describe THIS week.
|
|
22
|
+
MUST reference a concrete detail: a repo name, feature name, PR topic, or technical concept.
|
|
23
|
+
BAD (too generic): "A Productive Week", "Lots of Progress", "Bug Fixes and Features"
|
|
24
|
+
GOOD (specific): "OAuth2 PKCE lands in the auth service", "ecma262 editorial sprint", "Migrating the payment flow to Stripe v3"
|
|
25
|
+
- subtitle: one sentence expanding on the title with additional concrete details
|
|
26
|
+
- overview: 2-3 paragraphs. Set the scene, describe the main narrative arc of the week,
|
|
27
|
+
and mention what made it interesting. Each paragraph should be 2-4 sentences.
|
|
28
|
+
This is the reader's first impression, so make it engaging and substantive.
|
|
29
|
+
- summaries: ORDER BY what's most interesting this week. Lead with the most compelling story.
|
|
30
|
+
Skip types that would just repeat obvious stats with nothing insightful to say.
|
|
31
|
+
Include 3-6 sections total. You can mix predefined types with custom free-form sections.
|
|
32
|
+
Each summary has a heading (short, punchy) and body (2-4 sentences).
|
|
33
|
+
Add 2-4 chips per summary with key stats. Every chip MUST have a non-empty label and value.
|
|
34
|
+
- highlights: pick 2-5 notable items. Use exact PR titles from the data.
|
|
35
|
+
Each highlight has 1-2 sentences explaining why it mattered.
|
|
36
|
+
|
|
37
|
+
Predefined summary types (use when relevant):
|
|
38
|
+
- repo-summary: which repos were active and what the focus was
|
|
39
|
+
- commit-summary: commit patterns, volume, notable streaks
|
|
40
|
+
- review-summary: review activity, what kind of feedback was given/received
|
|
41
|
+
- contribution-summary: contributions to repos outside own org
|
|
42
|
+
- collaboration-summary: who was worked with, review dynamics
|
|
43
|
+
- activity-pattern: daily rhythm, peak days, rest days
|
|
44
|
+
|
|
45
|
+
Custom summary types:
|
|
46
|
+
You can also create free-form summary sections with any type name that fits the data.
|
|
47
|
+
Examples: "deep-dive", "tech-debt", "learning", "debugging-story", "architecture",
|
|
48
|
+
"testing", "devops", "content-creation", or anything else that captures a theme of the week.
|
|
49
|
+
Use custom types when the predefined ones don't capture something interesting about the week.
|
|
50
|
+
|
|
51
|
+
Available highlight types:
|
|
52
|
+
- pr: a notable pull request. meta format: "merged Apr 2 · +320 -45 · 12 files"
|
|
53
|
+
- release: a release that shipped. meta format: "released Apr 3"
|
|
54
|
+
- issue: a notable issue. meta format: "opened Apr 3" or "closed Apr 2"
|
|
55
|
+
- discussion: a GitHub discussion (if any)
|
|
56
|
+
|
|
57
|
+
YAML formatting rules:
|
|
58
|
+
- All string values MUST be quoted with double quotes
|
|
59
|
+
- Values starting with + MUST be quoted
|
|
60
|
+
- overview uses YAML block scalar (|) for multi-line text
|
|
61
|
+
- Respond with ONLY valid YAML. No markdown fences. No explanation before or after.
|
|
62
|
+
|
|
63
|
+
Schema:
|
|
64
|
+
|
|
65
|
+
title: "one-line title"
|
|
66
|
+
subtitle: "one sentence"
|
|
67
|
+
overview: |
|
|
68
|
+
First paragraph setting the scene and describing what drove the week.
|
|
69
|
+
|
|
70
|
+
Second paragraph diving into the main narrative arc. What shifted, what was interesting.
|
|
71
|
+
|
|
72
|
+
Third paragraph (optional) wrapping up the themes or looking ahead.
|
|
73
|
+
summaries:
|
|
74
|
+
- type: "repo-summary"
|
|
75
|
+
heading: "heading"
|
|
76
|
+
body: "2-4 sentences"
|
|
77
|
+
chips:
|
|
78
|
+
- label: "deariary/backend"
|
|
79
|
+
value: "19 PRs"
|
|
80
|
+
color: "default"
|
|
81
|
+
- type: "deep-dive"
|
|
82
|
+
heading: "heading about a specific technical topic"
|
|
83
|
+
body: "2-4 sentences about something technically interesting"
|
|
84
|
+
chips:
|
|
85
|
+
- label: "topic"
|
|
86
|
+
value: "OAuth2 PKCE"
|
|
87
|
+
color: "default"
|
|
88
|
+
- type: "activity-pattern"
|
|
89
|
+
heading: "heading"
|
|
90
|
+
body: "2-4 sentences"
|
|
91
|
+
chips:
|
|
92
|
+
- label: "peak"
|
|
93
|
+
value: "Tue 161"
|
|
94
|
+
color: "green"
|
|
95
|
+
highlights:
|
|
96
|
+
- type: "pr"
|
|
97
|
+
title: "exact PR title from data"
|
|
98
|
+
repo: "owner/repo"
|
|
99
|
+
meta: "merged Apr 2 · +320 -45 · 12 files"
|
|
100
|
+
body: "1-2 sentences"
|
|
101
|
+
- type: "release"
|
|
102
|
+
title: "v1.2.0"
|
|
103
|
+
repo: "owner/repo"
|
|
104
|
+
meta: "released Apr 3"
|
|
105
|
+
body: "1-2 sentences"
|
|
106
|
+
|
|
107
|
+
Activity data:
|
|
108
|
+
${buildLLMContext(input)}
|
|
30
109
|
`.trim();
|
|
110
|
+
};
|
|
31
111
|
//# sourceMappingURL=prompt.js.map
|
package/dist/llm/prompt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/llm/prompt.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/llm/prompt.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAGxD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAqB,EAAU,EAAE;IAC3D,MAAM,eAAe,GAAG,sBAAsB,CAAC,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,eAAe,CAAC,CAAC,CAAC,KAAK,eAAe,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAElE,OAAO;;;EAGP,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkGT,eAAe,CAAC,KAAK,CAAC;CACvB,CAAC,IAAI,EAAE,CAAC;AACT,CAAC,CAAC"}
|
|
@@ -6,7 +6,7 @@ export const createAnthropicProvider = (config) => {
|
|
|
6
6
|
generate: async (prompt) => {
|
|
7
7
|
const response = await client.messages.create({
|
|
8
8
|
model: config.model,
|
|
9
|
-
max_tokens:
|
|
9
|
+
max_tokens: 16384,
|
|
10
10
|
messages: [{ role: "user", content: prompt }],
|
|
11
11
|
});
|
|
12
12
|
const block = response.content[0];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/llm/providers/anthropic.ts"],"names":[],"mappings":"AAAA,oCAAoC;AAEpC,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAG1C,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAiB,EAAe,EAAE;IACxE,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAExD,OAAO;QACL,QAAQ,EAAE,KAAK,EAAE,MAAc,EAAmB,EAAE;YAClD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC5C,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/llm/providers/anthropic.ts"],"names":[],"mappings":"AAAA,oCAAoC;AAEpC,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAG1C,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAiB,EAAe,EAAE;IACxE,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAExD,OAAO;QACL,QAAQ,EAAE,KAAK,EAAE,MAAc,EAAmB,EAAE;YAClD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC5C,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,UAAU,EAAE,KAAK;gBACjB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;aAC9C,CAAC,CAAC;YACH,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAClC,OAAO,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grok.d.ts","sourceRoot":"","sources":["../../../src/llm/providers/grok.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI1D,eAAO,MAAM,kBAAkB,GAAI,QAAQ,SAAS,KAAG,WActD,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Grok (xAI) provider implementation (OpenAI-compatible API)
|
|
2
|
+
import OpenAI from "openai";
|
|
3
|
+
const BASE_URL = "https://api.x.ai/v1";
|
|
4
|
+
export const createGrokProvider = (config) => {
|
|
5
|
+
const client = new OpenAI({ apiKey: config.apiKey, baseURL: BASE_URL });
|
|
6
|
+
return {
|
|
7
|
+
generate: async (prompt) => {
|
|
8
|
+
const response = await client.chat.completions.create({
|
|
9
|
+
model: config.model,
|
|
10
|
+
messages: [{ role: "user", content: prompt }],
|
|
11
|
+
max_tokens: 16384,
|
|
12
|
+
temperature: 0.7,
|
|
13
|
+
});
|
|
14
|
+
return response.choices[0]?.message?.content?.trim() ?? "";
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=grok.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grok.js","sourceRoot":"","sources":["../../../src/llm/providers/grok.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,MAAM,QAAQ,GAAG,qBAAqB,CAAC;AAEvC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAAiB,EAAe,EAAE;IACnE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAExE,OAAO;QACL,QAAQ,EAAE,KAAK,EAAE,MAAc,EAAmB,EAAE;YAClD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBACpD,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;gBAC7C,UAAU,EAAE,KAAK;gBACjB,WAAW,EAAE,GAAG;aACjB,CAAC,CAAC;YACH,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groq.d.ts","sourceRoot":"","sources":["../../../src/llm/providers/groq.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI1D,eAAO,MAAM,kBAAkB,GAAI,QAAQ,SAAS,KAAG,WActD,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Groq provider implementation (OpenAI-compatible API, fast inference)
|
|
2
|
+
import OpenAI from "openai";
|
|
3
|
+
const BASE_URL = "https://api.groq.com/openai/v1";
|
|
4
|
+
export const createGroqProvider = (config) => {
|
|
5
|
+
const client = new OpenAI({ apiKey: config.apiKey, baseURL: BASE_URL });
|
|
6
|
+
return {
|
|
7
|
+
generate: async (prompt) => {
|
|
8
|
+
const response = await client.chat.completions.create({
|
|
9
|
+
model: config.model,
|
|
10
|
+
messages: [{ role: "user", content: prompt }],
|
|
11
|
+
max_tokens: 16384,
|
|
12
|
+
temperature: 0.7,
|
|
13
|
+
});
|
|
14
|
+
return response.choices[0]?.message?.content?.trim() ?? "";
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=groq.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groq.js","sourceRoot":"","sources":["../../../src/llm/providers/groq.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,MAAM,QAAQ,GAAG,gCAAgC,CAAC;AAElD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAAiB,EAAe,EAAE;IACnE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAExE,OAAO;QACL,QAAQ,EAAE,KAAK,EAAE,MAAc,EAAmB,EAAE;YAClD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBACpD,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;gBAC7C,UAAU,EAAE,KAAK;gBACjB,WAAW,EAAE,GAAG;aACjB,CAAC,CAAC;YACH,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -7,7 +7,7 @@ export const createOpenAIProvider = (config) => {
|
|
|
7
7
|
const response = await client.chat.completions.create({
|
|
8
8
|
model: config.model,
|
|
9
9
|
messages: [{ role: "user", content: prompt }],
|
|
10
|
-
max_tokens:
|
|
10
|
+
max_tokens: 16384,
|
|
11
11
|
temperature: 0.7,
|
|
12
12
|
});
|
|
13
13
|
return response.choices[0]?.message?.content?.trim() ?? "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/llm/providers/openai.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAEjC,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,MAAiB,EAAe,EAAE;IACrE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAErD,OAAO;QACL,QAAQ,EAAE,KAAK,EAAE,MAAc,EAAmB,EAAE;YAClD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBACpD,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;gBAC7C,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/llm/providers/openai.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAEjC,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,MAAiB,EAAe,EAAE;IACrE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAErD,OAAO;QACL,QAAQ,EAAE,KAAK,EAAE,MAAc,EAAmB,EAAE;YAClD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBACpD,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;gBAC7C,UAAU,EAAE,KAAK;gBACjB,WAAW,EAAE,GAAG;aACjB,CAAC,CAAC;YACH,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../../src/llm/providers/openrouter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI1D,eAAO,MAAM,wBAAwB,GAAI,QAAQ,SAAS,KAAG,WAc5D,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// OpenRouter provider implementation (OpenAI-compatible API)
|
|
2
|
+
import OpenAI from "openai";
|
|
3
|
+
const BASE_URL = "https://openrouter.ai/api/v1";
|
|
4
|
+
export const createOpenRouterProvider = (config) => {
|
|
5
|
+
const client = new OpenAI({ apiKey: config.apiKey, baseURL: BASE_URL });
|
|
6
|
+
return {
|
|
7
|
+
generate: async (prompt) => {
|
|
8
|
+
const response = await client.chat.completions.create({
|
|
9
|
+
model: config.model,
|
|
10
|
+
messages: [{ role: "user", content: prompt }],
|
|
11
|
+
max_tokens: 16384,
|
|
12
|
+
temperature: 0.7,
|
|
13
|
+
});
|
|
14
|
+
return response.choices[0]?.message?.content?.trim() ?? "";
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=openrouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../../src/llm/providers/openrouter.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,MAAM,QAAQ,GAAG,8BAA8B,CAAC;AAEhD,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,MAAiB,EAAe,EAAE;IACzE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAExE,OAAO;QACL,QAAQ,EAAE,KAAK,EAAE,MAAc,EAAmB,EAAE;YAClD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBACpD,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;gBAC7C,UAAU,EAAE,KAAK;gBACjB,WAAW,EAAE,GAAG;aACjB,CAAC,CAAC;YACH,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
|
package/dist/llm/types.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import type { WeeklyReportData, LLMProvider as LLMProviderName } from "../types.js";
|
|
1
|
+
import type { WeeklyReportData, LLMProvider as LLMProviderName, Language } from "../types.js";
|
|
2
2
|
export type LLMConfig = {
|
|
3
3
|
provider: LLMProviderName;
|
|
4
4
|
apiKey: string;
|
|
5
5
|
model: string;
|
|
6
|
+
language?: Language;
|
|
6
7
|
};
|
|
7
8
|
export type LLMProvider = {
|
|
8
9
|
generate: (prompt: string) => Promise<string>;
|
|
9
10
|
};
|
|
10
|
-
export type NarrativeInput = Omit<WeeklyReportData, "
|
|
11
|
+
export type NarrativeInput = Omit<WeeklyReportData, "aiContent"> & {
|
|
12
|
+
language?: Language;
|
|
13
|
+
};
|
|
11
14
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/llm/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/llm/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/llm/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,IAAI,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE9F,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,gBAAgB,EAAE,WAAW,CAAC,GAAG;IACjE,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC"}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import Handlebars from "handlebars";
|
|
2
|
-
|
|
2
|
+
import type { Language } from "../types.js";
|
|
3
|
+
export type HelperOptions = {
|
|
4
|
+
language: Language;
|
|
5
|
+
timezone: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const registerHelpers: (hbs: typeof Handlebars, options?: HelperOptions) => void;
|
|
3
8
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/renderer/helpers.ts"],"names":[],"mappings":"AAEA,OAAO,UAAU,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/renderer/helpers.ts"],"names":[],"mappings":"AAEA,OAAO,UAAU,MAAM,YAAY,CAAC;AAGpC,OAAO,KAAK,EAAsB,QAAQ,EAAE,MAAM,aAAa,CAAC;AAgBhE,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,KAAK,OAAO,UAAU,EACtB,UAAS,aAAmD,KAC3D,IAmFF,CAAC"}
|
package/dist/renderer/helpers.js
CHANGED
|
@@ -1,22 +1,59 @@
|
|
|
1
1
|
// Handlebars custom helpers
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
2
|
+
import Handlebars from "handlebars";
|
|
3
|
+
import { Marked } from "marked";
|
|
4
|
+
import DOMPurify from "isomorphic-dompurify";
|
|
5
|
+
import { getLocale, formatNumber as fmtNumber } from "../i18n/index.js";
|
|
6
|
+
import { parseLocalDate } from "../collector/date-range.js";
|
|
7
|
+
const sanitize = (html) => DOMPurify.sanitize(html, { USE_PROFILES: { html: true } });
|
|
8
|
+
const externalLinkRenderer = {
|
|
9
|
+
link({ href, text }) {
|
|
10
|
+
const escaped = href.replace(/"/g, """);
|
|
11
|
+
return `<a href="${escaped}" target="_blank" rel="noopener nofollow">${text}</a>`;
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
const marked = new Marked({ renderer: externalLinkRenderer });
|
|
15
|
+
export const registerHelpers = (hbs, options = { language: "en", timezone: "UTC" }) => {
|
|
16
|
+
const locale = getLocale(options.language);
|
|
17
|
+
hbs.registerHelper("weekLabel", (from, to) => `${from} - ${to}`);
|
|
18
|
+
hbs.registerHelper("paragraphs", (text) => text.split("\n\n").map((p) => p.trim()).filter(Boolean));
|
|
19
|
+
hbs.registerHelper("fixed", (value, digits) => value.toFixed(digits));
|
|
15
20
|
hbs.registerHelper("weekday", (dateStr) => {
|
|
16
|
-
const date =
|
|
17
|
-
|
|
21
|
+
const date = parseLocalDate(dateStr, options.timezone);
|
|
22
|
+
const dayIndex = new Intl.DateTimeFormat("en-US", {
|
|
23
|
+
timeZone: options.timezone,
|
|
24
|
+
weekday: "short",
|
|
25
|
+
}).formatToParts(date).find((p) => p.type === "weekday");
|
|
26
|
+
const dayMap = { Sun: 0, Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6 };
|
|
27
|
+
return locale.weekdaysShort[dayMap[dayIndex?.value ?? "Sun"] ?? 0];
|
|
28
|
+
});
|
|
29
|
+
hbs.registerHelper("formatNumber", (n) => fmtNumber(n, options.language));
|
|
30
|
+
hbs.registerHelper("repoBarWidth", (prsOpened, repos) => {
|
|
31
|
+
const max = Math.max(...repos.map((r) => r.prsOpened), 1);
|
|
32
|
+
return Math.round((prsOpened / max) * 100);
|
|
33
|
+
});
|
|
34
|
+
hbs.registerHelper("sortReposDesc", (repos) => [...repos].sort((a, b) => b.prsOpened - a.prsOpened));
|
|
35
|
+
// i18n formatters (functions that take arguments)
|
|
36
|
+
hbs.registerHelper("sectionsCount", (n) => locale.sectionsCount(n));
|
|
37
|
+
hbs.registerHelper("itemsCount", (n) => locale.itemsCount(n));
|
|
38
|
+
hbs.registerHelper("userWeek", (username) => locale.userWeek(username));
|
|
39
|
+
// Markdown rendering with HTML sanitization
|
|
40
|
+
// All links get target="_blank" rel="noopener nofollow",
|
|
41
|
+
// and DOMPurify strips any dangerous tags (script, iframe, etc.)
|
|
42
|
+
hbs.registerHelper("md", (text) => new Handlebars.SafeString(sanitize(marked.parse(text ?? ""))));
|
|
43
|
+
hbs.registerHelper("mdInline", (text) => new Handlebars.SafeString(sanitize(marked.parseInline(text ?? ""))));
|
|
44
|
+
// Escape a string for safe embedding inside a JSON-LD <script> block.
|
|
45
|
+
// Prevents breaking out of the JSON string or closing the script tag.
|
|
46
|
+
hbs.registerHelper("jsonLdEscape", (text) => {
|
|
47
|
+
const escaped = JSON.stringify(String(text ?? ""))
|
|
48
|
+
.slice(1, -1) // remove surrounding quotes added by JSON.stringify
|
|
49
|
+
.replace(/<\//g, "<\\/"); // prevent </script> injection
|
|
50
|
+
return new Handlebars.SafeString(escaped);
|
|
51
|
+
});
|
|
52
|
+
hbs.registerHelper("eq", function (a, b, opts) {
|
|
53
|
+
return a === b ? opts.fn(this) : opts.inverse(this);
|
|
54
|
+
});
|
|
55
|
+
hbs.registerHelper("neq", function (a, b, opts) {
|
|
56
|
+
return a !== b ? opts.fn(this) : opts.inverse(this);
|
|
18
57
|
});
|
|
19
|
-
hbs.registerHelper("fixed", (value, digits) => value.toFixed(digits));
|
|
20
|
-
hbs.registerHelper("paragraphs", (text) => text.split("\n\n").map((p) => p.trim()).filter(Boolean));
|
|
21
58
|
};
|
|
22
59
|
//# sourceMappingURL=helpers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/renderer/helpers.ts"],"names":[],"mappings":"AAAA,4BAA4B;
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/renderer/helpers.ts"],"names":[],"mappings":"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"}
|
package/dist/renderer/index.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
-
import type { WeeklyReportData,
|
|
2
|
-
export
|
|
1
|
+
import type { WeeklyReportData, Language } from "../types.js";
|
|
2
|
+
export type RenderOptions = {
|
|
3
|
+
language?: Language;
|
|
4
|
+
timezone?: string;
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
weekPath?: string;
|
|
7
|
+
siteTitle?: string;
|
|
8
|
+
prevWeek?: string;
|
|
9
|
+
nextWeek?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare const renderReport: (data: WeeklyReportData, options?: RenderOptions) => string;
|
|
3
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/renderer/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/renderer/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAoB,MAAM,aAAa,CAAC;AAoChF,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAaF,eAAO,MAAM,YAAY,GACvB,MAAM,gBAAgB,EACtB,UAAS,aAAkB,KAC1B,MA4BF,CAAC"}
|
package/dist/renderer/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
import { join, dirname } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import Handlebars from "handlebars";
|
|
6
|
+
import { getLocale } from "../i18n/index.js";
|
|
6
7
|
import { buildCSS } from "./themes.js";
|
|
7
8
|
import { registerHelpers } from "./helpers.js";
|
|
8
9
|
// Templates live at src/renderer/templates/ (both dev and npm package)
|
|
@@ -10,36 +11,57 @@ const TEMPLATES_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "..",
|
|
|
10
11
|
const readTemplate = (path) => readFileSync(join(TEMPLATES_DIR, path), "utf-8");
|
|
11
12
|
const PARTIAL_NAMES = [
|
|
12
13
|
"header",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"repositories",
|
|
17
|
-
"narrative",
|
|
14
|
+
"overview",
|
|
15
|
+
"summaries",
|
|
16
|
+
"highlights",
|
|
18
17
|
"footer",
|
|
19
18
|
];
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
const computeHeatmapLevels = (dailyCommits) => {
|
|
20
|
+
const max = Math.max(...dailyCommits.map((d) => d.count), 1);
|
|
21
|
+
return dailyCommits.map((d) => {
|
|
22
|
+
if (d.count === 0)
|
|
23
|
+
return { ...d, level: 0 };
|
|
24
|
+
const ratio = d.count / max;
|
|
25
|
+
if (ratio <= 0.25)
|
|
26
|
+
return { ...d, level: 1 };
|
|
27
|
+
if (ratio <= 0.5)
|
|
28
|
+
return { ...d, level: 2 };
|
|
29
|
+
if (ratio <= 0.75)
|
|
30
|
+
return { ...d, level: 3 };
|
|
31
|
+
return { ...d, level: 4 };
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
const createInstance = (language, timezone) => {
|
|
29
35
|
const hbs = Handlebars.create();
|
|
30
|
-
registerHelpers(hbs);
|
|
36
|
+
registerHelpers(hbs, { language, timezone });
|
|
31
37
|
PARTIAL_NAMES.forEach((name) => {
|
|
32
38
|
hbs.registerPartial(name, readTemplate(`partials/${name}.hbs`));
|
|
33
39
|
});
|
|
34
40
|
return hbs;
|
|
35
41
|
};
|
|
36
|
-
export const renderReport = (data,
|
|
37
|
-
const
|
|
42
|
+
export const renderReport = (data, options = {}) => {
|
|
43
|
+
const language = options.language ?? "en";
|
|
44
|
+
const timezone = options.timezone ?? "UTC";
|
|
45
|
+
const locale = getLocale(language);
|
|
46
|
+
const hbs = createInstance(language, timezone);
|
|
38
47
|
const template = hbs.compile(readTemplate("report.hbs"));
|
|
48
|
+
const baseUrl = options.baseUrl?.replace(/\/+$/, "") ?? "";
|
|
49
|
+
const weekPath = options.weekPath ?? "";
|
|
50
|
+
const canonicalUrl = baseUrl && weekPath ? `${baseUrl}/${weekPath}/` : undefined;
|
|
51
|
+
const ogImageUrl = baseUrl && weekPath ? `${baseUrl}/${weekPath}/og.png` : "og.png";
|
|
52
|
+
const siteTitle = options.siteTitle ?? "Dev\nPulse";
|
|
39
53
|
return template({
|
|
40
54
|
...data,
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
dailyCommits: computeHeatmapLevels(data.dailyCommits),
|
|
56
|
+
css: buildCSS(language),
|
|
57
|
+
lang: language,
|
|
58
|
+
i18n: locale,
|
|
59
|
+
baseUrl,
|
|
60
|
+
canonicalUrl,
|
|
61
|
+
ogImageUrl,
|
|
62
|
+
siteTitle,
|
|
63
|
+
prevWeek: options.prevWeek,
|
|
64
|
+
nextWeek: options.nextWeek,
|
|
43
65
|
});
|
|
44
66
|
};
|
|
45
67
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/renderer/index.ts"],"names":[],"mappings":"AAAA,sFAAsF;AAEtF,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,UAAU,MAAM,YAAY,CAAC;AAEpC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,uEAAuE;AACvE,MAAM,aAAa,GAAG,IAAI,CACxB,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EACvC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,CAC3C,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,IAAY,EAAU,EAAE,CAC5C,YAAY,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;AAEnD,MAAM,aAAa,GAAG;IACpB,QAAQ;IACR,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/renderer/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Language } from "../types.js";
|
|
2
|
+
export type OGImageData = {
|
|
3
|
+
title: string;
|
|
4
|
+
subtitle: string;
|
|
5
|
+
username: string;
|
|
6
|
+
dateRange: string;
|
|
7
|
+
language: Language;
|
|
8
|
+
stats: {
|
|
9
|
+
commits: number;
|
|
10
|
+
prs: number;
|
|
11
|
+
reviews: number;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export declare const generateOGImage: (data: OGImageData) => Promise<Buffer>;
|
|
15
|
+
//# sourceMappingURL=og-image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"og-image.d.ts","sourceRoot":"","sources":["../../src/renderer/og-image.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AA2B5C,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1D,CAAC;AA8HF,eAAO,MAAM,eAAe,GAAU,MAAM,WAAW,KAAG,OAAO,CAAC,MAAM,CAIvE,CAAC"}
|