@oss-autopilot/core 0.59.0 → 0.60.1
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/dist/cli.bundle.cjs +150 -111
- package/dist/core/ci-analysis.d.ts +5 -4
- package/dist/core/ci-analysis.js +13 -8
- package/dist/core/state-persistence.d.ts +1 -0
- package/dist/core/state-persistence.js +46 -84
- package/dist/core/state-schema.d.ts +539 -0
- package/dist/core/state-schema.js +214 -0
- package/dist/core/types.d.ts +4 -312
- package/dist/core/types.js +7 -41
- package/package.json +3 -2
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for all types persisted in state.json.
|
|
3
|
+
*
|
|
4
|
+
* This file is the single source of truth for persisted type shapes.
|
|
5
|
+
* Types are inferred via `z.infer<>` at the bottom of this file and
|
|
6
|
+
* re-exported through types.ts.
|
|
7
|
+
*
|
|
8
|
+
* Schemas are defined bottom-up (leaf types first, composites last).
|
|
9
|
+
* Unknown keys are stripped by default (Zod 4 behavior).
|
|
10
|
+
*/
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
// ── 1. Enum / union schemas ───────────────────────────────────────────
|
|
13
|
+
export const IssueStatusSchema = z.enum(['candidate', 'claimed', 'in_progress', 'pr_submitted']);
|
|
14
|
+
export const FetchedPRStatusSchema = z.enum(['needs_addressing', 'waiting_on_maintainer']);
|
|
15
|
+
export const ProjectCategorySchema = z.enum([
|
|
16
|
+
'nonprofit',
|
|
17
|
+
'devtools',
|
|
18
|
+
'infrastructure',
|
|
19
|
+
'web-frameworks',
|
|
20
|
+
'data-ml',
|
|
21
|
+
'education',
|
|
22
|
+
]);
|
|
23
|
+
export const IssueScopeSchema = z.enum(['beginner', 'intermediate', 'advanced']);
|
|
24
|
+
export const StateEventTypeSchema = z.enum([
|
|
25
|
+
'pr_tracked',
|
|
26
|
+
'pr_merged',
|
|
27
|
+
'pr_closed',
|
|
28
|
+
'pr_dormant',
|
|
29
|
+
'daily_check',
|
|
30
|
+
'comment_posted',
|
|
31
|
+
]);
|
|
32
|
+
// ── 2. Leaf schemas ──────────────────────────────────────────────────
|
|
33
|
+
export const RepoSignalsSchema = z.object({
|
|
34
|
+
hasActiveMaintainers: z.boolean(),
|
|
35
|
+
isResponsive: z.boolean(),
|
|
36
|
+
hasHostileComments: z.boolean(),
|
|
37
|
+
});
|
|
38
|
+
export const RepoScoreSchema = z.object({
|
|
39
|
+
repo: z.string(),
|
|
40
|
+
score: z.number(),
|
|
41
|
+
mergedPRCount: z.number(),
|
|
42
|
+
closedWithoutMergeCount: z.number(),
|
|
43
|
+
avgResponseDays: z.number().nullable(),
|
|
44
|
+
lastMergedAt: z.string().optional(),
|
|
45
|
+
lastEvaluatedAt: z.string(),
|
|
46
|
+
signals: RepoSignalsSchema,
|
|
47
|
+
stargazersCount: z.number().optional(),
|
|
48
|
+
language: z.string().nullable().optional(),
|
|
49
|
+
});
|
|
50
|
+
export const StateEventSchema = z.object({
|
|
51
|
+
id: z.string(),
|
|
52
|
+
type: StateEventTypeSchema,
|
|
53
|
+
at: z.string(),
|
|
54
|
+
data: z.record(z.string(), z.unknown()),
|
|
55
|
+
});
|
|
56
|
+
export const StoredMergedPRSchema = z.object({
|
|
57
|
+
url: z.string(),
|
|
58
|
+
title: z.string(),
|
|
59
|
+
mergedAt: z.string(),
|
|
60
|
+
});
|
|
61
|
+
export const StoredClosedPRSchema = z.object({
|
|
62
|
+
url: z.string(),
|
|
63
|
+
title: z.string(),
|
|
64
|
+
closedAt: z.string(),
|
|
65
|
+
});
|
|
66
|
+
// ── 3. Contribution schemas ──────────────────────────────────────────
|
|
67
|
+
export const ContributionGuidelinesSchema = z.object({
|
|
68
|
+
branchNamingConvention: z.string().optional(),
|
|
69
|
+
commitMessageFormat: z.string().optional(),
|
|
70
|
+
prTitleFormat: z.string().optional(),
|
|
71
|
+
requiredChecks: z.array(z.string()).optional(),
|
|
72
|
+
testFramework: z.string().optional(),
|
|
73
|
+
testCoverageRequired: z.boolean().optional(),
|
|
74
|
+
testFileNaming: z.string().optional(),
|
|
75
|
+
linter: z.string().optional(),
|
|
76
|
+
formatter: z.string().optional(),
|
|
77
|
+
styleGuideUrl: z.string().optional(),
|
|
78
|
+
issueClaimProcess: z.string().optional(),
|
|
79
|
+
reviewProcess: z.string().optional(),
|
|
80
|
+
claRequired: z.boolean().optional(),
|
|
81
|
+
rawContent: z.string().optional(),
|
|
82
|
+
});
|
|
83
|
+
export const IssueVettingResultSchema = z.object({
|
|
84
|
+
passedAllChecks: z.boolean(),
|
|
85
|
+
checks: z.object({
|
|
86
|
+
noExistingPR: z.boolean(),
|
|
87
|
+
notClaimed: z.boolean(),
|
|
88
|
+
projectActive: z.boolean(),
|
|
89
|
+
clearRequirements: z.boolean(),
|
|
90
|
+
contributionGuidelinesFound: z.boolean(),
|
|
91
|
+
}),
|
|
92
|
+
contributionGuidelines: ContributionGuidelinesSchema.optional(),
|
|
93
|
+
notes: z.array(z.string()),
|
|
94
|
+
});
|
|
95
|
+
export const TrackedIssueSchema = z.object({
|
|
96
|
+
id: z.number(),
|
|
97
|
+
url: z.string(),
|
|
98
|
+
repo: z.string(),
|
|
99
|
+
number: z.number(),
|
|
100
|
+
title: z.string(),
|
|
101
|
+
status: IssueStatusSchema,
|
|
102
|
+
labels: z.array(z.string()),
|
|
103
|
+
createdAt: z.string(),
|
|
104
|
+
updatedAt: z.string(),
|
|
105
|
+
vetted: z.boolean(),
|
|
106
|
+
vettingResult: IssueVettingResultSchema.optional(),
|
|
107
|
+
});
|
|
108
|
+
// ── 4. PR reference schemas ──────────────────────────────────────────
|
|
109
|
+
export const ShelvedPRRefSchema = z.object({
|
|
110
|
+
number: z.number(),
|
|
111
|
+
url: z.string(),
|
|
112
|
+
title: z.string(),
|
|
113
|
+
repo: z.string(),
|
|
114
|
+
daysSinceActivity: z.number(),
|
|
115
|
+
status: FetchedPRStatusSchema,
|
|
116
|
+
});
|
|
117
|
+
export const StatusOverrideSchema = z.object({
|
|
118
|
+
status: FetchedPRStatusSchema,
|
|
119
|
+
setAt: z.string(),
|
|
120
|
+
lastActivityAt: z.string(),
|
|
121
|
+
});
|
|
122
|
+
// ── 5. Config schema ─────────────────────────────────────────────────
|
|
123
|
+
export const AgentConfigSchema = z.object({
|
|
124
|
+
setupComplete: z.boolean().default(false),
|
|
125
|
+
setupCompletedAt: z.string().optional(),
|
|
126
|
+
maxActivePRs: z.number().default(10),
|
|
127
|
+
dormantThresholdDays: z.number().default(30),
|
|
128
|
+
approachingDormantDays: z.number().default(25),
|
|
129
|
+
maxIssueAgeDays: z.number().default(90),
|
|
130
|
+
languages: z.array(z.string()).default(['typescript', 'javascript']),
|
|
131
|
+
labels: z.array(z.string()).default(['good first issue', 'help wanted']),
|
|
132
|
+
scope: z.array(IssueScopeSchema).optional(),
|
|
133
|
+
excludeRepos: z.array(z.string()).default([]),
|
|
134
|
+
excludeOrgs: z.array(z.string()).optional(),
|
|
135
|
+
trustedProjects: z.array(z.string()).default([]),
|
|
136
|
+
githubUsername: z.string().default(''),
|
|
137
|
+
minRepoScoreThreshold: z.number().default(4),
|
|
138
|
+
starredRepos: z.array(z.string()).default([]),
|
|
139
|
+
starredReposLastFetched: z.string().optional(),
|
|
140
|
+
showHealthCheck: z.boolean().optional(),
|
|
141
|
+
squashByDefault: z.union([z.boolean(), z.literal('ask')]).default(true),
|
|
142
|
+
localRepoScanPaths: z.array(z.string()).optional(),
|
|
143
|
+
minStars: z.number().default(50),
|
|
144
|
+
includeDocIssues: z.boolean().default(true),
|
|
145
|
+
aiPolicyBlocklist: z.array(z.string()).default(['matplotlib/matplotlib']),
|
|
146
|
+
shelvedPRUrls: z.array(z.string()).default([]),
|
|
147
|
+
dismissedIssues: z.record(z.string(), z.string()).default({}),
|
|
148
|
+
statusOverrides: z.record(z.string(), StatusOverrideSchema).optional(),
|
|
149
|
+
issueListPath: z.string().optional(),
|
|
150
|
+
projectCategories: z.array(ProjectCategorySchema).default([]),
|
|
151
|
+
preferredOrgs: z.array(z.string()).default([]),
|
|
152
|
+
});
|
|
153
|
+
// ── 6. Cache schemas ─────────────────────────────────────────────────
|
|
154
|
+
export const LocalRepoCacheSchema = z.object({
|
|
155
|
+
repos: z.record(z.string(), z.object({
|
|
156
|
+
path: z.string(),
|
|
157
|
+
exists: z.boolean(),
|
|
158
|
+
currentBranch: z.string().nullable(),
|
|
159
|
+
})),
|
|
160
|
+
scanPaths: z.array(z.string()),
|
|
161
|
+
cachedAt: z.string(),
|
|
162
|
+
});
|
|
163
|
+
// ── 7. Digest schemas ────────────────────────────────────────────────
|
|
164
|
+
export const ClosedPRSchema = z.object({
|
|
165
|
+
url: z.string(),
|
|
166
|
+
repo: z.string(),
|
|
167
|
+
number: z.number(),
|
|
168
|
+
title: z.string(),
|
|
169
|
+
closedAt: z.string(),
|
|
170
|
+
closedBy: z.string().optional(),
|
|
171
|
+
});
|
|
172
|
+
export const MergedPRSchema = z.object({
|
|
173
|
+
url: z.string(),
|
|
174
|
+
repo: z.string(),
|
|
175
|
+
number: z.number(),
|
|
176
|
+
title: z.string(),
|
|
177
|
+
mergedAt: z.string(),
|
|
178
|
+
});
|
|
179
|
+
export const DailyDigestSummarySchema = z.object({
|
|
180
|
+
totalActivePRs: z.number(),
|
|
181
|
+
totalNeedingAttention: z.number(),
|
|
182
|
+
totalMergedAllTime: z.number(),
|
|
183
|
+
mergeRate: z.number(),
|
|
184
|
+
});
|
|
185
|
+
export const DailyDigestSchema = z.object({
|
|
186
|
+
generatedAt: z.string(),
|
|
187
|
+
// FetchedPR arrays — ephemeral, regenerated each run. Validated loosely.
|
|
188
|
+
openPRs: z.array(z.any()),
|
|
189
|
+
needsAddressingPRs: z.array(z.any()),
|
|
190
|
+
waitingOnMaintainerPRs: z.array(z.any()),
|
|
191
|
+
recentlyClosedPRs: z.array(ClosedPRSchema),
|
|
192
|
+
recentlyMergedPRs: z.array(MergedPRSchema),
|
|
193
|
+
shelvedPRs: z.array(ShelvedPRRefSchema),
|
|
194
|
+
autoUnshelvedPRs: z.array(ShelvedPRRefSchema),
|
|
195
|
+
summary: DailyDigestSummarySchema,
|
|
196
|
+
});
|
|
197
|
+
// ── 8. Root schema ───────────────────────────────────────────────────
|
|
198
|
+
export const AgentStateSchema = z.object({
|
|
199
|
+
version: z.literal(2),
|
|
200
|
+
repoScores: z.record(z.string(), RepoScoreSchema).default({}),
|
|
201
|
+
config: AgentConfigSchema.default(() => AgentConfigSchema.parse({})),
|
|
202
|
+
events: z.array(StateEventSchema).default([]),
|
|
203
|
+
lastRunAt: z.string().default(() => new Date().toISOString()),
|
|
204
|
+
lastDigestAt: z.string().optional(),
|
|
205
|
+
lastDigest: DailyDigestSchema.optional(),
|
|
206
|
+
monthlyMergedCounts: z.record(z.string(), z.number()).optional(),
|
|
207
|
+
monthlyClosedCounts: z.record(z.string(), z.number()).optional(),
|
|
208
|
+
monthlyOpenedCounts: z.record(z.string(), z.number()).optional(),
|
|
209
|
+
dailyActivityCounts: z.record(z.string(), z.number()).optional(),
|
|
210
|
+
localRepoCache: LocalRepoCacheSchema.optional(),
|
|
211
|
+
mergedPRs: z.array(StoredMergedPRSchema).optional(),
|
|
212
|
+
closedPRs: z.array(StoredClosedPRSchema).optional(),
|
|
213
|
+
activeIssues: z.array(TrackedIssueSchema).default([]),
|
|
214
|
+
});
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core types for the Open Source Contribution Agent
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
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';
|
|
4
|
+
import type { FetchedPRStatus, RepoSignals, TrackedIssue, IssueVettingResult, IssueScope, AgentConfig, AgentState } from './state-schema.js';
|
|
5
|
+
export type { IssueStatus, FetchedPRStatus, ProjectCategory, IssueScope, StateEventType, RepoSignals, RepoScore, StateEvent, StoredMergedPR, StoredClosedPR, ContributionGuidelines, IssueVettingResult, TrackedIssue, ShelvedPRRef, StatusOverride, AgentConfig, LocalRepoCache, ClosedPR, MergedPR, DailyDigest, AgentState, } from './state-schema.js';
|
|
12
6
|
/** CI pipeline status for a PR's latest commit. */
|
|
13
7
|
export type CIStatus = 'passing' | 'failing' | 'pending' | 'unknown';
|
|
14
8
|
/**
|
|
@@ -82,14 +76,6 @@ export type ActionReason = 'needs_response' | 'needs_changes' | 'failing_ci' | '
|
|
|
82
76
|
export type WaitReason = 'pending_review' | 'pending_merge' | 'changes_addressed' | 'ci_blocked' | 'stale_ci_failure';
|
|
83
77
|
/** How stale is the PR based on days since activity. Orthogonal to status. */
|
|
84
78
|
export type StalenessTier = 'active' | 'approaching_dormant' | 'dormant';
|
|
85
|
-
/**
|
|
86
|
-
* Top-level classification of a PR's state. Only two values:
|
|
87
|
-
* - `needs_addressing` — Contributor's turn. See `actionReason` for what to do.
|
|
88
|
-
* - `waiting_on_maintainer` — Maintainer's turn. See `waitReason` for why.
|
|
89
|
-
*
|
|
90
|
-
* Staleness (active/approaching_dormant/dormant) is tracked separately in `stalenessTier`.
|
|
91
|
-
*/
|
|
92
|
-
export type FetchedPRStatus = 'needs_addressing' | 'waiting_on_maintainer';
|
|
93
79
|
/**
|
|
94
80
|
* Hints about what a maintainer is asking for in their review comments.
|
|
95
81
|
* Extracted from comment text by keyword matching.
|
|
@@ -158,68 +144,6 @@ export interface FetchedPR {
|
|
|
158
144
|
/** Hints extracted from maintainer comments about what actions they are requesting. */
|
|
159
145
|
maintainerActionHints: MaintainerActionHint[];
|
|
160
146
|
}
|
|
161
|
-
/**
|
|
162
|
-
* Lightweight reference used in {@link DailyDigest} for shelved and auto-unshelved PRs.
|
|
163
|
-
* Contains only the fields needed for display, avoiding duplication of the full
|
|
164
|
-
* {@link FetchedPR} objects already present in `openPRs` and the status-specific arrays.
|
|
165
|
-
* Derived from {@link FetchedPR} via `Pick<>` to stay in sync automatically.
|
|
166
|
-
*/
|
|
167
|
-
export type ShelvedPRRef = Pick<FetchedPR, 'number' | 'url' | 'title' | 'repo' | 'daysSinceActivity' | 'status'>;
|
|
168
|
-
/** An issue tracked through the contribution pipeline from discovery to PR submission. */
|
|
169
|
-
export interface TrackedIssue {
|
|
170
|
-
id: number;
|
|
171
|
-
url: string;
|
|
172
|
-
repo: string;
|
|
173
|
-
number: number;
|
|
174
|
-
title: string;
|
|
175
|
-
status: IssueStatus;
|
|
176
|
-
labels: string[];
|
|
177
|
-
createdAt: string;
|
|
178
|
-
updatedAt: string;
|
|
179
|
-
/** Whether the issue has been through the vetting process (checking for existing PRs, activity, etc.). */
|
|
180
|
-
vetted: boolean;
|
|
181
|
-
vettingResult?: IssueVettingResult;
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Result of vetting an issue for contribution suitability.
|
|
185
|
-
* An issue passes vetting when all checks are true (no existing PR, not claimed, etc.).
|
|
186
|
-
*/
|
|
187
|
-
export interface IssueVettingResult {
|
|
188
|
-
passedAllChecks: boolean;
|
|
189
|
-
checks: {
|
|
190
|
-
noExistingPR: boolean;
|
|
191
|
-
notClaimed: boolean;
|
|
192
|
-
projectActive: boolean;
|
|
193
|
-
clearRequirements: boolean;
|
|
194
|
-
contributionGuidelinesFound: boolean;
|
|
195
|
-
};
|
|
196
|
-
contributionGuidelines?: ContributionGuidelines;
|
|
197
|
-
/** Free-text observations from the vetting process (e.g., "Issue has 3 linked PRs, all closed"). */
|
|
198
|
-
notes: string[];
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Structured representation of a project's contribution guidelines,
|
|
202
|
-
* extracted from CONTRIBUTING.md or similar files during issue vetting.
|
|
203
|
-
*/
|
|
204
|
-
export interface ContributionGuidelines {
|
|
205
|
-
branchNamingConvention?: string;
|
|
206
|
-
commitMessageFormat?: string;
|
|
207
|
-
prTitleFormat?: string;
|
|
208
|
-
requiredChecks?: string[];
|
|
209
|
-
testFramework?: string;
|
|
210
|
-
testCoverageRequired?: boolean;
|
|
211
|
-
/** Expected test file naming pattern (e.g., `"*.test.ts"`, `"*_spec.rb"`). */
|
|
212
|
-
testFileNaming?: string;
|
|
213
|
-
linter?: string;
|
|
214
|
-
formatter?: string;
|
|
215
|
-
styleGuideUrl?: string;
|
|
216
|
-
/** How to claim an issue (e.g., "Comment on the issue before starting work"). */
|
|
217
|
-
issueClaimProcess?: string;
|
|
218
|
-
reviewProcess?: string;
|
|
219
|
-
claRequired?: boolean;
|
|
220
|
-
/** Raw CONTRIBUTING.md content for reference when structured fields are insufficient. */
|
|
221
|
-
rawContent?: string;
|
|
222
|
-
}
|
|
223
147
|
/** Health snapshot of a GitHub repository, used to determine if a project is worth contributing to. */
|
|
224
148
|
export interface ProjectHealth {
|
|
225
149
|
repo: string;
|
|
@@ -239,38 +163,6 @@ export interface ProjectHealth {
|
|
|
239
163
|
checkFailed?: boolean;
|
|
240
164
|
failureReason?: string;
|
|
241
165
|
}
|
|
242
|
-
/**
|
|
243
|
-
* Quality score for a repository, used to prioritize issue search results.
|
|
244
|
-
* Score is on a 1-10 scale: base 5, logarithmic merge bonus (max +5: 1->+2, 2->+3, 3->+4, 5+->+5),
|
|
245
|
-
* -1 per closed-without-merge (max -3), +1 if lastMergedAt is set and within 90 days,
|
|
246
|
-
* +1 if responsive, -2 if hostile.
|
|
247
|
-
* Repos below `AgentConfig.minRepoScoreThreshold` are deprioritized.
|
|
248
|
-
*/
|
|
249
|
-
export interface RepoScore {
|
|
250
|
-
repo: string;
|
|
251
|
-
/** Overall score from 1 (avoid) to 10 (excellent track record). */
|
|
252
|
-
score: number;
|
|
253
|
-
/** Number of the contributor's PRs that were merged in this repo. */
|
|
254
|
-
mergedPRCount: number;
|
|
255
|
-
/** Number of the contributor's PRs closed without merge (indicates friction). */
|
|
256
|
-
closedWithoutMergeCount: number;
|
|
257
|
-
/** Average days for maintainers to respond; null if no data. */
|
|
258
|
-
avgResponseDays: number | null;
|
|
259
|
-
lastMergedAt?: string;
|
|
260
|
-
lastEvaluatedAt: string;
|
|
261
|
-
/** Qualitative signals about the repo's maintainer culture. */
|
|
262
|
-
signals: RepoSignals;
|
|
263
|
-
/** GitHub star count, fetched during daily check for dashboard filtering. */
|
|
264
|
-
stargazersCount?: number;
|
|
265
|
-
/** Primary programming language of the repo, fetched during daily check. */
|
|
266
|
-
language?: string | null;
|
|
267
|
-
}
|
|
268
|
-
/** Full set of qualitative signals about a repo's maintainer culture. */
|
|
269
|
-
export interface RepoSignals {
|
|
270
|
-
hasActiveMaintainers: boolean;
|
|
271
|
-
isResponsive: boolean;
|
|
272
|
-
hasHostileComments: boolean;
|
|
273
|
-
}
|
|
274
166
|
/** Signals computed from observed open PR data, suitable for merging into RepoScore.signals. */
|
|
275
167
|
export type ComputedRepoSignals = Pick<RepoSignals, 'isResponsive' | 'hasActiveMaintainers'>;
|
|
276
168
|
/**
|
|
@@ -294,141 +186,6 @@ export interface RepoMetadataEntry {
|
|
|
294
186
|
stars?: number;
|
|
295
187
|
language?: string | null;
|
|
296
188
|
}
|
|
297
|
-
/**
|
|
298
|
-
* Event types recorded in the {@link AgentState} audit log.
|
|
299
|
-
* - `pr_tracked` — A new PR was added to tracking
|
|
300
|
-
* - `pr_merged` — A tracked PR was merged
|
|
301
|
-
* - `pr_closed` — A tracked PR was closed without merge
|
|
302
|
-
* - `pr_dormant` — A PR crossed the dormant threshold
|
|
303
|
-
* - `daily_check` — A daily digest run completed
|
|
304
|
-
* - `comment_posted` — The agent posted a comment on a PR
|
|
305
|
-
*/
|
|
306
|
-
export type StateEventType = 'pr_tracked' | 'pr_merged' | 'pr_closed' | 'pr_dormant' | 'daily_check' | 'comment_posted';
|
|
307
|
-
/** An entry in the state audit log. Events are append-only and used for history tracking. */
|
|
308
|
-
export interface StateEvent {
|
|
309
|
-
id: string;
|
|
310
|
-
type: StateEventType;
|
|
311
|
-
/** ISO 8601 timestamp of when the event occurred. */
|
|
312
|
-
at: string;
|
|
313
|
-
/** Event-specific payload (e.g., `{ repo: "owner/repo", number: 42 }` for PR events). */
|
|
314
|
-
data: Record<string, unknown>;
|
|
315
|
-
}
|
|
316
|
-
/** Minimal record of a PR that was closed without being merged, used in the daily digest and dashboard detail view. */
|
|
317
|
-
export interface ClosedPR {
|
|
318
|
-
url: string;
|
|
319
|
-
repo: string;
|
|
320
|
-
number: number;
|
|
321
|
-
title: string;
|
|
322
|
-
closedAt: string;
|
|
323
|
-
closedBy?: string;
|
|
324
|
-
}
|
|
325
|
-
/** Minimal merged PR data persisted in state.json. Repo/number derived from URL at display time. */
|
|
326
|
-
export interface StoredMergedPR {
|
|
327
|
-
url: string;
|
|
328
|
-
title: string;
|
|
329
|
-
mergedAt: string;
|
|
330
|
-
}
|
|
331
|
-
/** Minimal closed PR data persisted in state.json. Repo/number derived from URL at display time. */
|
|
332
|
-
export interface StoredClosedPR {
|
|
333
|
-
url: string;
|
|
334
|
-
title: string;
|
|
335
|
-
closedAt: string;
|
|
336
|
-
}
|
|
337
|
-
/** Minimal record of a PR that was merged, used in the daily digest and dashboard detail view. */
|
|
338
|
-
export interface MergedPR {
|
|
339
|
-
url: string;
|
|
340
|
-
repo: string;
|
|
341
|
-
number: number;
|
|
342
|
-
title: string;
|
|
343
|
-
mergedAt: string;
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* The daily report produced by `PRMonitor.generateDigest()`.
|
|
347
|
-
* Contains all open PRs fetched fresh from GitHub, categorized by status,
|
|
348
|
-
* plus recently closed PRs and summary statistics. This is persisted in
|
|
349
|
-
* `AgentState.lastDigest` so the HTML dashboard can render it.
|
|
350
|
-
*/
|
|
351
|
-
export interface DailyDigest {
|
|
352
|
-
generatedAt: string;
|
|
353
|
-
/** All open PRs authored by the user, fetched from GitHub Search API. */
|
|
354
|
-
openPRs: FetchedPR[];
|
|
355
|
-
/** PRs where the contributor needs to take action. Subset of openPRs where status === 'needs_addressing'. */
|
|
356
|
-
needsAddressingPRs: FetchedPR[];
|
|
357
|
-
/** PRs waiting on the maintainer. Subset of openPRs where status === 'waiting_on_maintainer'. */
|
|
358
|
-
waitingOnMaintainerPRs: FetchedPR[];
|
|
359
|
-
/** PRs closed without merge in the last 7 days. Surfaced to alert the contributor. */
|
|
360
|
-
recentlyClosedPRs: ClosedPR[];
|
|
361
|
-
/** PRs merged in the last 7 days. Surfaced as wins in the dashboard. */
|
|
362
|
-
recentlyMergedPRs: MergedPR[];
|
|
363
|
-
/**
|
|
364
|
-
* PRs manually shelved by the user (excluded from capacity and actionable issues).
|
|
365
|
-
* Stored as lightweight references — full data is available in `openPRs`.
|
|
366
|
-
*/
|
|
367
|
-
shelvedPRs: ShelvedPRRef[];
|
|
368
|
-
/**
|
|
369
|
-
* PRs that were auto-unshelved this run because a maintainer engaged.
|
|
370
|
-
* Stored as lightweight references — full data is available in `openPRs`.
|
|
371
|
-
*/
|
|
372
|
-
autoUnshelvedPRs: ShelvedPRRef[];
|
|
373
|
-
summary: {
|
|
374
|
-
totalActivePRs: number;
|
|
375
|
-
/** Count of PRs requiring contributor action (response, CI fix, conflict resolution, etc.). */
|
|
376
|
-
totalNeedingAttention: number;
|
|
377
|
-
/** Lifetime merged PR count across all repos, derived from RepoScore data. */
|
|
378
|
-
totalMergedAllTime: number;
|
|
379
|
-
/** Percentage of all-time PRs that were merged (merged / (merged + closed)). */
|
|
380
|
-
mergeRate: number;
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Root state object persisted to `~/.oss-autopilot/state.json`.
|
|
385
|
-
*
|
|
386
|
-
* In v2 (current), PRs are fetched fresh from GitHub on each run via the Search API.
|
|
387
|
-
* The primary runtime data lives in `lastDigest` and `repoScores`.
|
|
388
|
-
*/
|
|
389
|
-
export interface AgentState {
|
|
390
|
-
/** Schema version. `2` = v2 fresh-fetch architecture. Used by `StateManager` for migrations. */
|
|
391
|
-
version: number;
|
|
392
|
-
/** Per-repo quality scores keyed by `"owner/repo"`. Used to prioritize issue search results. */
|
|
393
|
-
repoScores: Record<string, RepoScore>;
|
|
394
|
-
config: AgentConfig;
|
|
395
|
-
/** Append-only audit log of significant events (PR merged, daily check, etc.). */
|
|
396
|
-
events: StateEvent[];
|
|
397
|
-
/** ISO timestamp of the last CLI invocation. */
|
|
398
|
-
lastRunAt: string;
|
|
399
|
-
/** ISO timestamp of the last daily digest generation. */
|
|
400
|
-
lastDigestAt?: string;
|
|
401
|
-
/** Cached daily digest so the HTML dashboard can render without re-fetching from GitHub. */
|
|
402
|
-
lastDigest?: DailyDigest;
|
|
403
|
-
/** Monthly merged PR counts keyed by `"YYYY-MM"`. Powers the contribution timeline chart. */
|
|
404
|
-
monthlyMergedCounts?: Record<string, number>;
|
|
405
|
-
/** Monthly closed (without merge) PR counts keyed by `"YYYY-MM"`. Powers the timeline and success rate charts. */
|
|
406
|
-
monthlyClosedCounts?: Record<string, number>;
|
|
407
|
-
/** Monthly opened PR counts keyed by `"YYYY-MM"`. Combines PRs opened across merged+closed+open sets. */
|
|
408
|
-
monthlyOpenedCounts?: Record<string, number>;
|
|
409
|
-
/** Daily activity counts keyed by `"YYYY-MM-DD"`. Powers the activity heatmap chart. */
|
|
410
|
-
dailyActivityCounts?: Record<string, number>;
|
|
411
|
-
/** Cached local repo scan results (#84). Avoids re-scanning the filesystem every session. */
|
|
412
|
-
localRepoCache?: LocalRepoCache;
|
|
413
|
-
/** All merged PRs stored incrementally. Source of truth for the merged PR detail view. */
|
|
414
|
-
mergedPRs?: StoredMergedPR[];
|
|
415
|
-
/** All closed PRs stored incrementally. Source of truth for the closed PR detail view. */
|
|
416
|
-
closedPRs?: StoredClosedPR[];
|
|
417
|
-
activeIssues: TrackedIssue[];
|
|
418
|
-
}
|
|
419
|
-
/** Cached results from scanning the filesystem for local git clones (#84). */
|
|
420
|
-
export interface LocalRepoCache {
|
|
421
|
-
/** Map of "owner/repo" -> local repo info */
|
|
422
|
-
repos: Record<string, {
|
|
423
|
-
path: string;
|
|
424
|
-
exists: boolean;
|
|
425
|
-
currentBranch: string | null;
|
|
426
|
-
}>;
|
|
427
|
-
/** Directories that were scanned */
|
|
428
|
-
scanPaths: string[];
|
|
429
|
-
/** ISO 8601 timestamp of when the scan was performed */
|
|
430
|
-
cachedAt: string;
|
|
431
|
-
}
|
|
432
189
|
/** Filter for excluding repos below a minimum star count from PR count queries. */
|
|
433
190
|
export interface StarFilter {
|
|
434
191
|
minStars: number;
|
|
@@ -439,68 +196,6 @@ export interface StarFilter {
|
|
|
439
196
|
* Returns true if the repo is below the threshold or has unknown star count.
|
|
440
197
|
*/
|
|
441
198
|
export declare function isBelowMinStars(stargazersCount: number | undefined, minStars: number): boolean;
|
|
442
|
-
/** Manual status override for a PR, set via dashboard or CLI. Auto-clears when new activity is detected. */
|
|
443
|
-
export interface StatusOverride {
|
|
444
|
-
status: FetchedPRStatus;
|
|
445
|
-
setAt: string;
|
|
446
|
-
/** PR's updatedAt at the time the override was set. Used to detect new activity for auto-clear. */
|
|
447
|
-
lastActivityAt: string;
|
|
448
|
-
}
|
|
449
|
-
/** User-configurable settings, populated via `/setup-oss` and stored in {@link AgentState}. */
|
|
450
|
-
export interface AgentConfig {
|
|
451
|
-
/** False until the user completes initial setup via `/setup-oss`. */
|
|
452
|
-
setupComplete: boolean;
|
|
453
|
-
setupCompletedAt?: string;
|
|
454
|
-
maxActivePRs: number;
|
|
455
|
-
/** Days of inactivity before a PR is marked `dormant`. Default 30. */
|
|
456
|
-
dormantThresholdDays: number;
|
|
457
|
-
/** Days of inactivity before a PR is marked `approaching_dormant`. Default 25. */
|
|
458
|
-
approachingDormantDays: number;
|
|
459
|
-
/** Issues older than this (by `updated_at`) are filtered from search results. Default 90. */
|
|
460
|
-
maxIssueAgeDays: number;
|
|
461
|
-
/** Programming languages to search for issues in (e.g., `["typescript", "javascript"]`). */
|
|
462
|
-
languages: string[];
|
|
463
|
-
/** GitHub labels to filter issues by (e.g., `["good first issue", "help wanted"]`). */
|
|
464
|
-
labels: string[];
|
|
465
|
-
/** Issue scope tiers to search (e.g., `["beginner", "intermediate"]`). When set, scope tier labels are merged with custom `labels`. When absent, only `labels` is used (legacy behavior). */
|
|
466
|
-
scope?: IssueScope[];
|
|
467
|
-
/** Repos to exclude from issue discovery/search, in `"owner/repo"` format. */
|
|
468
|
-
excludeRepos: string[];
|
|
469
|
-
/** Organizations to exclude from issue discovery/search (case-insensitive match on owner segment). */
|
|
470
|
-
excludeOrgs?: string[];
|
|
471
|
-
/** Repos where the contributor has had PRs merged. Used for prioritization. */
|
|
472
|
-
trustedProjects: string[];
|
|
473
|
-
githubUsername: string;
|
|
474
|
-
/** Minimum {@link RepoScore} to include a repo in search results. Default 4. */
|
|
475
|
-
minRepoScoreThreshold: number;
|
|
476
|
-
/** User's GitHub starred repos, fetched periodically for prioritized issue discovery. */
|
|
477
|
-
starredRepos: string[];
|
|
478
|
-
starredReposLastFetched?: string;
|
|
479
|
-
/** Whether to show the health check notification on session start. Default true. */
|
|
480
|
-
showHealthCheck?: boolean;
|
|
481
|
-
/** Whether to squash commits before marking PR ready. `true` (default), `false`, or `"ask"`. */
|
|
482
|
-
squashByDefault?: boolean | 'ask';
|
|
483
|
-
/** Directories to scan for local git clones (#84). Falls back to default paths if not set. */
|
|
484
|
-
localRepoScanPaths?: string[];
|
|
485
|
-
/** Minimum GitHub star count for Phase 2 (general search) results. Default 50. Phases 0/1 are exempt. */
|
|
486
|
-
minStars?: number;
|
|
487
|
-
/** Whether to include documentation-only issues in search results. Default true. */
|
|
488
|
-
includeDocIssues?: boolean;
|
|
489
|
-
/** Repos known to have anti-AI contribution policies, in `"owner/repo"` format. Filtered from search results automatically. */
|
|
490
|
-
aiPolicyBlocklist?: string[];
|
|
491
|
-
/** PR URLs manually shelved by the user. Shelved PRs are excluded from capacity and actionable issues. Auto-unshelved when maintainers engage. */
|
|
492
|
-
shelvedPRUrls?: string[];
|
|
493
|
-
/** Issue URLs dismissed by the user, mapped to ISO timestamp of when dismissed. Issues with new responses after the dismiss timestamp resurface automatically. */
|
|
494
|
-
dismissedIssues?: Record<string, string>;
|
|
495
|
-
/** Manual status overrides for PRs. Maps PR URL to override metadata. Auto-clears when the PR has new activity. */
|
|
496
|
-
statusOverrides?: Record<string, StatusOverride>;
|
|
497
|
-
/** Path to the user's curated issue list file. Replaces config.md as the primary source for detectIssueList(). */
|
|
498
|
-
issueListPath?: string;
|
|
499
|
-
/** Project categories the user is interested in (e.g., devtools, nonprofit). Used to prioritize search results. */
|
|
500
|
-
projectCategories?: ProjectCategory[];
|
|
501
|
-
/** GitHub organizations the user wants to prioritize in issue search. Org names only (not owner/repo). */
|
|
502
|
-
preferredOrgs?: string[];
|
|
503
|
-
}
|
|
504
199
|
/** Status of a user's comment thread on a GitHub issue. */
|
|
505
200
|
export type IssueConversationStatus = 'new_response' | 'waiting' | 'acknowledged';
|
|
506
201
|
/** Base fields shared by all issue conversation states. */
|
|
@@ -538,10 +233,8 @@ export type CommentedIssue = CommentedIssueWithResponse | CommentedIssueWithoutR
|
|
|
538
233
|
export declare const DEFAULT_CONFIG: AgentConfig;
|
|
539
234
|
/** Initial state written to `~/.oss-autopilot/state.json` on first run. Uses v2 architecture. */
|
|
540
235
|
export declare const INITIAL_STATE: AgentState;
|
|
541
|
-
export declare const PROJECT_CATEGORIES:
|
|
542
|
-
export
|
|
543
|
-
export declare const ISSUE_SCOPES: readonly ["beginner", "intermediate", "advanced"];
|
|
544
|
-
export type IssueScope = (typeof ISSUE_SCOPES)[number];
|
|
236
|
+
export declare const PROJECT_CATEGORIES: ("nonprofit" | "devtools" | "infrastructure" | "web-frameworks" | "data-ml" | "education")[];
|
|
237
|
+
export declare const ISSUE_SCOPES: ("advanced" | "beginner" | "intermediate")[];
|
|
545
238
|
export declare const SCOPE_LABELS: Record<IssueScope, string[]>;
|
|
546
239
|
/** Priority tier for issue search results. Ordered: merged_pr > preferred_org > starred > normal. */
|
|
547
240
|
export type SearchPriority = 'merged_pr' | 'preferred_org' | 'starred' | 'normal';
|
|
@@ -555,4 +248,3 @@ export interface IssueCandidate {
|
|
|
555
248
|
viabilityScore: number;
|
|
556
249
|
searchPriority: SearchPriority;
|
|
557
250
|
}
|
|
558
|
-
export {};
|
package/dist/core/types.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core types for the Open Source Contribution Agent
|
|
3
3
|
*/
|
|
4
|
+
import { AgentConfigSchema, AgentStateSchema, ProjectCategorySchema, IssueScopeSchema } from './state-schema.js';
|
|
4
5
|
/**
|
|
5
6
|
* Check if a repo should be excluded based on its star count.
|
|
6
7
|
* Returns true if the repo is below the threshold or has unknown star count.
|
|
@@ -8,49 +9,14 @@
|
|
|
8
9
|
export function isBelowMinStars(stargazersCount, minStars) {
|
|
9
10
|
return stargazersCount === undefined || stargazersCount < minStars;
|
|
10
11
|
}
|
|
12
|
+
// ── Schema-derived constants ─────────────────────────────────────────
|
|
11
13
|
/** Default configuration applied to new state files. All fields can be overridden via `/setup-oss`. */
|
|
12
|
-
export const DEFAULT_CONFIG = {
|
|
13
|
-
setupComplete: false,
|
|
14
|
-
maxActivePRs: 10,
|
|
15
|
-
dormantThresholdDays: 30,
|
|
16
|
-
approachingDormantDays: 25,
|
|
17
|
-
maxIssueAgeDays: 90,
|
|
18
|
-
languages: ['typescript', 'javascript'],
|
|
19
|
-
labels: ['good first issue', 'help wanted'],
|
|
20
|
-
excludeRepos: [],
|
|
21
|
-
trustedProjects: [],
|
|
22
|
-
githubUsername: '',
|
|
23
|
-
minRepoScoreThreshold: 4,
|
|
24
|
-
starredRepos: [],
|
|
25
|
-
squashByDefault: true,
|
|
26
|
-
minStars: 50,
|
|
27
|
-
includeDocIssues: true,
|
|
28
|
-
aiPolicyBlocklist: ['matplotlib/matplotlib'],
|
|
29
|
-
shelvedPRUrls: [],
|
|
30
|
-
dismissedIssues: {},
|
|
31
|
-
projectCategories: [],
|
|
32
|
-
preferredOrgs: [],
|
|
33
|
-
};
|
|
14
|
+
export const DEFAULT_CONFIG = AgentConfigSchema.parse({});
|
|
34
15
|
/** Initial state written to `~/.oss-autopilot/state.json` on first run. Uses v2 architecture. */
|
|
35
|
-
export const INITIAL_STATE = {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
config: DEFAULT_CONFIG,
|
|
40
|
-
events: [],
|
|
41
|
-
lastRunAt: new Date().toISOString(),
|
|
42
|
-
};
|
|
43
|
-
// -- Project category types --
|
|
44
|
-
export const PROJECT_CATEGORIES = [
|
|
45
|
-
'nonprofit',
|
|
46
|
-
'devtools',
|
|
47
|
-
'infrastructure',
|
|
48
|
-
'web-frameworks',
|
|
49
|
-
'data-ml',
|
|
50
|
-
'education',
|
|
51
|
-
];
|
|
52
|
-
// -- Issue scope types --
|
|
53
|
-
export const ISSUE_SCOPES = ['beginner', 'intermediate', 'advanced'];
|
|
16
|
+
export const INITIAL_STATE = AgentStateSchema.parse({ version: 2 });
|
|
17
|
+
// ── Const arrays (derived from Zod schemas for runtime iteration) ────
|
|
18
|
+
export const PROJECT_CATEGORIES = ProjectCategorySchema.options;
|
|
19
|
+
export const ISSUE_SCOPES = IssueScopeSchema.options;
|
|
54
20
|
export const SCOPE_LABELS = {
|
|
55
21
|
beginner: ['good first issue', 'help wanted', 'easy', 'up-for-grabs', 'first-timers-only', 'beginner'],
|
|
56
22
|
intermediate: ['enhancement', 'feature', 'feature-request', 'contributions welcome'],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oss-autopilot/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.60.1",
|
|
4
4
|
"description": "CLI and core library for managing open source contributions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@octokit/plugin-throttling": "^11.0.3",
|
|
52
52
|
"@octokit/rest": "^22.0.1",
|
|
53
|
-
"commander": "^14.0.3"
|
|
53
|
+
"commander": "^14.0.3",
|
|
54
|
+
"zod": "^4.3.6"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
56
57
|
"@types/node": "^25.4.0",
|