@urmzd/github-insights 2.0.0 → 2.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 (57) hide show
  1. package/.github/workflows/release.yml +5 -1
  2. package/CHANGELOG.md +40 -0
  3. package/README.md +0 -2
  4. package/assets/insights/index.svg +14 -0
  5. package/assets/insights/metrics-calendar.svg +14 -0
  6. package/{metrics → assets/insights}/metrics-complexity.svg +1 -1
  7. package/{metrics → assets/insights}/metrics-contributions.svg +1 -1
  8. package/assets/insights/metrics-expertise.svg +14 -0
  9. package/assets/insights/metrics-languages.svg +14 -0
  10. package/{metrics → assets/insights}/metrics-pulse.svg +1 -1
  11. package/examples/classic/README.md +2 -2
  12. package/examples/classic/index.svg +2 -2
  13. package/examples/classic/metrics-calendar.svg +1 -1
  14. package/examples/classic/metrics-complexity.svg +1 -1
  15. package/examples/classic/metrics-contributions.svg +1 -1
  16. package/examples/classic/metrics-expertise.svg +2 -2
  17. package/examples/classic/metrics-languages.svg +1 -1
  18. package/examples/classic/metrics-pulse.svg +1 -1
  19. package/examples/ecosystem/README.md +23 -24
  20. package/examples/ecosystem/index.svg +2 -2
  21. package/examples/ecosystem/metrics-calendar.svg +1 -1
  22. package/examples/ecosystem/metrics-complexity.svg +1 -1
  23. package/examples/ecosystem/metrics-contributions.svg +1 -1
  24. package/examples/ecosystem/metrics-expertise.svg +2 -2
  25. package/examples/ecosystem/metrics-languages.svg +1 -1
  26. package/examples/ecosystem/metrics-pulse.svg +1 -1
  27. package/examples/minimal/README.md +2 -2
  28. package/examples/minimal/index.svg +2 -2
  29. package/examples/minimal/metrics-calendar.svg +1 -1
  30. package/examples/minimal/metrics-complexity.svg +1 -1
  31. package/examples/minimal/metrics-contributions.svg +1 -1
  32. package/examples/minimal/metrics-expertise.svg +2 -2
  33. package/examples/minimal/metrics-languages.svg +1 -1
  34. package/examples/minimal/metrics-pulse.svg +1 -1
  35. package/examples/modern/README.md +36 -38
  36. package/examples/modern/index.svg +2 -2
  37. package/examples/modern/metrics-calendar.svg +1 -1
  38. package/examples/modern/metrics-complexity.svg +1 -1
  39. package/examples/modern/metrics-contributions.svg +1 -1
  40. package/examples/modern/metrics-expertise.svg +2 -2
  41. package/examples/modern/metrics-languages.svg +1 -1
  42. package/examples/modern/metrics-pulse.svg +1 -1
  43. package/package.json +5 -5
  44. package/src/api.ts +1 -1
  45. package/src/config.ts +6 -12
  46. package/src/index.ts +6 -0
  47. package/src/metrics.ts +16 -2
  48. package/src/readme.test.ts +31 -25
  49. package/src/templates.test.ts +110 -13
  50. package/src/templates.ts +38 -11
  51. package/src/types.ts +3 -0
  52. package/metrics/index.svg +0 -14
  53. package/metrics/metrics-calendar.svg +0 -14
  54. package/metrics/metrics-expertise.svg +0 -14
  55. package/metrics/metrics-languages.svg +0 -14
  56. /package/{metrics → assets/insights}/metrics-domains.svg +0 -0
  57. /package/{metrics → assets/insights}/metrics-tech-stack.svg +0 -0
@@ -11,4 +11,4 @@
11
11
  .t-card-detail { font-size: 11px; fill: #8b949e; }
12
12
  .t-pill { font-size: 11px; font-weight: 600; }
13
13
  .t-bullet { font-size: 12px; fill: #c9d1d9; }
14
- </style></defs><rect width="808" height="390" rx="12" fill="#0d1117"/><text x="24" y="40" class="t t-h">SIGNATURE PROJECTS</text><text x="24" y="56" class="t t-sub">Top projects by technical complexity</text><rect x="24" y="66" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="66" width="4" height="52" rx="2" fill="#58a6ff"/><text x="40" y="84" class="t t-card-title">resume-generator</text><text x="768" y="84" class="t t-value" text-anchor="end">★ 10</text><text x="40" y="100" class="t t-card-detail">A data-driven CLI tool that converts YAML/JSON/TOML resume data into polished PDFs, DOCX,…</text><rect x="24" y="128" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="128" width="4" height="52" rx="2" fill="#3fb950"/><text x="40" y="146" class="t t-card-title">lepus-classifier</text><text x="768" y="146" class="t t-value" text-anchor="end">★ 2</text><text x="40" y="162" class="t t-card-detail">A CNN research project exploring optimal image classification architectures for small dat…</text><rect x="24" y="190" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="190" width="4" height="52" rx="2" fill="#d29922"/><text x="40" y="208" class="t t-card-title">linear-gp</text><text x="768" y="208" class="t t-value" text-anchor="end">★ 2</text><text x="40" y="224" class="t t-card-detail">A production-grade Rust framework for Linear Genetic Programming research, featuring modu…</text><rect x="24" y="252" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="252" width="4" height="52" rx="2" fill="#f85149"/><text x="40" y="270" class="t t-card-title">homai</text><text x="768" y="270" class="t t-value" text-anchor="end">★ 0</text><text x="40" y="286" class="t t-card-detail">Local-first, privacy-focused smart home control system. Manage Zigbee devices through a R…</text><rect x="24" y="314" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="314" width="4" height="52" rx="2" fill="#bc8cff"/><text x="40" y="332" class="t t-card-title">urmzd.com</text><text x="768" y="332" class="t t-value" text-anchor="end">★ 0</text><text x="40" y="348" class="t t-card-detail">Personal website and blog built with Astro, TypeScript, and MDX—featuring fast static sit…</text></svg>
14
+ </style></defs><rect width="808" height="390" rx="12" fill="#0d1117"/><text x="24" y="40" class="t t-h">SIGNATURE PROJECTS</text><text x="24" y="56" class="t t-sub">Top projects by technical complexity</text><rect x="24" y="66" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="66" width="4" height="52" rx="2" fill="#58a6ff"/><text x="40" y="84" class="t t-card-title">resume-generator</text><text x="768" y="84" class="t t-value" text-anchor="end">★ 10</text><text x="40" y="100" class="t t-card-detail">A data-driven CLI tool that converts YAML/JSON/TOML resume data into polished PDFs, DOCX,…</text><rect x="24" y="128" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="128" width="4" height="52" rx="2" fill="#3fb950"/><text x="40" y="146" class="t t-card-title">linear-gp</text><text x="768" y="146" class="t t-value" text-anchor="end">★ 2</text><text x="40" y="162" class="t t-card-detail">A production-grade Rust framework for Linear Genetic Programming research, featuring modu…</text><rect x="24" y="190" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="190" width="4" height="52" rx="2" fill="#d29922"/><text x="40" y="208" class="t t-card-title">zigbee-rest</text><text x="768" y="208" class="t t-value" text-anchor="end">★ 0</text><text x="40" y="224" class="t t-card-detail">Local-first, privacy-focused smart home control system. Manage Zigbee devices through a R…</text><rect x="24" y="252" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="252" width="4" height="52" rx="2" fill="#f85149"/><text x="40" y="270" class="t t-card-title">urmzd.com</text><text x="768" y="270" class="t t-value" text-anchor="end">★ 0</text><text x="40" y="286" class="t t-card-detail">Personal website and blog built with Astro, TypeScript, and MDX—featuring fast static sit…</text><rect x="24" y="314" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="314" width="4" height="52" rx="2" fill="#bc8cff"/><text x="40" y="332" class="t t-card-title">resume-generator-app</text><text x="768" y="332" class="t t-value" text-anchor="end">★ 0</text><text x="40" y="348" class="t t-card-detail">A native desktop app for building polished resumes with live PDF preview, template galler…</text></svg>
@@ -11,4 +11,4 @@
11
11
  .t-card-detail { font-size: 11px; fill: #8b949e; }
12
12
  .t-pill { font-size: 11px; font-weight: 600; }
13
13
  .t-bullet { font-size: 12px; fill: #c9d1d9; }
14
- </style></defs><rect width="808" height="186" rx="12" fill="#0d1117"/><text x="24" y="40" class="t t-h">OPEN SOURCE CONTRIBUTIONS</text><text x="24" y="56" class="t t-sub">External repositories contributed to (all time)</text><rect x="24" y="66" width="760" height="44" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="66" width="4" height="44" rx="2" fill="#58a6ff"/><text x="40" y="84" class="t t-card-title">MathisWellmann/gym-rs</text><text x="40" y="100" class="t t-card-detail">★ 126 · Rust</text><rect x="24" y="118" width="760" height="44" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="118" width="4" height="44" rx="2" fill="#3fb950"/><text x="40" y="136" class="t t-card-title">getzep/graphiti</text><text x="40" y="152" class="t t-card-detail">★ 23,772 · Python</text></svg>
14
+ </style></defs><rect width="808" height="186" rx="12" fill="#0d1117"/><text x="24" y="40" class="t t-h">OPEN SOURCE CONTRIBUTIONS</text><text x="24" y="56" class="t t-sub">External repositories contributed to (all time)</text><rect x="24" y="66" width="760" height="44" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="66" width="4" height="44" rx="2" fill="#58a6ff"/><text x="40" y="84" class="t t-card-title">MathisWellmann/gym-rs</text><text x="40" y="100" class="t t-card-detail">★ 127 · Rust</text><rect x="24" y="118" width="760" height="44" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="118" width="4" height="44" rx="2" fill="#3fb950"/><text x="40" y="136" class="t t-card-title">getzep/graphiti</text><text x="40" y="152" class="t t-card-detail">★ 23,825 · Python</text></svg>
@@ -1,4 +1,4 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="808" height="534" viewBox="0 0 808 534"><defs><style>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="808" height="550" viewBox="0 0 808 550"><defs><style>
2
2
  .t { font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif; }
3
3
  .t-h { font-size: 13px; fill: #c9d1d9; letter-spacing: 1.5px; font-weight: 600; }
4
4
  .t-sub { font-size: 11px; fill: #6e7681; }
@@ -11,4 +11,4 @@
11
11
  .t-card-detail { font-size: 11px; fill: #8b949e; }
12
12
  .t-pill { font-size: 11px; font-weight: 600; }
13
13
  .t-bullet { font-size: 12px; fill: #c9d1d9; }
14
- </style></defs><rect width="808" height="534" rx="12" fill="#0d1117"/><text x="24" y="40" class="t t-h">EXPERTISE</text><text x="24" y="56" class="t t-sub">Curated from dependencies, topics, and languages via AI analysis</text><text x="24" y="80" class="t t-subhdr">SYSTEMS PROGRAMMING &amp; CLI TOOLS</text><rect x="24" y="92" width="700" height="18" rx="4" fill="#58a6ff" fill-opacity="0.15"/><rect x="24" y="92" width="665" height="18" rx="4" fill="#58a6ff" fill-opacity="0.85"/><text x="734" y="105" class="t t-value">95%</text><text x="24" y="126" class="t t-card-detail">Go · Rust · Wails · Chezmoi · Nix</text><text x="24" y="154" class="t t-subhdr">MACHINE LEARNING &amp; AI</text><rect x="24" y="166" width="700" height="18" rx="4" fill="#3fb950" fill-opacity="0.15"/><rect x="24" y="166" width="630" height="18" rx="4" fill="#3fb950" fill-opacity="0.85"/><text x="734" y="179" class="t t-value">90%</text><text x="24" y="200" class="t t-card-detail">PyTorch · TensorFlow · Keras · Transformers · CNNs</text><text x="24" y="228" class="t t-subhdr">WEB DEVELOPMENT &amp; STATIC SITES</text><rect x="24" y="240" width="700" height="18" rx="4" fill="#d29922" fill-opacity="0.15"/><rect x="24" y="240" width="595" height="18" rx="4" fill="#d29922" fill-opacity="0.85"/><text x="734" y="253" class="t t-value">85%</text><text x="24" y="274" class="t t-card-detail">Astro · React · TypeScript · Tailwind CSS · MDX</text><text x="24" y="302" class="t t-subhdr">DEVOPS &amp; CI/CD AUTOMATION</text><rect x="24" y="314" width="700" height="18" rx="4" fill="#f85149" fill-opacity="0.15"/><rect x="24" y="314" width="560" height="18" rx="4" fill="#f85149" fill-opacity="0.85"/><text x="734" y="327" class="t t-value">80%</text><text x="24" y="348" class="t t-card-detail">GitHub Actions · Docker · Semantic Release · CI/CD · Embed-src</text><text x="24" y="376" class="t t-subhdr">KNOWLEDGE GRAPHS &amp; RETRIEVAL-AUGMENTED GENERATION</text><rect x="24" y="388" width="700" height="18" rx="4" fill="#bc8cff" fill-opacity="0.15"/><rect x="24" y="388" width="525" height="18" rx="4" fill="#bc8cff" fill-opacity="0.85"/><text x="734" y="401" class="t t-value">75%</text><text x="24" y="422" class="t t-card-detail">SurrealDB · Vector Search · RAG · kgdk · ragdk</text><text x="24" y="450" class="t t-subhdr">DESKTOP &amp; CROSS-PLATFORM APPS</text><rect x="24" y="462" width="700" height="18" rx="4" fill="#39d2c0" fill-opacity="0.15"/><rect x="24" y="462" width="489.99999999999994" height="18" rx="4" fill="#39d2c0" fill-opacity="0.85"/><text x="734" y="475" class="t t-value">70%</text><text x="24" y="496" class="t t-card-detail">JavaFX · Wails · React · Go · Rust</text></svg>
14
+ </style></defs><rect width="808" height="550" rx="12" fill="#0d1117"/><text x="24" y="40" class="t t-h">EXPERTISE</text><text x="24" y="56" class="t t-sub">Curated from dependencies, topics, and languages via AI analysis</text><text x="24" y="80" class="t t-subhdr">AI &amp; MACHINE LEARNING</text><rect x="24" y="92" width="700" height="18" rx="4" fill="#58a6ff" fill-opacity="0.15"/><rect x="24" y="92" width="630" height="18" rx="4" fill="#58a6ff" fill-opacity="0.85"/><text x="734" y="105" class="t t-value">90%</text><text x="24" y="126" class="t t-card-detail">PyTorch · PyTorch Lightning · Rust (Linear Genetic Programm… · Retrieval-Augmented Generatio… · Knowledge Graphs</text><text x="24" y="142" class="t t-card-detail">(SurrealDB) · Q-Learning</text><text x="24" y="170" class="t t-subhdr">WEB DEVELOPMENT &amp; STATIC SITES</text><rect x="24" y="182" width="700" height="18" rx="4" fill="#3fb950" fill-opacity="0.15"/><rect x="24" y="182" width="595" height="18" rx="4" fill="#3fb950" fill-opacity="0.85"/><text x="734" y="195" class="t t-value">85%</text><text x="24" y="216" class="t t-card-detail">Astro · React · TypeScript · Tailwind CSS · MDX</text><text x="24" y="244" class="t t-subhdr">BACKEND &amp; APIS</text><rect x="24" y="256" width="700" height="18" rx="4" fill="#d29922" fill-opacity="0.15"/><rect x="24" y="256" width="560" height="18" rx="4" fill="#d29922" fill-opacity="0.85"/><text x="734" y="269" class="t t-value">80%</text><text x="24" y="290" class="t t-card-detail">Go · FastAPI · OpenAPI · SurrealDB · Graph-enhanced Retrieval</text><text x="24" y="318" class="t t-subhdr">DEVOPS &amp; AUTOMATION</text><rect x="24" y="330" width="700" height="18" rx="4" fill="#f85149" fill-opacity="0.15"/><rect x="24" y="330" width="525" height="18" rx="4" fill="#f85149" fill-opacity="0.85"/><text x="734" y="343" class="t t-value">75%</text><text x="24" y="364" class="t t-card-detail">GitHub Actions · CI/CD · Chezmoi · Nix · Docker</text><text x="24" y="392" class="t t-subhdr">DESKTOP &amp; CLI APPLICATIONS</text><rect x="24" y="404" width="700" height="18" rx="4" fill="#bc8cff" fill-opacity="0.15"/><rect x="24" y="404" width="489.99999999999994" height="18" rx="4" fill="#bc8cff" fill-opacity="0.85"/><text x="734" y="417" class="t t-value">70%</text><text x="24" y="438" class="t t-card-detail">Rust · Go · JavaFX · Wails · Textual</text><text x="24" y="466" class="t t-subhdr">DOCUMENTATION &amp; PUBLISHING</text><rect x="24" y="478" width="700" height="18" rx="4" fill="#39d2c0" fill-opacity="0.15"/><rect x="24" y="478" width="420" height="18" rx="4" fill="#39d2c0" fill-opacity="0.85"/><text x="734" y="491" class="t t-value">60%</text><text x="24" y="512" class="t t-card-detail">TeX/LaTeX · Pandoc · Markdown · PDF Generation</text></svg>
@@ -11,4 +11,4 @@
11
11
  .t-card-detail { font-size: 11px; fill: #8b949e; }
12
12
  .t-pill { font-size: 11px; font-weight: 600; }
13
13
  .t-bullet { font-size: 12px; fill: #c9d1d9; }
14
- </style></defs><rect width="808" height="350" rx="12" fill="#0d1117"/><text x="24" y="40" class="t t-h">LANGUAGES</text><text x="24" y="56" class="t t-sub">By bytes of code across all public repos</text><circle cx="114" cy="156" r="70" fill="none" stroke="#00ADD8" stroke-width="28" stroke-dasharray="124.03007796372502 315.792893538846" stroke-dashoffset="0" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#dea584" stroke-width="28" stroke-dasharray="109.07609693263761 330.7468745699334" stroke-dashoffset="-124.03007796372502" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#3178c6" stroke-width="28" stroke-dasharray="103.35839830310418 336.4645731994668" stroke-dashoffset="-233.10617489636263" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#3D6117" stroke-width="28" stroke-dasharray="20.231856689118267 419.59111481345275" stroke-dashoffset="-336.4645731994668" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#3572A5" stroke-width="28" stroke-dasharray="17.15309588860027 422.66987561397076" stroke-dashoffset="-356.6964298885851" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#89e051" stroke-width="28" stroke-dasharray="16.713272917097697 423.1096985854733" stroke-dashoffset="-373.84952577718536" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#a52a22" stroke-width="28" stroke-dasharray="7.916813487046279 431.90615801552474" stroke-dashoffset="-390.56279869428306" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#b07219" stroke-width="28" stroke-dasharray="6.597344572538565 433.22562693003243" stroke-dashoffset="-398.47961218132934" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#000080" stroke-width="28" stroke-dasharray="6.157521601035993 433.66544990153506" stroke-dashoffset="-405.07695675386793" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#e34c26" stroke-width="28" stroke-dasharray="5.717698629533424 434.1052728730376" stroke-dashoffset="-411.2344783549039" transform="rotate(-90 114 156)" opacity="0.85"/><text x="114" y="161" class="t" fill="#c9d1d9" font-size="14" font-weight="700" text-anchor="middle">10</text><text x="114" y="176" class="t" fill="#6e7681" font-size="10" text-anchor="middle">languages</text><rect x="244" y="76" width="12" height="12" rx="2" fill="#00ADD8" opacity="0.85"/><text x="264" y="86" class="t t-label">Go</text><text x="444" y="86" class="t t-value" text-anchor="end">28.2%</text><rect x="244" y="100" width="12" height="12" rx="2" fill="#dea584" opacity="0.85"/><text x="264" y="110" class="t t-label">Rust</text><text x="444" y="110" class="t t-value" text-anchor="end">24.8%</text><rect x="244" y="124" width="12" height="12" rx="2" fill="#3178c6" opacity="0.85"/><text x="264" y="134" class="t t-label">TypeScript</text><text x="444" y="134" class="t t-value" text-anchor="end">23.5%</text><rect x="244" y="148" width="12" height="12" rx="2" fill="#3D6117" opacity="0.85"/><text x="264" y="158" class="t t-label">TeX</text><text x="444" y="158" class="t t-value" text-anchor="end">4.6%</text><rect x="244" y="172" width="12" height="12" rx="2" fill="#3572A5" opacity="0.85"/><text x="264" y="182" class="t t-label">Python</text><text x="444" y="182" class="t t-value" text-anchor="end">3.9%</text><rect x="244" y="196" width="12" height="12" rx="2" fill="#89e051" opacity="0.85"/><text x="264" y="206" class="t t-label">Shell</text><text x="444" y="206" class="t t-value" text-anchor="end">3.8%</text><rect x="244" y="220" width="12" height="12" rx="2" fill="#a52a22" opacity="0.85"/><text x="264" y="230" class="t t-label">Jinja</text><text x="444" y="230" class="t t-value" text-anchor="end">1.8%</text><rect x="244" y="244" width="12" height="12" rx="2" fill="#b07219" opacity="0.85"/><text x="264" y="254" class="t t-label">Java</text><text x="444" y="254" class="t t-value" text-anchor="end">1.5%</text><rect x="244" y="268" width="12" height="12" rx="2" fill="#000080" opacity="0.85"/><text x="264" y="278" class="t t-label">Lua</text><text x="444" y="278" class="t t-value" text-anchor="end">1.4%</text><rect x="244" y="292" width="12" height="12" rx="2" fill="#e34c26" opacity="0.85"/><text x="264" y="302" class="t t-label">HTML</text><text x="444" y="302" class="t t-value" text-anchor="end">1.3%</text></svg>
14
+ </style></defs><rect width="808" height="350" rx="12" fill="#0d1117"/><text x="24" y="40" class="t t-h">LANGUAGES</text><text x="24" y="56" class="t t-sub">By bytes of code across all public repos</text><circle cx="114" cy="156" r="70" fill="none" stroke="#00ADD8" stroke-width="28" stroke-dasharray="120.51149419170444 319.31147731086656" stroke-dashoffset="0" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#3178c6" stroke-width="28" stroke-dasharray="110.8353888186479 328.9875826839231" stroke-dashoffset="-120.51149419170444" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#dea584" stroke-width="28" stroke-dasharray="108.63627396113505 331.186697541436" stroke-dashoffset="-231.34688301035234" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#3D6117" stroke-width="28" stroke-dasharray="19.792033717615695 420.0309377849553" stroke-dashoffset="-339.9831569714874" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#89e051" stroke-width="28" stroke-dasharray="15.833626974092558 423.98934452847845" stroke-dashoffset="-359.7751906891031" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#3572A5" stroke-width="28" stroke-dasharray="13.634512116579701 426.18845938599134" stroke-dashoffset="-375.6088176631957" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#a52a22" stroke-width="28" stroke-dasharray="7.916813487046279 431.90615801552474" stroke-dashoffset="-389.24332977977537" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#b07219" stroke-width="28" stroke-dasharray="6.597344572538565 433.22562693003243" stroke-dashoffset="-397.16014326682165" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#663399" stroke-width="28" stroke-dasharray="5.717698629533424 434.1052728730376" stroke-dashoffset="-403.75748783936024" transform="rotate(-90 114 156)" opacity="0.85"/><circle cx="114" cy="156" r="70" fill="none" stroke="#000080" stroke-width="28" stroke-dasharray="5.717698629533424 434.1052728730376" stroke-dashoffset="-409.47518646889364" transform="rotate(-90 114 156)" opacity="0.85"/><text x="114" y="161" class="t" fill="#c9d1d9" font-size="14" font-weight="700" text-anchor="middle">10</text><text x="114" y="176" class="t" fill="#6e7681" font-size="10" text-anchor="middle">languages</text><rect x="244" y="76" width="12" height="12" rx="2" fill="#00ADD8" opacity="0.85"/><text x="264" y="86" class="t t-label">Go</text><text x="444" y="86" class="t t-value" text-anchor="end">27.4%</text><rect x="244" y="100" width="12" height="12" rx="2" fill="#3178c6" opacity="0.85"/><text x="264" y="110" class="t t-label">TypeScript</text><text x="444" y="110" class="t t-value" text-anchor="end">25.2%</text><rect x="244" y="124" width="12" height="12" rx="2" fill="#dea584" opacity="0.85"/><text x="264" y="134" class="t t-label">Rust</text><text x="444" y="134" class="t t-value" text-anchor="end">24.7%</text><rect x="244" y="148" width="12" height="12" rx="2" fill="#3D6117" opacity="0.85"/><text x="264" y="158" class="t t-label">TeX</text><text x="444" y="158" class="t t-value" text-anchor="end">4.5%</text><rect x="244" y="172" width="12" height="12" rx="2" fill="#89e051" opacity="0.85"/><text x="264" y="182" class="t t-label">Shell</text><text x="444" y="182" class="t t-value" text-anchor="end">3.6%</text><rect x="244" y="196" width="12" height="12" rx="2" fill="#3572A5" opacity="0.85"/><text x="264" y="206" class="t t-label">Python</text><text x="444" y="206" class="t t-value" text-anchor="end">3.1%</text><rect x="244" y="220" width="12" height="12" rx="2" fill="#a52a22" opacity="0.85"/><text x="264" y="230" class="t t-label">Jinja</text><text x="444" y="230" class="t t-value" text-anchor="end">1.8%</text><rect x="244" y="244" width="12" height="12" rx="2" fill="#b07219" opacity="0.85"/><text x="264" y="254" class="t t-label">Java</text><text x="444" y="254" class="t t-value" text-anchor="end">1.5%</text><rect x="244" y="268" width="12" height="12" rx="2" fill="#663399" opacity="0.85"/><text x="264" y="278" class="t t-label">CSS</text><text x="444" y="278" class="t t-value" text-anchor="end">1.3%</text><rect x="244" y="292" width="12" height="12" rx="2" fill="#000080" opacity="0.85"/><text x="264" y="302" class="t t-label">Lua</text><text x="444" y="302" class="t t-value" text-anchor="end">1.3%</text></svg>
@@ -11,4 +11,4 @@
11
11
  .t-card-detail { font-size: 11px; fill: #8b949e; }
12
12
  .t-pill { font-size: 11px; font-weight: 600; }
13
13
  .t-bullet { font-size: 12px; fill: #c9d1d9; }
14
- </style></defs><rect width="808" height="162" rx="12" fill="#0d1117"/><text x="24" y="40" class="t t-h">AT A GLANCE</text><text x="24" y="56" class="t t-sub">Contribution activity over the past year</text><rect x="24" y="66" width="140" height="72" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1"/><circle cx="38" cy="82" r="4" fill="#58a6ff"/><text x="48" y="86" class="t t-stat-label">COMMITS</text><text x="94" y="118" fill="#58a6ff" class="t t-stat-value" text-anchor="middle">1,049</text><rect x="179" y="66" width="140" height="72" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1"/><circle cx="193" cy="82" r="4" fill="#3fb950"/><text x="203" y="86" class="t t-stat-label">PRS</text><text x="249" y="118" fill="#3fb950" class="t t-stat-value" text-anchor="middle">3</text><rect x="334" y="66" width="140" height="72" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1"/><circle cx="348" cy="82" r="4" fill="#d29922"/><text x="358" y="86" class="t t-stat-label">REVIEWS</text><text x="404" y="118" fill="#d29922" class="t t-stat-value" text-anchor="middle">5</text><rect x="489" y="66" width="140" height="72" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1"/><circle cx="503" cy="82" r="4" fill="#bc8cff"/><text x="513" y="86" class="t t-stat-label">REPOS</text><text x="559" y="118" fill="#bc8cff" class="t t-stat-value" text-anchor="middle">24</text></svg>
14
+ </style></defs><rect width="808" height="162" rx="12" fill="#0d1117"/><text x="24" y="40" class="t t-h">AT A GLANCE</text><text x="24" y="56" class="t t-sub">Contribution activity over the past year</text><rect x="24" y="66" width="140" height="72" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1"/><circle cx="38" cy="82" r="4" fill="#58a6ff"/><text x="48" y="86" class="t t-stat-label">COMMITS</text><text x="94" y="118" fill="#58a6ff" class="t t-stat-value" text-anchor="middle">1,117</text><rect x="179" y="66" width="140" height="72" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1"/><circle cx="193" cy="82" r="4" fill="#3fb950"/><text x="203" y="86" class="t t-stat-label">PRS</text><text x="249" y="118" fill="#3fb950" class="t t-stat-value" text-anchor="middle">3</text><rect x="334" y="66" width="140" height="72" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1"/><circle cx="348" cy="82" r="4" fill="#d29922"/><text x="358" y="86" class="t t-stat-label">REVIEWS</text><text x="404" y="118" fill="#d29922" class="t t-stat-value" text-anchor="middle">5</text><rect x="489" y="66" width="140" height="72" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1"/><circle cx="503" cy="82" r="4" fill="#bc8cff"/><text x="513" y="86" class="t t-stat-label">REPOS</text><text x="559" y="118" fill="#bc8cff" class="t t-stat-value" text-anchor="middle">26</text></svg>
package/package.json CHANGED
@@ -16,6 +16,10 @@
16
16
  },
17
17
  "license": "Apache-2.0",
18
18
  "name": "@urmzd/github-insights",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/urmzd/github-insights.git"
22
+ },
19
23
  "scripts": {
20
24
  "build": "ncc build src/index.ts -o dist --source-map --license licenses.txt",
21
25
  "ci": "npm run fmt && npm run lint && npm run typecheck && npm run test && npm run build",
@@ -26,10 +30,6 @@
26
30
  "test": "vitest run",
27
31
  "typecheck": "tsc --noEmit"
28
32
  },
29
- "repository": {
30
- "type": "git",
31
- "url": "https://github.com/urmzd/github-insights.git"
32
- },
33
33
  "type": "module",
34
- "version": "2.0.0"
34
+ "version": "2.1.0"
35
35
  }
package/src/api.ts CHANGED
@@ -86,7 +86,7 @@ export const fetchAllRepoData = async (
86
86
  { username },
87
87
  );
88
88
 
89
- return data.user.repositories.nodes.filter((r) => !r.isArchived && !r.isFork);
89
+ return data.user.repositories.nodes.filter((r) => !r.isFork);
90
90
  };
91
91
 
92
92
  export const fetchManifestsForRepos = async (
package/src/config.ts CHANGED
@@ -17,10 +17,7 @@ function extractConfig(parsed: Record<string, unknown>): UserConfig {
17
17
  if (typeof parsed.name === "string" && parsed.name.trim()) {
18
18
  config.name = parsed.name.trim();
19
19
  }
20
- if (
21
- typeof parsed.pronunciation === "string" &&
22
- parsed.pronunciation.trim()
23
- ) {
20
+ if (typeof parsed.pronunciation === "string" && parsed.pronunciation.trim()) {
24
21
  config.pronunciation = parsed.pronunciation.trim();
25
22
  }
26
23
  if (typeof parsed.bio === "string" && parsed.bio.trim()) {
@@ -51,11 +48,14 @@ function extractConfig(parsed: Record<string, unknown>): UserConfig {
51
48
  return config;
52
49
  }
53
50
 
54
- export function parseUserConfig(raw: string, format: "yaml" | "toml" = "yaml"): UserConfig {
51
+ export function parseUserConfig(
52
+ raw: string,
53
+ format: "yaml" | "toml" = "yaml",
54
+ ): UserConfig {
55
55
  const parsed =
56
56
  format === "toml"
57
57
  ? toml.parse(raw)
58
- : (yaml.parse(raw) as Record<string, unknown>) ?? {};
58
+ : ((yaml.parse(raw) as Record<string, unknown>) ?? {});
59
59
  return extractConfig(parsed);
60
60
  }
61
61
 
@@ -93,11 +93,5 @@ function resolveConfigPath(): { path: string; format: "yaml" | "toml" } {
93
93
  if (existsSync("github-insights.yaml")) {
94
94
  return { path: "github-insights.yaml", format: "yaml" };
95
95
  }
96
- if (existsSync(".github-metrics.toml")) {
97
- console.warn(
98
- 'Warning: ".github-metrics.toml" is deprecated. Please rename it to "github-insights.yml".',
99
- );
100
- return { path: ".github-metrics.toml", format: "toml" };
101
- }
102
96
  return { path: "github-insights.yml", format: "yaml" };
103
97
  }
package/src/index.ts CHANGED
@@ -142,6 +142,7 @@ async function run(): Promise<void> {
142
142
  active: activeProjects,
143
143
  maintained: maintainedProjects,
144
144
  inactive: inactiveProjects,
145
+ archived: archivedProjects,
145
146
  } = splitProjectsByRecency(repos, contributionData, aiClassifications);
146
147
 
147
148
  const sectionDefs = buildSections({
@@ -227,6 +228,7 @@ async function run(): Promise<void> {
227
228
  ...activeProjects,
228
229
  ...maintainedProjects,
229
230
  ...inactiveProjects,
231
+ ...archivedProjects,
230
232
  ];
231
233
  const categorizedProjects: Record<string, typeof allProjectItems> = {};
232
234
  for (const project of allProjectItems) {
@@ -245,12 +247,14 @@ async function run(): Promise<void> {
245
247
  title: userConfig.title,
246
248
  bio: userConfig.bio,
247
249
  preamble,
250
+ templateName,
248
251
  svgs,
249
252
  sectionSvgs,
250
253
  profile: userProfile,
251
254
  activeProjects,
252
255
  maintainedProjects,
253
256
  inactiveProjects,
257
+ archivedProjects,
254
258
  allProjects: complexProjects,
255
259
  categorizedProjects,
256
260
  languages,
@@ -308,12 +312,14 @@ async function run(): Promise<void> {
308
312
  title: userConfig.title,
309
313
  bio: userConfig.bio,
310
314
  preamble,
315
+ templateName: tplName,
311
316
  svgs: previewSvgs,
312
317
  sectionSvgs: previewSectionSvgs,
313
318
  profile: userProfile,
314
319
  activeProjects,
315
320
  maintainedProjects,
316
321
  inactiveProjects,
322
+ archivedProjects,
317
323
  allProjects: complexProjects,
318
324
  categorizedProjects,
319
325
  languages,
package/src/metrics.ts CHANGED
@@ -117,6 +117,7 @@ const toProjectItem = (repo: RepoNode): ProjectItem => ({
117
117
  languageCount: repo.languages.edges.length,
118
118
  codeSize: repo.diskUsage,
119
119
  languages: repoLanguages(repo),
120
+ isArchived: repo.isArchived || undefined,
120
121
  });
121
122
 
122
123
  // ── Top Projects by Stars ───────────────────────────────────────────────────
@@ -190,6 +191,7 @@ export const splitProjectsByRecency = (
190
191
  active: ProjectItem[];
191
192
  maintained: ProjectItem[];
192
193
  inactive: ProjectItem[];
194
+ archived: ProjectItem[];
193
195
  } => {
194
196
  const commitMap = new Map<string, number>();
195
197
  for (const entry of contributionData.commitContributionsByRepository || []) {
@@ -206,8 +208,17 @@ export const splitProjectsByRecency = (
206
208
  const activeRepos: RepoNode[] = [];
207
209
  const maintainedRepos: RepoNode[] = [];
208
210
  const inactiveRepos: RepoNode[] = [];
211
+ const archivedRepos: RepoNode[] = [];
209
212
 
210
213
  for (const repo of repos) {
214
+ if (repo.isArchived) {
215
+ archivedRepos.push(repo);
216
+ console.info(
217
+ `[archived ] ${repo.name} (complexity=${complexityScore(repo).toFixed(1)})`,
218
+ );
219
+ continue;
220
+ }
221
+
211
222
  const commits = commitMap.get(repo.name) || 0;
212
223
  const aiEntry = aiMap.get(repo.name);
213
224
  const status = aiEntry?.status || heuristicStatus(commits, repo.createdAt);
@@ -227,7 +238,7 @@ export const splitProjectsByRecency = (
227
238
  }
228
239
 
229
240
  console.info(
230
- `Split: ${activeRepos.length} active, ${maintainedRepos.length} maintained, ${inactiveRepos.length} inactive`,
241
+ `Split: ${activeRepos.length} active, ${maintainedRepos.length} maintained, ${inactiveRepos.length} inactive, ${archivedRepos.length} archived`,
231
242
  );
232
243
 
233
244
  const sortByComplexity = (a: RepoNode, b: RepoNode) =>
@@ -248,8 +259,11 @@ export const splitProjectsByRecency = (
248
259
  const inactive: ProjectItem[] = inactiveRepos
249
260
  .sort(sortByComplexity)
250
261
  .map(toProjectItemWithSummary);
262
+ const archived: ProjectItem[] = archivedRepos
263
+ .sort(sortByComplexity)
264
+ .map(toProjectItemWithSummary);
251
265
 
252
- return { active, maintained, inactive };
266
+ return { active, maintained, inactive, archived };
253
267
  };
254
268
 
255
269
  // ── Section definitions ─────────────────────────────────────────────────────
@@ -5,10 +5,10 @@ describe("generateReadme", () => {
5
5
  it("renders minimal readme (name + single SVG)", () => {
6
6
  const result = generateReadme({
7
7
  name: "octocat",
8
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
8
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
9
9
  });
10
10
  expect(result).toContain(
11
- "# octocat\n\n![GitHub Metrics](metrics/index.svg)",
11
+ "# octocat\n\n![GitHub Metrics](assets/insights/index.svg)",
12
12
  );
13
13
  expect(result).toMatch(
14
14
  /Last generated on \d{4}-\d{2}-\d{2} using \[@urmzd\/github-insights\]/,
@@ -19,7 +19,7 @@ describe("generateReadme", () => {
19
19
  const result = generateReadme({
20
20
  name: "Urmzd",
21
21
  pronunciation: "/ˈʊrm.zəd/",
22
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
22
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
23
23
  });
24
24
  expect(result).toContain("# Urmzd <sub><i>(/ˈʊrm.zəd/)</i></sub>");
25
25
  });
@@ -27,7 +27,7 @@ describe("generateReadme", () => {
27
27
  it("omits pronunciation when not set", () => {
28
28
  const result = generateReadme({
29
29
  name: "Urmzd",
30
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
30
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
31
31
  });
32
32
  expect(result).not.toContain("<sub><i>");
33
33
  expect(result).toContain("# Urmzd\n");
@@ -37,7 +37,7 @@ describe("generateReadme", () => {
37
37
  const result = generateReadme({
38
38
  name: "Urmzd",
39
39
  title: "Senior Backend Engineer",
40
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
40
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
41
41
  });
42
42
  expect(result).toContain("> Senior Backend Engineer");
43
43
  });
@@ -45,7 +45,7 @@ describe("generateReadme", () => {
45
45
  it("omits title when not set", () => {
46
46
  const result = generateReadme({
47
47
  name: "Urmzd",
48
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
48
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
49
49
  });
50
50
  expect(result).not.toContain("> ");
51
51
  });
@@ -54,7 +54,7 @@ describe("generateReadme", () => {
54
54
  const result = generateReadme({
55
55
  name: "Urmzd",
56
56
  preamble: "Hello, I build things.",
57
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
57
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
58
58
  });
59
59
  expect(result).toContain("Hello, I build things.");
60
60
  });
@@ -62,19 +62,19 @@ describe("generateReadme", () => {
62
62
  it("omits preamble when not set", () => {
63
63
  const result = generateReadme({
64
64
  name: "Urmzd",
65
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
65
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
66
66
  });
67
67
  // Only heading + SVG + attribution + trailing newline
68
68
  expect(result).not.toContain("Hello");
69
69
  expect(result).toContain("# Urmzd");
70
- expect(result).toContain("![GitHub Metrics](metrics/index.svg)");
70
+ expect(result).toContain("![GitHub Metrics](assets/insights/index.svg)");
71
71
  });
72
72
 
73
73
  it("preamble is not wrapped in code fences", () => {
74
74
  const result = generateReadme({
75
75
  name: "Urmzd",
76
76
  preamble: "Hello, I build things.",
77
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
77
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
78
78
  });
79
79
  expect(result).toContain("Hello, I build things.");
80
80
  expect(result).not.toContain("```");
@@ -86,7 +86,7 @@ describe("generateReadme", () => {
86
86
  const result = generateReadme({
87
87
  name: "Urmzd",
88
88
  preamble: preamble,
89
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
89
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
90
90
  });
91
91
  expect(result).toContain(preamble);
92
92
  expect(result).toContain(`# Urmzd\n\n${preamble}\n\n![GitHub Metrics]`);
@@ -98,7 +98,7 @@ describe("generateReadme", () => {
98
98
  const result = generateReadme({
99
99
  name: "Urmzd",
100
100
  preamble: preamble,
101
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
101
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
102
102
  });
103
103
  expect(result).toContain("**bold**");
104
104
  expect(result).toContain(
@@ -114,14 +114,14 @@ describe("generateReadme", () => {
114
114
  pronunciation: "/ˈʊrm.zəd/",
115
115
  title: "Senior Backend Engineer",
116
116
  preamble: "Welcome to my profile!",
117
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
117
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
118
118
  bio: "Building tools for developers",
119
119
  });
120
120
  expect(result).toContain(
121
121
  "> Senior Backend Engineer\n\nWelcome to my profile!",
122
122
  );
123
123
  expect(result).toContain(
124
- "Welcome to my profile!\n\n![GitHub Metrics](metrics/index.svg)",
124
+ "Welcome to my profile!\n\n![GitHub Metrics](assets/insights/index.svg)",
125
125
  );
126
126
  });
127
127
 
@@ -129,7 +129,7 @@ describe("generateReadme", () => {
129
129
  const result = generateReadme({
130
130
  name: "Urmzd",
131
131
  bio: "Building tools for developers",
132
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
132
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
133
133
  });
134
134
  expect(result).toContain("---\n\n<sub>Building tools for developers</sub>");
135
135
  });
@@ -137,7 +137,7 @@ describe("generateReadme", () => {
137
137
  it("omits bio when not set", () => {
138
138
  const result = generateReadme({
139
139
  name: "Urmzd",
140
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
140
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
141
141
  });
142
142
  expect(result).not.toContain("---");
143
143
  // Should only have the attribution <sub>, not a bio <sub>
@@ -150,14 +150,20 @@ describe("generateReadme", () => {
150
150
  const result = generateReadme({
151
151
  name: "Urmzd",
152
152
  svgs: [
153
- { label: "Languages", path: "metrics/metrics-languages.svg" },
154
- { label: "Projects", path: "metrics/metrics-projects.svg" },
155
- { label: "Expertise", path: "metrics/metrics-expertise.svg" },
153
+ { label: "Languages", path: "assets/insights/metrics-languages.svg" },
154
+ { label: "Projects", path: "assets/insights/metrics-projects.svg" },
155
+ { label: "Expertise", path: "assets/insights/metrics-expertise.svg" },
156
156
  ],
157
157
  });
158
- expect(result).toContain("![Languages](metrics/metrics-languages.svg)");
159
- expect(result).toContain("![Projects](metrics/metrics-projects.svg)");
160
- expect(result).toContain("![Expertise](metrics/metrics-expertise.svg)");
158
+ expect(result).toContain(
159
+ "![Languages](assets/insights/metrics-languages.svg)",
160
+ );
161
+ expect(result).toContain(
162
+ "![Projects](assets/insights/metrics-projects.svg)",
163
+ );
164
+ expect(result).toContain(
165
+ "![Expertise](assets/insights/metrics-expertise.svg)",
166
+ );
161
167
  });
162
168
 
163
169
  it("renders all sections combined", () => {
@@ -166,7 +172,7 @@ describe("generateReadme", () => {
166
172
  pronunciation: "/ˈʊrm.zəd/",
167
173
  title: "Senior Backend Engineer",
168
174
  preamble: "Welcome to my profile!",
169
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
175
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
170
176
  bio: "Building tools for developers",
171
177
  });
172
178
  expect(result).toContain(
@@ -174,14 +180,14 @@ describe("generateReadme", () => {
174
180
  );
175
181
  expect(result).toContain("> Senior Backend Engineer");
176
182
  expect(result).toContain("Welcome to my profile!");
177
- expect(result).toContain("![GitHub Metrics](metrics/index.svg)");
183
+ expect(result).toContain("![GitHub Metrics](assets/insights/index.svg)");
178
184
  expect(result).toContain("---\n\n<sub>Building tools for developers</sub>");
179
185
  });
180
186
 
181
187
  it("ends with a trailing newline", () => {
182
188
  const result = generateReadme({
183
189
  name: "octocat",
184
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
190
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
185
191
  });
186
192
  expect(result.endsWith("\n")).toBe(true);
187
193
  expect(result.endsWith("\n\n")).toBe(false);