@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,311 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comments, Post, and Claim commands
|
|
3
|
+
* Handles GitHub comment interactions
|
|
4
|
+
*/
|
|
5
|
+
import { getStateManager, getOctokit, parseGitHubUrl, formatRelativeTime, getGitHubToken } from '../core/index.js';
|
|
6
|
+
import { paginateAll } from '../core/pagination.js';
|
|
7
|
+
import { outputJson, outputJsonError } from '../formatters/json.js';
|
|
8
|
+
import { validateUrl, validateMessage } from './validation.js';
|
|
9
|
+
export async function runComments(options) {
|
|
10
|
+
validateUrl(options.prUrl);
|
|
11
|
+
// Token is guaranteed by the preAction hook in cli.ts for non-LOCAL_ONLY_COMMANDS.
|
|
12
|
+
const token = getGitHubToken();
|
|
13
|
+
const stateManager = getStateManager();
|
|
14
|
+
const octokit = getOctokit(token);
|
|
15
|
+
// Parse PR URL
|
|
16
|
+
const parsed = parseGitHubUrl(options.prUrl);
|
|
17
|
+
if (!parsed || parsed.type !== 'pull') {
|
|
18
|
+
if (options.json) {
|
|
19
|
+
outputJsonError('Invalid PR URL format');
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
console.error('Invalid PR URL format');
|
|
23
|
+
}
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
const { owner, repo, number: pull_number } = parsed;
|
|
27
|
+
// Get PR details
|
|
28
|
+
const { data: pr } = await octokit.pulls.get({ owner, repo, pull_number });
|
|
29
|
+
// Get review comments (inline code comments)
|
|
30
|
+
const reviewComments = await paginateAll((page) => octokit.pulls.listReviewComments({
|
|
31
|
+
owner,
|
|
32
|
+
repo,
|
|
33
|
+
pull_number,
|
|
34
|
+
per_page: 100,
|
|
35
|
+
page,
|
|
36
|
+
}));
|
|
37
|
+
// Get issue comments (general PR discussion)
|
|
38
|
+
const issueComments = await paginateAll((page) => octokit.issues.listComments({
|
|
39
|
+
owner,
|
|
40
|
+
repo,
|
|
41
|
+
issue_number: pull_number,
|
|
42
|
+
per_page: 100,
|
|
43
|
+
page,
|
|
44
|
+
}));
|
|
45
|
+
// Get reviews
|
|
46
|
+
const reviews = await paginateAll((page) => octokit.pulls.listReviews({
|
|
47
|
+
owner,
|
|
48
|
+
repo,
|
|
49
|
+
pull_number,
|
|
50
|
+
per_page: 100,
|
|
51
|
+
page,
|
|
52
|
+
}));
|
|
53
|
+
// Filter out own comments, optionally show bots
|
|
54
|
+
const username = stateManager.getState().config.githubUsername;
|
|
55
|
+
const filterComment = (c) => {
|
|
56
|
+
if (!c.user)
|
|
57
|
+
return false;
|
|
58
|
+
if (c.user.login === username)
|
|
59
|
+
return false;
|
|
60
|
+
if (c.user.type === 'Bot' && !options.showBots)
|
|
61
|
+
return false;
|
|
62
|
+
return true;
|
|
63
|
+
};
|
|
64
|
+
const relevantReviewComments = reviewComments
|
|
65
|
+
.filter(filterComment)
|
|
66
|
+
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
67
|
+
const relevantIssueComments = issueComments
|
|
68
|
+
.filter(filterComment)
|
|
69
|
+
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
70
|
+
const relevantReviews = reviews
|
|
71
|
+
.filter((r) => filterComment(r) && r.body && r.body.trim())
|
|
72
|
+
.sort((a, b) => new Date(b.submitted_at || 0).getTime() - new Date(a.submitted_at || 0).getTime());
|
|
73
|
+
if (options.json) {
|
|
74
|
+
outputJson({
|
|
75
|
+
pr: {
|
|
76
|
+
title: pr.title,
|
|
77
|
+
state: pr.state,
|
|
78
|
+
mergeable: pr.mergeable,
|
|
79
|
+
head: pr.head.ref,
|
|
80
|
+
base: pr.base.ref,
|
|
81
|
+
url: pr.html_url,
|
|
82
|
+
},
|
|
83
|
+
reviews: relevantReviews.map((r) => ({
|
|
84
|
+
user: r.user?.login,
|
|
85
|
+
state: r.state,
|
|
86
|
+
body: r.body,
|
|
87
|
+
submittedAt: r.submitted_at,
|
|
88
|
+
})),
|
|
89
|
+
reviewComments: relevantReviewComments.map((c) => ({
|
|
90
|
+
user: c.user?.login,
|
|
91
|
+
body: c.body,
|
|
92
|
+
path: c.path,
|
|
93
|
+
createdAt: c.created_at,
|
|
94
|
+
})),
|
|
95
|
+
issueComments: relevantIssueComments.map((c) => ({
|
|
96
|
+
user: c.user?.login,
|
|
97
|
+
body: c.body,
|
|
98
|
+
createdAt: c.created_at,
|
|
99
|
+
})),
|
|
100
|
+
summary: {
|
|
101
|
+
reviewCount: relevantReviews.length,
|
|
102
|
+
inlineCommentCount: relevantReviewComments.length,
|
|
103
|
+
discussionCommentCount: relevantIssueComments.length,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// Text output
|
|
109
|
+
console.log(`\n💬 Fetching comments for: ${options.prUrl}\n`);
|
|
110
|
+
console.log(`## ${pr.title}\n`);
|
|
111
|
+
console.log(`**Status:** ${pr.state} | **Mergeable:** ${pr.mergeable ?? 'checking...'}`);
|
|
112
|
+
console.log(`**Branch:** ${pr.head.ref} → ${pr.base.ref}`);
|
|
113
|
+
console.log(`**URL:** ${pr.html_url}\n`);
|
|
114
|
+
if (relevantReviews.length > 0) {
|
|
115
|
+
console.log('### Reviews (newest first)\n');
|
|
116
|
+
for (const review of relevantReviews) {
|
|
117
|
+
const state = review.state === 'APPROVED' ? '✅' : review.state === 'CHANGES_REQUESTED' ? '❌' : '💬';
|
|
118
|
+
const time = review.submitted_at ? formatRelativeTime(review.submitted_at) : '';
|
|
119
|
+
console.log(`${state} **@${review.user?.login}** (${review.state}) - ${time}`);
|
|
120
|
+
if (review.body) {
|
|
121
|
+
console.log(`> ${review.body.split('\n').join('\n> ')}\n`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (relevantReviewComments.length > 0) {
|
|
126
|
+
console.log('### Inline Comments (newest first)\n');
|
|
127
|
+
for (const comment of relevantReviewComments) {
|
|
128
|
+
const time = formatRelativeTime(comment.created_at);
|
|
129
|
+
console.log(`**@${comment.user?.login}** on \`${comment.path}\` - ${time}`);
|
|
130
|
+
console.log(`> ${comment.body.split('\n').join('\n> ')}`);
|
|
131
|
+
if (comment.diff_hunk) {
|
|
132
|
+
console.log(`\`\`\`diff\n${comment.diff_hunk.slice(-500)}\n\`\`\``);
|
|
133
|
+
}
|
|
134
|
+
console.log('');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (relevantIssueComments.length > 0) {
|
|
138
|
+
console.log('### Discussion (newest first)\n');
|
|
139
|
+
for (const comment of relevantIssueComments) {
|
|
140
|
+
const time = formatRelativeTime(comment.created_at);
|
|
141
|
+
console.log(`**@${comment.user?.login}** - ${time}`);
|
|
142
|
+
console.log(`> ${comment.body?.split('\n').join('\n> ')}\n`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (relevantReviewComments.length === 0 && relevantIssueComments.length === 0 && relevantReviews.length === 0) {
|
|
146
|
+
console.log('No comments from other users.\n');
|
|
147
|
+
}
|
|
148
|
+
console.log('---');
|
|
149
|
+
console.log(`**Summary:** ${relevantReviews.length} reviews, ${relevantReviewComments.length} inline comments, ${relevantIssueComments.length} discussion comments`);
|
|
150
|
+
}
|
|
151
|
+
export async function runPost(options) {
|
|
152
|
+
validateUrl(options.url);
|
|
153
|
+
// Token is guaranteed by the preAction hook in cli.ts for non-LOCAL_ONLY_COMMANDS.
|
|
154
|
+
const token = getGitHubToken();
|
|
155
|
+
let message = options.message;
|
|
156
|
+
// Read from stdin if specified
|
|
157
|
+
if (options.stdin) {
|
|
158
|
+
const chunks = [];
|
|
159
|
+
for await (const chunk of process.stdin) {
|
|
160
|
+
chunks.push(chunk);
|
|
161
|
+
}
|
|
162
|
+
message = Buffer.concat(chunks).toString('utf-8').trim();
|
|
163
|
+
}
|
|
164
|
+
if (!message) {
|
|
165
|
+
if (options.json) {
|
|
166
|
+
outputJsonError('No message provided');
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
console.error('Error: No message provided');
|
|
170
|
+
}
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
try {
|
|
174
|
+
validateMessage(message);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
if (options.json) {
|
|
178
|
+
outputJsonError(error instanceof Error ? error.message : 'Invalid message');
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
console.error(`Error: ${error instanceof Error ? error.message : 'Invalid message'}`);
|
|
182
|
+
}
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
// Parse URL
|
|
186
|
+
const parsed = parseGitHubUrl(options.url);
|
|
187
|
+
if (!parsed) {
|
|
188
|
+
if (options.json) {
|
|
189
|
+
outputJsonError('Invalid GitHub URL format');
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.error('Invalid GitHub URL format');
|
|
193
|
+
}
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
const { owner, repo, number } = parsed;
|
|
197
|
+
const octokit = getOctokit(token);
|
|
198
|
+
if (!options.json) {
|
|
199
|
+
console.log('\n📝 Posting comment to:', options.url);
|
|
200
|
+
console.log('---');
|
|
201
|
+
console.log(message);
|
|
202
|
+
console.log('---\n');
|
|
203
|
+
}
|
|
204
|
+
try {
|
|
205
|
+
const { data: comment } = await octokit.issues.createComment({
|
|
206
|
+
owner,
|
|
207
|
+
repo,
|
|
208
|
+
issue_number: number,
|
|
209
|
+
body: message,
|
|
210
|
+
});
|
|
211
|
+
if (options.json) {
|
|
212
|
+
outputJson({
|
|
213
|
+
commentUrl: comment.html_url,
|
|
214
|
+
url: options.url,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
console.log('✅ Comment posted successfully!');
|
|
219
|
+
console.log(` ${comment.html_url}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
if (options.json) {
|
|
224
|
+
outputJsonError(error instanceof Error ? error.message : 'Unknown error');
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
console.error('❌ Failed to post comment:', error instanceof Error ? error.message : error);
|
|
228
|
+
}
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
export async function runClaim(options) {
|
|
233
|
+
validateUrl(options.issueUrl);
|
|
234
|
+
// Token is guaranteed by the preAction hook in cli.ts for non-LOCAL_ONLY_COMMANDS.
|
|
235
|
+
const token = getGitHubToken();
|
|
236
|
+
// Default claim message or custom
|
|
237
|
+
const message = options.message || "Hi! I'd like to work on this issue. Could you assign it to me?";
|
|
238
|
+
try {
|
|
239
|
+
validateMessage(message);
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
if (options.json) {
|
|
243
|
+
outputJsonError(error instanceof Error ? error.message : 'Invalid message');
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
console.error(`Error: ${error instanceof Error ? error.message : 'Invalid message'}`);
|
|
247
|
+
}
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
// Parse URL
|
|
251
|
+
const parsed = parseGitHubUrl(options.issueUrl);
|
|
252
|
+
if (!parsed || parsed.type !== 'issues') {
|
|
253
|
+
if (options.json) {
|
|
254
|
+
outputJsonError('Invalid issue URL format (must be an issue, not a PR)');
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
console.error('Invalid issue URL format (must be an issue, not a PR)');
|
|
258
|
+
}
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
const { owner, repo, number } = parsed;
|
|
262
|
+
if (!options.json) {
|
|
263
|
+
console.log('\n🙋 Claiming issue:', options.issueUrl);
|
|
264
|
+
console.log('---');
|
|
265
|
+
console.log(message);
|
|
266
|
+
console.log('---\n');
|
|
267
|
+
}
|
|
268
|
+
const octokit = getOctokit(token);
|
|
269
|
+
try {
|
|
270
|
+
const { data: comment } = await octokit.issues.createComment({
|
|
271
|
+
owner,
|
|
272
|
+
repo,
|
|
273
|
+
issue_number: number,
|
|
274
|
+
body: message,
|
|
275
|
+
});
|
|
276
|
+
// Add to tracked issues
|
|
277
|
+
const stateManager = getStateManager();
|
|
278
|
+
stateManager.addIssue({
|
|
279
|
+
id: number,
|
|
280
|
+
url: options.issueUrl,
|
|
281
|
+
repo: `${owner}/${repo}`,
|
|
282
|
+
number,
|
|
283
|
+
title: '(claimed)',
|
|
284
|
+
status: 'claimed',
|
|
285
|
+
labels: [],
|
|
286
|
+
createdAt: new Date().toISOString(),
|
|
287
|
+
updatedAt: new Date().toISOString(),
|
|
288
|
+
vetted: false,
|
|
289
|
+
});
|
|
290
|
+
stateManager.save();
|
|
291
|
+
if (options.json) {
|
|
292
|
+
outputJson({
|
|
293
|
+
commentUrl: comment.html_url,
|
|
294
|
+
issueUrl: options.issueUrl,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
console.log('✅ Issue claimed!');
|
|
299
|
+
console.log(` ${comment.html_url}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
if (options.json) {
|
|
304
|
+
outputJsonError(error instanceof Error ? error.message : 'Unknown error');
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
console.error('❌ Failed to claim issue:', error instanceof Error ? error.message : error);
|
|
308
|
+
}
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config command
|
|
3
|
+
* Shows or updates configuration
|
|
4
|
+
*/
|
|
5
|
+
import { getStateManager } from '../core/index.js';
|
|
6
|
+
import { outputJson, outputJsonError } from '../formatters/json.js';
|
|
7
|
+
function exitWithError(msg, json) {
|
|
8
|
+
if (json) {
|
|
9
|
+
outputJsonError(msg);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
console.error(msg);
|
|
13
|
+
}
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
export async function runConfig(options) {
|
|
17
|
+
const stateManager = getStateManager();
|
|
18
|
+
const currentConfig = stateManager.getState().config;
|
|
19
|
+
if (!options.key) {
|
|
20
|
+
// Show current config
|
|
21
|
+
if (options.json) {
|
|
22
|
+
outputJson({ config: currentConfig });
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.log('\n⚙️ Current Configuration:\n');
|
|
26
|
+
console.log(JSON.stringify(currentConfig, null, 2));
|
|
27
|
+
}
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (!options.value) {
|
|
31
|
+
exitWithError('Value required', options.json);
|
|
32
|
+
}
|
|
33
|
+
const value = options.value;
|
|
34
|
+
// Handle specific config keys
|
|
35
|
+
switch (options.key) {
|
|
36
|
+
case 'username':
|
|
37
|
+
stateManager.updateConfig({ githubUsername: value });
|
|
38
|
+
break;
|
|
39
|
+
case 'add-language':
|
|
40
|
+
if (!currentConfig.languages.includes(value)) {
|
|
41
|
+
stateManager.updateConfig({ languages: [...currentConfig.languages, value] });
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
case 'add-label':
|
|
45
|
+
if (!currentConfig.labels.includes(value)) {
|
|
46
|
+
stateManager.updateConfig({ labels: [...currentConfig.labels, value] });
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
case 'exclude-repo': {
|
|
50
|
+
const parts = value.split('/');
|
|
51
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
52
|
+
exitWithError(`Invalid repo format "${value}". Use "owner/repo" format. To exclude an entire org, use: config exclude-org ${value}`, options.json);
|
|
53
|
+
}
|
|
54
|
+
const valueLower = value.toLowerCase();
|
|
55
|
+
if (!currentConfig.excludeRepos.some((r) => r.toLowerCase() === valueLower)) {
|
|
56
|
+
stateManager.updateConfig({ excludeRepos: [...currentConfig.excludeRepos, value] });
|
|
57
|
+
stateManager.cleanupExcludedData([value], []);
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
case 'exclude-org': {
|
|
62
|
+
if (value.includes('/')) {
|
|
63
|
+
exitWithError(`Invalid org name "${value}". Use just the org name (e.g., "facebook"), not "owner/repo" format. To exclude a specific repo, use: config exclude-repo ${value}`, options.json);
|
|
64
|
+
}
|
|
65
|
+
const currentOrgs = currentConfig.excludeOrgs ?? [];
|
|
66
|
+
if (!currentOrgs.some((o) => o.toLowerCase() === value.toLowerCase())) {
|
|
67
|
+
stateManager.updateConfig({ excludeOrgs: [...currentOrgs, value] });
|
|
68
|
+
stateManager.cleanupExcludedData([], [value]);
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
default:
|
|
73
|
+
exitWithError(`Unknown config key: ${options.key}`, options.json);
|
|
74
|
+
}
|
|
75
|
+
stateManager.save();
|
|
76
|
+
if (options.json) {
|
|
77
|
+
outputJson({ success: true, key: options.key, value });
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
console.log(`Set ${options.key} to: ${value}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daily check command
|
|
3
|
+
* Fetches all open PRs fresh from GitHub (v2: no PR-level state tracking),
|
|
4
|
+
* generates a digest, and updates repo scores and analytics in local state.
|
|
5
|
+
*
|
|
6
|
+
* Domain logic lives in src/core/daily-logic.ts; this file is a thin
|
|
7
|
+
* orchestration layer that wires up the phases and handles I/O.
|
|
8
|
+
*/
|
|
9
|
+
import { type DailyOutput } from '../formatters/json.js';
|
|
10
|
+
export { computeRepoSignals, groupPRsByRepo, assessCapacity, collectActionableIssues, computeActionMenu, toShelvedPRRef, formatBriefSummary, formatSummary, printDigest, CRITICAL_STATUSES, } from '../core/index.js';
|
|
11
|
+
interface DailyOptions {
|
|
12
|
+
json?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function runDaily(options: DailyOptions): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Core daily check logic, extracted for reuse by the startup command.
|
|
17
|
+
* Fetches all open PRs, updates state, and returns structured output.
|
|
18
|
+
*
|
|
19
|
+
* Returns a deduplicated DailyOutput where category arrays contain PR URLs
|
|
20
|
+
* instead of full objects (#287). Full PR objects are in digest.openPRs only.
|
|
21
|
+
*
|
|
22
|
+
* Orchestrates five named phases:
|
|
23
|
+
* 1. fetchPRData — fetch open PRs, merged/closed counts, issues
|
|
24
|
+
* 2. updateRepoScores — update signals, star counts, trust in state
|
|
25
|
+
* 3. updateAnalytics — store monthly chart data
|
|
26
|
+
* 4. partitionPRs — expire snoozes, shelve/unshelve, generate digest
|
|
27
|
+
* 5. generateDigestOutput — capacity, dismiss filter, action menu assembly
|
|
28
|
+
*/
|
|
29
|
+
export declare function executeDailyCheck(token: string): Promise<DailyOutput>;
|