@oss-autopilot/core 0.41.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 (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +85 -0
  3. package/dist/cli.bundle.cjs +17657 -0
  4. package/dist/cli.d.ts +12 -0
  5. package/dist/cli.js +325 -0
  6. package/dist/commands/check-integration.d.ts +10 -0
  7. package/dist/commands/check-integration.js +192 -0
  8. package/dist/commands/comments.d.ts +24 -0
  9. package/dist/commands/comments.js +311 -0
  10. package/dist/commands/config.d.ts +11 -0
  11. package/dist/commands/config.js +82 -0
  12. package/dist/commands/daily.d.ts +29 -0
  13. package/dist/commands/daily.js +433 -0
  14. package/dist/commands/dashboard-data.d.ts +45 -0
  15. package/dist/commands/dashboard-data.js +132 -0
  16. package/dist/commands/dashboard-templates.d.ts +23 -0
  17. package/dist/commands/dashboard-templates.js +1627 -0
  18. package/dist/commands/dashboard.d.ts +18 -0
  19. package/dist/commands/dashboard.js +134 -0
  20. package/dist/commands/dismiss.d.ts +13 -0
  21. package/dist/commands/dismiss.js +49 -0
  22. package/dist/commands/init.d.ts +10 -0
  23. package/dist/commands/init.js +27 -0
  24. package/dist/commands/local-repos.d.ts +14 -0
  25. package/dist/commands/local-repos.js +155 -0
  26. package/dist/commands/parse-list.d.ts +13 -0
  27. package/dist/commands/parse-list.js +139 -0
  28. package/dist/commands/read.d.ts +12 -0
  29. package/dist/commands/read.js +33 -0
  30. package/dist/commands/search.d.ts +10 -0
  31. package/dist/commands/search.js +74 -0
  32. package/dist/commands/setup.d.ts +15 -0
  33. package/dist/commands/setup.js +276 -0
  34. package/dist/commands/shelve.d.ts +13 -0
  35. package/dist/commands/shelve.js +49 -0
  36. package/dist/commands/snooze.d.ts +18 -0
  37. package/dist/commands/snooze.js +83 -0
  38. package/dist/commands/startup.d.ts +33 -0
  39. package/dist/commands/startup.js +197 -0
  40. package/dist/commands/status.d.ts +10 -0
  41. package/dist/commands/status.js +43 -0
  42. package/dist/commands/track.d.ts +16 -0
  43. package/dist/commands/track.js +59 -0
  44. package/dist/commands/validation.d.ts +43 -0
  45. package/dist/commands/validation.js +112 -0
  46. package/dist/commands/vet.d.ts +10 -0
  47. package/dist/commands/vet.js +36 -0
  48. package/dist/core/checklist-analysis.d.ts +17 -0
  49. package/dist/core/checklist-analysis.js +39 -0
  50. package/dist/core/ci-analysis.d.ts +78 -0
  51. package/dist/core/ci-analysis.js +163 -0
  52. package/dist/core/comment-utils.d.ts +15 -0
  53. package/dist/core/comment-utils.js +52 -0
  54. package/dist/core/concurrency.d.ts +5 -0
  55. package/dist/core/concurrency.js +15 -0
  56. package/dist/core/daily-logic.d.ts +77 -0
  57. package/dist/core/daily-logic.js +512 -0
  58. package/dist/core/display-utils.d.ts +10 -0
  59. package/dist/core/display-utils.js +100 -0
  60. package/dist/core/errors.d.ts +24 -0
  61. package/dist/core/errors.js +34 -0
  62. package/dist/core/github-stats.d.ts +73 -0
  63. package/dist/core/github-stats.js +272 -0
  64. package/dist/core/github.d.ts +19 -0
  65. package/dist/core/github.js +60 -0
  66. package/dist/core/http-cache.d.ts +97 -0
  67. package/dist/core/http-cache.js +269 -0
  68. package/dist/core/index.d.ts +15 -0
  69. package/dist/core/index.js +15 -0
  70. package/dist/core/issue-conversation.d.ts +29 -0
  71. package/dist/core/issue-conversation.js +231 -0
  72. package/dist/core/issue-discovery.d.ts +85 -0
  73. package/dist/core/issue-discovery.js +589 -0
  74. package/dist/core/issue-filtering.d.ts +51 -0
  75. package/dist/core/issue-filtering.js +103 -0
  76. package/dist/core/issue-scoring.d.ts +40 -0
  77. package/dist/core/issue-scoring.js +92 -0
  78. package/dist/core/issue-vetting.d.ts +49 -0
  79. package/dist/core/issue-vetting.js +536 -0
  80. package/dist/core/logger.d.ts +21 -0
  81. package/dist/core/logger.js +49 -0
  82. package/dist/core/maintainer-analysis.d.ts +10 -0
  83. package/dist/core/maintainer-analysis.js +59 -0
  84. package/dist/core/pagination.d.ts +11 -0
  85. package/dist/core/pagination.js +20 -0
  86. package/dist/core/pr-monitor.d.ts +109 -0
  87. package/dist/core/pr-monitor.js +594 -0
  88. package/dist/core/review-analysis.d.ts +72 -0
  89. package/dist/core/review-analysis.js +163 -0
  90. package/dist/core/state.d.ts +371 -0
  91. package/dist/core/state.js +1089 -0
  92. package/dist/core/types.d.ts +507 -0
  93. package/dist/core/types.js +34 -0
  94. package/dist/core/utils.d.ts +249 -0
  95. package/dist/core/utils.js +422 -0
  96. package/dist/formatters/json.d.ts +269 -0
  97. package/dist/formatters/json.js +88 -0
  98. package/package.json +67 -0
@@ -0,0 +1,507 @@
1
+ /**
2
+ * Core types for the Open Source Contribution Agent
3
+ */
4
+ /**
5
+ * Lifecycle of a discovered issue through the contribution pipeline.
6
+ * - `candidate` — Discovered but not yet claimed
7
+ * - `claimed` — Contributor has claimed the issue (e.g., commented "I'll work on this")
8
+ * - `in_progress` — Work is underway locally
9
+ * - `pr_submitted` — A PR has been opened for this issue
10
+ */
11
+ export type IssueStatus = 'candidate' | 'claimed' | 'in_progress' | 'pr_submitted';
12
+ /** CI pipeline status for a PR's latest commit. */
13
+ export type CIStatus = 'passing' | 'failing' | 'pending' | 'unknown';
14
+ /**
15
+ * Classification of a CI check failure (#81).
16
+ * - `actionable` — Real test/build failure the contributor should fix
17
+ * - `fork_limitation` — Failure due to fork permissions (e.g., Vercel deploy, Netlify)
18
+ * - `auth_gate` — Authorization/approval gate, not a real failure
19
+ * - `infrastructure` — Runner timeout, dependency install failure, or other transient infra issue
20
+ */
21
+ export type CIFailureCategory = 'actionable' | 'fork_limitation' | 'auth_gate' | 'infrastructure';
22
+ /** A CI check with its failure classification (#81). */
23
+ export interface ClassifiedCheck {
24
+ name: string;
25
+ category: CIFailureCategory;
26
+ conclusion?: string;
27
+ }
28
+ /** Return type for PRMonitor.getCIStatus(). */
29
+ export interface CIStatusResult {
30
+ status: CIStatus;
31
+ failingCheckNames: string[];
32
+ failingCheckConclusions: Map<string, string>;
33
+ }
34
+ /**
35
+ * PRs grouped by repository (#80).
36
+ * Used to prevent parallel git state corruption when multiple PRs exist in the same repo.
37
+ */
38
+ export interface RepoGroup {
39
+ repo: string;
40
+ prs: FetchedPR[];
41
+ }
42
+ /** GitHub's pull request review decision (from the reviewDecision GraphQL field). */
43
+ export type ReviewDecision = 'approved' | 'changes_requested' | 'review_required' | 'unknown';
44
+ /** Input options for `PRMonitor.determineStatus()`. */
45
+ export interface DetermineStatusInput {
46
+ ciStatus: CIStatus;
47
+ hasMergeConflict: boolean;
48
+ hasUnrespondedComment: boolean;
49
+ hasIncompleteChecklist: boolean;
50
+ reviewDecision: ReviewDecision;
51
+ daysSinceActivity: number;
52
+ dormantThreshold: number;
53
+ approachingThreshold: number;
54
+ latestCommitDate?: string;
55
+ lastMaintainerCommentDate?: string;
56
+ latestChangesRequestedDate?: string;
57
+ }
58
+ /**
59
+ * Computed status for a {@link FetchedPR}, determined by `PRMonitor.determineStatus()`.
60
+ * Statuses are checked in priority order — the first match wins.
61
+ *
62
+ * **Action required (contributor must act):**
63
+ * - `needs_response` — Maintainer commented after the contributor's last activity
64
+ * - `needs_changes` — Reviewer requested changes (via review, not just a comment)
65
+ * - `failing_ci` — One or more CI checks are failing
66
+ * - `ci_blocked` — CI cannot run (e.g., first-time contributor approval needed) *(reserved)*
67
+ * - `ci_not_running` — No CI checks have been triggered *(reserved)*
68
+ * - `merge_conflict` — PR has merge conflicts with the base branch
69
+ * - `needs_rebase` — PR branch is significantly behind upstream *(reserved)*
70
+ * - `missing_required_files` — Required files like changesets or CLA are missing *(reserved)*
71
+ * - `incomplete_checklist` — PR body has unchecked required checkboxes
72
+ *
73
+ * **Waiting (no action needed right now):**
74
+ * - `changes_addressed` — Contributor pushed commits after reviewer feedback; awaiting re-review
75
+ * - `waiting` — CI is pending or no specific action needed
76
+ * - `waiting_on_maintainer` — PR is approved and CI passes; waiting for maintainer to merge
77
+ * - `healthy` — Everything looks good; normal review cycle
78
+ *
79
+ * **Staleness warnings:**
80
+ * - `approaching_dormant` — No activity for `approachingDormantDays` (default 25)
81
+ * - `dormant` — No activity for `dormantThresholdDays` (default 30)
82
+ */
83
+ export type FetchedPRStatus = 'needs_response' | 'failing_ci' | 'ci_blocked' | 'ci_not_running' | 'merge_conflict' | 'needs_rebase' | 'missing_required_files' | 'incomplete_checklist' | 'needs_changes' | 'changes_addressed' | 'waiting' | 'waiting_on_maintainer' | 'healthy' | 'approaching_dormant' | 'dormant';
84
+ /**
85
+ * Hints about what a maintainer is asking for in their review comments.
86
+ * Extracted from comment text by keyword matching.
87
+ */
88
+ export type MaintainerActionHint = 'demo_requested' | 'tests_requested' | 'changes_requested' | 'docs_requested' | 'rebase_requested';
89
+ /**
90
+ * Ephemeral PR data fetched fresh from GitHub on each run (v2 architecture).
91
+ * This is never persisted in local state — it represents a point-in-time snapshot
92
+ * of a PR's current condition.
93
+ */
94
+ export interface FetchedPR {
95
+ id: number;
96
+ url: string;
97
+ repo: string;
98
+ number: number;
99
+ title: string;
100
+ /** Computed by `PRMonitor.determineStatus()` based on the fields below. */
101
+ status: FetchedPRStatus;
102
+ /** Human-readable status label for consistent display (#79). E.g., "[CI Failing]", "[Needs Response]". */
103
+ displayLabel: string;
104
+ /** Brief description of what's happening (#79). E.g., "3 checks failed", "@maintainer commented". */
105
+ displayDescription: string;
106
+ createdAt: string;
107
+ updatedAt: string;
108
+ /** Calendar days since the most recent activity (comment, commit, review). */
109
+ daysSinceActivity: number;
110
+ ciStatus: CIStatus;
111
+ /** Names of failing CI checks. Useful for distinguishing real CI failures from validation bots. */
112
+ failingCheckNames: string[];
113
+ /** Failing checks with category classification (#81). Separates actionable failures from fork limitations and auth gates. */
114
+ classifiedChecks: ClassifiedCheck[];
115
+ hasMergeConflict: boolean;
116
+ reviewDecision: ReviewDecision;
117
+ /** How many commits the PR branch is behind the base branch. */
118
+ commitsBehindUpstream?: number;
119
+ headRefName?: string;
120
+ /** Target branch name (e.g., "main", "master"). */
121
+ baseRefName?: string;
122
+ /** Absolute path to local clone, if the repo is cloned on this machine. */
123
+ localRepoPath?: string;
124
+ /** Required files the PR is missing (e.g., `["changeset", "CLA"]`). */
125
+ missingRequiredFiles?: string[];
126
+ /** True when a maintainer commented after the contributor's last comment or commit. */
127
+ hasUnrespondedComment: boolean;
128
+ lastMaintainerComment?: {
129
+ author: string;
130
+ body: string;
131
+ createdAt: string;
132
+ };
133
+ /** ISO timestamp of the latest commit. Used to determine if changes were pushed after review feedback. */
134
+ latestCommitDate?: string;
135
+ /** True when the PR body contains unchecked required checkboxes. */
136
+ hasIncompleteChecklist: boolean;
137
+ checklistStats?: {
138
+ checked: number;
139
+ total: number;
140
+ };
141
+ /** Hints extracted from maintainer comments about what actions they are requesting. */
142
+ maintainerActionHints: MaintainerActionHint[];
143
+ }
144
+ /**
145
+ * Lightweight reference used in {@link DailyDigest} for shelved and auto-unshelved PRs.
146
+ * Contains only the fields needed for display, avoiding duplication of the full
147
+ * {@link FetchedPR} objects already present in `openPRs` and the status-specific arrays.
148
+ */
149
+ export interface ShelvedPRRef {
150
+ number: number;
151
+ url: string;
152
+ title: string;
153
+ repo: string;
154
+ daysSinceActivity: number;
155
+ status: FetchedPRStatus;
156
+ }
157
+ /** An issue tracked through the contribution pipeline from discovery to PR submission. */
158
+ export interface TrackedIssue {
159
+ id: number;
160
+ url: string;
161
+ repo: string;
162
+ number: number;
163
+ title: string;
164
+ status: IssueStatus;
165
+ labels: string[];
166
+ createdAt: string;
167
+ updatedAt: string;
168
+ /** Whether the issue has been through the vetting process (checking for existing PRs, activity, etc.). */
169
+ vetted: boolean;
170
+ vettingResult?: IssueVettingResult;
171
+ }
172
+ /**
173
+ * Result of vetting an issue for contribution suitability.
174
+ * An issue passes vetting when all checks are true (no existing PR, not claimed, etc.).
175
+ */
176
+ export interface IssueVettingResult {
177
+ passedAllChecks: boolean;
178
+ checks: {
179
+ noExistingPR: boolean;
180
+ notClaimed: boolean;
181
+ projectActive: boolean;
182
+ clearRequirements: boolean;
183
+ contributionGuidelinesFound: boolean;
184
+ };
185
+ contributionGuidelines?: ContributionGuidelines;
186
+ /** Free-text observations from the vetting process (e.g., "Issue has 3 linked PRs, all closed"). */
187
+ notes: string[];
188
+ }
189
+ /**
190
+ * Structured representation of a project's contribution guidelines,
191
+ * extracted from CONTRIBUTING.md or similar files during issue vetting.
192
+ */
193
+ export interface ContributionGuidelines {
194
+ branchNamingConvention?: string;
195
+ commitMessageFormat?: string;
196
+ prTitleFormat?: string;
197
+ requiredChecks?: string[];
198
+ testFramework?: string;
199
+ testCoverageRequired?: boolean;
200
+ /** Expected test file naming pattern (e.g., `"*.test.ts"`, `"*_spec.rb"`). */
201
+ testFileNaming?: string;
202
+ linter?: string;
203
+ formatter?: string;
204
+ styleGuideUrl?: string;
205
+ /** How to claim an issue (e.g., "Comment on the issue before starting work"). */
206
+ issueClaimProcess?: string;
207
+ reviewProcess?: string;
208
+ claRequired?: boolean;
209
+ /** Raw CONTRIBUTING.md content for reference when structured fields are insufficient. */
210
+ rawContent?: string;
211
+ }
212
+ /** Health snapshot of a GitHub repository, used to determine if a project is worth contributing to. */
213
+ export interface ProjectHealth {
214
+ repo: string;
215
+ lastCommitAt: string;
216
+ daysSinceLastCommit: number;
217
+ openIssuesCount: number;
218
+ /** Average number of days for maintainers to respond to issues. */
219
+ avgIssueResponseDays: number;
220
+ ciStatus: 'passing' | 'failing' | 'unknown';
221
+ /** Whether the project is considered active based on recent commit history. */
222
+ isActive: boolean;
223
+ /** GitHub star count, used for repo quality scoring (#98). */
224
+ stargazersCount?: number;
225
+ /** GitHub fork count, used for repo quality scoring (#98). */
226
+ forksCount?: number;
227
+ /** True if the health check itself failed (e.g., API error). */
228
+ checkFailed?: boolean;
229
+ failureReason?: string;
230
+ }
231
+ /**
232
+ * Quality score for a repository, used to prioritize issue search results.
233
+ * Score is on a 1-10 scale: base 5, logarithmic merge bonus (max +5: 1->+2, 2->+3, 3->+4, 5+->+5),
234
+ * -1 per closed-without-merge (max -3), +1 if lastMergedAt is set and within 90 days,
235
+ * +1 if responsive, -2 if hostile.
236
+ * Repos below `AgentConfig.minRepoScoreThreshold` are deprioritized.
237
+ */
238
+ export interface RepoScore {
239
+ repo: string;
240
+ /** Overall score from 1 (avoid) to 10 (excellent track record). */
241
+ score: number;
242
+ /** Number of the contributor's PRs that were merged in this repo. */
243
+ mergedPRCount: number;
244
+ /** Number of the contributor's PRs closed without merge (indicates friction). */
245
+ closedWithoutMergeCount: number;
246
+ /** Average days for maintainers to respond; null if no data. */
247
+ avgResponseDays: number | null;
248
+ lastMergedAt?: string;
249
+ lastEvaluatedAt: string;
250
+ /** Qualitative signals about the repo's maintainer culture. */
251
+ signals: RepoSignals;
252
+ /** GitHub star count, fetched during daily check for dashboard filtering. */
253
+ stargazersCount?: number;
254
+ }
255
+ /** Full set of qualitative signals about a repo's maintainer culture. */
256
+ export interface RepoSignals {
257
+ hasActiveMaintainers: boolean;
258
+ isResponsive: boolean;
259
+ hasHostileComments: boolean;
260
+ }
261
+ /** Signals computed from observed open PR data, suitable for merging into RepoScore.signals. */
262
+ export type ComputedRepoSignals = Pick<RepoSignals, 'isResponsive' | 'hasActiveMaintainers'>;
263
+ /**
264
+ * Subset of RepoScore fields that callers may update via `updateRepoScore()`.
265
+ * Excludes `score` (always derived), `repo` (immutable key), and `lastEvaluatedAt` (auto-set).
266
+ * The `signals` field accepts a partial update — only provided fields are merged.
267
+ */
268
+ export interface RepoScoreUpdate {
269
+ mergedPRCount?: number;
270
+ closedWithoutMergeCount?: number;
271
+ avgResponseDays?: number | null;
272
+ lastMergedAt?: string;
273
+ signals?: Partial<RepoSignals>;
274
+ stargazersCount?: number;
275
+ }
276
+ /**
277
+ * Event types recorded in the {@link AgentState} audit log.
278
+ * - `pr_tracked` — A new PR was added to tracking
279
+ * - `pr_merged` — A tracked PR was merged
280
+ * - `pr_closed` — A tracked PR was closed without merge
281
+ * - `pr_dormant` — A PR crossed the dormant threshold
282
+ * - `daily_check` — A daily digest run completed
283
+ * - `comment_posted` — The agent posted a comment on a PR
284
+ */
285
+ export type StateEventType = 'pr_tracked' | 'pr_merged' | 'pr_closed' | 'pr_dormant' | 'daily_check' | 'comment_posted';
286
+ /** An entry in the state audit log. Events are append-only and used for history tracking. */
287
+ export interface StateEvent {
288
+ id: string;
289
+ type: StateEventType;
290
+ /** ISO 8601 timestamp of when the event occurred. */
291
+ at: string;
292
+ /** Event-specific payload (e.g., `{ repo: "owner/repo", number: 42 }` for PR events). */
293
+ data: Record<string, unknown>;
294
+ }
295
+ /** Minimal record of a PR that was closed without being merged, used in the daily digest. */
296
+ export interface ClosedPR {
297
+ url: string;
298
+ repo: string;
299
+ number: number;
300
+ title: string;
301
+ closedAt: string;
302
+ closedBy?: string;
303
+ }
304
+ /** Minimal record of a PR that was merged, used in the daily digest. */
305
+ export interface MergedPR {
306
+ url: string;
307
+ repo: string;
308
+ number: number;
309
+ title: string;
310
+ mergedAt: string;
311
+ }
312
+ /**
313
+ * The daily report produced by `PRMonitor.generateDigest()`.
314
+ * Contains all open PRs fetched fresh from GitHub, categorized by status,
315
+ * plus recently closed PRs and summary statistics. This is persisted in
316
+ * `AgentState.lastDigest` so the HTML dashboard can render it.
317
+ */
318
+ export interface DailyDigest {
319
+ generatedAt: string;
320
+ /** All open PRs authored by the user, fetched from GitHub Search API. */
321
+ openPRs: FetchedPR[];
322
+ prsNeedingResponse: FetchedPR[];
323
+ ciFailingPRs: FetchedPR[];
324
+ ciBlockedPRs: FetchedPR[];
325
+ ciNotRunningPRs: FetchedPR[];
326
+ mergeConflictPRs: FetchedPR[];
327
+ needsRebasePRs: FetchedPR[];
328
+ missingRequiredFilesPRs: FetchedPR[];
329
+ incompleteChecklistPRs: FetchedPR[];
330
+ needsChangesPRs: FetchedPR[];
331
+ changesAddressedPRs: FetchedPR[];
332
+ waitingOnMaintainerPRs: FetchedPR[];
333
+ /** PRs with no activity for 25+ days (configurable via `approachingDormantDays`). */
334
+ approachingDormant: FetchedPR[];
335
+ dormantPRs: FetchedPR[];
336
+ healthyPRs: FetchedPR[];
337
+ /** PRs closed without merge in the last 7 days. Surfaced to alert the contributor. */
338
+ recentlyClosedPRs: ClosedPR[];
339
+ /** PRs merged in the last 7 days. Surfaced as wins in the dashboard. */
340
+ recentlyMergedPRs: MergedPR[];
341
+ /**
342
+ * PRs manually shelved by the user (excluded from capacity and actionable issues).
343
+ * Stored as lightweight references — full data is available in `openPRs`.
344
+ */
345
+ shelvedPRs: ShelvedPRRef[];
346
+ /**
347
+ * PRs that were auto-unshelved this run because a maintainer engaged.
348
+ * Stored as lightweight references — full data is available in `openPRs`.
349
+ */
350
+ autoUnshelvedPRs: ShelvedPRRef[];
351
+ summary: {
352
+ totalActivePRs: number;
353
+ /** Count of PRs requiring contributor action (response, CI fix, conflict resolution, etc.). */
354
+ totalNeedingAttention: number;
355
+ /** Lifetime merged PR count across all repos, derived from {@link RepoScore} data. */
356
+ totalMergedAllTime: number;
357
+ /** Percentage of all-time PRs that were merged (merged / (merged + closed)). */
358
+ mergeRate: number;
359
+ };
360
+ }
361
+ /**
362
+ * Root state object persisted to `~/.oss-autopilot/state.json`.
363
+ *
364
+ * In v2 (current), PRs are fetched fresh from GitHub on each run via the Search API.
365
+ * The primary runtime data lives in `lastDigest` and `repoScores`.
366
+ */
367
+ export interface AgentState {
368
+ /** Schema version. `2` = v2 fresh-fetch architecture. Used by `StateManager` for migrations. */
369
+ version: number;
370
+ /** Per-repo quality scores keyed by `"owner/repo"`. Used to prioritize issue search results. */
371
+ repoScores: Record<string, RepoScore>;
372
+ config: AgentConfig;
373
+ /** Append-only audit log of significant events (PR merged, daily check, etc.). */
374
+ events: StateEvent[];
375
+ /** ISO timestamp of the last CLI invocation. */
376
+ lastRunAt: string;
377
+ /** ISO timestamp of the last daily digest generation. */
378
+ lastDigestAt?: string;
379
+ /** Cached daily digest so the HTML dashboard can render without re-fetching from GitHub. */
380
+ lastDigest?: DailyDigest;
381
+ /** Monthly merged PR counts keyed by `"YYYY-MM"`. Powers the contribution timeline chart. */
382
+ monthlyMergedCounts?: Record<string, number>;
383
+ /** Monthly closed (without merge) PR counts keyed by `"YYYY-MM"`. Powers the timeline and success rate charts. */
384
+ monthlyClosedCounts?: Record<string, number>;
385
+ /** Monthly opened PR counts keyed by `"YYYY-MM"`. Combines PRs opened across merged+closed+open sets. */
386
+ monthlyOpenedCounts?: Record<string, number>;
387
+ /** Daily activity counts keyed by `"YYYY-MM-DD"`. Powers the activity heatmap chart. */
388
+ dailyActivityCounts?: Record<string, number>;
389
+ /** Cached local repo scan results (#84). Avoids re-scanning the filesystem every session. */
390
+ localRepoCache?: LocalRepoCache;
391
+ activeIssues: TrackedIssue[];
392
+ }
393
+ /** Cached results from scanning the filesystem for local git clones (#84). */
394
+ export interface LocalRepoCache {
395
+ /** Map of "owner/repo" -> local repo info */
396
+ repos: Record<string, {
397
+ path: string;
398
+ exists: boolean;
399
+ currentBranch: string | null;
400
+ }>;
401
+ /** Directories that were scanned */
402
+ scanPaths: string[];
403
+ /** ISO 8601 timestamp of when the scan was performed */
404
+ cachedAt: string;
405
+ }
406
+ /** Metadata for a snoozed PR's CI failure. */
407
+ export interface SnoozeInfo {
408
+ reason: string;
409
+ snoozedAt: string;
410
+ expiresAt: string;
411
+ }
412
+ /** User-configurable settings, populated via `/setup-oss` and stored in {@link AgentState}. */
413
+ export interface AgentConfig {
414
+ /** False until the user completes initial setup via `/setup-oss`. */
415
+ setupComplete: boolean;
416
+ setupCompletedAt?: string;
417
+ maxActivePRs: number;
418
+ /** Days of inactivity before a PR is marked `dormant`. Default 30. */
419
+ dormantThresholdDays: number;
420
+ /** Days of inactivity before a PR is marked `approaching_dormant`. Default 25. */
421
+ approachingDormantDays: number;
422
+ /** Issues older than this (by `updated_at`) are filtered from search results. Default 90. */
423
+ maxIssueAgeDays: number;
424
+ /** Programming languages to search for issues in (e.g., `["typescript", "javascript"]`). */
425
+ languages: string[];
426
+ /** GitHub labels to filter issues by (e.g., `["good first issue", "help wanted"]`). */
427
+ labels: string[];
428
+ /** Repos to exclude from search and stats, in `"owner/repo"` format. */
429
+ excludeRepos: string[];
430
+ /** Organizations to exclude from search and stats (case-insensitive match on owner segment). */
431
+ excludeOrgs?: string[];
432
+ /** Repos where the contributor has had PRs merged. Used for prioritization. */
433
+ trustedProjects: string[];
434
+ githubUsername: string;
435
+ /** Minimum {@link RepoScore} to include a repo in search results. Default 4. */
436
+ minRepoScoreThreshold: number;
437
+ /** User's GitHub starred repos, fetched periodically for prioritized issue discovery. */
438
+ starredRepos: string[];
439
+ starredReposLastFetched?: string;
440
+ /** Whether to show the health check notification on session start. Default true. */
441
+ showHealthCheck?: boolean;
442
+ /** Whether to squash commits before marking PR ready. `true` (default), `false`, or `"ask"`. */
443
+ squashByDefault?: boolean | 'ask';
444
+ /** Directories to scan for local git clones (#84). Falls back to default paths if not set. */
445
+ localRepoScanPaths?: string[];
446
+ /** Minimum GitHub star count for Phase 2 (general search) results. Default 50. Phases 0/1 are exempt. */
447
+ minStars?: number;
448
+ /** Whether to include documentation-only issues in search results. Default true. */
449
+ includeDocIssues?: boolean;
450
+ /** Repos known to have anti-AI contribution policies, in `"owner/repo"` format. Filtered from search results automatically. */
451
+ aiPolicyBlocklist?: string[];
452
+ /** PR URLs manually shelved by the user. Shelved PRs are excluded from capacity and actionable issues. Auto-unshelved when maintainers engage. */
453
+ shelvedPRUrls?: string[];
454
+ /** Issue URLs dismissed by the user, mapped to ISO timestamp of when dismissed. Issues with new responses after the dismiss timestamp resurface automatically. */
455
+ dismissedIssues?: Record<string, string>;
456
+ /** PR URLs with snoozed CI failures, mapped to snooze metadata. Snoozed PRs are excluded from actionable CI failure list until expiry. */
457
+ snoozedPRs?: Record<string, SnoozeInfo>;
458
+ }
459
+ /** Status of a user's comment thread on a GitHub issue. */
460
+ export type IssueConversationStatus = 'new_response' | 'waiting' | 'acknowledged';
461
+ /** Base fields shared by all issue conversation states. */
462
+ interface CommentedIssueBase {
463
+ repo: string;
464
+ number: number;
465
+ title: string;
466
+ url: string;
467
+ userLastCommentedAt: string;
468
+ labels: string[];
469
+ daysSinceUserComment: number;
470
+ }
471
+ /** Issue where someone responded after the user's last comment. */
472
+ export interface CommentedIssueWithResponse extends CommentedIssueBase {
473
+ status: 'new_response';
474
+ lastResponseAuthor: string;
475
+ lastResponseBody: string;
476
+ lastResponseAt: string;
477
+ /**
478
+ * True when the responder has OWNER, MEMBER, or COLLABORATOR author_association
479
+ * on the repository (i.e., someone with repo-level permissions, not just a community user).
480
+ */
481
+ isFromMaintainer: boolean;
482
+ }
483
+ /** Issue where no substantive maintainer response was found. */
484
+ interface CommentedIssueWithoutResponse extends CommentedIssueBase {
485
+ status: 'waiting' | 'acknowledged';
486
+ lastResponseAuthor?: undefined;
487
+ lastResponseBody?: undefined;
488
+ lastResponseAt?: undefined;
489
+ }
490
+ /** A GitHub issue the user has commented on, with conversation state. */
491
+ export type CommentedIssue = CommentedIssueWithResponse | CommentedIssueWithoutResponse;
492
+ /** Default configuration applied to new state files. All fields can be overridden via `/setup-oss`. */
493
+ export declare const DEFAULT_CONFIG: AgentConfig;
494
+ /** Initial state written to `~/.oss-autopilot/state.json` on first run. Uses v2 architecture. */
495
+ export declare const INITIAL_STATE: AgentState;
496
+ export type SearchPriority = 'merged_pr' | 'starred' | 'normal';
497
+ export interface IssueCandidate {
498
+ issue: TrackedIssue;
499
+ vettingResult: IssueVettingResult;
500
+ projectHealth: ProjectHealth;
501
+ recommendation: 'approve' | 'skip' | 'needs_review';
502
+ reasonsToSkip: string[];
503
+ reasonsToApprove: string[];
504
+ viabilityScore: number;
505
+ searchPriority: SearchPriority;
506
+ }
507
+ export {};
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Core types for the Open Source Contribution Agent
3
+ */
4
+ /** Default configuration applied to new state files. All fields can be overridden via `/setup-oss`. */
5
+ export const DEFAULT_CONFIG = {
6
+ setupComplete: false,
7
+ maxActivePRs: 10,
8
+ dormantThresholdDays: 30,
9
+ approachingDormantDays: 25,
10
+ maxIssueAgeDays: 90,
11
+ languages: ['typescript', 'javascript'],
12
+ labels: ['good first issue', 'help wanted'],
13
+ excludeRepos: [],
14
+ trustedProjects: [],
15
+ githubUsername: '',
16
+ minRepoScoreThreshold: 4,
17
+ starredRepos: [],
18
+ squashByDefault: true,
19
+ minStars: 50,
20
+ includeDocIssues: true,
21
+ aiPolicyBlocklist: ['matplotlib/matplotlib'],
22
+ shelvedPRUrls: [],
23
+ dismissedIssues: {},
24
+ snoozedPRs: {},
25
+ };
26
+ /** Initial state written to `~/.oss-autopilot/state.json` on first run. Uses v2 architecture. */
27
+ export const INITIAL_STATE = {
28
+ version: 2, // v2: Fresh GitHub fetching
29
+ activeIssues: [],
30
+ repoScores: {},
31
+ config: DEFAULT_CONFIG,
32
+ events: [],
33
+ lastRunAt: new Date().toISOString(),
34
+ };