@oss-autopilot/core 0.53.1 → 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 +197 -162
- package/dist/commands/dashboard-data.js +37 -30
- package/dist/commands/dashboard-server.js +8 -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 +91 -12
- package/dist/core/daily-logic.js +24 -33
- package/dist/core/display-utils.js +22 -2
- package/dist/core/github-stats.d.ts +1 -1
- package/dist/core/github-stats.js +1 -1
- 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 +14 -16
- package/dist/core/pr-monitor.js +26 -90
- package/dist/core/repo-health.d.ts +24 -0
- package/dist/core/repo-health.js +193 -0
- package/dist/core/repo-score-manager.js +2 -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/status-determination.d.ts +2 -0
- package/dist/core/status-determination.js +82 -22
- package/dist/core/types.d.ts +23 -2
- package/dist/core/types.js +7 -0
- package/dist/formatters/json.d.ts +1 -1
- package/package.json +1 -1
package/dist/commands/init.js
CHANGED
|
@@ -9,7 +9,6 @@ export async function runInit(options) {
|
|
|
9
9
|
const stateManager = getStateManager();
|
|
10
10
|
// Set username in config
|
|
11
11
|
stateManager.updateConfig({ githubUsername: options.username });
|
|
12
|
-
stateManager.save();
|
|
13
12
|
return {
|
|
14
13
|
username: options.username,
|
|
15
14
|
message: 'Username saved. Run `daily` to fetch your open PRs from GitHub.',
|
|
@@ -113,11 +113,10 @@ export async function runLocalRepos(options) {
|
|
|
113
113
|
const cachedAt = new Date().toISOString();
|
|
114
114
|
try {
|
|
115
115
|
stateManager.setLocalRepoCache({ repos, scanPaths, cachedAt });
|
|
116
|
-
stateManager.save();
|
|
117
116
|
}
|
|
118
117
|
catch (error) {
|
|
119
118
|
const msg = errorMessage(error);
|
|
120
|
-
console.error(`Warning: Failed to cache scan results: ${msg}`);
|
|
119
|
+
console.error(`Warning: Failed to cache scan results to disk: ${msg}`);
|
|
121
120
|
}
|
|
122
121
|
return {
|
|
123
122
|
repos,
|
package/dist/commands/move.js
CHANGED
|
@@ -21,15 +21,17 @@ export async function runMove(options) {
|
|
|
21
21
|
// Use current time — the CLI doesn't have cached PR data. The override
|
|
22
22
|
// will auto-clear on the next daily run if the PR has new activity after this.
|
|
23
23
|
const lastActivityAt = new Date().toISOString();
|
|
24
|
-
stateManager.
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
stateManager.batch(() => {
|
|
25
|
+
stateManager.setStatusOverride(options.prUrl, status, lastActivityAt);
|
|
26
|
+
stateManager.unshelvePR(options.prUrl);
|
|
27
|
+
});
|
|
27
28
|
return { url: options.prUrl, target, description: `Moved to ${label}` };
|
|
28
29
|
}
|
|
29
30
|
case 'shelved': {
|
|
30
|
-
stateManager.
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
stateManager.batch(() => {
|
|
32
|
+
stateManager.shelvePR(options.prUrl);
|
|
33
|
+
stateManager.clearStatusOverride(options.prUrl);
|
|
34
|
+
});
|
|
33
35
|
return {
|
|
34
36
|
url: options.prUrl,
|
|
35
37
|
target,
|
|
@@ -37,11 +39,10 @@ export async function runMove(options) {
|
|
|
37
39
|
};
|
|
38
40
|
}
|
|
39
41
|
case 'auto': {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
42
|
+
stateManager.batch(() => {
|
|
43
|
+
stateManager.clearStatusOverride(options.prUrl);
|
|
44
|
+
stateManager.unshelvePR(options.prUrl);
|
|
45
|
+
});
|
|
45
46
|
return {
|
|
46
47
|
url: options.prUrl,
|
|
47
48
|
target,
|
package/dist/commands/setup.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Setup command
|
|
3
3
|
* Interactive setup / configuration
|
|
4
4
|
*/
|
|
5
|
-
import { type ProjectCategory } from '../core/types.js';
|
|
5
|
+
import { type ProjectCategory, type IssueScope } from '../core/types.js';
|
|
6
6
|
interface SetupOptions {
|
|
7
7
|
reset?: boolean;
|
|
8
8
|
set?: string[];
|
|
@@ -23,6 +23,7 @@ export interface SetupCompleteOutput {
|
|
|
23
23
|
labels: string[];
|
|
24
24
|
projectCategories: ProjectCategory[];
|
|
25
25
|
preferredOrgs: string[];
|
|
26
|
+
scope: IssueScope[];
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
export interface SetupPrompt {
|
package/dist/commands/setup.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { getStateManager, DEFAULT_CONFIG } from '../core/index.js';
|
|
6
6
|
import { ValidationError } from '../core/errors.js';
|
|
7
7
|
import { validateGitHubUsername } from './validation.js';
|
|
8
|
-
import { PROJECT_CATEGORIES } from '../core/types.js';
|
|
8
|
+
import { PROJECT_CATEGORIES, ISSUE_SCOPES } from '../core/types.js';
|
|
9
9
|
/** Parse and validate a positive integer setting value. */
|
|
10
10
|
function parsePositiveInt(value, settingName) {
|
|
11
11
|
const parsed = Number(value);
|
|
@@ -21,153 +21,181 @@ export async function runSetup(options) {
|
|
|
21
21
|
if (options.set && options.set.length > 0) {
|
|
22
22
|
const results = {};
|
|
23
23
|
const warnings = [];
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
case 'dormantDays': {
|
|
40
|
-
const dormant = parsePositiveInt(value, 'dormantDays');
|
|
41
|
-
stateManager.updateConfig({ dormantThresholdDays: dormant });
|
|
42
|
-
results[key] = String(dormant);
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
45
|
-
case 'approachingDays': {
|
|
46
|
-
const approaching = parsePositiveInt(value, 'approachingDays');
|
|
47
|
-
stateManager.updateConfig({ approachingDormantDays: approaching });
|
|
48
|
-
results[key] = String(approaching);
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
case 'languages':
|
|
52
|
-
stateManager.updateConfig({ languages: value.split(',').map((l) => l.trim()) });
|
|
53
|
-
results[key] = value;
|
|
54
|
-
break;
|
|
55
|
-
case 'labels':
|
|
56
|
-
stateManager.updateConfig({ labels: value.split(',').map((l) => l.trim()) });
|
|
57
|
-
results[key] = value;
|
|
58
|
-
break;
|
|
59
|
-
case 'showHealthCheck':
|
|
60
|
-
stateManager.updateConfig({ showHealthCheck: value !== 'false' });
|
|
61
|
-
results[key] = value !== 'false' ? 'true' : 'false';
|
|
62
|
-
break;
|
|
63
|
-
case 'squashByDefault':
|
|
64
|
-
if (value === 'ask') {
|
|
65
|
-
stateManager.updateConfig({ squashByDefault: 'ask' });
|
|
66
|
-
results[key] = 'ask';
|
|
24
|
+
stateManager.batch(() => {
|
|
25
|
+
for (const setting of options.set) {
|
|
26
|
+
const [key, ...valueParts] = setting.split('=');
|
|
27
|
+
const value = valueParts.join('=');
|
|
28
|
+
switch (key) {
|
|
29
|
+
case 'username':
|
|
30
|
+
validateGitHubUsername(value);
|
|
31
|
+
stateManager.updateConfig({ githubUsername: value });
|
|
32
|
+
results[key] = value;
|
|
33
|
+
break;
|
|
34
|
+
case 'maxActivePRs': {
|
|
35
|
+
const maxPRs = parsePositiveInt(value, 'maxActivePRs');
|
|
36
|
+
stateManager.updateConfig({ maxActivePRs: maxPRs });
|
|
37
|
+
results[key] = String(maxPRs);
|
|
38
|
+
break;
|
|
67
39
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
40
|
+
case 'dormantDays': {
|
|
41
|
+
const dormant = parsePositiveInt(value, 'dormantDays');
|
|
42
|
+
stateManager.updateConfig({ dormantThresholdDays: dormant });
|
|
43
|
+
results[key] = String(dormant);
|
|
44
|
+
break;
|
|
71
45
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
46
|
+
case 'approachingDays': {
|
|
47
|
+
const approaching = parsePositiveInt(value, 'approachingDays');
|
|
48
|
+
stateManager.updateConfig({ approachingDormantDays: approaching });
|
|
49
|
+
results[key] = String(approaching);
|
|
50
|
+
break;
|
|
77
51
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const normalized = entry.replace(/\s+/g, '');
|
|
95
|
-
if (/^[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+$/.test(normalized)) {
|
|
96
|
-
valid.push(normalized);
|
|
52
|
+
case 'languages':
|
|
53
|
+
stateManager.updateConfig({ languages: value.split(',').map((l) => l.trim()) });
|
|
54
|
+
results[key] = value;
|
|
55
|
+
break;
|
|
56
|
+
case 'labels':
|
|
57
|
+
stateManager.updateConfig({ labels: value.split(',').map((l) => l.trim()) });
|
|
58
|
+
results[key] = value;
|
|
59
|
+
break;
|
|
60
|
+
case 'showHealthCheck':
|
|
61
|
+
stateManager.updateConfig({ showHealthCheck: value !== 'false' });
|
|
62
|
+
results[key] = value !== 'false' ? 'true' : 'false';
|
|
63
|
+
break;
|
|
64
|
+
case 'squashByDefault':
|
|
65
|
+
if (value === 'ask') {
|
|
66
|
+
stateManager.updateConfig({ squashByDefault: 'ask' });
|
|
67
|
+
results[key] = 'ask';
|
|
97
68
|
}
|
|
98
69
|
else {
|
|
99
|
-
|
|
70
|
+
stateManager.updateConfig({ squashByDefault: value !== 'false' });
|
|
71
|
+
results[key] = value !== 'false' ? 'true' : 'false';
|
|
100
72
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
results[key] =
|
|
73
|
+
break;
|
|
74
|
+
case 'minStars': {
|
|
75
|
+
const stars = Number(value);
|
|
76
|
+
if (!Number.isFinite(stars) || !Number.isInteger(stars) || stars < 0) {
|
|
77
|
+
throw new ValidationError(`Invalid value for minStars: "${value}". Must be a non-negative integer.`);
|
|
78
|
+
}
|
|
79
|
+
stateManager.updateConfig({ minStars: stars });
|
|
80
|
+
results[key] = String(stars);
|
|
109
81
|
break;
|
|
110
82
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
83
|
+
case 'includeDocIssues':
|
|
84
|
+
stateManager.updateConfig({ includeDocIssues: value === 'true' });
|
|
85
|
+
results[key] = value === 'true' ? 'true' : 'false';
|
|
86
|
+
break;
|
|
87
|
+
case 'aiPolicyBlocklist': {
|
|
88
|
+
const entries = value
|
|
89
|
+
.split(',')
|
|
90
|
+
.map((r) => r.trim())
|
|
91
|
+
.filter(Boolean);
|
|
92
|
+
const valid = [];
|
|
93
|
+
const invalid = [];
|
|
94
|
+
for (const entry of entries) {
|
|
95
|
+
const normalized = entry.replace(/\s+/g, '');
|
|
96
|
+
if (/^[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+$/.test(normalized)) {
|
|
97
|
+
valid.push(normalized);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
invalid.push(entry);
|
|
101
|
+
}
|
|
125
102
|
}
|
|
126
|
-
|
|
127
|
-
|
|
103
|
+
if (invalid.length > 0) {
|
|
104
|
+
warnings.push(`Warning: Skipping invalid entries (expected "owner/repo" format): ${invalid.join(', ')}`);
|
|
105
|
+
results['aiPolicyBlocklist_invalidEntries'] = invalid.join(', ');
|
|
106
|
+
}
|
|
107
|
+
if (valid.length === 0 && entries.length > 0) {
|
|
108
|
+
warnings.push('Warning: All entries were invalid. Blocklist not updated.');
|
|
109
|
+
results[key] = '(all entries invalid)';
|
|
110
|
+
break;
|
|
128
111
|
}
|
|
112
|
+
stateManager.updateConfig({ aiPolicyBlocklist: valid });
|
|
113
|
+
results[key] = valid.length > 0 ? valid.join(', ') : '(empty)';
|
|
114
|
+
break;
|
|
129
115
|
}
|
|
130
|
-
|
|
131
|
-
|
|
116
|
+
case 'projectCategories': {
|
|
117
|
+
const categories = value
|
|
118
|
+
.split(',')
|
|
119
|
+
.map((c) => c.trim())
|
|
120
|
+
.filter(Boolean);
|
|
121
|
+
const validCategories = [];
|
|
122
|
+
const invalidCategories = [];
|
|
123
|
+
for (const cat of categories) {
|
|
124
|
+
if (PROJECT_CATEGORIES.includes(cat)) {
|
|
125
|
+
validCategories.push(cat);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
invalidCategories.push(cat);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (invalidCategories.length > 0) {
|
|
132
|
+
warnings.push(`Unknown project categories: ${invalidCategories.join(', ')}. Valid: ${PROJECT_CATEGORIES.join(', ')}`);
|
|
133
|
+
}
|
|
134
|
+
const dedupedCategories = [...new Set(validCategories)];
|
|
135
|
+
stateManager.updateConfig({ projectCategories: dedupedCategories });
|
|
136
|
+
results[key] = dedupedCategories.length > 0 ? dedupedCategories.join(', ') : '(empty)';
|
|
137
|
+
break;
|
|
132
138
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
139
|
+
case 'preferredOrgs': {
|
|
140
|
+
const orgs = value
|
|
141
|
+
.split(',')
|
|
142
|
+
.map((o) => o.trim())
|
|
143
|
+
.filter(Boolean);
|
|
144
|
+
const validOrgs = [];
|
|
145
|
+
for (const org of orgs) {
|
|
146
|
+
if (org.includes('/')) {
|
|
147
|
+
warnings.push(`"${org}" looks like a repo path. Use org name only (e.g., "vercel" not "vercel/next.js").`);
|
|
148
|
+
}
|
|
149
|
+
else if (!/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(org)) {
|
|
150
|
+
warnings.push(`"${org}" is not a valid GitHub organization name. Skipping.`);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
validOrgs.push(org.toLowerCase());
|
|
154
|
+
}
|
|
147
155
|
}
|
|
148
|
-
|
|
149
|
-
|
|
156
|
+
const dedupedOrgs = [...new Set(validOrgs)];
|
|
157
|
+
stateManager.updateConfig({ preferredOrgs: dedupedOrgs });
|
|
158
|
+
results[key] = dedupedOrgs.length > 0 ? dedupedOrgs.join(', ') : '(empty)';
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
case 'scope': {
|
|
162
|
+
const scopeValues = value
|
|
163
|
+
.split(',')
|
|
164
|
+
.map((s) => s.trim())
|
|
165
|
+
.filter(Boolean);
|
|
166
|
+
const validScopes = [];
|
|
167
|
+
const invalidScopes = [];
|
|
168
|
+
for (const s of scopeValues) {
|
|
169
|
+
if (ISSUE_SCOPES.includes(s)) {
|
|
170
|
+
validScopes.push(s);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
invalidScopes.push(s);
|
|
174
|
+
}
|
|
150
175
|
}
|
|
151
|
-
|
|
152
|
-
|
|
176
|
+
if (invalidScopes.length > 0) {
|
|
177
|
+
warnings.push(`Unknown issue scopes: ${invalidScopes.join(', ')}. Valid: ${ISSUE_SCOPES.join(', ')}`);
|
|
153
178
|
}
|
|
179
|
+
const dedupedScopes = [...new Set(validScopes)];
|
|
180
|
+
stateManager.updateConfig({ scope: dedupedScopes.length > 0 ? dedupedScopes : undefined });
|
|
181
|
+
results[key] = dedupedScopes.length > 0 ? dedupedScopes.join(', ') : '(empty — using labels only)';
|
|
182
|
+
break;
|
|
154
183
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
184
|
+
case 'issueListPath':
|
|
185
|
+
stateManager.updateConfig({ issueListPath: value || undefined });
|
|
186
|
+
results[key] = value || '(cleared)';
|
|
187
|
+
break;
|
|
188
|
+
case 'complete':
|
|
189
|
+
if (value === 'true') {
|
|
190
|
+
stateManager.markSetupComplete();
|
|
191
|
+
results[key] = 'true';
|
|
192
|
+
}
|
|
193
|
+
break;
|
|
194
|
+
default:
|
|
195
|
+
warnings.push(`Unknown setting: ${key}`);
|
|
159
196
|
}
|
|
160
|
-
case 'complete':
|
|
161
|
-
if (value === 'true') {
|
|
162
|
-
stateManager.markSetupComplete();
|
|
163
|
-
results[key] = 'true';
|
|
164
|
-
}
|
|
165
|
-
break;
|
|
166
|
-
default:
|
|
167
|
-
warnings.push(`Unknown setting: ${key}`);
|
|
168
197
|
}
|
|
169
|
-
}
|
|
170
|
-
stateManager.save();
|
|
198
|
+
});
|
|
171
199
|
return { success: true, settings: results, warnings: warnings.length > 0 ? warnings : undefined };
|
|
172
200
|
}
|
|
173
201
|
// Show setup status
|
|
@@ -183,6 +211,7 @@ export async function runSetup(options) {
|
|
|
183
211
|
labels: config.labels,
|
|
184
212
|
projectCategories: config.projectCategories ?? [],
|
|
185
213
|
preferredOrgs: config.preferredOrgs ?? [],
|
|
214
|
+
scope: config.scope ?? [],
|
|
186
215
|
},
|
|
187
216
|
};
|
|
188
217
|
}
|
|
@@ -232,6 +261,13 @@ export async function runSetup(options) {
|
|
|
232
261
|
default: ['good first issue', 'help wanted'],
|
|
233
262
|
type: 'list',
|
|
234
263
|
},
|
|
264
|
+
{
|
|
265
|
+
setting: 'scope',
|
|
266
|
+
prompt: 'What scope of issues do you want to discover? (beginner, intermediate, advanced — leave empty for default labels only)',
|
|
267
|
+
current: config.scope ?? [],
|
|
268
|
+
default: [],
|
|
269
|
+
type: 'list',
|
|
270
|
+
},
|
|
235
271
|
{
|
|
236
272
|
setting: 'aiPolicyBlocklist',
|
|
237
273
|
prompt: 'Repos with anti-AI contribution policies to block (owner/repo, comma-separated)?',
|
package/dist/commands/shelve.js
CHANGED
|
@@ -15,21 +15,21 @@ export async function runShelve(options) {
|
|
|
15
15
|
validateUrl(options.prUrl);
|
|
16
16
|
validateGitHubUrl(options.prUrl, PR_URL_PATTERN, 'PR');
|
|
17
17
|
const stateManager = getStateManager();
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
stateManager.
|
|
22
|
-
}
|
|
18
|
+
let added = false;
|
|
19
|
+
stateManager.batch(() => {
|
|
20
|
+
added = stateManager.shelvePR(options.prUrl);
|
|
21
|
+
stateManager.clearStatusOverride(options.prUrl);
|
|
22
|
+
});
|
|
23
23
|
return { shelved: added, url: options.prUrl };
|
|
24
24
|
}
|
|
25
25
|
export async function runUnshelve(options) {
|
|
26
26
|
validateUrl(options.prUrl);
|
|
27
27
|
validateGitHubUrl(options.prUrl, PR_URL_PATTERN, 'PR');
|
|
28
28
|
const stateManager = getStateManager();
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
stateManager.
|
|
33
|
-
}
|
|
29
|
+
let removed = false;
|
|
30
|
+
stateManager.batch(() => {
|
|
31
|
+
removed = stateManager.unshelvePR(options.prUrl);
|
|
32
|
+
stateManager.clearStatusOverride(options.prUrl);
|
|
33
|
+
});
|
|
34
34
|
return { unshelved: removed, url: options.prUrl };
|
|
35
35
|
}
|
package/dist/commands/startup.js
CHANGED
|
@@ -10,6 +10,7 @@ import * as fs from 'fs';
|
|
|
10
10
|
import { execFile } from 'child_process';
|
|
11
11
|
import { getStateManager, getGitHubToken, getCLIVersion, detectGitHubUsername } from '../core/index.js';
|
|
12
12
|
import { errorMessage } from '../core/errors.js';
|
|
13
|
+
import { warn } from '../core/logger.js';
|
|
13
14
|
import { executeDailyCheck } from './daily.js';
|
|
14
15
|
import { launchDashboardServer } from './dashboard-lifecycle.js';
|
|
15
16
|
/**
|
|
@@ -53,22 +54,37 @@ export function countIssueListItems(content) {
|
|
|
53
54
|
export function detectIssueList() {
|
|
54
55
|
let issueListPath = '';
|
|
55
56
|
let source = 'auto-detected';
|
|
56
|
-
// 1. Check config
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
issueListPath = configuredPath;
|
|
64
|
-
source = 'configured';
|
|
65
|
-
}
|
|
57
|
+
// 1. Check state.json config (primary)
|
|
58
|
+
try {
|
|
59
|
+
const stateManager = getStateManager();
|
|
60
|
+
const configuredPath = stateManager.getState().config.issueListPath;
|
|
61
|
+
if (configuredPath && fs.existsSync(configuredPath)) {
|
|
62
|
+
issueListPath = configuredPath;
|
|
63
|
+
source = 'configured';
|
|
66
64
|
}
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
// State manager may not be initialized yet — fall through to legacy config.md
|
|
68
|
+
warn('startup', `Could not read issueListPath from state: ${errorMessage(error)}`);
|
|
69
|
+
}
|
|
70
|
+
// 2. Fallback: config.md (legacy — will be removed in future)
|
|
71
|
+
if (!issueListPath) {
|
|
72
|
+
const configPath = '.claude/oss-autopilot/config.md';
|
|
73
|
+
if (fs.existsSync(configPath)) {
|
|
74
|
+
try {
|
|
75
|
+
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
76
|
+
const configuredPath = parseIssueListPathFromConfig(configContent);
|
|
77
|
+
if (configuredPath && fs.existsSync(configuredPath)) {
|
|
78
|
+
issueListPath = configuredPath;
|
|
79
|
+
source = 'configured';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error('[STARTUP] Failed to read config:', errorMessage(error));
|
|
84
|
+
}
|
|
69
85
|
}
|
|
70
86
|
}
|
|
71
|
-
//
|
|
87
|
+
// 3. Probe known paths
|
|
72
88
|
if (!issueListPath) {
|
|
73
89
|
const probes = ['open-source/potential-issue-list.md', 'oss/issue-list.md', 'issues.md'];
|
|
74
90
|
for (const probe of probes) {
|
|
@@ -81,7 +97,7 @@ export function detectIssueList() {
|
|
|
81
97
|
}
|
|
82
98
|
if (!issueListPath)
|
|
83
99
|
return undefined;
|
|
84
|
-
//
|
|
100
|
+
// 4. Count available/completed items
|
|
85
101
|
try {
|
|
86
102
|
const content = fs.readFileSync(issueListPath, 'utf-8');
|
|
87
103
|
const { availableCount, completedCount } = countIssueListItems(content);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* CI Analysis - Classification and analysis of CI check runs and combined statuses.
|
|
3
3
|
* Extracted from PRMonitor to isolate CI-related logic (#263).
|
|
4
4
|
*/
|
|
5
|
+
import type { Octokit } from '@octokit/rest';
|
|
5
6
|
import { CIFailureCategory, ClassifiedCheck, CIStatusResult } from './types.js';
|
|
6
7
|
/**
|
|
7
8
|
* Classify a failing CI check as actionable, fork_limitation, auth_gate, or infrastructure (#81, #145).
|
|
@@ -61,4 +62,9 @@ export declare function analyzeCombinedStatus(combinedStatus: {
|
|
|
61
62
|
* Priority: failing > pending > passing > unknown.
|
|
62
63
|
*/
|
|
63
64
|
export declare function mergeStatuses(checkRunAnalysis: CheckRunAnalysis, combinedAnalysis: CombinedStatusAnalysis, checkRunCount: number): CIStatusResult;
|
|
65
|
+
/**
|
|
66
|
+
* Get CI status for a commit SHA by querying both the combined status API and check runs API.
|
|
67
|
+
* Returns the merged status and names of any failing checks for diagnostics.
|
|
68
|
+
*/
|
|
69
|
+
export declare function getCIStatus(octokit: Octokit, owner: string, repo: string, sha: string): Promise<CIStatusResult>;
|
|
64
70
|
export {};
|