@oss-autopilot/core 0.41.0 → 0.42.1
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 +1552 -1318
- package/dist/cli.js +593 -69
- package/dist/commands/check-integration.d.ts +3 -3
- package/dist/commands/check-integration.js +10 -43
- package/dist/commands/comments.d.ts +6 -9
- package/dist/commands/comments.js +102 -252
- package/dist/commands/config.d.ts +8 -2
- package/dist/commands/config.js +6 -28
- package/dist/commands/daily.d.ts +28 -4
- package/dist/commands/daily.js +33 -45
- package/dist/commands/dashboard-data.js +7 -6
- package/dist/commands/dashboard-server.d.ts +14 -0
- package/dist/commands/dashboard-server.js +362 -0
- package/dist/commands/dashboard.d.ts +5 -0
- package/dist/commands/dashboard.js +51 -1
- package/dist/commands/dismiss.d.ts +13 -5
- package/dist/commands/dismiss.js +4 -24
- package/dist/commands/index.d.ts +33 -0
- package/dist/commands/index.js +22 -0
- package/dist/commands/init.d.ts +5 -4
- package/dist/commands/init.js +4 -14
- package/dist/commands/local-repos.d.ts +4 -5
- package/dist/commands/local-repos.js +6 -33
- package/dist/commands/parse-list.d.ts +3 -4
- package/dist/commands/parse-list.js +8 -39
- package/dist/commands/read.d.ts +11 -5
- package/dist/commands/read.js +4 -18
- package/dist/commands/search.d.ts +3 -3
- package/dist/commands/search.js +39 -65
- package/dist/commands/setup.d.ts +34 -5
- package/dist/commands/setup.js +75 -166
- package/dist/commands/shelve.d.ts +13 -5
- package/dist/commands/shelve.js +4 -24
- package/dist/commands/snooze.d.ts +15 -9
- package/dist/commands/snooze.js +16 -59
- package/dist/commands/startup.d.ts +11 -6
- package/dist/commands/startup.js +44 -82
- package/dist/commands/status.d.ts +3 -3
- package/dist/commands/status.js +10 -29
- package/dist/commands/track.d.ts +10 -9
- package/dist/commands/track.js +17 -39
- package/dist/commands/validation.d.ts +2 -2
- package/dist/commands/validation.js +7 -15
- package/dist/commands/vet.d.ts +3 -3
- package/dist/commands/vet.js +16 -26
- package/dist/core/errors.d.ts +9 -0
- package/dist/core/errors.js +17 -0
- package/dist/core/github-stats.d.ts +14 -21
- package/dist/core/github-stats.js +84 -138
- package/dist/core/http-cache.d.ts +6 -0
- package/dist/core/http-cache.js +16 -4
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.js +2 -1
- package/dist/core/issue-conversation.js +4 -4
- package/dist/core/issue-discovery.js +14 -14
- package/dist/core/issue-vetting.js +17 -17
- package/dist/core/pr-monitor.d.ts +6 -20
- package/dist/core/pr-monitor.js +11 -52
- package/dist/core/state.js +4 -5
- package/dist/core/utils.d.ts +11 -0
- package/dist/core/utils.js +21 -0
- package/dist/formatters/json.d.ts +58 -0
- package/package.json +5 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Check integration command (#83)
|
|
3
3
|
* Detects new files in the current branch that aren't referenced elsewhere
|
|
4
4
|
*/
|
|
5
|
+
import type { CheckIntegrationOutput, NewFileInfo } from '../formatters/json.js';
|
|
5
6
|
interface CheckIntegrationOptions {
|
|
6
7
|
base: string;
|
|
7
|
-
json?: boolean;
|
|
8
8
|
}
|
|
9
|
-
export
|
|
10
|
-
export
|
|
9
|
+
export type { CheckIntegrationOutput, NewFileInfo };
|
|
10
|
+
export declare function runCheckIntegration(options: CheckIntegrationOptions): Promise<CheckIntegrationOutput>;
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import { execFileSync } from 'child_process';
|
|
7
|
-
import { outputJson, outputJsonError } from '../formatters/json.js';
|
|
8
7
|
import { debug } from '../core/index.js';
|
|
8
|
+
import { errorMessage } from '../core/errors.js';
|
|
9
9
|
/** File extensions we consider "code" that should be imported/referenced */
|
|
10
10
|
const CODE_EXTENSIONS = new Set([
|
|
11
11
|
'.ts',
|
|
@@ -77,14 +77,8 @@ export async function runCheckIntegration(options) {
|
|
|
77
77
|
newFiles = output ? output.split('\n').filter(Boolean) : [];
|
|
78
78
|
}
|
|
79
79
|
catch (error) {
|
|
80
|
-
const msg =
|
|
81
|
-
|
|
82
|
-
outputJsonError(`Failed to run git diff: ${msg}`);
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
console.error(`Error: Failed to run git diff: ${msg}`);
|
|
86
|
-
}
|
|
87
|
-
process.exit(1);
|
|
80
|
+
const msg = errorMessage(error);
|
|
81
|
+
throw new Error(`Failed to run git diff: ${msg}`, { cause: error });
|
|
88
82
|
}
|
|
89
83
|
// Filter to code files, excluding tests, configs, etc.
|
|
90
84
|
const codeFiles = newFiles.filter((f) => {
|
|
@@ -94,14 +88,7 @@ export async function runCheckIntegration(options) {
|
|
|
94
88
|
return !IGNORED_PATTERNS.some((p) => p.test(f));
|
|
95
89
|
});
|
|
96
90
|
if (codeFiles.length === 0) {
|
|
97
|
-
|
|
98
|
-
if (options.json) {
|
|
99
|
-
outputJson(result);
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
console.log('\nNo new code files to check.');
|
|
103
|
-
}
|
|
104
|
-
return;
|
|
91
|
+
return { newFiles: [], unreferencedCount: 0 };
|
|
105
92
|
}
|
|
106
93
|
// Get all tracked files in the repo for reference checking
|
|
107
94
|
let allFiles;
|
|
@@ -115,7 +102,7 @@ export async function runCheckIntegration(options) {
|
|
|
115
102
|
.filter(Boolean);
|
|
116
103
|
}
|
|
117
104
|
catch (err) {
|
|
118
|
-
// git ls-files failed (e.g. not a git repo)
|
|
105
|
+
// git ls-files failed (e.g. not a git repo) -- proceed without reference list
|
|
119
106
|
debug('check-integration', 'git ls-files failed, reference checking will be skipped', err);
|
|
120
107
|
allFiles = [];
|
|
121
108
|
}
|
|
@@ -147,10 +134,10 @@ export async function runCheckIntegration(options) {
|
|
|
147
134
|
}
|
|
148
135
|
catch (error) {
|
|
149
136
|
// git grep exit code 1 = no matches (expected), exit code 2+ = real error
|
|
150
|
-
const exitCode = error && typeof error === 'object' && 'status' in error ? error.status :
|
|
151
|
-
if (exitCode !==
|
|
152
|
-
const msg =
|
|
153
|
-
|
|
137
|
+
const exitCode = error && typeof error === 'object' && 'status' in error ? error.status : undefined;
|
|
138
|
+
if (exitCode !== undefined && exitCode !== 1) {
|
|
139
|
+
const msg = errorMessage(error);
|
|
140
|
+
debug('check-integration', `git grep failed for "${pattern}": ${msg}`);
|
|
154
141
|
}
|
|
155
142
|
}
|
|
156
143
|
}
|
|
@@ -168,25 +155,5 @@ export async function runCheckIntegration(options) {
|
|
|
168
155
|
results.push(info);
|
|
169
156
|
}
|
|
170
157
|
const unreferencedCount = results.filter((r) => !r.isIntegrated).length;
|
|
171
|
-
|
|
172
|
-
if (options.json) {
|
|
173
|
-
outputJson(output);
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
console.log(`\n🔍 Integration Check (base: ${base})\n`);
|
|
177
|
-
console.log(`New files: ${results.length} | Unreferenced: ${unreferencedCount}\n`);
|
|
178
|
-
for (const file of results) {
|
|
179
|
-
const status = file.isIntegrated ? '✅' : '⚠️';
|
|
180
|
-
console.log(`${status} ${file.path}`);
|
|
181
|
-
if (file.isIntegrated) {
|
|
182
|
-
console.log(` Referenced by: ${file.referencedBy.join(', ')}`);
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
console.log(' Not referenced by any file');
|
|
186
|
-
if (file.suggestedEntryPoints && file.suggestedEntryPoints.length > 0) {
|
|
187
|
-
console.log(` Suggested entry points: ${file.suggestedEntryPoints.join(', ')}`);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
158
|
+
return { newFiles: results, unreferencedCount };
|
|
192
159
|
}
|
|
@@ -2,23 +2,20 @@
|
|
|
2
2
|
* Comments, Post, and Claim commands
|
|
3
3
|
* Handles GitHub comment interactions
|
|
4
4
|
*/
|
|
5
|
+
import { type CommentsOutput, type PostOutput, type ClaimOutput } from '../formatters/json.js';
|
|
6
|
+
export { type CommentsOutput, type PostOutput, type ClaimOutput } from '../formatters/json.js';
|
|
5
7
|
interface CommentsOptions {
|
|
6
8
|
prUrl: string;
|
|
7
9
|
showBots?: boolean;
|
|
8
|
-
json?: boolean;
|
|
9
10
|
}
|
|
10
11
|
interface PostOptions {
|
|
11
12
|
url: string;
|
|
12
|
-
message
|
|
13
|
-
stdin?: boolean;
|
|
14
|
-
json?: boolean;
|
|
13
|
+
message: string;
|
|
15
14
|
}
|
|
16
15
|
interface ClaimOptions {
|
|
17
16
|
issueUrl: string;
|
|
18
17
|
message?: string;
|
|
19
|
-
json?: boolean;
|
|
20
18
|
}
|
|
21
|
-
export declare function runComments(options: CommentsOptions): Promise<
|
|
22
|
-
export declare function runPost(options: PostOptions): Promise<
|
|
23
|
-
export declare function runClaim(options: ClaimOptions): Promise<
|
|
24
|
-
export {};
|
|
19
|
+
export declare function runComments(options: CommentsOptions): Promise<CommentsOutput>;
|
|
20
|
+
export declare function runPost(options: PostOptions): Promise<PostOutput>;
|
|
21
|
+
export declare function runClaim(options: ClaimOptions): Promise<ClaimOutput>;
|
|
@@ -2,54 +2,46 @@
|
|
|
2
2
|
* Comments, Post, and Claim commands
|
|
3
3
|
* Handles GitHub comment interactions
|
|
4
4
|
*/
|
|
5
|
-
import { getStateManager, getOctokit, parseGitHubUrl,
|
|
5
|
+
import { getStateManager, getOctokit, parseGitHubUrl, requireGitHubToken } from '../core/index.js';
|
|
6
6
|
import { paginateAll } from '../core/pagination.js';
|
|
7
|
-
import { outputJson, outputJsonError } from '../formatters/json.js';
|
|
8
7
|
import { validateUrl, validateMessage } from './validation.js';
|
|
9
8
|
export async function runComments(options) {
|
|
10
9
|
validateUrl(options.prUrl);
|
|
11
|
-
|
|
12
|
-
const token = getGitHubToken();
|
|
10
|
+
const token = requireGitHubToken();
|
|
13
11
|
const stateManager = getStateManager();
|
|
14
12
|
const octokit = getOctokit(token);
|
|
15
13
|
// Parse PR URL
|
|
16
14
|
const parsed = parseGitHubUrl(options.prUrl);
|
|
17
15
|
if (!parsed || parsed.type !== 'pull') {
|
|
18
|
-
|
|
19
|
-
outputJsonError('Invalid PR URL format');
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
console.error('Invalid PR URL format');
|
|
23
|
-
}
|
|
24
|
-
process.exit(1);
|
|
16
|
+
throw new Error('Invalid PR URL format');
|
|
25
17
|
}
|
|
26
18
|
const { owner, repo, number: pull_number } = parsed;
|
|
27
19
|
// Get PR details
|
|
28
20
|
const { data: pr } = await octokit.pulls.get({ owner, repo, pull_number });
|
|
29
|
-
//
|
|
30
|
-
const reviewComments = await
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
21
|
+
// Fetch review comments, issue comments, and reviews in parallel
|
|
22
|
+
const [reviewComments, issueComments, reviews] = await Promise.all([
|
|
23
|
+
paginateAll((page) => octokit.pulls.listReviewComments({
|
|
24
|
+
owner,
|
|
25
|
+
repo,
|
|
26
|
+
pull_number,
|
|
27
|
+
per_page: 100,
|
|
28
|
+
page,
|
|
29
|
+
})),
|
|
30
|
+
paginateAll((page) => octokit.issues.listComments({
|
|
31
|
+
owner,
|
|
32
|
+
repo,
|
|
33
|
+
issue_number: pull_number,
|
|
34
|
+
per_page: 100,
|
|
35
|
+
page,
|
|
36
|
+
})),
|
|
37
|
+
paginateAll((page) => octokit.pulls.listReviews({
|
|
38
|
+
owner,
|
|
39
|
+
repo,
|
|
40
|
+
pull_number,
|
|
41
|
+
per_page: 100,
|
|
42
|
+
page,
|
|
43
|
+
})),
|
|
44
|
+
]);
|
|
53
45
|
// Filter out own comments, optionally show bots
|
|
54
46
|
const username = stateManager.getState().config.githubUsername;
|
|
55
47
|
const filterComment = (c) => {
|
|
@@ -70,242 +62,100 @@ export async function runComments(options) {
|
|
|
70
62
|
const relevantReviews = reviews
|
|
71
63
|
.filter((r) => filterComment(r) && r.body && r.body.trim())
|
|
72
64
|
.sort((a, b) => new Date(b.submitted_at || 0).getTime() - new Date(a.submitted_at || 0).getTime());
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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`);
|
|
65
|
+
return {
|
|
66
|
+
pr: {
|
|
67
|
+
title: pr.title,
|
|
68
|
+
state: pr.state,
|
|
69
|
+
mergeable: pr.mergeable,
|
|
70
|
+
head: pr.head.ref,
|
|
71
|
+
base: pr.base.ref,
|
|
72
|
+
url: pr.html_url,
|
|
73
|
+
},
|
|
74
|
+
reviews: relevantReviews.map((r) => ({
|
|
75
|
+
user: r.user?.login,
|
|
76
|
+
state: r.state,
|
|
77
|
+
body: r.body ?? null,
|
|
78
|
+
submittedAt: r.submitted_at ?? null,
|
|
79
|
+
})),
|
|
80
|
+
reviewComments: relevantReviewComments.map((c) => ({
|
|
81
|
+
user: c.user?.login,
|
|
82
|
+
body: c.body,
|
|
83
|
+
path: c.path,
|
|
84
|
+
createdAt: c.created_at,
|
|
85
|
+
})),
|
|
86
|
+
issueComments: relevantIssueComments.map((c) => ({
|
|
87
|
+
user: c.user?.login,
|
|
88
|
+
body: c.body,
|
|
89
|
+
createdAt: c.created_at,
|
|
90
|
+
})),
|
|
91
|
+
summary: {
|
|
92
|
+
reviewCount: relevantReviews.length,
|
|
93
|
+
inlineCommentCount: relevantReviewComments.length,
|
|
94
|
+
discussionCommentCount: relevantIssueComments.length,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
150
97
|
}
|
|
151
98
|
export async function runPost(options) {
|
|
152
99
|
validateUrl(options.url);
|
|
153
|
-
|
|
154
|
-
|
|
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);
|
|
100
|
+
if (!options.message.trim()) {
|
|
101
|
+
throw new Error('No message provided');
|
|
184
102
|
}
|
|
103
|
+
validateMessage(options.message);
|
|
104
|
+
const token = requireGitHubToken();
|
|
185
105
|
// Parse URL
|
|
186
106
|
const parsed = parseGitHubUrl(options.url);
|
|
187
107
|
if (!parsed) {
|
|
188
|
-
|
|
189
|
-
outputJsonError('Invalid GitHub URL format');
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
console.error('Invalid GitHub URL format');
|
|
193
|
-
}
|
|
194
|
-
process.exit(1);
|
|
108
|
+
throw new Error('Invalid GitHub URL format');
|
|
195
109
|
}
|
|
196
110
|
const { owner, repo, number } = parsed;
|
|
197
111
|
const octokit = getOctokit(token);
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
-
}
|
|
112
|
+
const { data: comment } = await octokit.issues.createComment({
|
|
113
|
+
owner,
|
|
114
|
+
repo,
|
|
115
|
+
issue_number: number,
|
|
116
|
+
body: options.message,
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
commentUrl: comment.html_url,
|
|
120
|
+
url: options.url,
|
|
121
|
+
};
|
|
231
122
|
}
|
|
232
123
|
export async function runClaim(options) {
|
|
233
124
|
validateUrl(options.issueUrl);
|
|
234
|
-
|
|
235
|
-
const token = getGitHubToken();
|
|
125
|
+
const token = requireGitHubToken();
|
|
236
126
|
// Default claim message or custom
|
|
237
127
|
const message = options.message || "Hi! I'd like to work on this issue. Could you assign it to me?";
|
|
238
|
-
|
|
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
|
-
}
|
|
128
|
+
validateMessage(message);
|
|
250
129
|
// Parse URL
|
|
251
130
|
const parsed = parseGitHubUrl(options.issueUrl);
|
|
252
131
|
if (!parsed || parsed.type !== 'issues') {
|
|
253
|
-
|
|
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);
|
|
132
|
+
throw new Error('Invalid issue URL format (must be an issue, not a PR)');
|
|
260
133
|
}
|
|
261
134
|
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
135
|
const octokit = getOctokit(token);
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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
|
-
}
|
|
136
|
+
const { data: comment } = await octokit.issues.createComment({
|
|
137
|
+
owner,
|
|
138
|
+
repo,
|
|
139
|
+
issue_number: number,
|
|
140
|
+
body: message,
|
|
141
|
+
});
|
|
142
|
+
// Add to tracked issues
|
|
143
|
+
const stateManager = getStateManager();
|
|
144
|
+
stateManager.addIssue({
|
|
145
|
+
id: number,
|
|
146
|
+
url: options.issueUrl,
|
|
147
|
+
repo: `${owner}/${repo}`,
|
|
148
|
+
number,
|
|
149
|
+
title: '(claimed)',
|
|
150
|
+
status: 'claimed',
|
|
151
|
+
labels: [],
|
|
152
|
+
createdAt: new Date().toISOString(),
|
|
153
|
+
updatedAt: new Date().toISOString(),
|
|
154
|
+
vetted: false,
|
|
155
|
+
});
|
|
156
|
+
stateManager.save();
|
|
157
|
+
return {
|
|
158
|
+
commentUrl: comment.html_url,
|
|
159
|
+
issueUrl: options.issueUrl,
|
|
160
|
+
};
|
|
311
161
|
}
|
|
@@ -2,10 +2,16 @@
|
|
|
2
2
|
* Config command
|
|
3
3
|
* Shows or updates configuration
|
|
4
4
|
*/
|
|
5
|
+
import type { ConfigOutput } from '../formatters/json.js';
|
|
5
6
|
interface ConfigOptions {
|
|
6
7
|
key?: string;
|
|
7
8
|
value?: string;
|
|
8
|
-
json?: boolean;
|
|
9
9
|
}
|
|
10
|
-
export
|
|
10
|
+
export interface ConfigSetOutput {
|
|
11
|
+
success: true;
|
|
12
|
+
key: string;
|
|
13
|
+
value: string;
|
|
14
|
+
}
|
|
15
|
+
export type ConfigCommandOutput = ConfigOutput | ConfigSetOutput;
|
|
16
|
+
export declare function runConfig(options: ConfigOptions): Promise<ConfigCommandOutput>;
|
|
11
17
|
export {};
|
package/dist/commands/config.js
CHANGED
|
@@ -3,32 +3,15 @@
|
|
|
3
3
|
* Shows or updates configuration
|
|
4
4
|
*/
|
|
5
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
6
|
export async function runConfig(options) {
|
|
17
7
|
const stateManager = getStateManager();
|
|
18
8
|
const currentConfig = stateManager.getState().config;
|
|
19
9
|
if (!options.key) {
|
|
20
10
|
// Show current config
|
|
21
|
-
|
|
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;
|
|
11
|
+
return { config: currentConfig };
|
|
29
12
|
}
|
|
30
13
|
if (!options.value) {
|
|
31
|
-
|
|
14
|
+
throw new Error('Value required');
|
|
32
15
|
}
|
|
33
16
|
const value = options.value;
|
|
34
17
|
// Handle specific config keys
|
|
@@ -49,7 +32,7 @@ export async function runConfig(options) {
|
|
|
49
32
|
case 'exclude-repo': {
|
|
50
33
|
const parts = value.split('/');
|
|
51
34
|
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
52
|
-
|
|
35
|
+
throw new Error(`Invalid repo format "${value}". Use "owner/repo" format. To exclude an entire org, use: config exclude-org ${value}`);
|
|
53
36
|
}
|
|
54
37
|
const valueLower = value.toLowerCase();
|
|
55
38
|
if (!currentConfig.excludeRepos.some((r) => r.toLowerCase() === valueLower)) {
|
|
@@ -60,7 +43,7 @@ export async function runConfig(options) {
|
|
|
60
43
|
}
|
|
61
44
|
case 'exclude-org': {
|
|
62
45
|
if (value.includes('/')) {
|
|
63
|
-
|
|
46
|
+
throw new Error(`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}`);
|
|
64
47
|
}
|
|
65
48
|
const currentOrgs = currentConfig.excludeOrgs ?? [];
|
|
66
49
|
if (!currentOrgs.some((o) => o.toLowerCase() === value.toLowerCase())) {
|
|
@@ -70,13 +53,8 @@ export async function runConfig(options) {
|
|
|
70
53
|
break;
|
|
71
54
|
}
|
|
72
55
|
default:
|
|
73
|
-
|
|
56
|
+
throw new Error(`Unknown config key: ${options.key}`);
|
|
74
57
|
}
|
|
75
58
|
stateManager.save();
|
|
76
|
-
|
|
77
|
-
outputJson({ success: true, key: options.key, value });
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
console.log(`Set ${options.key} to: ${value}`);
|
|
81
|
-
}
|
|
59
|
+
return { success: true, key: options.key, value };
|
|
82
60
|
}
|
package/dist/commands/daily.d.ts
CHANGED
|
@@ -6,12 +6,26 @@
|
|
|
6
6
|
* Domain logic lives in src/core/daily-logic.ts; this file is a thin
|
|
7
7
|
* orchestration layer that wires up the phases and handles I/O.
|
|
8
8
|
*/
|
|
9
|
-
import { type
|
|
9
|
+
import { type DailyDigest, type CommentedIssue, type PRCheckFailure, type RepoGroup } from '../core/index.js';
|
|
10
|
+
import { type DailyOutput, type CapacityAssessment, type ActionableIssue, type ActionMenu } from '../formatters/json.js';
|
|
10
11
|
export { computeRepoSignals, groupPRsByRepo, assessCapacity, collectActionableIssues, computeActionMenu, toShelvedPRRef, formatBriefSummary, formatSummary, printDigest, CRITICAL_STATUSES, } from '../core/index.js';
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Internal result of the daily check, using full (non-deduplicated) types.
|
|
14
|
+
* Consumed by printDigest() (text mode) and converted to DailyOutput (JSON mode)
|
|
15
|
+
* via toDailyOutput() which deduplicates PR objects.
|
|
16
|
+
*/
|
|
17
|
+
export interface DailyCheckResult {
|
|
18
|
+
digest: DailyDigest;
|
|
19
|
+
updates: unknown[];
|
|
20
|
+
capacity: CapacityAssessment;
|
|
21
|
+
summary: string;
|
|
22
|
+
briefSummary: string;
|
|
23
|
+
actionableIssues: ActionableIssue[];
|
|
24
|
+
actionMenu: ActionMenu;
|
|
25
|
+
commentedIssues: CommentedIssue[];
|
|
26
|
+
repoGroups: RepoGroup[];
|
|
27
|
+
failures: PRCheckFailure[];
|
|
13
28
|
}
|
|
14
|
-
export declare function runDaily(options: DailyOptions): Promise<void>;
|
|
15
29
|
/**
|
|
16
30
|
* Core daily check logic, extracted for reuse by the startup command.
|
|
17
31
|
* Fetches all open PRs, updates state, and returns structured output.
|
|
@@ -27,3 +41,13 @@ export declare function runDaily(options: DailyOptions): Promise<void>;
|
|
|
27
41
|
* 5. generateDigestOutput — capacity, dismiss filter, action menu assembly
|
|
28
42
|
*/
|
|
29
43
|
export declare function executeDailyCheck(token: string): Promise<DailyOutput>;
|
|
44
|
+
/**
|
|
45
|
+
* Run the daily check and return deduplicated DailyOutput.
|
|
46
|
+
* Errors propagate to the caller.
|
|
47
|
+
*/
|
|
48
|
+
export declare function runDaily(): Promise<DailyOutput>;
|
|
49
|
+
/**
|
|
50
|
+
* Run the daily check and return the full (non-deduplicated) result.
|
|
51
|
+
* Used by CLI text mode where printDigest() needs full PR objects.
|
|
52
|
+
*/
|
|
53
|
+
export declare function runDailyForDisplay(): Promise<DailyCheckResult>;
|