@ossintel/scoring 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 turboforge-dev
3
+ Copyright (c) 2026 ossintel
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -23,7 +23,7 @@
23
23
 
24
24
  # @ossintel/scoring
25
25
 
26
- Deterministic OSS scoring engine.
26
+ Deterministic OSS scoring engine with modular architecture.
27
27
 
28
28
  ## Purpose
29
29
 
@@ -31,33 +31,54 @@ Converts normalized repository and developer metrics into objective scores.
31
31
 
32
32
  ## Responsibilities
33
33
 
34
- Calculate:
34
+ ### Repository Scoring
35
35
 
36
- - Overall Score
37
- - Health Score
38
- - Impact Score
39
- - Activity Score
40
- - Community Score
41
- - Risk Score
36
+ - Health, Impact, Activity, Community, Risk, and Overall scores
42
37
 
43
- ## Philosophy
38
+ ### Identity Scoring (OSSIQ)
39
+
40
+ Four-pillar reputation engine:
44
41
 
45
- Scores should always be reproducible.
42
+ - **Maintainer** Repository health weighted by popularity (GitHub-only)
43
+ - **Contributor** — Quality-weighted external PR scoring
44
+ - **Organization** — Active org leadership evaluation
45
+ - **Influence** — Downstream reach (stars, forks + additive npm/SO bonuses)
46
46
 
47
- The same inputs should always produce the same outputs.
47
+ ### Capability Scoring
48
48
 
49
- No AI should participate in score calculation.
49
+ - **Package Publishing** (`calculatePublishingScore`) npm downloads, active packages, verified publisher (extensible to NuGet, PyPI, crates.io, Go)
50
+ - **Knowledge Sharing** (`calculateKnowledgeScore`) — Stack Overflow reputation, answers, acceptance rate (extensible to Dev.to, Hashnode)
50
51
 
51
- ## Inputs
52
+ ### Supporting Modules
52
53
 
53
- Normalized domain models.
54
+ - **Badges** — Achievement detection from cross-platform activity
55
+ - **Skills** — Topic expertise radar aggregating GitHub, npm, and Stack Overflow signals
56
+ - **Evidence & Factors** — Human-readable explanations for each pillar
54
57
 
55
- ## Outputs
58
+ ## Philosophy
56
59
 
57
- ```ts
58
- {
59
- overall, health, impact, activity, community, risk;
60
- }
60
+ - Scores are **deterministic**: same inputs → same outputs
61
+ - Scores are **monotonic**: linking additional providers can only increase reputation
62
+ - GitHub defines the **core OSS reputation** (~80-85%)
63
+ - Additional providers contribute **additive capability bonuses**
64
+ - No AI participates in score calculation
65
+
66
+ ## Module Architecture
67
+
68
+ ```text
69
+ index.ts
70
+ ├── repository-scoring.ts # Repo-level: health, impact, activity, community, risk
71
+ ├── identity-scoring.ts # Orchestrator: computes overall OSSIQ score
72
+ ├── maintainer-scoring.ts # Pillar: GitHub repo health weighted average
73
+ ├── contributor-scoring.ts # Pillar: external PR quality weighting
74
+ ├── organization-scoring.ts # Pillar: org leadership evaluation
75
+ ├── influence-scoring.ts # Pillar: stars + forks + additive bonuses
76
+ ├── publishing-scoring.ts # Capability: Package Publishing (npm)
77
+ ├── knowledge-scoring.ts # Capability: Knowledge Sharing (Stack Overflow)
78
+ ├── badges.ts # Achievement detection
79
+ ├── skills.ts # Topic expertise aggregation
80
+ ├── evidence.ts # Evidence & factors generation
81
+ └── topic-mappings.ts # Canonical topic → keyword mappings
61
82
  ```
62
83
 
63
84
  ## Non-goals
@@ -77,8 +98,44 @@ No external dependencies should affect score calculation.
77
98
 
78
99
  ## ✨ Why @ossintel/scoring?
79
100
 
80
- -
81
- -
101
+ - **100% Deterministic & Transparent**: Zero network requests or probabilistic AI models; calculations are mathematical and fully reproducible.
102
+ - **Modular Pillar Architecture**: Each scoring dimension (Maintainer, Contributor, Organization, Influence) is a self-contained module, easy to extend or override.
103
+ - **Capability-Specific Scoring**: First-class `calculatePublishingScore` and `calculateKnowledgeScore` exports for direct use by consumers.
104
+ - **Monotonic Guarantees**: Linking npm or Stack Overflow can only increase scores, never reduce them.
105
+ - **Fully Tested**: Every score calculation is validated by comprehensive unit tests to prevent regression.
106
+
107
+ ---
108
+
109
+ ## 🌍 Open Source Ecosystem Impact Engine
110
+
111
+ The Ecosystem Impact Engine measures developer impact beyond owned repositories, focusing on contributions to external projects.
112
+
113
+ ### Heuristics Classification Pipeline
114
+
115
+ ```text
116
+ [User Merged PR]
117
+
118
+ ├──► Contains "typo", "readme", "docs" in Title/Labels? ─────► [Docs / Typo Fix] (Weight: 0.4x)
119
+ ├──► Contains "test", "spec", "qa" in Title/Labels? ────────► [Test Contribution] (Weight: 1.2x)
120
+ ├──► Contains "chore", "dependencies" in Title/Labels? ──────► [Chore / Dependency] (Weight: 0.5x)
121
+ └──► Default Code change ────────────────────────────────────► [Core Code Contribution] (Weight: 1.0x)
122
+ ```
123
+
124
+ ### Weighting Matrix
125
+
126
+ Merged pull requests are weighted according to target repository popularity and quality multipliers:
127
+
128
+ | Target Repo Stargazers | Tier Category | Base Weight | Multiplier Applied |
129
+ | ---------------------- | ----------------------- | ----------- | ---------------------------------------------------------------- |
130
+ | **≥ 20,000 Stars** | **Tier 1 (Frameworks)** | 5.0 | Quality Multiplier (Docs: 0.4, Test: 1.2, Chore: 0.5, Code: 1.0) |
131
+ | **≥ 2,000 Stars** | **Tier 2 (Medium OSS)** | 3.0 | Quality Multiplier |
132
+ | **< 2,000 Stars** | **Tier 3 (Small OSS)** | 1.0 | Quality Multiplier |
133
+
134
+ The resulting Ecosystem Contribution Score ($S_{\text{eco}}$) is aggregated as:
135
+
136
+ $$
137
+ S_{\text{eco}} = \min\left(100, \sum (\text{BaseWeight} \times \text{QualityMultiplier})\right)
138
+ $$
82
139
 
83
140
  ---
84
141
 
package/dist/index.d.mts CHANGED
@@ -1,4 +1,34 @@
1
- import { NormalizedRepository, NormalizedContributor, NormalizedRelease, NormalizedLanguage } from '@ossintel/github-normalizer';
1
+ import { NormalizedContribution, NormalizedRepository, NormalizedContributor, NormalizedRelease, NormalizedLanguage } from '@ossintel/github-normalizer';
2
+ import { NormalizedNpmUser } from '@ossintel/npm';
3
+ import { NormalizedStackOverflowUser } from '@ossintel/stackoverflow';
4
+
5
+ interface BadgeInputs {
6
+ externalContributions: NormalizedContribution[];
7
+ activeOrgsCount: number;
8
+ totalStarsCount: number;
9
+ totalNpmDownloads: number;
10
+ npmUser?: NormalizedNpmUser | null;
11
+ stackoverflowUser?: NormalizedStackOverflowUser | null;
12
+ }
13
+ /** Compute achievement badges based on cross-platform activity. */
14
+ declare const calculateBadges: (inputs: BadgeInputs) => string[];
15
+
16
+ interface ContributorResult {
17
+ /** Final contributor score (0-100). */
18
+ score: number;
19
+ /** Per-repo breakdown of earned points. */
20
+ breakdown: Array<{
21
+ repo: string;
22
+ points: number;
23
+ }>;
24
+ }
25
+ /**
26
+ * Calculate the contributor pillar score from external (upstream) PRs.
27
+ *
28
+ * Quality-weighted scoring: PR type (code/docs/test/chore) and target
29
+ * repository importance (star count) determine point allocation.
30
+ */
31
+ declare const calculateContributorScore: (externalContributions: NormalizedContribution[]) => ContributorResult;
2
32
 
3
33
  interface ScoringInputs {
4
34
  repository: NormalizedRepository;
@@ -14,23 +44,211 @@ interface RepositoryScores {
14
44
  community: number;
15
45
  risk: number;
16
46
  }
17
- interface NpmPackageStats {
18
- name: string;
19
- downloads: number;
20
- stars?: number;
47
+ interface TopicExpertise {
48
+ topic: string;
49
+ score: number;
50
+ evidence: {
51
+ githubStars: number;
52
+ githubPrs: number;
53
+ npmDownloads: number;
54
+ npmPackages: number;
55
+ stackoverflowScore: number;
56
+ stackoverflowAnswers: number;
57
+ };
21
58
  }
22
59
  interface IdentityScoringInputs {
23
60
  repositories: NormalizedRepository[];
24
- npmPackages?: NpmPackageStats[];
61
+ npmUser?: NormalizedNpmUser | null;
62
+ stackoverflowUser?: NormalizedStackOverflowUser | null;
63
+ externalContributions?: NormalizedContribution[];
64
+ organizations?: {
65
+ login?: string;
66
+ publicRepos: number;
67
+ followers?: number;
68
+ stars?: number;
69
+ }[];
70
+ }
71
+ interface PillarEvidence {
72
+ maintainer: string[];
73
+ contributor: string[];
74
+ influence: string[];
75
+ organization: string[];
76
+ }
77
+ interface PillarFactors {
78
+ maintainer: string[];
79
+ contributor: string[];
80
+ influence: string[];
81
+ organization: string[];
82
+ }
83
+ interface IdentityScores {
84
+ overall: number;
85
+ maintainer: number;
86
+ contributor: number;
87
+ organization: number;
88
+ influence: number;
89
+ confidence: "High" | "Medium" | "Low";
90
+ evidence: PillarEvidence;
91
+ factors: PillarFactors;
92
+ badges: string[];
93
+ skills: TopicExpertise[];
94
+ }
95
+
96
+ interface EvidenceInputs {
97
+ activeRepos: IdentityScoringInputs["repositories"];
98
+ allRepos: IdentityScoringInputs["repositories"];
99
+ externalContributions: NormalizedContribution[];
100
+ organizations: NonNullable<IdentityScoringInputs["organizations"]>;
101
+ contributorBreakdown: Array<{
102
+ repo: string;
103
+ points: number;
104
+ }>;
105
+ maintainerScore: number;
106
+ sustainedCount: number;
107
+ totalStarsCount: number;
108
+ totalForksCount: number;
109
+ totalNpmDownloads: number;
110
+ soReputation: number;
111
+ npmUser?: NormalizedNpmUser | null;
112
+ stackoverflowUser?: NormalizedStackOverflowUser | null;
113
+ }
114
+ /** Generate factual evidence lists for each identity pillar. */
115
+ declare const generateEvidence: (inputs: EvidenceInputs) => PillarEvidence;
116
+ /** Generate positive/negative factor descriptions for each identity pillar. */
117
+ declare const generateFactors: (inputs: EvidenceInputs) => PillarFactors;
118
+
119
+ /**
120
+ * Calculate the unified OSS identity score.
121
+ *
122
+ * GitHub is the primary identity (~80-85% weight). npm (Package Publishing)
123
+ * and Stack Overflow (Knowledge Sharing) provide additive evidence bonuses
124
+ * that can never reduce the score.
125
+ *
126
+ * @see {@link file://docs/domain-model.md} for scoring philosophy.
127
+ */
128
+ declare const calculateIdentityScore: (inputs: IdentityScoringInputs) => IdentityScores;
129
+
130
+ interface InfluenceResult {
131
+ /** Final influence score (0-100). */
132
+ score: number;
133
+ /** GitHub-only influence base. */
134
+ githubBase: number;
135
+ /** Additive npm bonus (0-15). */
136
+ npmBonus: number;
137
+ /** Additive Stack Overflow bonus (0-15). */
138
+ soBonus: number;
139
+ }
140
+ /**
141
+ * Calculate the influence pillar score.
142
+ *
143
+ * GitHub stars and forks form the base. npm downloads and
144
+ * Stack Overflow reputation provide bounded additive bonuses.
145
+ */
146
+ declare const calculateInfluenceScore: (totalStarsCount: number, totalForksCount: number, totalNpmDownloads: number, soReputation: number) => InfluenceResult;
147
+
148
+ interface KnowledgeScore {
149
+ /** Overall knowledge sharing score (0-100). */
150
+ score: number;
151
+ /** Breakdown of sub-scores contributing to the overall. */
152
+ breakdown: {
153
+ /** Score based on reputation volume (0-100). */
154
+ reputation: number;
155
+ /** Score based on answer count (0-100). */
156
+ answers: number;
157
+ /** Score based on acceptance rate (0-100). */
158
+ acceptance: number;
159
+ };
160
+ }
161
+ /**
162
+ * Calculate a Knowledge Sharing capability score.
163
+ *
164
+ * Currently evaluates Stack Overflow presence only. Designed to be
165
+ * extended with additional platforms (Dev.to, Hashnode, etc.)
166
+ * by adding optional parameters without breaking existing callers.
167
+ *
168
+ * @returns A score (0-100) with breakdown, or null if no data is available.
169
+ */
170
+ declare const calculateKnowledgeScore: (stackoverflowUser?: NormalizedStackOverflowUser | null) => KnowledgeScore | null;
171
+
172
+ interface MaintainerResult {
173
+ /** Final maintainer score (0-100), including additive npm bonus. */
174
+ score: number;
175
+ /** GitHub-only base score before npm bonus. */
176
+ githubBase: number;
177
+ /** Additive npm bonus (0-10). */
178
+ npmBonus: number;
179
+ /** Number of repos with sustained long-term maintenance. */
180
+ sustainedCount: number;
181
+ }
182
+ /**
183
+ * Calculate the maintainer pillar score.
184
+ *
185
+ * GitHub repo health is the primary signal. npm download volume
186
+ * provides a small additive bonus (capped at 10 points) that can
187
+ * never reduce the score.
188
+ */
189
+ declare const calculateMaintainerScore: (repositories: NormalizedRepository[], totalNpmDownloads: number) => MaintainerResult;
190
+
191
+ interface OrganizationResult {
192
+ /** Final organization leadership score (0-100). */
193
+ score: number;
194
+ /** Number of active organizations. */
195
+ activeCount: number;
25
196
  }
26
- type IdentityScores = RepositoryScores;
197
+ /** Calculate the organization leadership pillar score. */
198
+ declare const calculateOrganizationScore: (organizations: NonNullable<IdentityScoringInputs["organizations"]>) => OrganizationResult;
27
199
 
200
+ interface PublishingScore {
201
+ /** Overall publishing reputation score (0-100). */
202
+ score: number;
203
+ /** Breakdown of sub-scores contributing to the overall. */
204
+ breakdown: {
205
+ /** Score based on total download volume (0-100). */
206
+ downloads: number;
207
+ /** Score based on active package count (0-100). */
208
+ packages: number;
209
+ /** Score based on verified publisher status (0 or 100). */
210
+ verified: number;
211
+ };
212
+ }
213
+ /**
214
+ * Calculate a Package Publishing capability score.
215
+ *
216
+ * Currently evaluates npm presence only. Designed to be extended
217
+ * with additional registries (NuGet, PyPI, crates.io, Go, etc.)
218
+ * by adding optional parameters without breaking existing callers.
219
+ *
220
+ * @returns A score (0-100) with breakdown, or null if no data is available.
221
+ */
222
+ declare const calculatePublishingScore: (npmUser?: NormalizedNpmUser | null) => PublishingScore | null;
223
+
224
+ /** Calculate the impact score based on stars, forks, and watchers. */
28
225
  declare const calculateImpactScore: (repository: ScoringInputs["repository"]) => number;
226
+ /** Calculate the activity score based on push recency and release frequency. */
29
227
  declare const calculateActivityScore: (repository: ScoringInputs["repository"], releases: ScoringInputs["releases"]) => number;
228
+ /** Calculate the community score from contributors, topics, and metadata. */
30
229
  declare const calculateCommunityScore: (repository: ScoringInputs["repository"], contributors: ScoringInputs["contributors"]) => number;
230
+ /** Calculate repository health based on issue density, update recency, and fork status. */
31
231
  declare const calculateHealthScore: (repository: ScoringInputs["repository"]) => number;
232
+ /** Calculate risk score based on staleness, contributor count, fork status, and issue density. */
32
233
  declare const calculateRiskScore: (repository: ScoringInputs["repository"], contributors: ScoringInputs["contributors"]) => number;
234
+ /** Calculate aggregate repository scores across all dimensions. */
33
235
  declare const calculateRepositoryScore: (inputs: ScoringInputs) => RepositoryScores;
34
- declare const calculateIdentityScore: (inputs: IdentityScoringInputs) => IdentityScores;
35
236
 
36
- export { type IdentityScores, type IdentityScoringInputs, type NpmPackageStats, type RepositoryScores, type ScoringInputs, calculateActivityScore, calculateCommunityScore, calculateHealthScore, calculateIdentityScore, calculateImpactScore, calculateRepositoryScore, calculateRiskScore };
237
+ interface SkillsInputs {
238
+ repositories: IdentityScoringInputs["repositories"];
239
+ externalContributions: NormalizedContribution[];
240
+ npmUser?: NormalizedNpmUser | null;
241
+ stackoverflowUser?: NormalizedStackOverflowUser | null;
242
+ }
243
+ /**
244
+ * Compute topic expertise scores by aggregating signals across
245
+ * GitHub repos, PRs, npm packages, and Stack Overflow tags.
246
+ */
247
+ declare const calculateSkills: (inputs: SkillsInputs) => TopicExpertise[];
248
+
249
+ /** Canonical topic-to-keyword mappings for skill classification. */
250
+ declare const TOPIC_MAPPINGS: Record<string, string[]>;
251
+ /** Match a raw topic/language string to a canonical category name. */
252
+ declare const matchTopic: (nameOrTopic: string) => string | null;
253
+
254
+ export { type ContributorResult, type IdentityScores, type IdentityScoringInputs, type InfluenceResult, type KnowledgeScore, type MaintainerResult, type OrganizationResult, type PillarEvidence, type PillarFactors, type PublishingScore, type RepositoryScores, type ScoringInputs, TOPIC_MAPPINGS, type TopicExpertise, calculateActivityScore, calculateBadges, calculateCommunityScore, calculateContributorScore, calculateHealthScore, calculateIdentityScore, calculateImpactScore, calculateInfluenceScore, calculateKnowledgeScore, calculateMaintainerScore, calculateOrganizationScore, calculatePublishingScore, calculateRepositoryScore, calculateRiskScore, calculateSkills, generateEvidence, generateFactors, matchTopic };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,34 @@
1
- import { NormalizedRepository, NormalizedContributor, NormalizedRelease, NormalizedLanguage } from '@ossintel/github-normalizer';
1
+ import { NormalizedContribution, NormalizedRepository, NormalizedContributor, NormalizedRelease, NormalizedLanguage } from '@ossintel/github-normalizer';
2
+ import { NormalizedNpmUser } from '@ossintel/npm';
3
+ import { NormalizedStackOverflowUser } from '@ossintel/stackoverflow';
4
+
5
+ interface BadgeInputs {
6
+ externalContributions: NormalizedContribution[];
7
+ activeOrgsCount: number;
8
+ totalStarsCount: number;
9
+ totalNpmDownloads: number;
10
+ npmUser?: NormalizedNpmUser | null;
11
+ stackoverflowUser?: NormalizedStackOverflowUser | null;
12
+ }
13
+ /** Compute achievement badges based on cross-platform activity. */
14
+ declare const calculateBadges: (inputs: BadgeInputs) => string[];
15
+
16
+ interface ContributorResult {
17
+ /** Final contributor score (0-100). */
18
+ score: number;
19
+ /** Per-repo breakdown of earned points. */
20
+ breakdown: Array<{
21
+ repo: string;
22
+ points: number;
23
+ }>;
24
+ }
25
+ /**
26
+ * Calculate the contributor pillar score from external (upstream) PRs.
27
+ *
28
+ * Quality-weighted scoring: PR type (code/docs/test/chore) and target
29
+ * repository importance (star count) determine point allocation.
30
+ */
31
+ declare const calculateContributorScore: (externalContributions: NormalizedContribution[]) => ContributorResult;
2
32
 
3
33
  interface ScoringInputs {
4
34
  repository: NormalizedRepository;
@@ -14,23 +44,211 @@ interface RepositoryScores {
14
44
  community: number;
15
45
  risk: number;
16
46
  }
17
- interface NpmPackageStats {
18
- name: string;
19
- downloads: number;
20
- stars?: number;
47
+ interface TopicExpertise {
48
+ topic: string;
49
+ score: number;
50
+ evidence: {
51
+ githubStars: number;
52
+ githubPrs: number;
53
+ npmDownloads: number;
54
+ npmPackages: number;
55
+ stackoverflowScore: number;
56
+ stackoverflowAnswers: number;
57
+ };
21
58
  }
22
59
  interface IdentityScoringInputs {
23
60
  repositories: NormalizedRepository[];
24
- npmPackages?: NpmPackageStats[];
61
+ npmUser?: NormalizedNpmUser | null;
62
+ stackoverflowUser?: NormalizedStackOverflowUser | null;
63
+ externalContributions?: NormalizedContribution[];
64
+ organizations?: {
65
+ login?: string;
66
+ publicRepos: number;
67
+ followers?: number;
68
+ stars?: number;
69
+ }[];
70
+ }
71
+ interface PillarEvidence {
72
+ maintainer: string[];
73
+ contributor: string[];
74
+ influence: string[];
75
+ organization: string[];
76
+ }
77
+ interface PillarFactors {
78
+ maintainer: string[];
79
+ contributor: string[];
80
+ influence: string[];
81
+ organization: string[];
82
+ }
83
+ interface IdentityScores {
84
+ overall: number;
85
+ maintainer: number;
86
+ contributor: number;
87
+ organization: number;
88
+ influence: number;
89
+ confidence: "High" | "Medium" | "Low";
90
+ evidence: PillarEvidence;
91
+ factors: PillarFactors;
92
+ badges: string[];
93
+ skills: TopicExpertise[];
94
+ }
95
+
96
+ interface EvidenceInputs {
97
+ activeRepos: IdentityScoringInputs["repositories"];
98
+ allRepos: IdentityScoringInputs["repositories"];
99
+ externalContributions: NormalizedContribution[];
100
+ organizations: NonNullable<IdentityScoringInputs["organizations"]>;
101
+ contributorBreakdown: Array<{
102
+ repo: string;
103
+ points: number;
104
+ }>;
105
+ maintainerScore: number;
106
+ sustainedCount: number;
107
+ totalStarsCount: number;
108
+ totalForksCount: number;
109
+ totalNpmDownloads: number;
110
+ soReputation: number;
111
+ npmUser?: NormalizedNpmUser | null;
112
+ stackoverflowUser?: NormalizedStackOverflowUser | null;
113
+ }
114
+ /** Generate factual evidence lists for each identity pillar. */
115
+ declare const generateEvidence: (inputs: EvidenceInputs) => PillarEvidence;
116
+ /** Generate positive/negative factor descriptions for each identity pillar. */
117
+ declare const generateFactors: (inputs: EvidenceInputs) => PillarFactors;
118
+
119
+ /**
120
+ * Calculate the unified OSS identity score.
121
+ *
122
+ * GitHub is the primary identity (~80-85% weight). npm (Package Publishing)
123
+ * and Stack Overflow (Knowledge Sharing) provide additive evidence bonuses
124
+ * that can never reduce the score.
125
+ *
126
+ * @see {@link file://docs/domain-model.md} for scoring philosophy.
127
+ */
128
+ declare const calculateIdentityScore: (inputs: IdentityScoringInputs) => IdentityScores;
129
+
130
+ interface InfluenceResult {
131
+ /** Final influence score (0-100). */
132
+ score: number;
133
+ /** GitHub-only influence base. */
134
+ githubBase: number;
135
+ /** Additive npm bonus (0-15). */
136
+ npmBonus: number;
137
+ /** Additive Stack Overflow bonus (0-15). */
138
+ soBonus: number;
139
+ }
140
+ /**
141
+ * Calculate the influence pillar score.
142
+ *
143
+ * GitHub stars and forks form the base. npm downloads and
144
+ * Stack Overflow reputation provide bounded additive bonuses.
145
+ */
146
+ declare const calculateInfluenceScore: (totalStarsCount: number, totalForksCount: number, totalNpmDownloads: number, soReputation: number) => InfluenceResult;
147
+
148
+ interface KnowledgeScore {
149
+ /** Overall knowledge sharing score (0-100). */
150
+ score: number;
151
+ /** Breakdown of sub-scores contributing to the overall. */
152
+ breakdown: {
153
+ /** Score based on reputation volume (0-100). */
154
+ reputation: number;
155
+ /** Score based on answer count (0-100). */
156
+ answers: number;
157
+ /** Score based on acceptance rate (0-100). */
158
+ acceptance: number;
159
+ };
160
+ }
161
+ /**
162
+ * Calculate a Knowledge Sharing capability score.
163
+ *
164
+ * Currently evaluates Stack Overflow presence only. Designed to be
165
+ * extended with additional platforms (Dev.to, Hashnode, etc.)
166
+ * by adding optional parameters without breaking existing callers.
167
+ *
168
+ * @returns A score (0-100) with breakdown, or null if no data is available.
169
+ */
170
+ declare const calculateKnowledgeScore: (stackoverflowUser?: NormalizedStackOverflowUser | null) => KnowledgeScore | null;
171
+
172
+ interface MaintainerResult {
173
+ /** Final maintainer score (0-100), including additive npm bonus. */
174
+ score: number;
175
+ /** GitHub-only base score before npm bonus. */
176
+ githubBase: number;
177
+ /** Additive npm bonus (0-10). */
178
+ npmBonus: number;
179
+ /** Number of repos with sustained long-term maintenance. */
180
+ sustainedCount: number;
181
+ }
182
+ /**
183
+ * Calculate the maintainer pillar score.
184
+ *
185
+ * GitHub repo health is the primary signal. npm download volume
186
+ * provides a small additive bonus (capped at 10 points) that can
187
+ * never reduce the score.
188
+ */
189
+ declare const calculateMaintainerScore: (repositories: NormalizedRepository[], totalNpmDownloads: number) => MaintainerResult;
190
+
191
+ interface OrganizationResult {
192
+ /** Final organization leadership score (0-100). */
193
+ score: number;
194
+ /** Number of active organizations. */
195
+ activeCount: number;
25
196
  }
26
- type IdentityScores = RepositoryScores;
197
+ /** Calculate the organization leadership pillar score. */
198
+ declare const calculateOrganizationScore: (organizations: NonNullable<IdentityScoringInputs["organizations"]>) => OrganizationResult;
27
199
 
200
+ interface PublishingScore {
201
+ /** Overall publishing reputation score (0-100). */
202
+ score: number;
203
+ /** Breakdown of sub-scores contributing to the overall. */
204
+ breakdown: {
205
+ /** Score based on total download volume (0-100). */
206
+ downloads: number;
207
+ /** Score based on active package count (0-100). */
208
+ packages: number;
209
+ /** Score based on verified publisher status (0 or 100). */
210
+ verified: number;
211
+ };
212
+ }
213
+ /**
214
+ * Calculate a Package Publishing capability score.
215
+ *
216
+ * Currently evaluates npm presence only. Designed to be extended
217
+ * with additional registries (NuGet, PyPI, crates.io, Go, etc.)
218
+ * by adding optional parameters without breaking existing callers.
219
+ *
220
+ * @returns A score (0-100) with breakdown, or null if no data is available.
221
+ */
222
+ declare const calculatePublishingScore: (npmUser?: NormalizedNpmUser | null) => PublishingScore | null;
223
+
224
+ /** Calculate the impact score based on stars, forks, and watchers. */
28
225
  declare const calculateImpactScore: (repository: ScoringInputs["repository"]) => number;
226
+ /** Calculate the activity score based on push recency and release frequency. */
29
227
  declare const calculateActivityScore: (repository: ScoringInputs["repository"], releases: ScoringInputs["releases"]) => number;
228
+ /** Calculate the community score from contributors, topics, and metadata. */
30
229
  declare const calculateCommunityScore: (repository: ScoringInputs["repository"], contributors: ScoringInputs["contributors"]) => number;
230
+ /** Calculate repository health based on issue density, update recency, and fork status. */
31
231
  declare const calculateHealthScore: (repository: ScoringInputs["repository"]) => number;
232
+ /** Calculate risk score based on staleness, contributor count, fork status, and issue density. */
32
233
  declare const calculateRiskScore: (repository: ScoringInputs["repository"], contributors: ScoringInputs["contributors"]) => number;
234
+ /** Calculate aggregate repository scores across all dimensions. */
33
235
  declare const calculateRepositoryScore: (inputs: ScoringInputs) => RepositoryScores;
34
- declare const calculateIdentityScore: (inputs: IdentityScoringInputs) => IdentityScores;
35
236
 
36
- export { type IdentityScores, type IdentityScoringInputs, type NpmPackageStats, type RepositoryScores, type ScoringInputs, calculateActivityScore, calculateCommunityScore, calculateHealthScore, calculateIdentityScore, calculateImpactScore, calculateRepositoryScore, calculateRiskScore };
237
+ interface SkillsInputs {
238
+ repositories: IdentityScoringInputs["repositories"];
239
+ externalContributions: NormalizedContribution[];
240
+ npmUser?: NormalizedNpmUser | null;
241
+ stackoverflowUser?: NormalizedStackOverflowUser | null;
242
+ }
243
+ /**
244
+ * Compute topic expertise scores by aggregating signals across
245
+ * GitHub repos, PRs, npm packages, and Stack Overflow tags.
246
+ */
247
+ declare const calculateSkills: (inputs: SkillsInputs) => TopicExpertise[];
248
+
249
+ /** Canonical topic-to-keyword mappings for skill classification. */
250
+ declare const TOPIC_MAPPINGS: Record<string, string[]>;
251
+ /** Match a raw topic/language string to a canonical category name. */
252
+ declare const matchTopic: (nameOrTopic: string) => string | null;
253
+
254
+ export { type ContributorResult, type IdentityScores, type IdentityScoringInputs, type InfluenceResult, type KnowledgeScore, type MaintainerResult, type OrganizationResult, type PillarEvidence, type PillarFactors, type PublishingScore, type RepositoryScores, type ScoringInputs, TOPIC_MAPPINGS, type TopicExpertise, calculateActivityScore, calculateBadges, calculateCommunityScore, calculateContributorScore, calculateHealthScore, calculateIdentityScore, calculateImpactScore, calculateInfluenceScore, calculateKnowledgeScore, calculateMaintainerScore, calculateOrganizationScore, calculatePublishingScore, calculateRepositoryScore, calculateRiskScore, calculateSkills, generateEvidence, generateFactors, matchTopic };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var M=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var F=(t,e)=>{for(var o in e)M(t,o,{get:e[o],enumerable:!0})},z=(t,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let c of A(e))!R.call(t,c)&&c!==o&&M(t,c,{get:()=>e[c],enumerable:!(i=x(e,c))||i.enumerable});return t};var T=t=>z(M({},"__esModule",{value:!0}),t);var H={};F(H,{calculateActivityScore:()=>C,calculateCommunityScore:()=>w,calculateHealthScore:()=>y,calculateIdentityScore:()=>Y,calculateImpactScore:()=>k,calculateRepositoryScore:()=>v,calculateRiskScore:()=>D});module.exports=T(H);var k=t=>{let e=t.stargazersCount,o=t.forksCount,i=t.watchersCount,c=Math.min(100,Math.log10(e+1)*20),n=Math.min(100,Math.log10(o+1)*25),s=Math.min(100,Math.log10(i+1)*30);return Math.round(c*.5+n*.35+s*.15)},C=(t,e)=>{if(t.isArchived)return 0;let o=new Date,i=new Date(t.pushedAt),c=o.getTime()-i.getTime(),n=Math.max(0,c/(1e3*60*60*24)),s=0;n<=1?s=100:n<=7?s=90:n<=30?s=80:n<=90?s=60:n<=180?s=40:n<=365&&(s=20);let u=50;if(e){let l=new Date;l.setFullYear(o.getFullYear()-1);let p=e.filter(f=>f.publishedAt&&new Date(f.publishedAt)>=l).length;u=Math.min(100,p*20)}return Math.round(s*.6+u*.4)},w=(t,e)=>{let o=e?e.length:0,i=Math.min(100,Math.log10(o+1)*50),c=t.topics.length>0?100:0,n=(t.description?50:0)+(t.homepage?50:0);return Math.round(i*.7+c*.15+n*.15)},y=t=>{if(t.isArchived)return 0;let e=t.stargazersCount+t.forksCount,o=100;if(t.openIssuesCount>0){let l=t.openIssuesCount/(e+10);o=Math.max(0,100-l*500)}let i=new Date(t.updatedAt),c=Date.now()-i.getTime(),n=Math.max(0,c/(1e3*60*60*24)),s=0;n<=30?s=100:n<=90?s=80:n<=180?s=60:n<=365?s=40:s=10;let u=t.isFork?50:100;return Math.round(o*.5+s*.3+u*.2)},D=(t,e)=>{let o=0,i=new Date(t.pushedAt),c=(Date.now()-i.getTime())/(1e3*60*60*24);c>365?o+=30:c>180?o+=20:c>90&&(o+=10);let n=e?e.length:1;n<=1?o+=30:n<=3?o+=20:n<=5&&(o+=10),t.isFork&&(o+=20);let s=t.stargazersCount+t.forksCount;return t.openIssuesCount>50&&t.openIssuesCount>s?o+=20:t.openIssuesCount>20&&(o+=10),Math.min(100,Math.round(o))},v=t=>{let{repository:e,contributors:o,releases:i}=t,c=y(e),n=k(e),s=C(e,i),u=w(e,o),l=D(e,o);return{overall:Math.round(c*.3+n*.25+s*.2+u*.15+(100-l)*.1),health:c,impact:n,activity:s,community:u,risk:l}},Y=t=>{let{repositories:e,npmPackages:o}=t;if(e.length===0)return{overall:0,health:0,impact:0,activity:0,community:0,risk:100};let i=e.reduce((r,a)=>r+a.stargazersCount,0),c=e.reduce((r,a)=>r+a.forksCount,0),n=e.reduce((r,a)=>r+a.watchersCount,0),s=Math.min(100,Math.log10(i+1)*20),u=Math.min(100,Math.log10(c+1)*25),l=Math.min(100,Math.log10(n+1)*30),p=s*.5+u*.35+l*.15;if(o&&o.length>0){let r=o.reduce((h,b)=>h+b.downloads,0),a=Math.min(100,Math.log10(r+1)*15);p=p*.8+a*.2}let f=Math.round(p),I=e.filter(r=>!r.isArchived),m=0,d=0,g=0,S=100;if(I.length>0){let r=I.map(a=>v({repository:a}));m=Math.round(r.reduce((a,h)=>a+h.health,0)/r.length),d=Math.round(r.reduce((a,h)=>a+h.activity,0)/r.length),g=Math.round(r.reduce((a,h)=>a+h.community,0)/r.length),S=Math.round(r.reduce((a,h)=>a+h.risk,0)/r.length)}return{overall:Math.round(m*.3+f*.25+d*.2+g*.15+(100-S)*.1),health:m,impact:f,activity:d,community:g,risk:S}};0&&(module.exports={calculateActivityScore,calculateCommunityScore,calculateHealthScore,calculateIdentityScore,calculateImpactScore,calculateRepositoryScore,calculateRiskScore});
1
+ "use strict";var U=Object.defineProperty;var rt=Object.getOwnPropertyDescriptor;var st=Object.getOwnPropertyNames;var at=Object.prototype.hasOwnProperty;var it=(o,t)=>{for(var e in t)U(o,e,{get:t[e],enumerable:!0})},ct=(o,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of st(t))!at.call(o,a)&&a!==e&&U(o,a,{get:()=>t[a],enumerable:!(s=rt(t,a))||s.enumerable});return o};var lt=o=>ct(U({},"__esModule",{value:!0}),o);var ut={};it(ut,{TOPIC_MAPPINGS:()=>v,calculateActivityScore:()=>L,calculateBadges:()=>z,calculateCommunityScore:()=>W,calculateContributorScore:()=>I,calculateHealthScore:()=>H,calculateIdentityScore:()=>Y,calculateImpactScore:()=>E,calculateInfluenceScore:()=>D,calculateKnowledgeScore:()=>O,calculateMaintainerScore:()=>$,calculateOrganizationScore:()=>T,calculatePublishingScore:()=>F,calculateRepositoryScore:()=>A,calculateRiskScore:()=>q,calculateSkills:()=>j,generateEvidence:()=>N,generateFactors:()=>P,matchTopic:()=>x});module.exports=lt(ut);var z=o=>{let{externalContributions:t,activeOrgsCount:e,totalStarsCount:s,totalNpmDownloads:a,npmUser:n,stackoverflowUser:i}=o,r=[],c=i?.reputation??0,l=t.length;return t.some(g=>g.targetRepoStars>=2e4)&&r.push("Framework Contributor"),e>=1&&r.push("OSS Founder"),n?.packages&&n.packages.length>=1&&r.push("Package Publisher"),c>=1e4&&r.push("StackOverflow Elite"),i&&i.answerCount>=100&&r.push("Community Helper"),i&&i.acceptanceRate>=80&&i.answerCount>=10&&r.push("High Acceptance"),t.filter(g=>g.type==="test").length>=5&&r.push("Test Champion"),t.some(g=>/\b(security|vuln|cve|fix|patch)\b/i.test(g.title))&&r.push("Security Champion"),l>=15&&r.push("Prodigious Contributor"),s>=1e3&&r.push("1k Stars Earned"),a>=1e6&&r.push("1M npm Downloads"),r};var I=o=>{let t={};for(let n of o)t[n.repoFullName]||(t[n.repoFullName]={repoFullName:n.repoFullName,prs:[],stars:n.targetRepoStars||0}),t[n.repoFullName].prs.push(n);let e=0,s=[];for(let n of Object.keys(t)){let i=t[n],{prs:r,stars:c}=i,l=Math.log10(c+1)/4,u=20+Math.round(Math.min(1,l)*20),m=[...r].sort((w,p)=>new Date(w.createdAt).getTime()-new Date(p.createdAt).getTime()),f=m[0],g=1;f.type==="docs"?g=.4:f.type==="test"?g=1.2:f.type==="chore"&&(g=.5);let b=Math.min(1,l)*g*15;b=b+Math.max(0,l-1)*10;let d=0;for(let w=1;w<m.length;w++){let p=m[w],h=1;p.type==="docs"?h=.4:p.type==="test"?h=1.2:p.type==="chore"&&(h=.5),d+=h*5}d=d*.5;let S=Math.min(u,Math.round(b+d));e+=S,s.push({repo:n,points:S})}return{score:Math.min(100,e),breakdown:s}};var N=o=>{let{activeRepos:t,externalContributions:e,organizations:s,contributorBreakdown:a,maintainerScore:n,sustainedCount:i,totalStarsCount:r,totalForksCount:c,totalNpmDownloads:l,soReputation:u}=o,m=[`${t.length} active repositories`,`${n}% average repository health`];if(i>0&&m.push(`${i} sustained maintenance projects`),t.length>0){let p=[...t].sort((h,y)=>y.stargazersCount-h.stargazersCount)[0];m.push(`Flagship project: ${p.name}`)}let f=e.length,g=[`${f} merged pull requests`];if(a.length>0){let p=[...a].sort((h,y)=>y.points-h.points)[0];g.push(`Top upstream: ${p.repo}`)}if(f>0){let p=e.filter(C=>C.type==="code").length,h=e.filter(C=>C.type==="docs").length,y=e.filter(C=>C.type==="test").length;g.push(`Classified: ${p} code, ${h} docs, ${y} tests`)}let b=[`${r.toLocaleString()} total stargazers`,`${c.toLocaleString()} repository forks`];l>0&&b.push(`${l.toLocaleString()} weekly npm downloads`),u>0&&b.push(`Stack Overflow reputation: ${u.toLocaleString()}`);let S=[`${s.filter(p=>(p.publicRepos||0)>0||(p.followers||0)>0).length} managed organizations`,`${s.reduce((p,h)=>p+(h.publicRepos||0),0)} collective repositories`],w=s.reduce((p,h)=>p+(h.followers||0),0);return w>0&&S.push(`${w.toLocaleString()} total organization followers`),{maintainer:m,contributor:g,influence:b,organization:S}},P=o=>{let{allRepos:t,externalContributions:e,organizations:s,contributorBreakdown:a,maintainerScore:n,sustainedCount:i,totalStarsCount:r,totalNpmDownloads:c,soReputation:l,stackoverflowUser:u}=o,m=e.length,f=e.some(k=>k.targetRepoStars>=2e4),g=[];n>=80&&g.push("Active flagship projects with excellent health"),i>0&&g.push("Sustained long-term repository maintenance"),t.filter(k=>k.isArchived).length>0&&g.push("Some repositories are archived/inactive"),g.length===0&&g.push("Moderate repository activity and health");let d=[];m>0&&d.push(`+ ${m} merged pull requests`),f&&d.push("+ PRs merged into high-importance frameworks");let w=[...a].sort((k,M)=>M.points-k.points)[0];w&&e.filter(M=>M.repoFullName===w.repo).length>2&&d.push(`+ Repeat contributor bonus for ${w.repo}`),m===0?d.push("- No external repository contributions found"):e.some(M=>(Date.now()-new Date(M.createdAt).getTime())/864e5<90)||d.push("- No recent upstream activity (past 90 days)");let p=[];r>=500&&p.push(`+ High community interest (${r} stars)`),c>=1e4&&p.push(`+ Strong download footprint (${c.toLocaleString()} weekly downloads)`),l>=1e3&&p.push(`+ High developer authority (${l.toLocaleString()} Stack Overflow reputation)`),u||p.push("- No Stack Overflow activity linked"),p.length===0&&p.push("Growing library adoption and ecosystem footprint");let h=s.filter(k=>(k.publicRepos||0)>0||(k.followers||0)>0).length,y=s.reduce((k,M)=>k+(M.followers||0),0),C=[];return h>0&&C.push(`+ Active leadership in ${h} organizations`),y>100&&C.push(`+ High organization follower presence (${y})`),h===0&&C.push("- No active organization leadership detected"),{maintainer:g,contributor:d,influence:p,organization:C}};var D=(o,t,e,s)=>{let a=Math.log10(o+1)*20,n=Math.log10(t+1)*20,i=Math.min(100,Math.round(a+n)),r=e>0?Math.min(15,Math.log10(e+1)*2.5):0,c=s>0?Math.min(15,Math.log10(s+1)*2.5):0;return{score:Math.min(100,Math.round(i+r+c)),githubBase:i,npmBonus:r,soBonus:c}};var O=o=>{if(!o)return null;let t=o.reputation??0,e=Math.min(100,Math.log10(t+1)*20),s=Math.min(100,o.answerCount*2),a=o.acceptanceRate||0;return{score:Math.min(100,Math.round(e*.5+s*.3+a*.2)),breakdown:{reputation:Math.round(e),answers:Math.round(s),acceptance:Math.round(a)}}};var E=o=>{let t=o.stargazersCount,e=o.forksCount,s=o.watchersCount,a=Math.min(100,Math.log10(t+1)*20),n=Math.min(100,Math.log10(e+1)*25),i=Math.min(100,Math.log10(s+1)*30);return Math.round(a*.5+n*.35+i*.15)},L=(o,t)=>{if(o.isArchived)return 0;let e=new Date,s=new Date(o.pushedAt),a=e.getTime()-s.getTime(),n=Math.max(0,a/(1e3*60*60*24)),i=0;n<=1?i=100:n<=7?i=90:n<=30?i=80:n<=90?i=60:n<=180?i=40:n<=365&&(i=20);let r=50;if(t){let c=new Date;c.setFullYear(e.getFullYear()-1);let l=t.filter(u=>u.publishedAt&&new Date(u.publishedAt)>=c).length;r=Math.min(100,l*20)}return Math.round(i*.6+r*.4)},W=(o,t)=>{let e=t&&t.length>0?t.length:Math.max(1,Math.min(100,Math.floor(Math.sqrt(o.stargazersCount)))),s=Math.min(100,Math.log10(e+1)*50),a=o.topics.length>0?100:0,n=(o.description?50:0)+(o.homepage?50:0);return Math.round(s*.7+a*.15+n*.15)},H=o=>{if(o.isArchived)return 0;let t=o.stargazersCount+o.forksCount,e=100;if(o.openIssuesCount>0){let c=o.openIssuesCount/(t+10);e=Math.max(0,100-c*500)}let s=new Date(o.updatedAt),a=Date.now()-s.getTime(),n=Math.max(0,a/(1e3*60*60*24)),i=0;n<=30?i=100:n<=90?i=80:n<=180?i=60:n<=365?i=40:i=10;let r=o.isFork?50:100;return Math.round(e*.5+i*.3+r*.2)},q=(o,t)=>{let e=0,s=new Date(o.pushedAt),a=(Date.now()-s.getTime())/(1e3*60*60*24);a>365?e+=30:a>180?e+=20:a>90&&(e+=10);let n=t&&t.length>0?t.length:Math.max(1,Math.min(100,Math.floor(Math.sqrt(o.stargazersCount))));n<=1?e+=30:n<=3?e+=20:n<=5&&(e+=10),o.isFork&&(e+=20);let i=o.stargazersCount+o.forksCount;return o.openIssuesCount>50&&o.openIssuesCount>i?e+=20:o.openIssuesCount>20&&(e+=10),Math.min(100,Math.round(e))},A=o=>{let{repository:t,contributors:e,releases:s}=o,a=H(t),n=E(t),i=L(t,s),r=W(t,e),c=q(t,e);return{overall:Math.round(a*.3+n*.25+i*.2+r*.15+(100-c)*.1),health:a,impact:n,activity:i,community:r,risk:c}};var $=(o,t)=>{let e=o.filter(l=>!l.isArchived),s=0,a=0,n=0;for(let l of e){let m=A({repository:l}).health,f=(Date.now()-new Date(l.pushedAt).getTime())/(1e3*60*60*24),b=(Date.now()-new Date(l.createdAt).getTime())/(1e3*60*60*24)>365&&f<90,d=b?Math.min(100,m+10):m;b&&n++;let S=Math.log10(l.stargazersCount+l.forksCount+1)+1;a+=d*S,s+=S}let i=s>0?Math.round(a/s):0,r=0;return t>0&&(r=Math.min(10,Math.log10(t+1)*1.5+2)),{score:Math.min(100,Math.round(i+r)),githubBase:i,npmBonus:r,sustainedCount:n}};var T=o=>{let t=o.filter(n=>(n.publicRepos||0)>0||(n.followers||0)>0),e=t.length,s=0;for(let n of t){let i=n.stars||0,r=n.followers||0,c=n.publicRepos||0,l=Math.log10(r+c+i+1)*8;s+=l}return{score:Math.min(100,Math.round(e*20+s)),activeCount:e}};var F=o=>{if(!o)return null;let t=o.totalWeeklyDownloads??0,e=Math.min(100,Math.log10(t+1)*15),s=Math.min(100,o.activePackagesCount*10),a=o.isVerifiedPublisher?100:0;return{score:Math.min(100,Math.round(e*.5+s*.3+a*.2)),breakdown:{downloads:Math.round(e),packages:Math.round(s),verified:a}}};var v={React:["react","reactjs","jsx","react-dom","remix","nextjs","next.js"],TypeScript:["typescript","ts"],"Node.js":["nodejs","node","express","koa","npm","yarn","pnpm","nest","nestjs"],JavaScript:["javascript","js","ecmascript"],Python:["python","py","django","flask","fastapi","numpy","pandas"],Rust:["rust","cargo","wasm-bindgen"],"Next.js":["nextjs","next.js"],Vue:["vue","vuejs","nuxt","nuxtjs"],Docker:["docker","kubernetes","k8s","devops","aws","gcp"],Database:["sql","postgres","postgresql","mysql","mongodb","redis","sqlite","prisma"],CSS:["css","sass","scss","tailwind","tailwindcss","postcss"]},x=o=>{let t=o.toLowerCase().replace(/[^a-z0-9]/g,"");for(let[e,s]of Object.entries(v)){if(e.toLowerCase()===t)return e;for(let a of s)if(a.toLowerCase().replace(/[^a-z0-9]/g,"")===t)return e}return null};var j=o=>{let{repositories:t,externalContributions:e,npmUser:s,stackoverflowUser:a}=o,n={};for(let r of Object.keys(v))n[r]={githubStars:0,githubPrs:0,npmDownloads:0,npmPackages:0,stackoverflowScore:0,stackoverflowAnswers:0};for(let r of t){let c=[r.language,...r.topics||[]].filter(Boolean),l=new Set;for(let u of c){let m=x(u);m&&l.add(m)}for(let u of l)n[u].githubStars+=r.stargazersCount}for(let r of e){let c=`${r.repoFullName} ${r.title} ${r.labels.join(" ")}`,l=new Set;for(let[u,m]of Object.entries(v))for(let f of m)new RegExp(`\\b${f}\\b`,"i").test(c)&&l.add(u);for(let u of l)n[u].githubPrs+=1}if(s?.packages)for(let r of s.packages){let c=`${r.name} ${r.description||""} ${r.categories.join(" ")}`,l=new Set;for(let[u,m]of Object.entries(v))for(let f of m)new RegExp(`\\b${f}\\b`,"i").test(c)&&l.add(u);for(let u of l)n[u].npmPackages+=1,n[u].npmDownloads+=r.weeklyDownloads}if(a?.topTags)for(let r of a.topTags){let c=x(r.name);c&&(n[c].stackoverflowScore+=r.score,n[c].stackoverflowAnswers+=r.count)}let i=[];for(let[r,c]of Object.entries(n)){let l=Math.min(40,Math.log10(c.githubStars+1)*10),u=Math.min(25,c.githubPrs*2.5),m=Math.min(20,c.npmPackages*5),f=Math.min(30,Math.log10(c.npmDownloads+1)*5),g=Math.min(35,Math.log10(c.stackoverflowScore+1)*10),b=Math.min(25,c.stackoverflowAnswers*.5),d=l+u+m+f+g+b,S=Math.round(Math.min(100,d));S>0&&i.push({topic:r,score:S,evidence:c})}return i.sort((r,c)=>c.score-r.score),i};var Y=o=>{let{repositories:t=[],npmUser:e=null,stackoverflowUser:s=null,externalContributions:a=[],organizations:n=[]}=o,i=t.reduce((R,B)=>R+B.stargazersCount,0),r=t.reduce((R,B)=>R+B.forksCount,0),c=e?.totalWeeklyDownloads??0,l=s?.reputation??0;if(t.length===0&&a.length===0&&!e&&!s&&n.length===0)return{overall:0,maintainer:0,contributor:0,organization:0,influence:0,confidence:"Low",evidence:{maintainer:[],contributor:[],influence:[],organization:[]},factors:{maintainer:[],contributor:[],influence:[],organization:[]},badges:[],skills:[]};let u=$(t,c),m=I(a),f=T(n),g=D(i,r,c,l),b=t.length,d=a.length,S="Low";b>=10||d>=15||c>=5e3||l>=1e3?S="High":(b>=3||d>=3||l>=100)&&(S="Medium");let w=u.githubBase,p=m.score,h=f.score,y=g.githubBase,C=0;f.activeCount>0?C=Math.round(w*.35+p*.3+h*.15+y*.2):C=Math.round(w*.45+p*.35+y*.2);let k=F(e),M=O(s),K=1+(100-C)/100,_=8,V=8,J=k?k.score/100*_*K:0,Q=M?M.score/100*V*K:0,X=Math.min(100,Math.round(C+J+Q)),Z=t.filter(R=>!R.isArchived),tt=z({externalContributions:a,activeOrgsCount:f.activeCount,totalStarsCount:i,totalNpmDownloads:c,npmUser:e,stackoverflowUser:s}),G={activeRepos:Z,allRepos:t,externalContributions:a,organizations:n,contributorBreakdown:m.breakdown,maintainerScore:u.score,sustainedCount:u.sustainedCount,totalStarsCount:i,totalForksCount:r,totalNpmDownloads:c,soReputation:l,npmUser:e,stackoverflowUser:s},et=N(G),ot=P(G),nt=j({repositories:t,externalContributions:a,npmUser:e,stackoverflowUser:s});return{overall:X,maintainer:u.score,contributor:m.score,organization:h,influence:g.score,confidence:S,evidence:et,factors:ot,badges:tt,skills:nt}};0&&(module.exports={TOPIC_MAPPINGS,calculateActivityScore,calculateBadges,calculateCommunityScore,calculateContributorScore,calculateHealthScore,calculateIdentityScore,calculateImpactScore,calculateInfluenceScore,calculateKnowledgeScore,calculateMaintainerScore,calculateOrganizationScore,calculatePublishingScore,calculateRepositoryScore,calculateRiskScore,calculateSkills,generateEvidence,generateFactors,matchTopic});
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- var k=t=>{let o=t.stargazersCount,e=t.forksCount,i=t.watchersCount,a=Math.min(100,Math.log10(o+1)*20),n=Math.min(100,Math.log10(e+1)*25),s=Math.min(100,Math.log10(i+1)*30);return Math.round(a*.5+n*.35+s*.15)},C=(t,o)=>{if(t.isArchived)return 0;let e=new Date,i=new Date(t.pushedAt),a=e.getTime()-i.getTime(),n=Math.max(0,a/(1e3*60*60*24)),s=0;n<=1?s=100:n<=7?s=90:n<=30?s=80:n<=90?s=60:n<=180?s=40:n<=365&&(s=20);let u=50;if(o){let l=new Date;l.setFullYear(e.getFullYear()-1);let p=o.filter(f=>f.publishedAt&&new Date(f.publishedAt)>=l).length;u=Math.min(100,p*20)}return Math.round(s*.6+u*.4)},w=(t,o)=>{let e=o?o.length:0,i=Math.min(100,Math.log10(e+1)*50),a=t.topics.length>0?100:0,n=(t.description?50:0)+(t.homepage?50:0);return Math.round(i*.7+a*.15+n*.15)},y=t=>{if(t.isArchived)return 0;let o=t.stargazersCount+t.forksCount,e=100;if(t.openIssuesCount>0){let l=t.openIssuesCount/(o+10);e=Math.max(0,100-l*500)}let i=new Date(t.updatedAt),a=Date.now()-i.getTime(),n=Math.max(0,a/(1e3*60*60*24)),s=0;n<=30?s=100:n<=90?s=80:n<=180?s=60:n<=365?s=40:s=10;let u=t.isFork?50:100;return Math.round(e*.5+s*.3+u*.2)},D=(t,o)=>{let e=0,i=new Date(t.pushedAt),a=(Date.now()-i.getTime())/(1e3*60*60*24);a>365?e+=30:a>180?e+=20:a>90&&(e+=10);let n=o?o.length:1;n<=1?e+=30:n<=3?e+=20:n<=5&&(e+=10),t.isFork&&(e+=20);let s=t.stargazersCount+t.forksCount;return t.openIssuesCount>50&&t.openIssuesCount>s?e+=20:t.openIssuesCount>20&&(e+=10),Math.min(100,Math.round(e))},v=t=>{let{repository:o,contributors:e,releases:i}=t,a=y(o),n=k(o),s=C(o,i),u=w(o,e),l=D(o,e);return{overall:Math.round(a*.3+n*.25+s*.2+u*.15+(100-l)*.1),health:a,impact:n,activity:s,community:u,risk:l}},x=t=>{let{repositories:o,npmPackages:e}=t;if(o.length===0)return{overall:0,health:0,impact:0,activity:0,community:0,risk:100};let i=o.reduce((c,r)=>c+r.stargazersCount,0),a=o.reduce((c,r)=>c+r.forksCount,0),n=o.reduce((c,r)=>c+r.watchersCount,0),s=Math.min(100,Math.log10(i+1)*20),u=Math.min(100,Math.log10(a+1)*25),l=Math.min(100,Math.log10(n+1)*30),p=s*.5+u*.35+l*.15;if(e&&e.length>0){let c=e.reduce((h,I)=>h+I.downloads,0),r=Math.min(100,Math.log10(c+1)*15);p=p*.8+r*.2}let f=Math.round(p),M=o.filter(c=>!c.isArchived),m=0,d=0,g=0,S=100;if(M.length>0){let c=M.map(r=>v({repository:r}));m=Math.round(c.reduce((r,h)=>r+h.health,0)/c.length),d=Math.round(c.reduce((r,h)=>r+h.activity,0)/c.length),g=Math.round(c.reduce((r,h)=>r+h.community,0)/c.length),S=Math.round(c.reduce((r,h)=>r+h.risk,0)/c.length)}return{overall:Math.round(m*.3+f*.25+d*.2+g*.15+(100-S)*.1),health:m,impact:f,activity:d,community:g,risk:S}};export{C as calculateActivityScore,w as calculateCommunityScore,y as calculateHealthScore,x as calculateIdentityScore,k as calculateImpactScore,v as calculateRepositoryScore,D as calculateRiskScore};
1
+ var I=r=>{let{externalContributions:o,activeOrgsCount:e,totalStarsCount:s,totalNpmDownloads:c,npmUser:t,stackoverflowUser:a}=r,n=[],i=a?.reputation??0,l=o.length;return o.some(g=>g.targetRepoStars>=2e4)&&n.push("Framework Contributor"),e>=1&&n.push("OSS Founder"),t?.packages&&t.packages.length>=1&&n.push("Package Publisher"),i>=1e4&&n.push("StackOverflow Elite"),a&&a.answerCount>=100&&n.push("Community Helper"),a&&a.acceptanceRate>=80&&a.answerCount>=10&&n.push("High Acceptance"),o.filter(g=>g.type==="test").length>=5&&n.push("Test Champion"),o.some(g=>/\b(security|vuln|cve|fix|patch)\b/i.test(g.title))&&n.push("Security Champion"),l>=15&&n.push("Prodigious Contributor"),s>=1e3&&n.push("1k Stars Earned"),c>=1e6&&n.push("1M npm Downloads"),n};var N=r=>{let o={};for(let t of r)o[t.repoFullName]||(o[t.repoFullName]={repoFullName:t.repoFullName,prs:[],stars:t.targetRepoStars||0}),o[t.repoFullName].prs.push(t);let e=0,s=[];for(let t of Object.keys(o)){let a=o[t],{prs:n,stars:i}=a,l=Math.log10(i+1)/4,u=20+Math.round(Math.min(1,l)*20),m=[...n].sort((w,p)=>new Date(w.createdAt).getTime()-new Date(p.createdAt).getTime()),f=m[0],g=1;f.type==="docs"?g=.4:f.type==="test"?g=1.2:f.type==="chore"&&(g=.5);let b=Math.min(1,l)*g*15;b=b+Math.max(0,l-1)*10;let d=0;for(let w=1;w<m.length;w++){let p=m[w],h=1;p.type==="docs"?h=.4:p.type==="test"?h=1.2:p.type==="chore"&&(h=.5),d+=h*5}d=d*.5;let S=Math.min(u,Math.round(b+d));e+=S,s.push({repo:t,points:S})}return{score:Math.min(100,e),breakdown:s}};var P=r=>{let{activeRepos:o,externalContributions:e,organizations:s,contributorBreakdown:c,maintainerScore:t,sustainedCount:a,totalStarsCount:n,totalForksCount:i,totalNpmDownloads:l,soReputation:u}=r,m=[`${o.length} active repositories`,`${t}% average repository health`];if(a>0&&m.push(`${a} sustained maintenance projects`),o.length>0){let p=[...o].sort((h,y)=>y.stargazersCount-h.stargazersCount)[0];m.push(`Flagship project: ${p.name}`)}let f=e.length,g=[`${f} merged pull requests`];if(c.length>0){let p=[...c].sort((h,y)=>y.points-h.points)[0];g.push(`Top upstream: ${p.repo}`)}if(f>0){let p=e.filter(C=>C.type==="code").length,h=e.filter(C=>C.type==="docs").length,y=e.filter(C=>C.type==="test").length;g.push(`Classified: ${p} code, ${h} docs, ${y} tests`)}let b=[`${n.toLocaleString()} total stargazers`,`${i.toLocaleString()} repository forks`];l>0&&b.push(`${l.toLocaleString()} weekly npm downloads`),u>0&&b.push(`Stack Overflow reputation: ${u.toLocaleString()}`);let S=[`${s.filter(p=>(p.publicRepos||0)>0||(p.followers||0)>0).length} managed organizations`,`${s.reduce((p,h)=>p+(h.publicRepos||0),0)} collective repositories`],w=s.reduce((p,h)=>p+(h.followers||0),0);return w>0&&S.push(`${w.toLocaleString()} total organization followers`),{maintainer:m,contributor:g,influence:b,organization:S}},D=r=>{let{allRepos:o,externalContributions:e,organizations:s,contributorBreakdown:c,maintainerScore:t,sustainedCount:a,totalStarsCount:n,totalNpmDownloads:i,soReputation:l,stackoverflowUser:u}=r,m=e.length,f=e.some(k=>k.targetRepoStars>=2e4),g=[];t>=80&&g.push("Active flagship projects with excellent health"),a>0&&g.push("Sustained long-term repository maintenance"),o.filter(k=>k.isArchived).length>0&&g.push("Some repositories are archived/inactive"),g.length===0&&g.push("Moderate repository activity and health");let d=[];m>0&&d.push(`+ ${m} merged pull requests`),f&&d.push("+ PRs merged into high-importance frameworks");let w=[...c].sort((k,M)=>M.points-k.points)[0];w&&e.filter(M=>M.repoFullName===w.repo).length>2&&d.push(`+ Repeat contributor bonus for ${w.repo}`),m===0?d.push("- No external repository contributions found"):e.some(M=>(Date.now()-new Date(M.createdAt).getTime())/864e5<90)||d.push("- No recent upstream activity (past 90 days)");let p=[];n>=500&&p.push(`+ High community interest (${n} stars)`),i>=1e4&&p.push(`+ Strong download footprint (${i.toLocaleString()} weekly downloads)`),l>=1e3&&p.push(`+ High developer authority (${l.toLocaleString()} Stack Overflow reputation)`),u||p.push("- No Stack Overflow activity linked"),p.length===0&&p.push("Growing library adoption and ecosystem footprint");let h=s.filter(k=>(k.publicRepos||0)>0||(k.followers||0)>0).length,y=s.reduce((k,M)=>k+(M.followers||0),0),C=[];return h>0&&C.push(`+ Active leadership in ${h} organizations`),y>100&&C.push(`+ High organization follower presence (${y})`),h===0&&C.push("- No active organization leadership detected"),{maintainer:g,contributor:d,influence:p,organization:C}};var O=(r,o,e,s)=>{let c=Math.log10(r+1)*20,t=Math.log10(o+1)*20,a=Math.min(100,Math.round(c+t)),n=e>0?Math.min(15,Math.log10(e+1)*2.5):0,i=s>0?Math.min(15,Math.log10(s+1)*2.5):0;return{score:Math.min(100,Math.round(a+n+i)),githubBase:a,npmBonus:n,soBonus:i}};var A=r=>{if(!r)return null;let o=r.reputation??0,e=Math.min(100,Math.log10(o+1)*20),s=Math.min(100,r.answerCount*2),c=r.acceptanceRate||0;return{score:Math.min(100,Math.round(e*.5+s*.3+c*.2)),breakdown:{reputation:Math.round(e),answers:Math.round(s),acceptance:Math.round(c)}}};var L=r=>{let o=r.stargazersCount,e=r.forksCount,s=r.watchersCount,c=Math.min(100,Math.log10(o+1)*20),t=Math.min(100,Math.log10(e+1)*25),a=Math.min(100,Math.log10(s+1)*30);return Math.round(c*.5+t*.35+a*.15)},W=(r,o)=>{if(r.isArchived)return 0;let e=new Date,s=new Date(r.pushedAt),c=e.getTime()-s.getTime(),t=Math.max(0,c/(1e3*60*60*24)),a=0;t<=1?a=100:t<=7?a=90:t<=30?a=80:t<=90?a=60:t<=180?a=40:t<=365&&(a=20);let n=50;if(o){let i=new Date;i.setFullYear(e.getFullYear()-1);let l=o.filter(u=>u.publishedAt&&new Date(u.publishedAt)>=i).length;n=Math.min(100,l*20)}return Math.round(a*.6+n*.4)},H=(r,o)=>{let e=o&&o.length>0?o.length:Math.max(1,Math.min(100,Math.floor(Math.sqrt(r.stargazersCount)))),s=Math.min(100,Math.log10(e+1)*50),c=r.topics.length>0?100:0,t=(r.description?50:0)+(r.homepage?50:0);return Math.round(s*.7+c*.15+t*.15)},q=r=>{if(r.isArchived)return 0;let o=r.stargazersCount+r.forksCount,e=100;if(r.openIssuesCount>0){let i=r.openIssuesCount/(o+10);e=Math.max(0,100-i*500)}let s=new Date(r.updatedAt),c=Date.now()-s.getTime(),t=Math.max(0,c/(1e3*60*60*24)),a=0;t<=30?a=100:t<=90?a=80:t<=180?a=60:t<=365?a=40:a=10;let n=r.isFork?50:100;return Math.round(e*.5+a*.3+n*.2)},K=(r,o)=>{let e=0,s=new Date(r.pushedAt),c=(Date.now()-s.getTime())/(1e3*60*60*24);c>365?e+=30:c>180?e+=20:c>90&&(e+=10);let t=o&&o.length>0?o.length:Math.max(1,Math.min(100,Math.floor(Math.sqrt(r.stargazersCount))));t<=1?e+=30:t<=3?e+=20:t<=5&&(e+=10),r.isFork&&(e+=20);let a=r.stargazersCount+r.forksCount;return r.openIssuesCount>50&&r.openIssuesCount>a?e+=20:r.openIssuesCount>20&&(e+=10),Math.min(100,Math.round(e))},$=r=>{let{repository:o,contributors:e,releases:s}=r,c=q(o),t=L(o),a=W(o,s),n=H(o,e),i=K(o,e);return{overall:Math.round(c*.3+t*.25+a*.2+n*.15+(100-i)*.1),health:c,impact:t,activity:a,community:n,risk:i}};var T=(r,o)=>{let e=r.filter(l=>!l.isArchived),s=0,c=0,t=0;for(let l of e){let m=$({repository:l}).health,f=(Date.now()-new Date(l.pushedAt).getTime())/(1e3*60*60*24),b=(Date.now()-new Date(l.createdAt).getTime())/(1e3*60*60*24)>365&&f<90,d=b?Math.min(100,m+10):m;b&&t++;let S=Math.log10(l.stargazersCount+l.forksCount+1)+1;c+=d*S,s+=S}let a=s>0?Math.round(c/s):0,n=0;return o>0&&(n=Math.min(10,Math.log10(o+1)*1.5+2)),{score:Math.min(100,Math.round(a+n)),githubBase:a,npmBonus:n,sustainedCount:t}};var F=r=>{let o=r.filter(t=>(t.publicRepos||0)>0||(t.followers||0)>0),e=o.length,s=0;for(let t of o){let a=t.stars||0,n=t.followers||0,i=t.publicRepos||0,l=Math.log10(n+i+a+1)*8;s+=l}return{score:Math.min(100,Math.round(e*20+s)),activeCount:e}};var j=r=>{if(!r)return null;let o=r.totalWeeklyDownloads??0,e=Math.min(100,Math.log10(o+1)*15),s=Math.min(100,r.activePackagesCount*10),c=r.isVerifiedPublisher?100:0;return{score:Math.min(100,Math.round(e*.5+s*.3+c*.2)),breakdown:{downloads:Math.round(e),packages:Math.round(s),verified:c}}};var v={React:["react","reactjs","jsx","react-dom","remix","nextjs","next.js"],TypeScript:["typescript","ts"],"Node.js":["nodejs","node","express","koa","npm","yarn","pnpm","nest","nestjs"],JavaScript:["javascript","js","ecmascript"],Python:["python","py","django","flask","fastapi","numpy","pandas"],Rust:["rust","cargo","wasm-bindgen"],"Next.js":["nextjs","next.js"],Vue:["vue","vuejs","nuxt","nuxtjs"],Docker:["docker","kubernetes","k8s","devops","aws","gcp"],Database:["sql","postgres","postgresql","mysql","mongodb","redis","sqlite","prisma"],CSS:["css","sass","scss","tailwind","tailwindcss","postcss"]},x=r=>{let o=r.toLowerCase().replace(/[^a-z0-9]/g,"");for(let[e,s]of Object.entries(v)){if(e.toLowerCase()===o)return e;for(let c of s)if(c.toLowerCase().replace(/[^a-z0-9]/g,"")===o)return e}return null};var B=r=>{let{repositories:o,externalContributions:e,npmUser:s,stackoverflowUser:c}=r,t={};for(let n of Object.keys(v))t[n]={githubStars:0,githubPrs:0,npmDownloads:0,npmPackages:0,stackoverflowScore:0,stackoverflowAnswers:0};for(let n of o){let i=[n.language,...n.topics||[]].filter(Boolean),l=new Set;for(let u of i){let m=x(u);m&&l.add(m)}for(let u of l)t[u].githubStars+=n.stargazersCount}for(let n of e){let i=`${n.repoFullName} ${n.title} ${n.labels.join(" ")}`,l=new Set;for(let[u,m]of Object.entries(v))for(let f of m)new RegExp(`\\b${f}\\b`,"i").test(i)&&l.add(u);for(let u of l)t[u].githubPrs+=1}if(s?.packages)for(let n of s.packages){let i=`${n.name} ${n.description||""} ${n.categories.join(" ")}`,l=new Set;for(let[u,m]of Object.entries(v))for(let f of m)new RegExp(`\\b${f}\\b`,"i").test(i)&&l.add(u);for(let u of l)t[u].npmPackages+=1,t[u].npmDownloads+=n.weeklyDownloads}if(c?.topTags)for(let n of c.topTags){let i=x(n.name);i&&(t[i].stackoverflowScore+=n.score,t[i].stackoverflowAnswers+=n.count)}let a=[];for(let[n,i]of Object.entries(t)){let l=Math.min(40,Math.log10(i.githubStars+1)*10),u=Math.min(25,i.githubPrs*2.5),m=Math.min(20,i.npmPackages*5),f=Math.min(30,Math.log10(i.npmDownloads+1)*5),g=Math.min(35,Math.log10(i.stackoverflowScore+1)*10),b=Math.min(25,i.stackoverflowAnswers*.5),d=l+u+m+f+g+b,S=Math.round(Math.min(100,d));S>0&&a.push({topic:n,score:S,evidence:i})}return a.sort((n,i)=>i.score-n.score),a};var ot=r=>{let{repositories:o=[],npmUser:e=null,stackoverflowUser:s=null,externalContributions:c=[],organizations:t=[]}=r,a=o.reduce((R,z)=>R+z.stargazersCount,0),n=o.reduce((R,z)=>R+z.forksCount,0),i=e?.totalWeeklyDownloads??0,l=s?.reputation??0;if(o.length===0&&c.length===0&&!e&&!s&&t.length===0)return{overall:0,maintainer:0,contributor:0,organization:0,influence:0,confidence:"Low",evidence:{maintainer:[],contributor:[],influence:[],organization:[]},factors:{maintainer:[],contributor:[],influence:[],organization:[]},badges:[],skills:[]};let u=T(o,i),m=N(c),f=F(t),g=O(a,n,i,l),b=o.length,d=c.length,S="Low";b>=10||d>=15||i>=5e3||l>=1e3?S="High":(b>=3||d>=3||l>=100)&&(S="Medium");let w=u.githubBase,p=m.score,h=f.score,y=g.githubBase,C=0;f.activeCount>0?C=Math.round(w*.35+p*.3+h*.15+y*.2):C=Math.round(w*.45+p*.35+y*.2);let k=j(e),M=A(s),U=1+(100-C)/100,G=8,Y=8,_=k?k.score/100*G*U:0,V=M?M.score/100*Y*U:0,J=Math.min(100,Math.round(C+_+V)),Q=o.filter(R=>!R.isArchived),X=I({externalContributions:c,activeOrgsCount:f.activeCount,totalStarsCount:a,totalNpmDownloads:i,npmUser:e,stackoverflowUser:s}),E={activeRepos:Q,allRepos:o,externalContributions:c,organizations:t,contributorBreakdown:m.breakdown,maintainerScore:u.score,sustainedCount:u.sustainedCount,totalStarsCount:a,totalForksCount:n,totalNpmDownloads:i,soReputation:l,npmUser:e,stackoverflowUser:s},Z=P(E),tt=D(E),et=B({repositories:o,externalContributions:c,npmUser:e,stackoverflowUser:s});return{overall:J,maintainer:u.score,contributor:m.score,organization:h,influence:g.score,confidence:S,evidence:Z,factors:tt,badges:X,skills:et}};export{v as TOPIC_MAPPINGS,W as calculateActivityScore,I as calculateBadges,H as calculateCommunityScore,N as calculateContributorScore,q as calculateHealthScore,ot as calculateIdentityScore,L as calculateImpactScore,O as calculateInfluenceScore,A as calculateKnowledgeScore,T as calculateMaintainerScore,F as calculateOrganizationScore,j as calculatePublishingScore,$ as calculateRepositoryScore,K as calculateRiskScore,B as calculateSkills,P as generateEvidence,D as generateFactors,x as matchTopic};
package/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "name": "@ossintel/scoring",
3
3
  "author": "Mayank Kumar Chaudhari <https://mayankchaudhari.com>",
4
4
  "private": false,
5
- "version": "0.0.0",
6
- "description": "Deterministic scoring engine for calculating OSS health, impact, risk, activity, and community metrics from normalized repository and ecosystem data.",
5
+ "version": "0.1.0",
6
+ "description": "Mathematical, deterministic metrics calculator to evaluate open-source software health, impact, activity, community adoption, and risk profiles.",
7
7
  "license": "MIT",
8
8
  "main": "./dist/index.js",
9
9
  "module": "./dist/index.mjs",
@@ -33,15 +33,19 @@
33
33
  "dist/**"
34
34
  ],
35
35
  "dependencies": {
36
- "@ossintel/github-normalizer": "0.0.0"
36
+ "@ossintel/github-normalizer": "0.1.0",
37
+ "@ossintel/npm": "0.0.1",
38
+ "@ossintel/stackoverflow": "0.0.1"
37
39
  },
38
40
  "devDependencies": {
39
41
  "@types/node": "latest",
40
42
  "tsup": "latest",
41
- "typescript": "latest"
43
+ "typescript": "^6.0.3"
42
44
  },
43
45
  "forge": {
44
- "aliases": [],
46
+ "aliases": [
47
+ "ossintel"
48
+ ],
45
49
  "icon": "LibraryBig",
46
50
  "description": ""
47
51
  },
@@ -52,7 +56,12 @@
52
56
  }
53
57
  ],
54
58
  "keywords": [
55
- "@ossintel/scoring",
59
+ "deterministic-scoring",
60
+ "oss-health",
61
+ "software-metrics",
62
+ "risk-calculation",
63
+ "developer-impact",
64
+ "math-engine",
56
65
  "turboforge"
57
66
  ],
58
67
  "scripts": {