@oss-autopilot/core 0.54.0 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.bundle.cjs +63 -63
- package/dist/commands/comments.js +0 -1
- package/dist/commands/config.js +45 -5
- package/dist/commands/daily.js +190 -157
- package/dist/commands/dashboard-data.js +37 -30
- package/dist/commands/dashboard-server.js +0 -1
- package/dist/commands/dismiss.js +0 -6
- package/dist/commands/init.js +0 -1
- package/dist/commands/local-repos.js +1 -2
- package/dist/commands/move.js +12 -11
- package/dist/commands/setup.d.ts +2 -1
- package/dist/commands/setup.js +166 -130
- package/dist/commands/shelve.js +10 -10
- package/dist/commands/startup.js +30 -14
- package/dist/core/ci-analysis.d.ts +6 -0
- package/dist/core/ci-analysis.js +89 -12
- package/dist/core/daily-logic.js +24 -33
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.js +2 -1
- package/dist/core/issue-discovery.d.ts +7 -44
- package/dist/core/issue-discovery.js +83 -188
- package/dist/core/issue-eligibility.d.ts +35 -0
- package/dist/core/issue-eligibility.js +126 -0
- package/dist/core/issue-vetting.d.ts +6 -21
- package/dist/core/issue-vetting.js +15 -279
- package/dist/core/pr-monitor.d.ts +7 -12
- package/dist/core/pr-monitor.js +14 -80
- package/dist/core/repo-health.d.ts +24 -0
- package/dist/core/repo-health.js +193 -0
- package/dist/core/search-phases.d.ts +55 -0
- package/dist/core/search-phases.js +155 -0
- package/dist/core/state.d.ts +11 -0
- package/dist/core/state.js +63 -4
- package/dist/core/types.d.ts +8 -1
- package/dist/core/types.js +7 -0
- package/dist/formatters/json.d.ts +1 -1
- package/package.json +1 -1
package/dist/core/state.js
CHANGED
|
@@ -21,6 +21,8 @@ export class StateManager {
|
|
|
21
21
|
state;
|
|
22
22
|
inMemoryOnly;
|
|
23
23
|
lastLoadedMtimeMs = 0;
|
|
24
|
+
_batching = false;
|
|
25
|
+
_batchDirty = false;
|
|
24
26
|
/**
|
|
25
27
|
* Create a new StateManager instance.
|
|
26
28
|
* @param inMemoryOnly - When true, state is held only in memory and never read from or
|
|
@@ -38,6 +40,37 @@ export class StateManager {
|
|
|
38
40
|
this.lastLoadedMtimeMs = result.mtimeMs;
|
|
39
41
|
}
|
|
40
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Execute multiple mutations as a single batch, deferring disk I/O until the
|
|
45
|
+
* batch completes. Nested `batch()` calls are flattened — only the outermost saves.
|
|
46
|
+
*/
|
|
47
|
+
batch(fn) {
|
|
48
|
+
if (this._batching) {
|
|
49
|
+
fn();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this._batching = true;
|
|
53
|
+
this._batchDirty = false;
|
|
54
|
+
try {
|
|
55
|
+
fn();
|
|
56
|
+
if (this._batchDirty)
|
|
57
|
+
this.save();
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
this._batching = false;
|
|
61
|
+
this._batchDirty = false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Auto-persist after a mutation. Inside a `batch()`, defers to the batch boundary.
|
|
66
|
+
*/
|
|
67
|
+
autoSave() {
|
|
68
|
+
if (this._batching) {
|
|
69
|
+
this._batchDirty = true;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
this.save();
|
|
73
|
+
}
|
|
41
74
|
/**
|
|
42
75
|
* Check if initial setup has been completed.
|
|
43
76
|
*/
|
|
@@ -50,6 +83,7 @@ export class StateManager {
|
|
|
50
83
|
markSetupComplete() {
|
|
51
84
|
this.state.config.setupComplete = true;
|
|
52
85
|
this.state.config.setupCompletedAt = new Date().toISOString();
|
|
86
|
+
this.autoSave();
|
|
53
87
|
}
|
|
54
88
|
/**
|
|
55
89
|
* Initialize state with sensible defaults for zero-config onboarding.
|
|
@@ -60,10 +94,11 @@ export class StateManager {
|
|
|
60
94
|
debug(MODULE, `Setup already complete, skipping initializeWithDefaults for "${username}"`);
|
|
61
95
|
return;
|
|
62
96
|
}
|
|
63
|
-
this.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
97
|
+
this.batch(() => {
|
|
98
|
+
this.updateConfig({ githubUsername: username });
|
|
99
|
+
this.markSetupComplete();
|
|
100
|
+
debug(MODULE, `Initialized with defaults for user "${username}"`);
|
|
101
|
+
});
|
|
67
102
|
}
|
|
68
103
|
/**
|
|
69
104
|
* Persist the current state to disk, creating a timestamped backup of the previous
|
|
@@ -100,21 +135,27 @@ export class StateManager {
|
|
|
100
135
|
setLastDigest(digest) {
|
|
101
136
|
this.state.lastDigest = digest;
|
|
102
137
|
this.state.lastDigestAt = digest.generatedAt;
|
|
138
|
+
this.autoSave();
|
|
103
139
|
}
|
|
104
140
|
setMonthlyMergedCounts(counts) {
|
|
105
141
|
this.state.monthlyMergedCounts = counts;
|
|
142
|
+
this.autoSave();
|
|
106
143
|
}
|
|
107
144
|
setMonthlyClosedCounts(counts) {
|
|
108
145
|
this.state.monthlyClosedCounts = counts;
|
|
146
|
+
this.autoSave();
|
|
109
147
|
}
|
|
110
148
|
setMonthlyOpenedCounts(counts) {
|
|
111
149
|
this.state.monthlyOpenedCounts = counts;
|
|
150
|
+
this.autoSave();
|
|
112
151
|
}
|
|
113
152
|
setDailyActivityCounts(counts) {
|
|
114
153
|
this.state.dailyActivityCounts = counts;
|
|
154
|
+
this.autoSave();
|
|
115
155
|
}
|
|
116
156
|
setLocalRepoCache(cache) {
|
|
117
157
|
this.state.localRepoCache = cache;
|
|
158
|
+
this.autoSave();
|
|
118
159
|
}
|
|
119
160
|
// === Merged PR Storage ===
|
|
120
161
|
getMergedPRs() {
|
|
@@ -132,6 +173,7 @@ export class StateManager {
|
|
|
132
173
|
this.state.mergedPRs.push(...newPRs);
|
|
133
174
|
this.state.mergedPRs.sort((a, b) => b.mergedAt.localeCompare(a.mergedAt));
|
|
134
175
|
debug(MODULE, `Added ${newPRs.length} merged PRs (total: ${this.state.mergedPRs.length})`);
|
|
176
|
+
this.autoSave();
|
|
135
177
|
}
|
|
136
178
|
getMergedPRWatermark() {
|
|
137
179
|
return this.state.mergedPRs?.[0]?.mergedAt || undefined;
|
|
@@ -152,6 +194,7 @@ export class StateManager {
|
|
|
152
194
|
this.state.closedPRs.push(...newPRs);
|
|
153
195
|
this.state.closedPRs.sort((a, b) => b.closedAt.localeCompare(a.closedAt));
|
|
154
196
|
debug(MODULE, `Added ${newPRs.length} closed PRs (total: ${this.state.closedPRs.length})`);
|
|
197
|
+
this.autoSave();
|
|
155
198
|
}
|
|
156
199
|
getClosedPRWatermark() {
|
|
157
200
|
return this.state.closedPRs?.[0]?.closedAt || undefined;
|
|
@@ -159,6 +202,7 @@ export class StateManager {
|
|
|
159
202
|
// === Configuration ===
|
|
160
203
|
updateConfig(config) {
|
|
161
204
|
this.state.config = { ...this.state.config, ...config };
|
|
205
|
+
this.autoSave();
|
|
162
206
|
}
|
|
163
207
|
// === Event Logging ===
|
|
164
208
|
appendEvent(type, data) {
|
|
@@ -173,6 +217,7 @@ export class StateManager {
|
|
|
173
217
|
if (this.state.events.length > MAX_EVENTS) {
|
|
174
218
|
this.state.events = this.state.events.slice(-MAX_EVENTS);
|
|
175
219
|
}
|
|
220
|
+
this.autoSave();
|
|
176
221
|
}
|
|
177
222
|
getEventsByType(type) {
|
|
178
223
|
return this.state.events.filter((e) => e.type === type);
|
|
@@ -192,12 +237,14 @@ export class StateManager {
|
|
|
192
237
|
}
|
|
193
238
|
this.state.activeIssues.push(issue);
|
|
194
239
|
debug(MODULE, `Added issue: ${issue.repo}#${issue.number}`);
|
|
240
|
+
this.autoSave();
|
|
195
241
|
}
|
|
196
242
|
// === Trusted Projects ===
|
|
197
243
|
addTrustedProject(repo) {
|
|
198
244
|
if (!this.state.config.trustedProjects.includes(repo)) {
|
|
199
245
|
this.state.config.trustedProjects.push(repo);
|
|
200
246
|
debug(MODULE, `Added trusted project: ${repo}`);
|
|
247
|
+
this.autoSave();
|
|
201
248
|
}
|
|
202
249
|
}
|
|
203
250
|
static matchesExclusion(repo, repos, orgs) {
|
|
@@ -215,6 +262,7 @@ export class StateManager {
|
|
|
215
262
|
const removedTrusted = beforeTrusted - this.state.config.trustedProjects.length;
|
|
216
263
|
if (removedTrusted > 0) {
|
|
217
264
|
debug(MODULE, `Removed ${removedTrusted} trusted project(s) for excluded repos/orgs`);
|
|
265
|
+
this.autoSave();
|
|
218
266
|
}
|
|
219
267
|
}
|
|
220
268
|
// === Starred Repos Management ===
|
|
@@ -225,6 +273,7 @@ export class StateManager {
|
|
|
225
273
|
this.state.config.starredRepos = repos;
|
|
226
274
|
this.state.config.starredReposLastFetched = new Date().toISOString();
|
|
227
275
|
debug(MODULE, `Updated starred repos: ${repos.length} repositories`);
|
|
276
|
+
this.autoSave();
|
|
228
277
|
}
|
|
229
278
|
isStarredReposStale() {
|
|
230
279
|
const lastFetched = this.state.config.starredReposLastFetched;
|
|
@@ -245,6 +294,7 @@ export class StateManager {
|
|
|
245
294
|
return false;
|
|
246
295
|
}
|
|
247
296
|
this.state.config.shelvedPRUrls.push(url);
|
|
297
|
+
this.autoSave();
|
|
248
298
|
return true;
|
|
249
299
|
}
|
|
250
300
|
unshelvePR(url) {
|
|
@@ -256,6 +306,7 @@ export class StateManager {
|
|
|
256
306
|
return false;
|
|
257
307
|
}
|
|
258
308
|
this.state.config.shelvedPRUrls.splice(index, 1);
|
|
309
|
+
this.autoSave();
|
|
259
310
|
return true;
|
|
260
311
|
}
|
|
261
312
|
isPRShelved(url) {
|
|
@@ -270,6 +321,7 @@ export class StateManager {
|
|
|
270
321
|
return false;
|
|
271
322
|
}
|
|
272
323
|
this.state.config.dismissedIssues[url] = timestamp;
|
|
324
|
+
this.autoSave();
|
|
273
325
|
return true;
|
|
274
326
|
}
|
|
275
327
|
undismissIssue(url) {
|
|
@@ -277,6 +329,7 @@ export class StateManager {
|
|
|
277
329
|
return false;
|
|
278
330
|
}
|
|
279
331
|
delete this.state.config.dismissedIssues[url];
|
|
332
|
+
this.autoSave();
|
|
280
333
|
return true;
|
|
281
334
|
}
|
|
282
335
|
getIssueDismissedAt(url) {
|
|
@@ -292,12 +345,14 @@ export class StateManager {
|
|
|
292
345
|
setAt: new Date().toISOString(),
|
|
293
346
|
lastActivityAt,
|
|
294
347
|
};
|
|
348
|
+
this.autoSave();
|
|
295
349
|
}
|
|
296
350
|
clearStatusOverride(url) {
|
|
297
351
|
if (!this.state.config.statusOverrides || !(url in this.state.config.statusOverrides)) {
|
|
298
352
|
return false;
|
|
299
353
|
}
|
|
300
354
|
delete this.state.config.statusOverrides[url];
|
|
355
|
+
this.autoSave();
|
|
301
356
|
return true;
|
|
302
357
|
}
|
|
303
358
|
getStatusOverride(url, currentUpdatedAt) {
|
|
@@ -317,15 +372,19 @@ export class StateManager {
|
|
|
317
372
|
}
|
|
318
373
|
updateRepoScore(repo, updates) {
|
|
319
374
|
repoScoring.updateRepoScore(this.state, repo, updates);
|
|
375
|
+
this.autoSave();
|
|
320
376
|
}
|
|
321
377
|
incrementMergedCount(repo) {
|
|
322
378
|
repoScoring.incrementMergedCount(this.state, repo);
|
|
379
|
+
this.autoSave();
|
|
323
380
|
}
|
|
324
381
|
incrementClosedCount(repo) {
|
|
325
382
|
repoScoring.incrementClosedCount(this.state, repo);
|
|
383
|
+
this.autoSave();
|
|
326
384
|
}
|
|
327
385
|
markRepoHostile(repo) {
|
|
328
386
|
repoScoring.markRepoHostile(this.state, repo);
|
|
387
|
+
this.autoSave();
|
|
329
388
|
}
|
|
330
389
|
getReposWithMergedPRs() {
|
|
331
390
|
return repoScoring.getReposWithMergedPRs(this.state);
|
package/dist/core/types.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export interface ClassifiedCheck {
|
|
|
25
25
|
category: CIFailureCategory;
|
|
26
26
|
conclusion?: string;
|
|
27
27
|
}
|
|
28
|
-
/**
|
|
28
|
+
/** CI status result returned by getCIStatus(). */
|
|
29
29
|
export interface CIStatusResult {
|
|
30
30
|
status: CIStatus;
|
|
31
31
|
failingCheckNames: string[];
|
|
@@ -468,6 +468,8 @@ export interface AgentConfig {
|
|
|
468
468
|
languages: string[];
|
|
469
469
|
/** GitHub labels to filter issues by (e.g., `["good first issue", "help wanted"]`). */
|
|
470
470
|
labels: string[];
|
|
471
|
+
/** 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). */
|
|
472
|
+
scope?: IssueScope[];
|
|
471
473
|
/** Repos to exclude from issue discovery/search, in `"owner/repo"` format. */
|
|
472
474
|
excludeRepos: string[];
|
|
473
475
|
/** Organizations to exclude from issue discovery/search (case-insensitive match on owner segment). */
|
|
@@ -498,6 +500,8 @@ export interface AgentConfig {
|
|
|
498
500
|
dismissedIssues?: Record<string, string>;
|
|
499
501
|
/** Manual status overrides for PRs. Maps PR URL to override metadata. Auto-clears when the PR has new activity. */
|
|
500
502
|
statusOverrides?: Record<string, StatusOverride>;
|
|
503
|
+
/** Path to the user's curated issue list file. Replaces config.md as the primary source for detectIssueList(). */
|
|
504
|
+
issueListPath?: string;
|
|
501
505
|
/** Project categories the user is interested in (e.g., devtools, nonprofit). Used to prioritize search results. */
|
|
502
506
|
projectCategories?: ProjectCategory[];
|
|
503
507
|
/** GitHub organizations the user wants to prioritize in issue search. Org names only (not owner/repo). */
|
|
@@ -542,6 +546,9 @@ export declare const DEFAULT_CONFIG: AgentConfig;
|
|
|
542
546
|
export declare const INITIAL_STATE: AgentState;
|
|
543
547
|
export declare const PROJECT_CATEGORIES: readonly ["nonprofit", "devtools", "infrastructure", "web-frameworks", "data-ml", "education"];
|
|
544
548
|
export type ProjectCategory = (typeof PROJECT_CATEGORIES)[number];
|
|
549
|
+
export declare const ISSUE_SCOPES: readonly ["beginner", "intermediate", "advanced"];
|
|
550
|
+
export type IssueScope = (typeof ISSUE_SCOPES)[number];
|
|
551
|
+
export declare const SCOPE_LABELS: Record<IssueScope, string[]>;
|
|
545
552
|
/** Priority tier for issue search results. Ordered: merged_pr > preferred_org > starred > normal. */
|
|
546
553
|
export type SearchPriority = 'merged_pr' | 'preferred_org' | 'starred' | 'normal';
|
|
547
554
|
export interface IssueCandidate {
|
package/dist/core/types.js
CHANGED
|
@@ -49,3 +49,10 @@ export const PROJECT_CATEGORIES = [
|
|
|
49
49
|
'data-ml',
|
|
50
50
|
'education',
|
|
51
51
|
];
|
|
52
|
+
// -- Issue scope types --
|
|
53
|
+
export const ISSUE_SCOPES = ['beginner', 'intermediate', 'advanced'];
|
|
54
|
+
export const SCOPE_LABELS = {
|
|
55
|
+
beginner: ['good first issue', 'help wanted', 'easy', 'up-for-grabs', 'first-timers-only', 'beginner'],
|
|
56
|
+
intermediate: ['enhancement', 'feature', 'feature-request', 'contributions welcome'],
|
|
57
|
+
advanced: ['proposal', 'RFC', 'accepted', 'design'],
|
|
58
|
+
};
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import type { FetchedPR, DailyDigest, AgentState, RepoGroup, CommentedIssue, ShelvedPRRef } from '../core/types.js';
|
|
6
6
|
import type { ContributionStats } from '../core/stats.js';
|
|
7
7
|
import type { PRCheckFailure } from '../core/pr-monitor.js';
|
|
8
|
-
import type { SearchPriority } from '../core/
|
|
8
|
+
import type { SearchPriority } from '../core/types.js';
|
|
9
9
|
export interface JsonOutput<T = unknown> {
|
|
10
10
|
success: boolean;
|
|
11
11
|
data?: T;
|