@urmzd/github-insights 2.1.0 → 2.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.
Files changed (103) hide show
  1. package/.githooks/commit-msg +4 -0
  2. package/.githooks/pre-commit +4 -0
  3. package/AGENTS.md +32 -19
  4. package/CHANGELOG.md +45 -0
  5. package/CONTRIBUTING.md +18 -19
  6. package/README.md +21 -24
  7. package/action.yml +1 -1
  8. package/assets/insights/index.svg +45 -4
  9. package/assets/insights/metrics-constellation.svg +55 -0
  10. package/assets/insights/metrics-impact.svg +55 -0
  11. package/assets/insights/metrics-rhythm.svg +55 -0
  12. package/assets/insights/metrics-velocity.svg +55 -0
  13. package/examples/classic/README.md +36 -2
  14. package/examples/classic/index.svg +45 -4
  15. package/examples/classic/metrics-constellation.svg +55 -0
  16. package/examples/classic/metrics-impact.svg +55 -0
  17. package/examples/classic/metrics-rhythm.svg +55 -0
  18. package/examples/classic/metrics-velocity.svg +55 -0
  19. package/examples/ecosystem/README.md +39 -28
  20. package/examples/ecosystem/index.svg +45 -4
  21. package/examples/ecosystem/metrics-constellation.svg +55 -0
  22. package/examples/ecosystem/metrics-impact.svg +55 -0
  23. package/examples/ecosystem/metrics-rhythm.svg +55 -0
  24. package/examples/ecosystem/metrics-velocity.svg +55 -0
  25. package/examples/minimal/README.md +36 -2
  26. package/examples/minimal/index.svg +45 -4
  27. package/examples/minimal/metrics-constellation.svg +55 -0
  28. package/examples/minimal/metrics-impact.svg +55 -0
  29. package/examples/minimal/metrics-rhythm.svg +55 -0
  30. package/examples/minimal/metrics-velocity.svg +55 -0
  31. package/examples/modern/README.md +62 -50
  32. package/examples/modern/index.svg +45 -4
  33. package/examples/modern/metrics-constellation.svg +55 -0
  34. package/examples/modern/metrics-impact.svg +55 -0
  35. package/examples/modern/metrics-rhythm.svg +55 -0
  36. package/examples/modern/metrics-velocity.svg +55 -0
  37. package/llms.txt +4 -4
  38. package/package.json +1 -1
  39. package/skills/github-insights/SKILL.md +35 -81
  40. package/sr.yaml +9 -0
  41. package/src/api.ts +2 -140
  42. package/src/components/contribution-rhythm.tsx +152 -0
  43. package/src/components/full-svg.test.tsx +4 -1
  44. package/src/components/full-svg.tsx +14 -7
  45. package/src/components/impact-trail.tsx +90 -0
  46. package/src/components/language-velocity.tsx +181 -0
  47. package/src/components/project-constellation.tsx +97 -0
  48. package/src/components/section.test.tsx +5 -3
  49. package/src/components/section.tsx +5 -13
  50. package/src/components/style-defs.tsx +44 -3
  51. package/src/index.ts +28 -47
  52. package/src/metrics.test.ts +50 -57
  53. package/src/metrics.ts +277 -95
  54. package/src/readme.test.ts +2 -4
  55. package/src/templates.test.ts +19 -16
  56. package/src/templates.ts +30 -16
  57. package/src/theme.ts +11 -1
  58. package/src/types.ts +28 -7
  59. package/assets/insights/metrics-calendar.svg +0 -14
  60. package/assets/insights/metrics-complexity.svg +0 -14
  61. package/assets/insights/metrics-contributions.svg +0 -14
  62. package/assets/insights/metrics-expertise.svg +0 -14
  63. package/assets/insights/metrics-languages.svg +0 -14
  64. package/assets/insights/metrics-pulse.svg +0 -14
  65. package/examples/classic/metrics-calendar.svg +0 -14
  66. package/examples/classic/metrics-complexity.svg +0 -14
  67. package/examples/classic/metrics-contributions.svg +0 -14
  68. package/examples/classic/metrics-expertise.svg +0 -14
  69. package/examples/classic/metrics-languages.svg +0 -14
  70. package/examples/classic/metrics-pulse.svg +0 -14
  71. package/examples/ecosystem/metrics-calendar.svg +0 -14
  72. package/examples/ecosystem/metrics-complexity.svg +0 -14
  73. package/examples/ecosystem/metrics-contributions.svg +0 -14
  74. package/examples/ecosystem/metrics-expertise.svg +0 -14
  75. package/examples/ecosystem/metrics-languages.svg +0 -14
  76. package/examples/ecosystem/metrics-pulse.svg +0 -14
  77. package/examples/minimal/metrics-calendar.svg +0 -14
  78. package/examples/minimal/metrics-complexity.svg +0 -14
  79. package/examples/minimal/metrics-contributions.svg +0 -14
  80. package/examples/minimal/metrics-expertise.svg +0 -14
  81. package/examples/minimal/metrics-languages.svg +0 -14
  82. package/examples/minimal/metrics-pulse.svg +0 -14
  83. package/examples/modern/metrics-calendar.svg +0 -14
  84. package/examples/modern/metrics-complexity.svg +0 -14
  85. package/examples/modern/metrics-contributions.svg +0 -14
  86. package/examples/modern/metrics-expertise.svg +0 -14
  87. package/examples/modern/metrics-languages.svg +0 -14
  88. package/examples/modern/metrics-pulse.svg +0 -14
  89. package/src/components/bar-chart.test.tsx +0 -38
  90. package/src/components/bar-chart.tsx +0 -54
  91. package/src/components/contribution-calendar.test.tsx +0 -44
  92. package/src/components/contribution-calendar.tsx +0 -94
  93. package/src/components/contribution-cards.test.tsx +0 -36
  94. package/src/components/contribution-cards.tsx +0 -58
  95. package/src/components/donut-chart.test.tsx +0 -36
  96. package/src/components/donut-chart.tsx +0 -102
  97. package/src/components/project-cards.test.tsx +0 -46
  98. package/src/components/project-cards.tsx +0 -66
  99. package/src/components/stat-cards.test.tsx +0 -32
  100. package/src/components/stat-cards.tsx +0 -57
  101. package/src/components/tech-highlights.test.tsx +0 -63
  102. package/src/components/tech-highlights.tsx +0 -109
  103. package/teasr.toml +0 -14
@@ -0,0 +1,55 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="808" height="340" viewBox="0 0 808 340"><defs><style>
2
+ .t { font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif; font-variant-numeric: tabular-lining; }
3
+ .t-h { font-size: 14px; fill: #c9d1d9; letter-spacing: 2px; font-weight: 600; }
4
+ .t-sub { font-size: 11px; fill: #6e7681; }
5
+ .t-label { font-size: 12px; fill: #8b949e; }
6
+ .t-value { font-size: 11px; fill: #6e7681; }
7
+ .t-subhdr { font-size: 11px; fill: #8b949e; letter-spacing: 1px; font-weight: 600; }
8
+ .t-stat-label { font-size: 10px; fill: #8b949e; font-weight: 600; }
9
+ .t-stat-value { font-size: 22px; font-weight: 700; }
10
+ .t-card-title { font-size: 12px; fill: #58a6ff; font-weight: 700; }
11
+ .t-card-detail { font-size: 11px; fill: #8b949e; }
12
+ .t-pill { font-size: 11px; font-weight: 600; }
13
+ .t-bullet { font-size: 12px; fill: #c9d1d9; }
14
+ .bg-fill { fill: #0d1117; }
15
+ .card-fill { fill: #161b22; }
16
+ .border-stroke { stroke: #30363d; }
17
+
18
+ @media (prefers-color-scheme: light) {
19
+ .bg-fill { fill: #ffffff; }
20
+ .card-fill { fill: #f6f8fa; }
21
+ .border-stroke { stroke: #d0d7de; }
22
+ .t-h { fill: #1f2328; }
23
+ .t-sub { fill: #656d76; }
24
+ .t-label { fill: #656d76; }
25
+ .t-value { fill: #656d76; }
26
+ .t-subhdr { fill: #656d76; }
27
+ .t-stat-label { fill: #656d76; }
28
+ .t-card-title { fill: #0969da; }
29
+ .t-card-detail { fill: #656d76; }
30
+ .t-bullet { fill: #1f2328; }
31
+ }
32
+
33
+ @keyframes fadeIn {
34
+ from { opacity: 0; transform: translateY(8px); }
35
+ to { opacity: 1; transform: translateY(0); }
36
+ }
37
+ @keyframes scaleIn {
38
+ from { transform: scale(0); opacity: 0; }
39
+ to { transform: scale(1); opacity: 1; }
40
+ }
41
+ @keyframes drawPath {
42
+ from { stroke-dashoffset: var(--path-length); }
43
+ to { stroke-dashoffset: 0; }
44
+ }
45
+ @keyframes radarReveal {
46
+ from { transform: scale(0); opacity: 0; }
47
+ to { transform: scale(1); opacity: 0.6; }
48
+ }
49
+ .fade-1 { animation: fadeIn 0.6s ease-out 0.1s both; }
50
+ .fade-2 { animation: fadeIn 0.6s ease-out 0.25s both; }
51
+ .fade-3 { animation: fadeIn 0.6s ease-out 0.4s both; }
52
+ .fade-4 { animation: fadeIn 0.6s ease-out 0.55s both; }
53
+ .fade-5 { animation: fadeIn 0.6s ease-out 0.7s both; }
54
+ .fade-6 { animation: fadeIn 0.6s ease-out 0.85s both; }
55
+ </style></defs><rect width="808" height="340" rx="12" class="bg-fill" fill="#0d1117"/><text x="24" y="40" class="t t-h">CONTRIBUTION RHYTHM</text><text x="24" y="56" class="t t-sub">Activity patterns and statistics over the past year</text><circle cx="144" cy="186" r="22.5" fill="none" stroke="#30363d" stroke-width="1" stroke-opacity="0.4"/><circle cx="144" cy="186" r="45" fill="none" stroke="#30363d" stroke-width="1" stroke-opacity="0.4"/><circle cx="144" cy="186" r="67.5" fill="none" stroke="#30363d" stroke-width="1" stroke-opacity="0.4"/><circle cx="144" cy="186" r="90" fill="none" stroke="#30363d" stroke-width="1" stroke-opacity="0.4"/><line x1="144" y1="186" x2="144" y2="96" stroke="#30363d" stroke-width="1" stroke-opacity="0.3"/><line x1="144" y1="186" x2="214.36483342212267" y2="129.88591783271397" stroke="#30363d" stroke-width="1" stroke-opacity="0.3"/><line x1="144" y1="186" x2="231.74351209636413" y2="206.0268840560683" stroke="#30363d" stroke-width="1" stroke-opacity="0.3"/><line x1="144" y1="186" x2="183.04953652058023" y2="267.08719811121773" stroke="#30363d" stroke-width="1" stroke-opacity="0.3"/><line x1="144" y1="186" x2="104.95046347941977" y2="267.08719811121773" stroke="#30363d" stroke-width="1" stroke-opacity="0.3"/><line x1="144" y1="186" x2="56.25648790363587" y2="206.0268840560683" stroke="#30363d" stroke-width="1" stroke-opacity="0.3"/><line x1="144" y1="186" x2="73.63516657787731" y2="129.885917832714" stroke="#30363d" stroke-width="1" stroke-opacity="0.3"/><polygon points="144,160.02272727272728 176.46377541975204,160.11100300009304 172.11780728542578,192.41770602705824 154.91612043643494,208.66755765381768 132.551385883739,209.7732921735161 56.25648790363587,206.0268840560683 96.18389728814844,147.86793052723064" fill="#58a6ff" fill-opacity="0.2" stroke="#58a6ff" stroke-width="2" stroke-opacity="0.8" class="fade-2" style="transform-origin: 144px 186px"/><circle cx="144" cy="160.02272727272728" r="3" fill="#58a6ff" class="fade-1"/><circle cx="176.46377541975204" cy="160.11100300009304" r="3" fill="#58a6ff" class="fade-2"/><circle cx="172.11780728542578" cy="192.41770602705824" r="3" fill="#58a6ff" class="fade-3"/><circle cx="154.91612043643494" cy="208.66755765381768" r="3" fill="#58a6ff" class="fade-4"/><circle cx="132.551385883739" cy="209.7732921735161" r="3" fill="#58a6ff" class="fade-5"/><circle cx="56.25648790363587" cy="206.0268840560683" r="3" fill="#58a6ff" class="fade-6"/><circle cx="96.18389728814844" cy="147.86793052723064" r="3" fill="#58a6ff" class="fade-6"/><text x="144" y="84" class="t t-value" text-anchor="middle">Sun</text><text x="226.87413714161116" y="123.91008100297425" class="t t-value" text-anchor="middle">Mon</text><text x="247.34235869127332" y="213.58721899936933" class="t t-value" text-anchor="middle">Tue</text><text x="189.99167634646116" y="285.50269999765646" class="t t-value" text-anchor="middle">Wed</text><text x="98.00832365353884" y="285.50269999765646" class="t t-value" text-anchor="middle">Thu</text><text x="40.657641308726696" y="213.58721899936933" class="t t-value" text-anchor="middle">Fri</text><text x="61.12586285838883" y="123.91008100297427" class="t t-value" text-anchor="middle">Sat</text><text x="324" y="96" class="t t-stat-label">COMMITS</text><text x="324" y="118" fill="#58a6ff" class="t t-stat-value">1,352</text><text x="324" y="138" class="t t-stat-label">PRS</text><text x="324" y="160" fill="#3fb950" class="t t-stat-value">4</text><text x="324" y="180" class="t t-stat-label">REVIEWS</text><text x="324" y="202" fill="#d29922" class="t t-stat-value">5</text><text x="324" y="222" class="t t-stat-label">REPOS</text><text x="324" y="244" fill="#bc8cff" class="t t-stat-value">24</text><text x="324" y="264" class="t t-stat-label">STREAK</text><text x="324" y="286" fill="#39d2c0" class="t t-stat-value">15d</text><text x="324" y="316" class="t t-sub">Most active: Fridays</text></svg>
@@ -0,0 +1,55 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="808" height="250" viewBox="0 0 808 250"><defs><style>
2
+ .t { font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif; font-variant-numeric: tabular-lining; }
3
+ .t-h { font-size: 14px; fill: #c9d1d9; letter-spacing: 2px; font-weight: 600; }
4
+ .t-sub { font-size: 11px; fill: #6e7681; }
5
+ .t-label { font-size: 12px; fill: #8b949e; }
6
+ .t-value { font-size: 11px; fill: #6e7681; }
7
+ .t-subhdr { font-size: 11px; fill: #8b949e; letter-spacing: 1px; font-weight: 600; }
8
+ .t-stat-label { font-size: 10px; fill: #8b949e; font-weight: 600; }
9
+ .t-stat-value { font-size: 22px; font-weight: 700; }
10
+ .t-card-title { font-size: 12px; fill: #58a6ff; font-weight: 700; }
11
+ .t-card-detail { font-size: 11px; fill: #8b949e; }
12
+ .t-pill { font-size: 11px; font-weight: 600; }
13
+ .t-bullet { font-size: 12px; fill: #c9d1d9; }
14
+ .bg-fill { fill: #0d1117; }
15
+ .card-fill { fill: #161b22; }
16
+ .border-stroke { stroke: #30363d; }
17
+
18
+ @media (prefers-color-scheme: light) {
19
+ .bg-fill { fill: #ffffff; }
20
+ .card-fill { fill: #f6f8fa; }
21
+ .border-stroke { stroke: #d0d7de; }
22
+ .t-h { fill: #1f2328; }
23
+ .t-sub { fill: #656d76; }
24
+ .t-label { fill: #656d76; }
25
+ .t-value { fill: #656d76; }
26
+ .t-subhdr { fill: #656d76; }
27
+ .t-stat-label { fill: #656d76; }
28
+ .t-card-title { fill: #0969da; }
29
+ .t-card-detail { fill: #656d76; }
30
+ .t-bullet { fill: #1f2328; }
31
+ }
32
+
33
+ @keyframes fadeIn {
34
+ from { opacity: 0; transform: translateY(8px); }
35
+ to { opacity: 1; transform: translateY(0); }
36
+ }
37
+ @keyframes scaleIn {
38
+ from { transform: scale(0); opacity: 0; }
39
+ to { transform: scale(1); opacity: 1; }
40
+ }
41
+ @keyframes drawPath {
42
+ from { stroke-dashoffset: var(--path-length); }
43
+ to { stroke-dashoffset: 0; }
44
+ }
45
+ @keyframes radarReveal {
46
+ from { transform: scale(0); opacity: 0; }
47
+ to { transform: scale(1); opacity: 0.6; }
48
+ }
49
+ .fade-1 { animation: fadeIn 0.6s ease-out 0.1s both; }
50
+ .fade-2 { animation: fadeIn 0.6s ease-out 0.25s both; }
51
+ .fade-3 { animation: fadeIn 0.6s ease-out 0.4s both; }
52
+ .fade-4 { animation: fadeIn 0.6s ease-out 0.55s both; }
53
+ .fade-5 { animation: fadeIn 0.6s ease-out 0.7s both; }
54
+ .fade-6 { animation: fadeIn 0.6s ease-out 0.85s both; }
55
+ </style></defs><rect width="808" height="250" rx="12" class="bg-fill" fill="#0d1117"/><text x="24" y="40" class="t t-h">LANGUAGE VELOCITY</text><text x="24" y="56" class="t t-sub">How language usage has evolved over the past year</text><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.24865831842575 150.66666666666669,205.24865831842575 C 182.33333333333334,205.24865831842575 182.33333333333334,204.4973166368515 214,204.4973166368515 C 245.66666666666669,204.4973166368515 245.66666666666669,205.49910554561717 277.33333333333337,205.49910554561717 C 309,205.49910554561717 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,195.98211091234347 404,195.98211091234347 C 435.6666666666667,195.98211091234347 435.6666666666667,203.9964221824687 467.33333333333337,203.9964221824687 C 499.00000000000006,203.9964221824687 499.00000000000006,198.23613595706618 530.6666666666667,198.23613595706618 C 562.3333333333334,198.23613595706618 562.3333333333334,204.4973166368515 594,204.4973166368515 C 625.6666666666667,204.4973166368515 625.6666666666667,157.66368515205724 657.3333333333334,157.66368515205724 C 689,157.66368515205724 689,87.28801431127013 720.6666666666667,87.28801431127013 C 752.3333333333334,87.28801431127013 752.3333333333334,66 784,66 L 784,67.25223613595705 C 752.3333333333334,67.25223613595705 752.3333333333334,88.28980322003578 720.6666666666667,88.28980322003578 C 689,88.28980322003578 689,158.16457960644007 657.3333333333334,158.16457960644007 C 625.6666666666667,158.16457960644007 625.6666666666667,204.4973166368515 594,204.4973166368515 C 562.3333333333334,204.4973166368515 562.3333333333334,198.23613595706618 530.6666666666667,198.23613595706618 C 499.00000000000006,198.23613595706618 499.00000000000006,203.9964221824687 467.33333333333337,203.9964221824687 C 435.6666666666667,203.9964221824687 435.6666666666667,195.98211091234347 404,195.98211091234347 C 372.33333333333337,195.98211091234347 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.49910554561717 277.33333333333337,205.49910554561717 C 245.66666666666669,205.49910554561717 245.66666666666669,204.4973166368515 214,204.4973166368515 C 182.33333333333334,204.4973166368515 182.33333333333334,205.24865831842575 150.66666666666669,205.24865831842575 C 119.00000000000001,205.24865831842575 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#DA5B0B" fill-opacity="0.75" class="fade-1"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.24865831842575 150.66666666666669,205.24865831842575 C 182.33333333333334,205.24865831842575 182.33333333333334,204.4973166368515 214,204.4973166368515 C 245.66666666666669,204.4973166368515 245.66666666666669,205.49910554561717 277.33333333333337,205.49910554561717 C 309,205.49910554561717 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,195.98211091234347 404,195.98211091234347 C 435.6666666666667,195.98211091234347 435.6666666666667,203.9964221824687 467.33333333333337,203.9964221824687 C 499.00000000000006,203.9964221824687 499.00000000000006,198.23613595706618 530.6666666666667,198.23613595706618 C 562.3333333333334,198.23613595706618 562.3333333333334,204.4973166368515 594,204.4973166368515 C 625.6666666666667,204.4973166368515 625.6666666666667,158.16457960644007 657.3333333333334,158.16457960644007 C 689,158.16457960644007 689,88.28980322003578 720.6666666666667,88.28980322003578 C 752.3333333333334,88.28980322003578 752.3333333333334,67.25223613595705 784,67.25223613595705 L 784,72.76207513416816 C 752.3333333333334,72.76207513416816 752.3333333333334,93.04830053667264 720.6666666666667,93.04830053667264 C 689,93.04830053667264 689,160.16815742397137 657.3333333333334,160.16815742397137 C 625.6666666666667,160.16815742397137 625.6666666666667,204.4973166368515 594,204.4973166368515 C 562.3333333333334,204.4973166368515 562.3333333333334,198.4865831842576 530.6666666666667,198.4865831842576 C 499.00000000000006,198.4865831842576 499.00000000000006,203.9964221824687 467.33333333333337,203.9964221824687 C 435.6666666666667,203.9964221824687 435.6666666666667,196.4830053667263 404,196.4830053667263 C 372.33333333333337,196.4830053667263 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.49910554561717 277.33333333333337,205.49910554561717 C 245.66666666666669,205.49910554561717 245.66666666666669,204.4973166368515 214,204.4973166368515 C 182.33333333333334,204.4973166368515 182.33333333333334,205.24865831842575 150.66666666666669,205.24865831842575 C 119.00000000000001,205.24865831842575 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#b07219" fill-opacity="0.75" class="fade-2"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.24865831842575 150.66666666666669,205.24865831842575 C 182.33333333333334,205.24865831842575 182.33333333333334,204.4973166368515 214,204.4973166368515 C 245.66666666666669,204.4973166368515 245.66666666666669,205.49910554561717 277.33333333333337,205.49910554561717 C 309,205.49910554561717 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,196.4830053667263 404,196.4830053667263 C 435.6666666666667,196.4830053667263 435.6666666666667,203.9964221824687 467.33333333333337,203.9964221824687 C 499.00000000000006,203.9964221824687 499.00000000000006,198.4865831842576 530.6666666666667,198.4865831842576 C 562.3333333333334,198.4865831842576 562.3333333333334,204.4973166368515 594,204.4973166368515 C 625.6666666666667,204.4973166368515 625.6666666666667,160.16815742397137 657.3333333333334,160.16815742397137 C 689,160.16815742397137 689,93.04830053667264 720.6666666666667,93.04830053667264 C 752.3333333333334,93.04830053667264 752.3333333333334,72.76207513416816 784,72.76207513416816 L 784,87.28801431127013 C 752.3333333333334,87.28801431127013 752.3333333333334,105.32021466905186 720.6666666666667,105.32021466905186 C 689,105.32021466905186 689,165.17710196779964 657.3333333333334,165.17710196779964 C 625.6666666666667,165.17710196779964 625.6666666666667,204.74776386404292 594,204.74776386404292 C 562.3333333333334,204.74776386404292 562.3333333333334,199.23792486583184 530.6666666666667,199.23792486583184 C 499.00000000000006,199.23792486583184 499.00000000000006,204.24686940966012 467.33333333333337,204.24686940966012 C 435.6666666666667,204.24686940966012 435.6666666666667,197.48479427549194 404,197.48479427549194 C 372.33333333333337,197.48479427549194 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.49910554561717 277.33333333333337,205.49910554561717 C 245.66666666666669,205.49910554561717 245.66666666666669,204.74776386404292 214,204.74776386404292 C 182.33333333333334,204.74776386404292 182.33333333333334,205.24865831842575 150.66666666666669,205.24865831842575 C 119.00000000000001,205.24865831842575 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#3572A5" fill-opacity="0.75" class="fade-3"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.24865831842575 150.66666666666669,205.24865831842575 C 182.33333333333334,205.24865831842575 182.33333333333334,204.74776386404292 214,204.74776386404292 C 245.66666666666669,204.74776386404292 245.66666666666669,205.49910554561717 277.33333333333337,205.49910554561717 C 309,205.49910554561717 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,197.48479427549194 404,197.48479427549194 C 435.6666666666667,197.48479427549194 435.6666666666667,204.24686940966012 467.33333333333337,204.24686940966012 C 499.00000000000006,204.24686940966012 499.00000000000006,199.23792486583184 530.6666666666667,199.23792486583184 C 562.3333333333334,199.23792486583184 562.3333333333334,204.74776386404292 594,204.74776386404292 C 625.6666666666667,204.74776386404292 625.6666666666667,165.17710196779964 657.3333333333334,165.17710196779964 C 689,165.17710196779964 689,105.32021466905186 720.6666666666667,105.32021466905186 C 752.3333333333334,105.32021466905186 752.3333333333334,87.28801431127013 784,87.28801431127013 L 784,103.8175313059034 C 752.3333333333334,103.8175313059034 752.3333333333334,119.34525939177102 720.6666666666667,119.34525939177102 C 689,119.34525939177102 689,170.93738819320214 657.3333333333334,170.93738819320214 C 625.6666666666667,170.93738819320214 625.6666666666667,204.99821109123434 594,204.99821109123434 C 562.3333333333334,204.99821109123434 562.3333333333334,200.2397137745975 530.6666666666667,200.2397137745975 C 499.00000000000006,200.2397137745975 499.00000000000006,204.4973166368515 467.33333333333337,204.4973166368515 C 435.6666666666667,204.4973166368515 435.6666666666667,198.737030411449 404,198.737030411449 C 372.33333333333337,198.737030411449 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.49910554561717 277.33333333333337,205.49910554561717 C 245.66666666666669,205.49910554561717 245.66666666666669,204.99821109123434 214,204.99821109123434 C 182.33333333333334,204.99821109123434 182.33333333333334,205.24865831842575 150.66666666666669,205.24865831842575 C 119.00000000000001,205.24865831842575 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#00ADD8" fill-opacity="0.75" class="fade-4"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.24865831842575 150.66666666666669,205.24865831842575 C 182.33333333333334,205.24865831842575 182.33333333333334,204.99821109123434 214,204.99821109123434 C 245.66666666666669,204.99821109123434 245.66666666666669,205.49910554561717 277.33333333333337,205.49910554561717 C 309,205.49910554561717 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,198.737030411449 404,198.737030411449 C 435.6666666666667,198.737030411449 435.6666666666667,204.4973166368515 467.33333333333337,204.4973166368515 C 499.00000000000006,204.4973166368515 499.00000000000006,200.2397137745975 530.6666666666667,200.2397137745975 C 562.3333333333334,200.2397137745975 562.3333333333334,204.99821109123434 594,204.99821109123434 C 625.6666666666667,204.99821109123434 625.6666666666667,170.93738819320214 657.3333333333334,170.93738819320214 C 689,170.93738819320214 689,119.34525939177102 720.6666666666667,119.34525939177102 C 752.3333333333334,119.34525939177102 752.3333333333334,103.8175313059034 784,103.8175313059034 L 784,124.35420393559927 C 752.3333333333334,124.35420393559927 752.3333333333334,136.87656529516994 720.6666666666667,136.87656529516994 C 689,136.87656529516994 689,177.9499105545617 657.3333333333334,177.9499105545617 C 625.6666666666667,177.9499105545617 625.6666666666667,205.24865831842575 594,205.24865831842575 C 562.3333333333334,205.24865831842575 562.3333333333334,201.49194991055455 530.6666666666667,201.49194991055455 C 499.00000000000006,201.49194991055455 499.00000000000006,204.74776386404292 467.33333333333337,204.74776386404292 C 435.6666666666667,204.74776386404292 435.6666666666667,200.2397137745975 404,200.2397137745975 C 372.33333333333337,200.2397137745975 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.49910554561717 277.33333333333337,205.49910554561717 C 245.66666666666669,205.49910554561717 245.66666666666669,205.24865831842575 214,205.24865831842575 C 182.33333333333334,205.24865831842575 182.33333333333334,205.49910554561717 150.66666666666669,205.49910554561717 C 119.00000000000001,205.49910554561717 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#89e051" fill-opacity="0.75" class="fade-5"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.49910554561717 150.66666666666669,205.49910554561717 C 182.33333333333334,205.49910554561717 182.33333333333334,205.24865831842575 214,205.24865831842575 C 245.66666666666669,205.24865831842575 245.66666666666669,205.49910554561717 277.33333333333337,205.49910554561717 C 309,205.49910554561717 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,200.2397137745975 404,200.2397137745975 C 435.6666666666667,200.2397137745975 435.6666666666667,204.74776386404292 467.33333333333337,204.74776386404292 C 499.00000000000006,204.74776386404292 499.00000000000006,201.49194991055455 530.6666666666667,201.49194991055455 C 562.3333333333334,201.49194991055455 562.3333333333334,205.24865831842575 594,205.24865831842575 C 625.6666666666667,205.24865831842575 625.6666666666667,177.9499105545617 657.3333333333334,177.9499105545617 C 689,177.9499105545617 689,136.87656529516994 720.6666666666667,136.87656529516994 C 752.3333333333334,136.87656529516994 752.3333333333334,124.35420393559927 784,124.35420393559927 L 784,156.912343470483 C 752.3333333333334,156.912343470483 752.3333333333334,164.4257602862254 720.6666666666667,164.4257602862254 C 689,164.4257602862254 689,189.22003577817532 657.3333333333334,189.22003577817532 C 625.6666666666667,189.22003577817532 625.6666666666667,205.49910554561717 594,205.49910554561717 C 562.3333333333334,205.49910554561717 562.3333333333334,203.24508050089446 530.6666666666667,203.24508050089446 C 499.00000000000006,203.24508050089446 499.00000000000006,205.24865831842575 467.33333333333337,205.24865831842575 C 435.6666666666667,205.24865831842575 435.6666666666667,202.4937388193202 404,202.4937388193202 C 372.33333333333337,202.4937388193202 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.74955277280858 277.33333333333337,205.74955277280858 C 245.66666666666669,205.74955277280858 245.66666666666669,205.49910554561717 214,205.49910554561717 C 182.33333333333334,205.49910554561717 182.33333333333334,205.74955277280858 150.66666666666669,205.74955277280858 C 119.00000000000001,205.74955277280858 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#3178c6" fill-opacity="0.75" class="fade-6"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.74955277280858 150.66666666666669,205.74955277280858 C 182.33333333333334,205.74955277280858 182.33333333333334,205.49910554561717 214,205.49910554561717 C 245.66666666666669,205.49910554561717 245.66666666666669,205.74955277280858 277.33333333333337,205.74955277280858 C 309,205.74955277280858 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,202.4937388193202 404,202.4937388193202 C 435.6666666666667,202.4937388193202 435.6666666666667,205.24865831842575 467.33333333333337,205.24865831842575 C 499.00000000000006,205.24865831842575 499.00000000000006,203.24508050089446 530.6666666666667,203.24508050089446 C 562.3333333333334,203.24508050089446 562.3333333333334,205.49910554561717 594,205.49910554561717 C 625.6666666666667,205.49910554561717 625.6666666666667,189.22003577817532 657.3333333333334,189.22003577817532 C 689,189.22003577817532 689,164.4257602862254 720.6666666666667,164.4257602862254 C 752.3333333333334,164.4257602862254 752.3333333333334,156.912343470483 784,156.912343470483 L 784,206 C 752.3333333333334,206 752.3333333333334,206 720.6666666666667,206 C 689,206 689,206 657.3333333333334,206 C 625.6666666666667,206 625.6666666666667,206 594,206 C 562.3333333333334,206 562.3333333333334,206 530.6666666666667,206 C 499.00000000000006,206 499.00000000000006,206 467.33333333333337,206 C 435.6666666666667,206 435.6666666666667,206 404,206 C 372.33333333333337,206 372.33333333333337,206 340.6666666666667,206 C 309,206 309,206 277.33333333333337,206 C 245.66666666666669,206 245.66666666666669,206 214,206 C 182.33333333333334,206 182.33333333333334,206 150.66666666666669,206 C 119.00000000000001,206 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#dea584" fill-opacity="0.75" class="fade-6"/><rect x="24" y="212" width="8" height="8" rx="2" fill="#dea584" opacity="0.85"/><text x="36" y="220" class="t t-value">Rust</text><rect x="80" y="212" width="8" height="8" rx="2" fill="#3178c6" opacity="0.85"/><text x="92" y="220" class="t t-value">TypeScript</text><rect x="178" y="212" width="8" height="8" rx="2" fill="#89e051" opacity="0.85"/><text x="190" y="220" class="t t-value">Shell</text><rect x="241" y="212" width="8" height="8" rx="2" fill="#00ADD8" opacity="0.85"/><text x="253" y="220" class="t t-value">Go</text><rect x="283" y="212" width="8" height="8" rx="2" fill="#3572A5" opacity="0.85"/><text x="295" y="220" class="t t-value">Python</text><rect x="353" y="212" width="8" height="8" rx="2" fill="#b07219" opacity="0.85"/><text x="365" y="220" class="t t-value">Java</text><rect x="409" y="212" width="8" height="8" rx="2" fill="#DA5B0B" opacity="0.85"/><text x="421" y="220" class="t t-value">Jupyter Notebook</text><text x="24" y="220" class="t t-value" text-anchor="start" opacity="0">Feb</text><text x="150.66666666666669" y="220" class="t t-value" text-anchor="start" opacity="0">Apr</text><text x="277.33333333333337" y="220" class="t t-value" text-anchor="start" opacity="0">Jun</text><text x="404" y="220" class="t t-value" text-anchor="start" opacity="0">Aug</text><text x="530.6666666666667" y="220" class="t t-value" text-anchor="start" opacity="0">Oct</text><text x="657.3333333333334" y="220" class="t t-value" text-anchor="start" opacity="0">Dec</text><text x="784" y="220" class="t t-value" text-anchor="start" opacity="0">Feb</text></svg>
package/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
- # GitHub Metrics
1
+ # GitHub Insights
2
2
 
3
- > A GitHub Action that generates beautiful SVG metrics visualizations for GitHub profile READMEs. Produces language breakdowns (donut chart), AI-powered expertise analysis with proficiency scores, contribution pulse, signature projects, external open source contributions, social badges, and an auto-generated profile introduction. Built with TypeScript/Node.js using React JSX for SVG rendering.
3
+ > A GitHub Action that generates beautiful SVG metrics visualizations for GitHub profile READMEs. Produces language velocity streamgraphs, contribution rhythm radar charts, project constellation maps, open source impact trails, AI-powered project classification, social badges, and an auto-generated profile introduction. SVGs support light/dark theme switching and CSS animations. Built with TypeScript/Node.js using JSX for SVG string rendering.
4
4
 
5
5
  ## Docs
6
6
 
@@ -13,9 +13,9 @@
13
13
 
14
14
  - [src/index.ts](https://github.com/urmzd/github-insights/blob/main/src/index.ts): Main action entry point
15
15
  - [src/api.ts](https://github.com/urmzd/github-insights/blob/main/src/api.ts): GitHub GraphQL/REST API calls + AI model calls
16
- - [src/metrics.ts](https://github.com/urmzd/github-insights/blob/main/src/metrics.ts): Data aggregation and section definitions
16
+ - [src/metrics.ts](https://github.com/urmzd/github-insights/blob/main/src/metrics.ts): Data aggregation, velocity/rhythm/constellation computation, section definitions
17
17
  - [src/types.ts](https://github.com/urmzd/github-insights/blob/main/src/types.ts): Shared type definitions (UserConfig, SectionDef, etc.)
18
- - [src/components/](https://github.com/urmzd/github-insights/blob/main/src/components/): SVG rendering components (donut chart, bar chart, stat cards)
18
+ - [src/components/](https://github.com/urmzd/github-insights/blob/main/src/components/): SVG rendering components (streamgraph, radar chart, constellation, impact trail)
19
19
  - [action.yml](https://github.com/urmzd/github-insights/blob/main/action.yml): GitHub Action definition
20
20
 
21
21
  ## Optional
package/package.json CHANGED
@@ -31,5 +31,5 @@
31
31
  "typecheck": "tsc --noEmit"
32
32
  },
33
33
  "type": "module",
34
- "version": "2.1.0"
34
+ "version": "2.2.0"
35
35
  }
@@ -8,9 +8,9 @@ description: >-
8
8
  argument-hint: [setup | customize | generate | debug | extend]
9
9
  ---
10
10
 
11
- # GitHub Metrics — Agent Skill
11
+ # GitHub Insights — Agent Skill
12
12
 
13
- Generate beautiful dark-themed SVG metrics for GitHub profile READMEs. Sections include language breakdowns (donut chart), AI expertise analysis (proficiency bars), contribution pulse (stat cards), contribution calendar (heatmap), signature projects (by stars), and open source contributions.
13
+ Generate beautiful SVG metrics for GitHub profile READMEs. Sections include language velocity streamgraph, contribution rhythm radar chart, project constellation map, and open source impact trail. SVGs support light/dark theme switching and CSS animations.
14
14
 
15
15
  ## Quick Reference
16
16
 
@@ -18,7 +18,7 @@ Generate beautiful dark-themed SVG metrics for GitHub profile READMEs. Sections
18
18
  |------|---------|
19
19
  | Generate locally | `npm run generate` (requires `gh auth login`) |
20
20
  | Full CI check | `npm run ci` (fmt + lint + typecheck + test + build) |
21
- | Build bundle | `npm run build` (ncc `dist/`) |
21
+ | Build bundle | `npm run build` (ncc -> `dist/`) |
22
22
  | Run tests | `npm test` (vitest) |
23
23
  | Type-check | `npm run typecheck` |
24
24
  | Lint | `npm run lint` (biome) |
@@ -66,8 +66,7 @@ npm run generate
66
66
  Local mode differences:
67
67
  - `commit-push` defaults to `false` (no git operations)
68
68
  - README writes to `_README.md` (not `README.md`)
69
- - All three template previews are generated in `examples/{classic,modern,minimal}/`
70
- - Both preamble variants (full + short) are generated for preview
69
+ - All four template previews are generated in `examples/{classic,modern,minimal,ecosystem}/`
71
70
 
72
71
  ## Configuration
73
72
 
@@ -76,18 +75,16 @@ Local mode differences:
76
75
  ```yaml
77
76
  name: Display Name # overrides GitHub profile name
78
77
  pronunciation: pronunciation # shown as subscript in heading
79
- title: Software Engineer # blockquote under heading; guides AI expertise
80
- desired_title: Senior SWE # AI context only — biases expertise categories
78
+ title: Software Engineer # blockquote under heading
79
+ desired_title: Senior SWE # AI context only
81
80
  bio: Short bio text. # footer text in classic template
82
81
  preamble: PREAMBLE.md # path to custom preamble (bypasses AI generation)
83
- template: classic # "classic" | "modern" | "minimal"
82
+ template: classic # "classic" | "modern" | "minimal" | "ecosystem"
84
83
  sections:
85
- - pulse
86
- - languages
87
- - expertise
88
- - projects
89
- - contributions
90
- - calendar
84
+ - velocity
85
+ - rhythm
86
+ - constellation
87
+ - impact
91
88
  ```
92
89
 
93
90
  ### Action inputs
@@ -109,41 +106,38 @@ sections:
109
106
 
110
107
  | Key | SVG filename | What it renders |
111
108
  |-----|-------------|-----------------|
112
- | `pulse` | `metrics-pulse.svg` | 4 stat cards: commits, PRs, reviews, active repos |
113
- | `languages` | `metrics-languages.svg` | Donut chart of top 10 languages by bytes |
114
- | `expertise` | `metrics-expertise.svg` | AI-generated proficiency bars by category |
115
- | `projects` | `metrics-complexity.svg` | Top 5 repos by stars with descriptions |
116
- | `calendar` | `metrics-calendar.svg` | GitHub contribution heatmap (1 year) |
117
- | `contributions` | `metrics-contributions.svg` | External repos contributed to |
109
+ | `velocity` | `metrics-velocity.svg` | Streamgraph of language usage over 12 months |
110
+ | `rhythm` | `metrics-rhythm.svg` | 7-spoke radar chart + contribution stats |
111
+ | `constellation` | `metrics-constellation.svg` | Project map by language and complexity |
112
+ | `impact` | `metrics-impact.svg` | External contributions with impact bars |
118
113
 
119
114
  ### Templates
120
115
 
121
- - **`classic`** (default): Formal layout — `# Name`, blockquote title, full AI preamble (2–4 paragraphs), social badges, SVG metrics, bio footer, attribution.
122
- - **`modern`**: Friendly — `# Hi, I'm {firstName} 👋`, short preamble, active/maintained/inactive project lists in markdown, selective SVG sections.
123
- - **`minimal`**: Clean — `# {firstName}`, short preamble, social badges, SVG metrics, attribution.
116
+ - **`classic`** (default): Formal layout — `# Name`, blockquote title, preamble, social badges, SVG metrics, bio footer.
117
+ - **`modern`**: Friendly — `# Hi, I'm {firstName}`, projects by activity, Project Map, GitHub Stats, Impact.
118
+ - **`minimal`**: Clean — `# {firstName}`, preamble, social badges, SVG metrics.
119
+ - **`ecosystem`**: Categorized — projects by purpose (Developer Tools/SDKs/Applications/Research), Project Map, GitHub Stats, Impact.
124
120
 
125
121
  ## Architecture
126
122
 
127
123
  ### Execution flow
128
124
 
129
125
  ```
130
- Inputs Fetch (parallel) AI calls (sequential) Transform Render sections Write SVGs Generate README Commit
126
+ Inputs -> Fetch (parallel) -> AI calls -> Transform -> Compute velocity/rhythm/constellation -> Render sections -> Write SVGs -> Generate README -> Commit
131
127
  ```
132
128
 
133
129
  ### Key source files
134
130
 
135
131
  | File | Role |
136
132
  |------|------|
137
- | `src/index.ts` | Orchestration: fetch transform render write commit |
133
+ | `src/index.ts` | Orchestration: fetch -> transform -> render -> write -> commit |
138
134
  | `src/api.ts` | GitHub GraphQL queries + GitHub Models AI calls |
139
- | `src/metrics.ts` | Data aggregation, complexity scoring, section building |
140
- | `src/config.ts` | TOML config loading |
141
- | `src/types.ts` | All TypeScript interfaces (`UserConfig`, `SectionDef`, `TemplateContext`, etc.) |
142
- | `src/templates.ts` | Three README template functions + social badge builder |
143
- | `src/theme.ts` | `THEME` colors, `LAYOUT` dimensions, `BAR_COLORS` palette |
144
- | `src/parsers.ts` | Dependency manifest parsers (package.json, Cargo.toml, go.mod, etc.) |
145
- | `src/components/` | SVG rendering components (custom JSX → SVG strings) |
146
- | `src/jsx-factory.ts` | Custom `h()` / `Fragment()` JSX runtime (no React) |
135
+ | `src/metrics.ts` | Data aggregation, velocity/rhythm/constellation computation, section building |
136
+ | `src/config.ts` | YAML/TOML config loading |
137
+ | `src/types.ts` | All TypeScript interfaces |
138
+ | `src/templates.ts` | Four README template functions + social badge builder |
139
+ | `src/theme.ts` | `THEME`/`THEME_LIGHT` colors, `LAYOUT` dimensions, `BAR_COLORS` palette |
140
+ | `src/components/` | SVG rendering components (custom JSX -> SVG strings) |
147
141
 
148
142
  ### Component rendering pattern
149
143
 
@@ -155,25 +149,6 @@ function renderXxx(data: ..., y: number): { svg: string; height: number }
155
149
 
156
150
  Components return SVG string fragments and their rendered height. The `y` parameter is the vertical cursor; heights are accumulated to stack sections vertically.
157
151
 
158
- ### Theme constants (hardcoded in `src/theme.ts`)
159
-
160
- ```
161
- THEME.bg = "#0d1117" (dark background)
162
- THEME.cardBg = "#161b22" (card backgrounds)
163
- THEME.border = "#30363d" (card borders)
164
- THEME.link = "#58a6ff" (card titles - blue)
165
- THEME.text = "#c9d1d9" (primary text)
166
- THEME.secondary= "#8b949e" (labels)
167
- THEME.muted = "#6e7681" (values)
168
-
169
- LAYOUT.width = 808 (fixed SVG canvas width)
170
- LAYOUT.padX = 24
171
- LAYOUT.padY = 24
172
- LAYOUT.sectionGap = 30
173
- ```
174
-
175
- These are not configurable via inputs or TOML — changing them requires editing source.
176
-
177
152
  ## Extending
178
153
 
179
154
  ### Add a new section
@@ -183,16 +158,7 @@ These are not configurable via inputs or TOML — changing them requires editing
183
158
  3. Add the section key to `SECTION_KEYS` map in `src/metrics.ts`
184
159
  4. Add a `SectionDef` entry in the `buildSections()` function in `src/metrics.ts`
185
160
  5. Fetch any new data needed in `src/index.ts`
186
- 6. Add a `*.test.ts` file alongside the component
187
- 7. Update `action.yml` if new inputs are needed
188
-
189
- ### Add a new dependency parser
190
-
191
- 1. Implement `PackageParser` interface in `src/parsers.ts`:
192
- ```ts
193
- { filenames: string[]; parseDependencies(text: string): string[] }
194
- ```
195
- 2. Add it to the `PARSERS` array — it auto-registers in `PARSER_MAP`
161
+ 6. Add a `*.test.tsx` file alongside the component
196
162
 
197
163
  ### Add a new README template
198
164
 
@@ -202,36 +168,24 @@ These are not configurable via inputs or TOML — changing them requires editing
202
168
 
203
169
  ## Troubleshooting
204
170
 
205
- ### "Expertise section missing"
206
- The expertise section only appears when the AI call succeeds. Check:
207
- - Token has `models: read` permission
208
- - The workflow has `permissions: models: read`
209
- - GitHub Models endpoint is reachable
171
+ ### "Velocity section is flat"
172
+ The streamgraph distributes per-repo commits using the contribution calendar's monthly activity weights. If there's no calendar data, velocity will be empty.
210
173
 
211
- ### "Calendar section missing"
212
- Only rendered when contribution calendar data exists. The user must have public contributions.
174
+ ### "Constellation section missing"
175
+ Only rendered when there are projects with language data. Ensure repos have detectable languages.
213
176
 
214
- ### "Contributions section missing"
215
- Only rendered when the user has contributed to external (non-owned) repositories in the past year.
177
+ ### "Impact section missing"
178
+ Only rendered when the user has contributed to external (non-owned) repositories.
216
179
 
217
180
  ### AI preamble is empty or generic
218
181
  - The AI call uses `gpt-4.1` via GitHub Models — it needs diverse profile data to generate good output
219
- - Provide `title` and `desired_title` in TOML config for better results
182
+ - Provide `title` in config for better results
220
183
  - Create a custom `PREAMBLE.md` to bypass AI entirely
221
184
 
222
185
  ### Local generation fails
223
186
  - Ensure `gh auth login` is done and `gh auth token` returns a valid token
224
187
  - Ensure Node.js 22+ (`node --version`)
225
- - The `GITHUB_TOKEN` and `GITHUB_REPOSITORY_OWNER` env vars are set automatically by `npm run generate` via `gh`
226
188
 
227
189
  ### SVG looks wrong after changes
228
190
  - Run `npm run build` to rebuild the `dist/` bundle — the action runs `dist/index.js`, not source directly
229
191
  - SVG width is fixed at 808px; all layout math depends on this
230
-
231
- ## Code Style Rules
232
-
233
- - TypeScript strict mode, ES modules
234
- - Biome for formatting and linting (not ESLint/Prettier)
235
- - Tests colocated as `*.test.ts` / `*.test.tsx` alongside source
236
- - Custom JSX factory (`h`, `Fragment`) — NOT React
237
- - All AI calls and contribution fetches are non-fatal (catch → return empty)
package/sr.yaml CHANGED
@@ -14,3 +14,12 @@ commit_types:
14
14
 
15
15
  artifacts:
16
16
  - dist.tar.gz
17
+
18
+ hooks:
19
+ commit-msg:
20
+ - sr hook commit-msg
21
+ pre-commit:
22
+ - npm run fmt
23
+ - npm run lint
24
+ - npm run typecheck
25
+ - npm run test
package/src/api.ts CHANGED
@@ -7,7 +7,6 @@ import type {
7
7
  RepoClassificationInput,
8
8
  RepoClassificationOutput,
9
9
  RepoNode,
10
- TechHighlight,
11
10
  UserConfig,
12
11
  UserProfile,
13
12
  } from "./types.js";
@@ -320,7 +319,6 @@ export interface PreambleContext {
320
319
  profile: UserProfile;
321
320
  userConfig: UserConfig;
322
321
  languages: { name: string; percent: string }[];
323
- techHighlights: TechHighlight[];
324
322
  activeProjects: ProjectItem[];
325
323
  complexProjects: ProjectItem[];
326
324
  }
@@ -330,21 +328,12 @@ export const fetchAIPreamble = async (
330
328
  context: PreambleContext,
331
329
  ): Promise<string | undefined> => {
332
330
  try {
333
- const {
334
- profile,
335
- userConfig,
336
- languages,
337
- techHighlights,
338
- activeProjects,
339
- complexProjects,
340
- } = context;
331
+ const { profile, userConfig, languages, activeProjects, complexProjects } =
332
+ context;
341
333
 
342
334
  const langLines = languages
343
335
  .map((l) => `- ${l.name}: ${l.percent}%`)
344
336
  .join("\n");
345
- const techLines = techHighlights
346
- .map((h) => `- ${h.category}: ${h.items.join(", ")} (score: ${h.score})`)
347
- .join("\n");
348
337
 
349
338
  const formatProject = (p: ProjectItem): string => {
350
339
  const langs = p.languages?.length ? ` [${p.languages.join(", ")}]` : "";
@@ -373,9 +362,6 @@ ${profileLines}
373
362
  Languages (by code volume):
374
363
  ${langLines}
375
364
 
376
- Expertise areas:
377
- ${techLines}
378
-
379
365
  Most technically complex projects (by language diversity, codebase size, and depth):
380
366
  ${complexProjectLines || "None"}
381
367
 
@@ -474,130 +460,6 @@ Generate 1-2 sentences that:
474
460
  }
475
461
  };
476
462
 
477
- export const fetchExpertiseAnalysis = async (
478
- token: string,
479
- languages: { name: string; percent: string }[],
480
- allDeps: string[],
481
- allTopics: string[],
482
- repos: RepoNode[],
483
- readmeMap: ReadmeMap,
484
- userConfig: UserConfig = {},
485
- ): Promise<TechHighlight[]> => {
486
- try {
487
- const langLines = languages
488
- .map((l) => `- ${l.name}: ${l.percent}%`)
489
- .join("\n");
490
-
491
- const repoSummaries = repos
492
- .slice(0, 20)
493
- .map((r) => {
494
- const readme = readmeMap.get(r.name) || "";
495
- const snippet = readme.slice(0, 500).replace(/\n/g, " ");
496
- const desc = r.description || "";
497
- return `- ${r.name}: ${desc} | ${snippet}`;
498
- })
499
- .join("\n");
500
-
501
- const desiredTitle = userConfig.desired_title || userConfig.title;
502
- let titleContext = "";
503
- if (userConfig.title) {
504
- titleContext = `\nDeveloper context:\n- Current title: ${userConfig.title}`;
505
- if (desiredTitle && desiredTitle !== userConfig.title) {
506
- titleContext += `\n- Desired title: ${desiredTitle}`;
507
- }
508
- titleContext += `\n- Tailor the expertise categories to highlight skills most relevant to ${desiredTitle}. Prioritize domains and technologies that align with this role.\n`;
509
- }
510
-
511
- const prompt = `You are analyzing a developer's GitHub profile to create a curated expertise showcase.
512
- ${titleContext}
513
- Languages (by code volume):
514
- ${langLines}
515
-
516
- Dependencies found across repositories:
517
- ${allDeps.join(", ")}
518
-
519
- Repository topics:
520
- ${allTopics.join(", ")}
521
-
522
- Repository descriptions and README excerpts:
523
- ${repoSummaries}
524
-
525
- From this data, produce a curated expertise profile:
526
- - Group the most notable technologies into 3-6 expertise categories
527
- - Use domain-oriented category names (e.g., "Machine Learning", "Web Development", "DevOps", "Backend & APIs", "Data Science", "Systems Programming")
528
- - Include 3-6 of the most relevant technologies/tools per category
529
- - Normalize names to their common display form (e.g., "pg" → "PostgreSQL", "torch" → "PyTorch", "boto3" → "AWS SDK")
530
- - Skip trivial utility libraries (lodash, uuid, etc.) that don't showcase meaningful expertise
531
- - Only include categories where there's meaningful evidence of usage
532
- - Assign each category a proficiency score from 0 to 100 based on evidence strength:
533
- language code volume, dependency count, topic mentions, and README depth.
534
- Use the full range (e.g. 80-95 for primary stack, 50-70 for secondary, 30-50 for minor).`;
535
-
536
- const res = await fetchWithRetry(
537
- "https://models.github.ai/inference/chat/completions",
538
- {
539
- method: "POST",
540
- headers: {
541
- Authorization: `bearer ${token}`,
542
- "Content-Type": "application/json",
543
- },
544
- body: JSON.stringify({
545
- model: "gpt-4.1",
546
- messages: [{ role: "user", content: prompt }],
547
- temperature: 0.1,
548
- response_format: {
549
- type: "json_schema",
550
- json_schema: {
551
- name: "tech_highlights",
552
- strict: true,
553
- schema: {
554
- type: "object",
555
- properties: {
556
- highlights: {
557
- type: "array",
558
- items: {
559
- type: "object",
560
- properties: {
561
- category: { type: "string" },
562
- items: { type: "array", items: { type: "string" } },
563
- score: { type: "number" },
564
- },
565
- required: ["category", "items", "score"],
566
- additionalProperties: false,
567
- },
568
- },
569
- },
570
- required: ["highlights"],
571
- additionalProperties: false,
572
- },
573
- },
574
- },
575
- }),
576
- },
577
- "Expertise",
578
- );
579
-
580
- if (!res?.ok) {
581
- if (res) console.warn(`GitHub Models API error: ${res.status}`);
582
- return [];
583
- }
584
-
585
- const json = (await res.json()) as {
586
- choices?: { message?: { content?: string } }[];
587
- };
588
- const content = json.choices?.[0]?.message?.content || "{}";
589
- const parsed = JSON.parse(content) as { highlights?: TechHighlight[] };
590
- return (parsed.highlights || [])
591
- .filter((h) => h.category && Array.isArray(h.items) && h.items.length > 0)
592
- .map((h) => ({ ...h, score: Math.max(0, Math.min(100, h.score || 0)) }))
593
- .sort((a, b) => b.score - a.score);
594
- } catch (err: unknown) {
595
- const msg = err instanceof Error ? err.message : String(err);
596
- console.warn(`Expertise analysis failed (non-fatal): ${msg}`);
597
- return [];
598
- }
599
- };
600
-
601
463
  export const fetchProjectClassifications = async (
602
464
  token: string,
603
465
  repos: RepoClassificationInput[],