@oss-autopilot/core 0.48.0 → 0.50.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.
@@ -21,6 +21,8 @@ export interface ViabilityScoreParams {
21
21
  mergedPRCount: number;
22
22
  orgHasMergedPRs: boolean;
23
23
  repoQualityBonus?: number;
24
+ /** True when the repo matches one of the user's preferred project categories. */
25
+ matchesPreferredCategory?: boolean;
24
26
  }
25
27
  /**
26
28
  * Calculate viability score for an issue (0-100 scale)
@@ -33,6 +35,7 @@ export interface ViabilityScoreParams {
33
35
  * - +15 for freshness (recently updated)
34
36
  * - +10 for contribution guidelines
35
37
  * - +5 for org affinity (merged PRs in same org)
38
+ * - +5 for category preference (matches user's project categories)
36
39
  * - -30 if existing PR
37
40
  * - -20 if claimed
38
41
  * - -15 if closed-without-merge history with no merges
@@ -37,6 +37,7 @@ export function calculateRepoQualityBonus(stargazersCount, forksCount) {
37
37
  * - +15 for freshness (recently updated)
38
38
  * - +10 for contribution guidelines
39
39
  * - +5 for org affinity (merged PRs in same org)
40
+ * - +5 for category preference (matches user's project categories)
40
41
  * - -30 if existing PR
41
42
  * - -20 if claimed
42
43
  * - -15 if closed-without-merge history with no merges
@@ -75,6 +76,10 @@ export function calculateViabilityScore(params) {
75
76
  if (params.orgHasMergedPRs) {
76
77
  score += 5;
77
78
  }
79
+ // Category preference bonus (+5) — repo matches user's preferred project categories
80
+ if (params.matchesPreferredCategory) {
81
+ score += 5;
82
+ }
78
83
  // Penalty for existing PR (-30)
79
84
  if (params.hasExistingPR) {
80
85
  score -= 30;
@@ -10,6 +10,7 @@ import { ValidationError, errorMessage, isRateLimitError } from './errors.js';
10
10
  import { warn } from './logger.js';
11
11
  import { getHttpCache, cachedRequest, cachedTimeBased } from './http-cache.js';
12
12
  import { calculateRepoQualityBonus, calculateViabilityScore } from './issue-scoring.js';
13
+ import { repoBelongsToCategory } from './category-mapping.js';
13
14
  const MODULE = 'issue-vetting';
14
15
  const MAX_CONCURRENT_REQUESTS = DEFAULT_CONCURRENCY;
15
16
  // Cache for contribution guidelines (expires after 1 hour, max 100 entries)
@@ -173,6 +174,12 @@ export class IssueVetter {
173
174
  if (orgHasMergedPRs) {
174
175
  reasonsToApprove.push(`Org affinity (merged PRs in other ${orgName} repos)`);
175
176
  }
177
+ // Check for category preference match
178
+ const projectCategories = config.projectCategories ?? [];
179
+ const matchesCategory = repoBelongsToCategory(repoFullName, projectCategories);
180
+ if (matchesCategory) {
181
+ reasonsToApprove.push('Matches preferred project category');
182
+ }
176
183
  let recommendation;
177
184
  if (vettingResult.passedAllChecks) {
178
185
  recommendation = 'approve';
@@ -207,12 +214,17 @@ export class IssueVetter {
207
214
  mergedPRCount: effectiveMergedCount,
208
215
  orgHasMergedPRs,
209
216
  repoQualityBonus,
217
+ matchesPreferredCategory: matchesCategory,
210
218
  });
211
219
  const starredRepos = this.stateManager.getStarredRepos();
220
+ const preferredOrgs = config.preferredOrgs ?? [];
212
221
  let searchPriority = 'normal';
213
222
  if (effectiveMergedCount > 0) {
214
223
  searchPriority = 'merged_pr';
215
224
  }
225
+ else if (preferredOrgs.some((o) => o.toLowerCase() === orgName?.toLowerCase())) {
226
+ searchPriority = 'preferred_org';
227
+ }
216
228
  else if (starredRepos.includes(repoFullName)) {
217
229
  searchPriority = 'starred';
218
230
  }
@@ -485,6 +485,10 @@ export interface AgentConfig {
485
485
  snoozedPRs?: Record<string, SnoozeInfo>;
486
486
  /** Manual status overrides for PRs. Maps PR URL to override metadata. Auto-clears when the PR has new activity. */
487
487
  statusOverrides?: Record<string, StatusOverride>;
488
+ /** Project categories the user is interested in (e.g., devtools, nonprofit). Used to prioritize search results. */
489
+ projectCategories?: ProjectCategory[];
490
+ /** GitHub organizations the user wants to prioritize in issue search. Org names only (not owner/repo). */
491
+ preferredOrgs?: string[];
488
492
  }
489
493
  /** Status of a user's comment thread on a GitHub issue. */
490
494
  export type IssueConversationStatus = 'new_response' | 'waiting' | 'acknowledged';
@@ -523,7 +527,10 @@ export type CommentedIssue = CommentedIssueWithResponse | CommentedIssueWithoutR
523
527
  export declare const DEFAULT_CONFIG: AgentConfig;
524
528
  /** Initial state written to `~/.oss-autopilot/state.json` on first run. Uses v2 architecture. */
525
529
  export declare const INITIAL_STATE: AgentState;
526
- export type SearchPriority = 'merged_pr' | 'starred' | 'normal';
530
+ export declare const PROJECT_CATEGORIES: readonly ["nonprofit", "devtools", "infrastructure", "web-frameworks", "data-ml", "education"];
531
+ export type ProjectCategory = (typeof PROJECT_CATEGORIES)[number];
532
+ /** Priority tier for issue search results. Ordered: merged_pr > preferred_org > starred > normal. */
533
+ export type SearchPriority = 'merged_pr' | 'preferred_org' | 'starred' | 'normal';
527
534
  export interface IssueCandidate {
528
535
  issue: TrackedIssue;
529
536
  vettingResult: IssueVettingResult;
@@ -29,6 +29,8 @@ export const DEFAULT_CONFIG = {
29
29
  shelvedPRUrls: [],
30
30
  dismissedIssues: {},
31
31
  snoozedPRs: {},
32
+ projectCategories: [],
33
+ preferredOrgs: [],
32
34
  };
33
35
  /** Initial state written to `~/.oss-autopilot/state.json` on first run. Uses v2 architecture. */
34
36
  export const INITIAL_STATE = {
@@ -39,3 +41,12 @@ export const INITIAL_STATE = {
39
41
  events: [],
40
42
  lastRunAt: new Date().toISOString(),
41
43
  };
44
+ // -- Project category types --
45
+ export const PROJECT_CATEGORIES = [
46
+ 'nonprofit',
47
+ 'devtools',
48
+ 'infrastructure',
49
+ 'web-frameworks',
50
+ 'data-ml',
51
+ 'education',
52
+ ];
@@ -25,6 +25,8 @@ export interface ActionableIssue {
25
25
  type: ActionableIssueType;
26
26
  pr: FetchedPR;
27
27
  label: string;
28
+ /** True if the PR was created after the last daily digest (first time seen). */
29
+ isNewContribution: boolean;
28
30
  }
29
31
  /**
30
32
  * Compact version of ActionableIssue for JSON output.
@@ -36,6 +38,8 @@ export interface CompactActionableIssue {
36
38
  type: ActionableIssueType;
37
39
  prUrl: string;
38
40
  label: string;
41
+ /** True if the PR was created after the last daily digest (first time seen). */
42
+ isNewContribution: boolean;
39
43
  }
40
44
  /**
41
45
  * A single action menu item pre-computed by the CLI.
@@ -30,6 +30,7 @@ export function compactActionableIssues(issues) {
30
30
  type: issue.type,
31
31
  prUrl: issue.pr.url,
32
32
  label: issue.label,
33
+ isNewContribution: issue.isNewContribution,
33
34
  }));
34
35
  }
35
36
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-autopilot/core",
3
- "version": "0.48.0",
3
+ "version": "0.50.0",
4
4
  "description": "CLI and core library for managing open source contributions",
5
5
  "type": "module",
6
6
  "bin": {