@oss-autopilot/core 0.58.0 → 0.60.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 (56) hide show
  1. package/dist/cli-registry.js +54 -0
  2. package/dist/cli.bundle.cjs +151 -108
  3. package/dist/commands/comments.d.ts +28 -0
  4. package/dist/commands/comments.js +28 -0
  5. package/dist/commands/config.d.ts +11 -0
  6. package/dist/commands/config.js +11 -0
  7. package/dist/commands/daily.d.ts +26 -2
  8. package/dist/commands/daily.js +26 -2
  9. package/dist/commands/detect-formatters.d.ts +11 -0
  10. package/dist/commands/detect-formatters.js +24 -0
  11. package/dist/commands/dismiss.d.ts +17 -0
  12. package/dist/commands/dismiss.js +17 -0
  13. package/dist/commands/index.d.ts +3 -1
  14. package/dist/commands/index.js +2 -0
  15. package/dist/commands/init.d.ts +8 -0
  16. package/dist/commands/init.js +8 -0
  17. package/dist/commands/move.d.ts +10 -0
  18. package/dist/commands/move.js +10 -0
  19. package/dist/commands/search.d.ts +18 -0
  20. package/dist/commands/search.js +18 -0
  21. package/dist/commands/setup.d.ts +17 -0
  22. package/dist/commands/setup.js +17 -0
  23. package/dist/commands/shelve.d.ts +16 -0
  24. package/dist/commands/shelve.js +16 -0
  25. package/dist/commands/startup.d.ts +16 -7
  26. package/dist/commands/startup.js +16 -7
  27. package/dist/commands/status.d.ts +8 -0
  28. package/dist/commands/status.js +8 -0
  29. package/dist/commands/track.d.ts +16 -0
  30. package/dist/commands/track.js +16 -0
  31. package/dist/commands/vet.d.ts +8 -0
  32. package/dist/commands/vet.js +8 -0
  33. package/dist/core/daily-logic.d.ts +60 -7
  34. package/dist/core/daily-logic.js +52 -7
  35. package/dist/core/formatter-detection.d.ts +61 -0
  36. package/dist/core/formatter-detection.js +360 -0
  37. package/dist/core/github.d.ts +25 -2
  38. package/dist/core/github.js +25 -2
  39. package/dist/core/index.d.ts +1 -0
  40. package/dist/core/index.js +1 -0
  41. package/dist/core/issue-discovery.d.ts +46 -6
  42. package/dist/core/issue-discovery.js +46 -6
  43. package/dist/core/logger.d.ts +13 -0
  44. package/dist/core/logger.js +13 -0
  45. package/dist/core/pr-monitor.d.ts +43 -8
  46. package/dist/core/pr-monitor.js +43 -8
  47. package/dist/core/state-persistence.d.ts +1 -0
  48. package/dist/core/state-persistence.js +46 -84
  49. package/dist/core/state-schema.d.ts +539 -0
  50. package/dist/core/state-schema.js +214 -0
  51. package/dist/core/state.d.ts +167 -0
  52. package/dist/core/state.js +167 -0
  53. package/dist/core/types.d.ts +4 -318
  54. package/dist/core/types.js +7 -41
  55. package/dist/formatters/json.d.ts +5 -0
  56. package/package.json +8 -4
@@ -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
+ });
@@ -30,6 +30,7 @@ export declare class StateManager {
30
30
  /**
31
31
  * Execute multiple mutations as a single batch, deferring disk I/O until the
32
32
  * batch completes. Nested `batch()` calls are flattened — only the outermost saves.
33
+ * @param fn - The function containing mutations to batch
33
34
  */
34
35
  batch(fn: () => void): void;
35
36
  /**
@@ -63,51 +64,217 @@ export declare class StateManager {
63
64
  * Returns true if state was reloaded, false if unchanged or in-memory mode.
64
65
  */
65
66
  reloadIfChanged(): boolean;
67
+ /**
68
+ * Store the latest daily digest and update the digest timestamp.
69
+ * @param digest - The daily digest to store
70
+ */
66
71
  setLastDigest(digest: DailyDigest): void;
72
+ /**
73
+ * Update monthly merged PR counts for dashboard display.
74
+ * @param counts - Monthly merged PR counts keyed by YYYY-MM
75
+ */
67
76
  setMonthlyMergedCounts(counts: Record<string, number>): void;
77
+ /**
78
+ * Update monthly closed PR counts for dashboard display.
79
+ * @param counts - Monthly closed PR counts keyed by YYYY-MM
80
+ */
68
81
  setMonthlyClosedCounts(counts: Record<string, number>): void;
82
+ /**
83
+ * Update monthly opened PR counts for dashboard display.
84
+ * @param counts - Monthly opened PR counts keyed by YYYY-MM
85
+ */
69
86
  setMonthlyOpenedCounts(counts: Record<string, number>): void;
87
+ /**
88
+ * Update daily activity counts for dashboard display.
89
+ * @param counts - Daily activity counts keyed by YYYY-MM-DD
90
+ */
70
91
  setDailyActivityCounts(counts: Record<string, number>): void;
92
+ /**
93
+ * Update the local repository cache.
94
+ * @param cache - Local repository cache mapping repo names to paths
95
+ */
71
96
  setLocalRepoCache(cache: LocalRepoCache): void;
97
+ /** Returns all stored merged PRs (sorted by merge date descending via addMergedPRs). */
72
98
  getMergedPRs(): StoredMergedPR[];
99
+ /**
100
+ * Add merged PRs to storage, deduplicating by URL.
101
+ * @param prs - Merged PRs to add (duplicates by URL are ignored)
102
+ */
73
103
  addMergedPRs(prs: StoredMergedPR[]): void;
104
+ /** Returns the most recent merge date, used as a watermark for incremental fetching. */
74
105
  getMergedPRWatermark(): string | undefined;
106
+ /** Returns all stored closed-without-merge PRs (sorted by close date descending via addClosedPRs). */
75
107
  getClosedPRs(): StoredClosedPR[];
108
+ /**
109
+ * Add closed PRs to storage, deduplicating by URL.
110
+ * @param prs - Closed PRs to add (duplicates by URL are ignored)
111
+ */
76
112
  addClosedPRs(prs: StoredClosedPR[]): void;
113
+ /** Returns the most recent close date, used as a watermark for incremental fetching. */
77
114
  getClosedPRWatermark(): string | undefined;
115
+ /**
116
+ * Merge partial config updates into the current configuration.
117
+ * @param config - Partial config object to merge
118
+ */
78
119
  updateConfig(config: Partial<AgentState['config']>): void;
120
+ /**
121
+ * Append a new event to the event log and auto-persist.
122
+ * Events are capped at 1000 to prevent unbounded growth.
123
+ * @param type - The event type identifier
124
+ * @param data - Arbitrary event payload
125
+ */
79
126
  appendEvent(type: StateEventType, data: Record<string, unknown>): void;
127
+ /**
128
+ * Filter events by type.
129
+ * @param type - The event type to filter by
130
+ * @returns Events matching the given type
131
+ */
80
132
  getEventsByType(type: StateEventType): StateEvent[];
133
+ /**
134
+ * Filter events within a date range.
135
+ * @param since - Start of range (inclusive)
136
+ * @param until - End of range (inclusive), defaults to now
137
+ * @returns Events within the date range
138
+ */
81
139
  getEventsInRange(since: Date, until?: Date): StateEvent[];
140
+ /**
141
+ * Track a new issue. No-op if the issue URL is already tracked.
142
+ * @param issue - The issue to track
143
+ */
82
144
  addIssue(issue: TrackedIssue): void;
145
+ /**
146
+ * Add a repository to the trusted projects list. No-op if already trusted.
147
+ * @param repo - Repository in "owner/repo" format
148
+ */
83
149
  addTrustedProject(repo: string): void;
84
150
  private static matchesExclusion;
151
+ /**
152
+ * Remove excluded repos/orgs from trusted projects.
153
+ * @param repos - Repository names to exclude
154
+ * @param orgs - Organization names to exclude
155
+ */
85
156
  cleanupExcludedData(repos: string[], orgs: string[]): void;
157
+ /** Returns cached starred repository names. */
86
158
  getStarredRepos(): string[];
159
+ /**
160
+ * Update the cached starred repositories and timestamp.
161
+ * @param repos - Repository names in "owner/repo" format
162
+ */
87
163
  setStarredRepos(repos: string[]): void;
164
+ /** Returns true if starred repos cache is older than 24 hours. */
88
165
  isStarredReposStale(): boolean;
166
+ /**
167
+ * Shelve a PR URL, hiding it from daily digest and capacity.
168
+ * @param url - The PR URL to shelve
169
+ * @returns true if newly shelved, false if already shelved
170
+ */
89
171
  shelvePR(url: string): boolean;
172
+ /**
173
+ * Unshelve a PR URL, restoring it to daily digest.
174
+ * @param url - The PR URL to unshelve
175
+ * @returns true if removed from shelf, false if not shelved
176
+ */
90
177
  unshelvePR(url: string): boolean;
178
+ /**
179
+ * Check if a PR is currently shelved.
180
+ * @param url - The PR URL to check
181
+ * @returns true if the PR is shelved
182
+ */
91
183
  isPRShelved(url: string): boolean;
184
+ /**
185
+ * Dismiss an issue's notifications. Auto-resurfaces on new activity.
186
+ * @param url - The issue URL to dismiss
187
+ * @param timestamp - ISO timestamp of dismissal
188
+ * @returns true if newly dismissed, false if already dismissed
189
+ */
92
190
  dismissIssue(url: string, timestamp: string): boolean;
191
+ /**
192
+ * Restore a dismissed issue to notifications.
193
+ * @param url - The issue URL to undismiss
194
+ * @returns true if undismissed, false if not currently dismissed
195
+ */
93
196
  undismissIssue(url: string): boolean;
197
+ /**
198
+ * Get the timestamp when an issue was dismissed, or undefined if not dismissed.
199
+ * @param url - The issue URL to check
200
+ */
94
201
  getIssueDismissedAt(url: string): string | undefined;
202
+ /**
203
+ * Set a manual status override for a PR. Auto-clears when the PR has new activity.
204
+ * @param url - The PR URL
205
+ * @param status - The overridden status
206
+ * @param lastActivityAt - ISO timestamp of PR's last activity when override was set
207
+ */
95
208
  setStatusOverride(url: string, status: FetchedPRStatus, lastActivityAt: string): void;
209
+ /**
210
+ * Remove a manual status override for a PR.
211
+ * @param url - The PR URL
212
+ * @returns true if an override was removed, false if none existed
213
+ */
96
214
  clearStatusOverride(url: string): boolean;
215
+ /**
216
+ * Get the status override for a PR, auto-clearing if new activity has occurred.
217
+ * @param url - The PR URL
218
+ * @param currentUpdatedAt - PR's current updatedAt timestamp for staleness check
219
+ * @returns The override if still valid, undefined otherwise
220
+ */
97
221
  getStatusOverride(url: string, currentUpdatedAt?: string): StatusOverride | undefined;
222
+ /**
223
+ * Get the score record for a repository.
224
+ * @param repo - Repository in "owner/repo" format
225
+ * @returns Read-only score record, or undefined if not tracked
226
+ */
98
227
  getRepoScore(repo: string): Readonly<RepoScore> | undefined;
228
+ /**
229
+ * Update scoring data for a repository.
230
+ * @param repo - Repository in "owner/repo" format
231
+ * @param updates - Partial score fields to merge
232
+ */
99
233
  updateRepoScore(repo: string, updates: RepoScoreUpdate): void;
234
+ /**
235
+ * Increment the merged PR count for a repository.
236
+ * @param repo - Repository in "owner/repo" format
237
+ */
100
238
  incrementMergedCount(repo: string): void;
239
+ /**
240
+ * Increment the closed-without-merge PR count.
241
+ * @param repo - Repository in "owner/repo" format
242
+ */
101
243
  incrementClosedCount(repo: string): void;
244
+ /**
245
+ * Mark a repository as hostile (score zeroed).
246
+ * @param repo - Repository in "owner/repo" format
247
+ */
102
248
  markRepoHostile(repo: string): void;
249
+ /** Returns repository names that have at least one merged PR. */
103
250
  getReposWithMergedPRs(): string[];
251
+ /** Returns repository names with open PRs but no merged PRs yet. */
104
252
  getReposWithOpenPRs(): string[];
253
+ /**
254
+ * Returns repos above the score threshold.
255
+ * @param minScore - Minimum score (default: config.minRepoScoreThreshold)
256
+ */
105
257
  getHighScoringRepos(minScore?: number): string[];
258
+ /**
259
+ * Returns repos below the score threshold.
260
+ * @param maxScore - Maximum score (default: config.minRepoScoreThreshold)
261
+ */
106
262
  getLowScoringRepos(maxScore?: number): string[];
263
+ /** Returns aggregate contribution statistics (merge rate, PR counts, repo breakdown). */
107
264
  getStats(): Stats;
108
265
  }
109
266
  /**
110
267
  * Get the singleton StateManager instance, creating it on first call.
268
+ * @returns The shared StateManager instance
269
+ *
270
+ * @example
271
+ * ```typescript
272
+ * import { getStateManager } from '@oss-autopilot/core';
273
+ *
274
+ * const state = getStateManager();
275
+ * const config = state.getState().config;
276
+ * console.log(config.githubUsername);
277
+ * ```
111
278
  */
112
279
  export declare function getStateManager(): StateManager;
113
280
  /**