@oss-autopilot/core 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +85 -0
- package/dist/cli.bundle.cjs +17657 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.js +325 -0
- package/dist/commands/check-integration.d.ts +10 -0
- package/dist/commands/check-integration.js +192 -0
- package/dist/commands/comments.d.ts +24 -0
- package/dist/commands/comments.js +311 -0
- package/dist/commands/config.d.ts +11 -0
- package/dist/commands/config.js +82 -0
- package/dist/commands/daily.d.ts +29 -0
- package/dist/commands/daily.js +433 -0
- package/dist/commands/dashboard-data.d.ts +45 -0
- package/dist/commands/dashboard-data.js +132 -0
- package/dist/commands/dashboard-templates.d.ts +23 -0
- package/dist/commands/dashboard-templates.js +1627 -0
- package/dist/commands/dashboard.d.ts +18 -0
- package/dist/commands/dashboard.js +134 -0
- package/dist/commands/dismiss.d.ts +13 -0
- package/dist/commands/dismiss.js +49 -0
- package/dist/commands/init.d.ts +10 -0
- package/dist/commands/init.js +27 -0
- package/dist/commands/local-repos.d.ts +14 -0
- package/dist/commands/local-repos.js +155 -0
- package/dist/commands/parse-list.d.ts +13 -0
- package/dist/commands/parse-list.js +139 -0
- package/dist/commands/read.d.ts +12 -0
- package/dist/commands/read.js +33 -0
- package/dist/commands/search.d.ts +10 -0
- package/dist/commands/search.js +74 -0
- package/dist/commands/setup.d.ts +15 -0
- package/dist/commands/setup.js +276 -0
- package/dist/commands/shelve.d.ts +13 -0
- package/dist/commands/shelve.js +49 -0
- package/dist/commands/snooze.d.ts +18 -0
- package/dist/commands/snooze.js +83 -0
- package/dist/commands/startup.d.ts +33 -0
- package/dist/commands/startup.js +197 -0
- package/dist/commands/status.d.ts +10 -0
- package/dist/commands/status.js +43 -0
- package/dist/commands/track.d.ts +16 -0
- package/dist/commands/track.js +59 -0
- package/dist/commands/validation.d.ts +43 -0
- package/dist/commands/validation.js +112 -0
- package/dist/commands/vet.d.ts +10 -0
- package/dist/commands/vet.js +36 -0
- package/dist/core/checklist-analysis.d.ts +17 -0
- package/dist/core/checklist-analysis.js +39 -0
- package/dist/core/ci-analysis.d.ts +78 -0
- package/dist/core/ci-analysis.js +163 -0
- package/dist/core/comment-utils.d.ts +15 -0
- package/dist/core/comment-utils.js +52 -0
- package/dist/core/concurrency.d.ts +5 -0
- package/dist/core/concurrency.js +15 -0
- package/dist/core/daily-logic.d.ts +77 -0
- package/dist/core/daily-logic.js +512 -0
- package/dist/core/display-utils.d.ts +10 -0
- package/dist/core/display-utils.js +100 -0
- package/dist/core/errors.d.ts +24 -0
- package/dist/core/errors.js +34 -0
- package/dist/core/github-stats.d.ts +73 -0
- package/dist/core/github-stats.js +272 -0
- package/dist/core/github.d.ts +19 -0
- package/dist/core/github.js +60 -0
- package/dist/core/http-cache.d.ts +97 -0
- package/dist/core/http-cache.js +269 -0
- package/dist/core/index.d.ts +15 -0
- package/dist/core/index.js +15 -0
- package/dist/core/issue-conversation.d.ts +29 -0
- package/dist/core/issue-conversation.js +231 -0
- package/dist/core/issue-discovery.d.ts +85 -0
- package/dist/core/issue-discovery.js +589 -0
- package/dist/core/issue-filtering.d.ts +51 -0
- package/dist/core/issue-filtering.js +103 -0
- package/dist/core/issue-scoring.d.ts +40 -0
- package/dist/core/issue-scoring.js +92 -0
- package/dist/core/issue-vetting.d.ts +49 -0
- package/dist/core/issue-vetting.js +536 -0
- package/dist/core/logger.d.ts +21 -0
- package/dist/core/logger.js +49 -0
- package/dist/core/maintainer-analysis.d.ts +10 -0
- package/dist/core/maintainer-analysis.js +59 -0
- package/dist/core/pagination.d.ts +11 -0
- package/dist/core/pagination.js +20 -0
- package/dist/core/pr-monitor.d.ts +109 -0
- package/dist/core/pr-monitor.js +594 -0
- package/dist/core/review-analysis.d.ts +72 -0
- package/dist/core/review-analysis.js +163 -0
- package/dist/core/state.d.ts +371 -0
- package/dist/core/state.js +1089 -0
- package/dist/core/types.d.ts +507 -0
- package/dist/core/types.js +34 -0
- package/dist/core/utils.d.ts +249 -0
- package/dist/core/utils.js +422 -0
- package/dist/formatters/json.d.ts +269 -0
- package/dist/formatters/json.js +88 -0
- package/package.json +67 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search command
|
|
3
|
+
* Searches for new issues to work on
|
|
4
|
+
*/
|
|
5
|
+
import { IssueDiscovery, getGitHubToken, getStateManager, DEFAULT_CONFIG } from '../core/index.js';
|
|
6
|
+
import { outputJson } from '../formatters/json.js';
|
|
7
|
+
export async function runSearch(options) {
|
|
8
|
+
// Token is guaranteed by the preAction hook in cli.ts for non-LOCAL_ONLY_COMMANDS.
|
|
9
|
+
const token = getGitHubToken();
|
|
10
|
+
const discovery = new IssueDiscovery(token);
|
|
11
|
+
if (!options.json) {
|
|
12
|
+
console.log(`\n🔍 Searching for issues (max ${options.maxResults})...\n`);
|
|
13
|
+
}
|
|
14
|
+
const candidates = await discovery.searchIssues({ maxResults: options.maxResults });
|
|
15
|
+
if (options.json) {
|
|
16
|
+
const stateManager = getStateManager();
|
|
17
|
+
const { config } = stateManager.getState();
|
|
18
|
+
const excludedRepos = config.excludeRepos || [];
|
|
19
|
+
const aiPolicyBlocklist = config.aiPolicyBlocklist ?? DEFAULT_CONFIG.aiPolicyBlocklist ?? [];
|
|
20
|
+
const searchOutput = {
|
|
21
|
+
candidates: candidates.map((c) => {
|
|
22
|
+
const repoScoreRecord = stateManager.getRepoScore(c.issue.repo);
|
|
23
|
+
return {
|
|
24
|
+
issue: {
|
|
25
|
+
repo: c.issue.repo,
|
|
26
|
+
number: c.issue.number,
|
|
27
|
+
title: c.issue.title,
|
|
28
|
+
url: c.issue.url,
|
|
29
|
+
labels: c.issue.labels,
|
|
30
|
+
},
|
|
31
|
+
recommendation: c.recommendation,
|
|
32
|
+
reasonsToApprove: c.reasonsToApprove,
|
|
33
|
+
reasonsToSkip: c.reasonsToSkip,
|
|
34
|
+
searchPriority: c.searchPriority,
|
|
35
|
+
viabilityScore: c.viabilityScore,
|
|
36
|
+
repoScore: repoScoreRecord
|
|
37
|
+
? {
|
|
38
|
+
score: repoScoreRecord.score,
|
|
39
|
+
mergedPRCount: repoScoreRecord.mergedPRCount,
|
|
40
|
+
closedWithoutMergeCount: repoScoreRecord.closedWithoutMergeCount,
|
|
41
|
+
isResponsive: repoScoreRecord.signals?.isResponsive ?? false,
|
|
42
|
+
lastMergedAt: repoScoreRecord.lastMergedAt,
|
|
43
|
+
}
|
|
44
|
+
: undefined,
|
|
45
|
+
};
|
|
46
|
+
}),
|
|
47
|
+
excludedRepos,
|
|
48
|
+
aiPolicyBlocklist,
|
|
49
|
+
};
|
|
50
|
+
if (discovery.rateLimitWarning) {
|
|
51
|
+
searchOutput.rateLimitWarning = discovery.rateLimitWarning;
|
|
52
|
+
}
|
|
53
|
+
outputJson(searchOutput);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
if (candidates.length === 0) {
|
|
57
|
+
if (discovery.rateLimitWarning) {
|
|
58
|
+
console.warn(`\n⚠ ${discovery.rateLimitWarning}\n`);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
console.log('No matching issues found.');
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (discovery.rateLimitWarning) {
|
|
66
|
+
console.warn(`\n⚠ ${discovery.rateLimitWarning}\n`);
|
|
67
|
+
}
|
|
68
|
+
console.log(`Found ${candidates.length} candidates:\n`);
|
|
69
|
+
for (const candidate of candidates) {
|
|
70
|
+
console.log(discovery.formatCandidate(candidate));
|
|
71
|
+
console.log('---');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup command
|
|
3
|
+
* Interactive setup / configuration
|
|
4
|
+
*/
|
|
5
|
+
interface SetupOptions {
|
|
6
|
+
reset?: boolean;
|
|
7
|
+
set?: string[];
|
|
8
|
+
json?: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface CheckSetupOptions {
|
|
11
|
+
json?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function runSetup(options: SetupOptions): Promise<void>;
|
|
14
|
+
export declare function runCheckSetup(options: CheckSetupOptions): Promise<void>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup command
|
|
3
|
+
* Interactive setup / configuration
|
|
4
|
+
*/
|
|
5
|
+
import { getStateManager, DEFAULT_CONFIG } from '../core/index.js';
|
|
6
|
+
import { outputJson } from '../formatters/json.js';
|
|
7
|
+
import { validateGitHubUsername } from './validation.js';
|
|
8
|
+
export async function runSetup(options) {
|
|
9
|
+
const stateManager = getStateManager();
|
|
10
|
+
const config = stateManager.getState().config;
|
|
11
|
+
// Handle --set mode: apply settings directly
|
|
12
|
+
if (options.set && options.set.length > 0) {
|
|
13
|
+
const results = {};
|
|
14
|
+
for (const setting of options.set) {
|
|
15
|
+
const [key, ...valueParts] = setting.split('=');
|
|
16
|
+
const value = valueParts.join('=');
|
|
17
|
+
switch (key) {
|
|
18
|
+
case 'username':
|
|
19
|
+
validateGitHubUsername(value);
|
|
20
|
+
stateManager.updateConfig({ githubUsername: value });
|
|
21
|
+
results[key] = value;
|
|
22
|
+
break;
|
|
23
|
+
case 'maxActivePRs':
|
|
24
|
+
stateManager.updateConfig({ maxActivePRs: parseInt(value) || 10 });
|
|
25
|
+
results[key] = value;
|
|
26
|
+
break;
|
|
27
|
+
case 'dormantDays':
|
|
28
|
+
stateManager.updateConfig({ dormantThresholdDays: parseInt(value) || 30 });
|
|
29
|
+
results[key] = value;
|
|
30
|
+
break;
|
|
31
|
+
case 'approachingDays':
|
|
32
|
+
stateManager.updateConfig({ approachingDormantDays: parseInt(value) || 25 });
|
|
33
|
+
results[key] = value;
|
|
34
|
+
break;
|
|
35
|
+
case 'languages':
|
|
36
|
+
stateManager.updateConfig({ languages: value.split(',').map((l) => l.trim()) });
|
|
37
|
+
results[key] = value;
|
|
38
|
+
break;
|
|
39
|
+
case 'labels':
|
|
40
|
+
stateManager.updateConfig({ labels: value.split(',').map((l) => l.trim()) });
|
|
41
|
+
results[key] = value;
|
|
42
|
+
break;
|
|
43
|
+
case 'showHealthCheck':
|
|
44
|
+
stateManager.updateConfig({ showHealthCheck: value !== 'false' });
|
|
45
|
+
results[key] = value !== 'false' ? 'true' : 'false';
|
|
46
|
+
break;
|
|
47
|
+
case 'squashByDefault':
|
|
48
|
+
if (value === 'ask') {
|
|
49
|
+
stateManager.updateConfig({ squashByDefault: 'ask' });
|
|
50
|
+
results[key] = 'ask';
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
stateManager.updateConfig({ squashByDefault: value !== 'false' });
|
|
54
|
+
results[key] = value !== 'false' ? 'true' : 'false';
|
|
55
|
+
}
|
|
56
|
+
break;
|
|
57
|
+
case 'minStars': {
|
|
58
|
+
const parsed = parseInt(value);
|
|
59
|
+
stateManager.updateConfig({ minStars: isNaN(parsed) ? 50 : parsed });
|
|
60
|
+
results[key] = value;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case 'includeDocIssues':
|
|
64
|
+
stateManager.updateConfig({ includeDocIssues: value === 'true' });
|
|
65
|
+
results[key] = value === 'true' ? 'true' : 'false';
|
|
66
|
+
break;
|
|
67
|
+
case 'aiPolicyBlocklist': {
|
|
68
|
+
const entries = value
|
|
69
|
+
.split(',')
|
|
70
|
+
.map((r) => r.trim())
|
|
71
|
+
.filter(Boolean);
|
|
72
|
+
const valid = [];
|
|
73
|
+
const invalid = [];
|
|
74
|
+
for (const entry of entries) {
|
|
75
|
+
const normalized = entry.replace(/\s+/g, '');
|
|
76
|
+
if (/^[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+$/.test(normalized)) {
|
|
77
|
+
valid.push(normalized);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
invalid.push(entry);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (invalid.length > 0) {
|
|
84
|
+
if (!options.json) {
|
|
85
|
+
console.warn(`Warning: Skipping invalid entries (expected "owner/repo" format): ${invalid.join(', ')}`);
|
|
86
|
+
}
|
|
87
|
+
results['aiPolicyBlocklist_invalidEntries'] = invalid.join(', ');
|
|
88
|
+
}
|
|
89
|
+
if (valid.length === 0 && entries.length > 0) {
|
|
90
|
+
if (!options.json) {
|
|
91
|
+
console.warn('Warning: All entries were invalid. Blocklist not updated.');
|
|
92
|
+
}
|
|
93
|
+
results[key] = '(all entries invalid)';
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
stateManager.updateConfig({ aiPolicyBlocklist: valid });
|
|
97
|
+
results[key] = valid.length > 0 ? valid.join(', ') : '(empty)';
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
case 'complete':
|
|
101
|
+
if (value === 'true') {
|
|
102
|
+
stateManager.markSetupComplete();
|
|
103
|
+
results[key] = 'true';
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
default:
|
|
107
|
+
if (!options.json) {
|
|
108
|
+
console.warn(`Unknown setting: ${key}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
stateManager.save();
|
|
113
|
+
if (options.json) {
|
|
114
|
+
outputJson({ success: true, settings: results });
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
for (const [key, value] of Object.entries(results)) {
|
|
118
|
+
console.log(`✓ ${key}: ${value}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// Show setup status
|
|
124
|
+
if (config.setupComplete && !options.reset) {
|
|
125
|
+
if (options.json) {
|
|
126
|
+
outputJson({
|
|
127
|
+
setupComplete: true,
|
|
128
|
+
config: {
|
|
129
|
+
githubUsername: config.githubUsername,
|
|
130
|
+
maxActivePRs: config.maxActivePRs,
|
|
131
|
+
dormantThresholdDays: config.dormantThresholdDays,
|
|
132
|
+
approachingDormantDays: config.approachingDormantDays,
|
|
133
|
+
languages: config.languages,
|
|
134
|
+
labels: config.labels,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
console.log('\n⚙️ OSS Autopilot Setup\n');
|
|
140
|
+
console.log('✓ Setup already complete!\n');
|
|
141
|
+
console.log('Current settings:');
|
|
142
|
+
console.log(` GitHub username: ${config.githubUsername || '(not set)'}`);
|
|
143
|
+
console.log(` Max active PRs: ${config.maxActivePRs}`);
|
|
144
|
+
console.log(` Dormant threshold: ${config.dormantThresholdDays} days`);
|
|
145
|
+
console.log(` Approaching dormant: ${config.approachingDormantDays} days`);
|
|
146
|
+
console.log(` Languages: ${config.languages.join(', ')}`);
|
|
147
|
+
console.log(` Labels: ${config.labels.join(', ')}`);
|
|
148
|
+
console.log(`\nRun 'setup --reset' to reconfigure.`);
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// Output setup prompts
|
|
153
|
+
if (options.json) {
|
|
154
|
+
outputJson({
|
|
155
|
+
setupRequired: true,
|
|
156
|
+
prompts: [
|
|
157
|
+
{
|
|
158
|
+
setting: 'username',
|
|
159
|
+
prompt: 'What is your GitHub username?',
|
|
160
|
+
current: config.githubUsername || null,
|
|
161
|
+
required: true,
|
|
162
|
+
type: 'string',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
setting: 'maxActivePRs',
|
|
166
|
+
prompt: 'How many PRs do you want to work on at once?',
|
|
167
|
+
current: config.maxActivePRs,
|
|
168
|
+
default: 10,
|
|
169
|
+
type: 'number',
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
setting: 'dormantDays',
|
|
173
|
+
prompt: 'After how many days of inactivity should a PR be considered dormant?',
|
|
174
|
+
current: config.dormantThresholdDays,
|
|
175
|
+
default: 30,
|
|
176
|
+
type: 'number',
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
setting: 'approachingDays',
|
|
180
|
+
prompt: 'At how many days should we warn about approaching dormancy?',
|
|
181
|
+
current: config.approachingDormantDays,
|
|
182
|
+
default: 25,
|
|
183
|
+
type: 'number',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
setting: 'languages',
|
|
187
|
+
prompt: 'What programming languages do you want to contribute to?',
|
|
188
|
+
current: config.languages,
|
|
189
|
+
default: ['typescript', 'javascript'],
|
|
190
|
+
type: 'list',
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
setting: 'labels',
|
|
194
|
+
prompt: 'What issue labels should we search for?',
|
|
195
|
+
current: config.labels,
|
|
196
|
+
default: ['good first issue', 'help wanted'],
|
|
197
|
+
type: 'list',
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
setting: 'aiPolicyBlocklist',
|
|
201
|
+
prompt: 'Repos with anti-AI contribution policies to block (owner/repo, comma-separated)?',
|
|
202
|
+
current: config.aiPolicyBlocklist ?? DEFAULT_CONFIG.aiPolicyBlocklist,
|
|
203
|
+
default: ['matplotlib/matplotlib'],
|
|
204
|
+
type: 'list',
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
console.log('\n⚙️ OSS Autopilot Setup\n');
|
|
211
|
+
console.log('SETUP_REQUIRED');
|
|
212
|
+
console.log('---');
|
|
213
|
+
console.log('Please configure the following settings:\n');
|
|
214
|
+
console.log('SETTING: username');
|
|
215
|
+
console.log('PROMPT: What is your GitHub username?');
|
|
216
|
+
console.log(`CURRENT: ${config.githubUsername || '(not set)'}`);
|
|
217
|
+
console.log('REQUIRED: true');
|
|
218
|
+
console.log('');
|
|
219
|
+
console.log('SETTING: maxActivePRs');
|
|
220
|
+
console.log('PROMPT: How many PRs do you want to work on at once?');
|
|
221
|
+
console.log(`CURRENT: ${config.maxActivePRs}`);
|
|
222
|
+
console.log('DEFAULT: 10');
|
|
223
|
+
console.log('TYPE: number');
|
|
224
|
+
console.log('');
|
|
225
|
+
console.log('SETTING: dormantDays');
|
|
226
|
+
console.log('PROMPT: After how many days of inactivity should a PR be considered dormant?');
|
|
227
|
+
console.log(`CURRENT: ${config.dormantThresholdDays}`);
|
|
228
|
+
console.log('DEFAULT: 30');
|
|
229
|
+
console.log('TYPE: number');
|
|
230
|
+
console.log('');
|
|
231
|
+
console.log('SETTING: approachingDays');
|
|
232
|
+
console.log('PROMPT: At how many days should we warn about approaching dormancy?');
|
|
233
|
+
console.log(`CURRENT: ${config.approachingDormantDays}`);
|
|
234
|
+
console.log('DEFAULT: 25');
|
|
235
|
+
console.log('TYPE: number');
|
|
236
|
+
console.log('');
|
|
237
|
+
console.log('SETTING: languages');
|
|
238
|
+
console.log('PROMPT: What programming languages do you want to contribute to? (comma-separated)');
|
|
239
|
+
console.log(`CURRENT: ${config.languages.join(', ')}`);
|
|
240
|
+
console.log('DEFAULT: typescript, javascript');
|
|
241
|
+
console.log('TYPE: list');
|
|
242
|
+
console.log('');
|
|
243
|
+
console.log('SETTING: labels');
|
|
244
|
+
console.log('PROMPT: What issue labels should we search for? (comma-separated)');
|
|
245
|
+
console.log(`CURRENT: ${config.labels.join(', ')}`);
|
|
246
|
+
console.log('DEFAULT: good first issue, help wanted');
|
|
247
|
+
console.log('TYPE: list');
|
|
248
|
+
console.log('');
|
|
249
|
+
console.log('SETTING: aiPolicyBlocklist');
|
|
250
|
+
console.log('PROMPT: Repos with anti-AI contribution policies to block? (owner/repo, comma-separated)');
|
|
251
|
+
console.log(`CURRENT: ${(config.aiPolicyBlocklist ?? DEFAULT_CONFIG.aiPolicyBlocklist ?? []).join(', ')}`);
|
|
252
|
+
console.log('DEFAULT: matplotlib/matplotlib');
|
|
253
|
+
console.log('TYPE: list');
|
|
254
|
+
console.log('');
|
|
255
|
+
console.log('---');
|
|
256
|
+
console.log('END_SETUP_PROMPTS');
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
export async function runCheckSetup(options) {
|
|
260
|
+
const stateManager = getStateManager();
|
|
261
|
+
if (options.json) {
|
|
262
|
+
outputJson({
|
|
263
|
+
setupComplete: stateManager.isSetupComplete(),
|
|
264
|
+
username: stateManager.getState().config.githubUsername,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
if (stateManager.isSetupComplete()) {
|
|
269
|
+
console.log('SETUP_COMPLETE');
|
|
270
|
+
console.log(`username=${stateManager.getState().config.githubUsername}`);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
console.log('SETUP_INCOMPLETE');
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shelve/Unshelve commands
|
|
3
|
+
* Manages shelving PRs to exclude them from capacity and actionable issues.
|
|
4
|
+
* Shelved PRs are auto-unshelved when a maintainer engages.
|
|
5
|
+
*/
|
|
6
|
+
import { PR_URL_PATTERN } from './validation.js';
|
|
7
|
+
interface ShelveCommandOptions {
|
|
8
|
+
prUrl: string;
|
|
9
|
+
json?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export { PR_URL_PATTERN };
|
|
12
|
+
export declare function runShelve(options: ShelveCommandOptions): Promise<void>;
|
|
13
|
+
export declare function runUnshelve(options: ShelveCommandOptions): Promise<void>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shelve/Unshelve commands
|
|
3
|
+
* Manages shelving PRs to exclude them from capacity and actionable issues.
|
|
4
|
+
* Shelved PRs are auto-unshelved when a maintainer engages.
|
|
5
|
+
*/
|
|
6
|
+
import { getStateManager } from '../core/index.js';
|
|
7
|
+
import { outputJson } from '../formatters/json.js';
|
|
8
|
+
import { PR_URL_PATTERN, validateGitHubUrl, validateUrl } from './validation.js';
|
|
9
|
+
// Re-export for backward compatibility with tests
|
|
10
|
+
export { PR_URL_PATTERN };
|
|
11
|
+
export async function runShelve(options) {
|
|
12
|
+
validateUrl(options.prUrl);
|
|
13
|
+
validateGitHubUrl(options.prUrl, PR_URL_PATTERN, 'PR', options.json);
|
|
14
|
+
const stateManager = getStateManager();
|
|
15
|
+
const added = stateManager.shelvePR(options.prUrl);
|
|
16
|
+
if (added) {
|
|
17
|
+
stateManager.save();
|
|
18
|
+
}
|
|
19
|
+
if (options.json) {
|
|
20
|
+
outputJson({ shelved: added, url: options.prUrl });
|
|
21
|
+
}
|
|
22
|
+
else if (added) {
|
|
23
|
+
console.log(`Shelved: ${options.prUrl}`);
|
|
24
|
+
console.log('This PR is now excluded from capacity and actionable issues.');
|
|
25
|
+
console.log('It will auto-unshelve if a maintainer engages.');
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
console.log('PR is already shelved.');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export async function runUnshelve(options) {
|
|
32
|
+
validateUrl(options.prUrl);
|
|
33
|
+
validateGitHubUrl(options.prUrl, PR_URL_PATTERN, 'PR', options.json);
|
|
34
|
+
const stateManager = getStateManager();
|
|
35
|
+
const removed = stateManager.unshelvePR(options.prUrl);
|
|
36
|
+
if (removed) {
|
|
37
|
+
stateManager.save();
|
|
38
|
+
}
|
|
39
|
+
if (options.json) {
|
|
40
|
+
outputJson({ unshelved: removed, url: options.prUrl });
|
|
41
|
+
}
|
|
42
|
+
else if (removed) {
|
|
43
|
+
console.log(`Unshelved: ${options.prUrl}`);
|
|
44
|
+
console.log('This PR is now active again.');
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log('PR was not shelved.');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snooze/Unsnooze commands
|
|
3
|
+
* Manages snoozing CI failure notifications for PRs with known upstream/infrastructure issues.
|
|
4
|
+
* Snoozed PRs are excluded from the actionable CI failure list until the snooze expires.
|
|
5
|
+
*/
|
|
6
|
+
interface SnoozeCommandOptions {
|
|
7
|
+
prUrl: string;
|
|
8
|
+
reason: string;
|
|
9
|
+
days?: number;
|
|
10
|
+
json?: boolean;
|
|
11
|
+
}
|
|
12
|
+
interface UnsnoozeCommandOptions {
|
|
13
|
+
prUrl: string;
|
|
14
|
+
json?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function runSnooze(options: SnoozeCommandOptions): Promise<void>;
|
|
17
|
+
export declare function runUnsnooze(options: UnsnoozeCommandOptions): Promise<void>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snooze/Unsnooze commands
|
|
3
|
+
* Manages snoozing CI failure notifications for PRs with known upstream/infrastructure issues.
|
|
4
|
+
* Snoozed PRs are excluded from the actionable CI failure list until the snooze expires.
|
|
5
|
+
*/
|
|
6
|
+
import { getStateManager } from '../core/index.js';
|
|
7
|
+
import { outputJson, outputJsonError } from '../formatters/json.js';
|
|
8
|
+
import { PR_URL_PATTERN, validateGitHubUrl, validateUrl, validateMessage } from './validation.js';
|
|
9
|
+
const DEFAULT_SNOOZE_DAYS = 7;
|
|
10
|
+
export async function runSnooze(options) {
|
|
11
|
+
validateUrl(options.prUrl);
|
|
12
|
+
validateGitHubUrl(options.prUrl, PR_URL_PATTERN, 'PR', options.json);
|
|
13
|
+
validateMessage(options.reason);
|
|
14
|
+
const days = options.days ?? DEFAULT_SNOOZE_DAYS;
|
|
15
|
+
if (!Number.isFinite(days) || days <= 0) {
|
|
16
|
+
if (options.json) {
|
|
17
|
+
outputJsonError('Snooze duration must be a positive number of days.');
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
console.error('Error: Snooze duration must be a positive number of days.');
|
|
21
|
+
}
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const stateManager = getStateManager();
|
|
26
|
+
const added = stateManager.snoozePR(options.prUrl, options.reason, days);
|
|
27
|
+
if (added) {
|
|
28
|
+
stateManager.save();
|
|
29
|
+
}
|
|
30
|
+
const snoozeInfo = stateManager.getSnoozeInfo(options.prUrl);
|
|
31
|
+
if (options.json) {
|
|
32
|
+
outputJson({
|
|
33
|
+
snoozed: added,
|
|
34
|
+
url: options.prUrl,
|
|
35
|
+
days,
|
|
36
|
+
reason: options.reason,
|
|
37
|
+
expiresAt: snoozeInfo?.expiresAt,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
else if (added) {
|
|
41
|
+
console.log(`Snoozed: ${options.prUrl}`);
|
|
42
|
+
console.log(`Reason: ${options.reason}`);
|
|
43
|
+
console.log(`Duration: ${days} day${days === 1 ? '' : 's'}`);
|
|
44
|
+
console.log(`Expires: ${snoozeInfo?.expiresAt ? new Date(snoozeInfo.expiresAt).toLocaleString() : 'unknown'}`);
|
|
45
|
+
console.log('CI failure notifications are now muted for this PR.');
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.log('PR is already snoozed.');
|
|
49
|
+
if (snoozeInfo) {
|
|
50
|
+
console.log(`Expires: ${new Date(snoozeInfo.expiresAt).toLocaleString()}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
56
|
+
if (options.json) {
|
|
57
|
+
outputJsonError(`Snooze failed: ${msg}`);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
console.error(`Error: Snooze failed: ${msg}`);
|
|
61
|
+
}
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export async function runUnsnooze(options) {
|
|
66
|
+
validateUrl(options.prUrl);
|
|
67
|
+
validateGitHubUrl(options.prUrl, PR_URL_PATTERN, 'PR', options.json);
|
|
68
|
+
const stateManager = getStateManager();
|
|
69
|
+
const removed = stateManager.unsnoozePR(options.prUrl);
|
|
70
|
+
if (removed) {
|
|
71
|
+
stateManager.save();
|
|
72
|
+
}
|
|
73
|
+
if (options.json) {
|
|
74
|
+
outputJson({ unsnoozed: removed, url: options.prUrl });
|
|
75
|
+
}
|
|
76
|
+
else if (removed) {
|
|
77
|
+
console.log(`Unsnoozed: ${options.prUrl}`);
|
|
78
|
+
console.log('CI failure notifications are active again for this PR.');
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
console.log('PR was not snoozed.');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Startup command
|
|
3
|
+
* Combines all pre-flight checks into a single CLI invocation:
|
|
4
|
+
* auth check, setup check, daily fetch, dashboard generation, version detection, issue list detection.
|
|
5
|
+
*
|
|
6
|
+
* Replaces the ~100-line inline bash script in commands/oss.md with a single
|
|
7
|
+
* `node cli.bundle.cjs startup --json` call, reducing UI noise in Claude Code.
|
|
8
|
+
*/
|
|
9
|
+
import { type IssueListInfo } from '../formatters/json.js';
|
|
10
|
+
interface StartupOptions {
|
|
11
|
+
json?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Parse issueListPath from a config file's YAML frontmatter.
|
|
15
|
+
* Returns the path string or undefined if not found.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseIssueListPathFromConfig(configContent: string): string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Count available and completed items in an issue list file.
|
|
20
|
+
* Available: list items (- [) NOT struck through or marked Done.
|
|
21
|
+
* Completed: list items that ARE struck through or marked Done.
|
|
22
|
+
*/
|
|
23
|
+
export declare function countIssueListItems(content: string): {
|
|
24
|
+
availableCount: number;
|
|
25
|
+
completedCount: number;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Detect an issue list file from config or known paths.
|
|
29
|
+
* Returns IssueListInfo or undefined if no list found.
|
|
30
|
+
*/
|
|
31
|
+
export declare function detectIssueList(): IssueListInfo | undefined;
|
|
32
|
+
export declare function runStartup(options: StartupOptions): Promise<void>;
|
|
33
|
+
export {};
|