@oss-autopilot/core 0.42.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 +236 -282
- package/dist/cli.js +4 -16
- package/dist/commands/check-integration.js +5 -4
- package/dist/commands/comments.js +24 -24
- package/dist/commands/daily.js +14 -13
- package/dist/commands/dashboard-data.js +7 -6
- package/dist/commands/dashboard-server.js +3 -2
- package/dist/commands/dashboard.js +2 -1
- package/dist/commands/local-repos.js +2 -1
- package/dist/commands/parse-list.js +2 -1
- package/dist/commands/startup.js +6 -16
- package/dist/commands/validation.js +5 -5
- 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/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* async token fetch to avoid blocking the event loop on `gh auth token`.
|
|
11
11
|
*/
|
|
12
12
|
import { Command } from 'commander';
|
|
13
|
-
import { getGitHubTokenAsync, enableDebug, debug, formatRelativeTime } from './core/index.js';
|
|
13
|
+
import { getGitHubTokenAsync, enableDebug, debug, formatRelativeTime, getCLIVersion } from './core/index.js';
|
|
14
|
+
import { errorMessage } from './core/errors.js';
|
|
14
15
|
import { outputJson, outputJsonError } from './formatters/json.js';
|
|
15
16
|
/** Print local repos in human-readable format */
|
|
16
17
|
function printRepos(repos) {
|
|
@@ -23,7 +24,7 @@ function printRepos(repos) {
|
|
|
23
24
|
}
|
|
24
25
|
/** Shared error handler for CLI action catch blocks. */
|
|
25
26
|
function handleCommandError(err, json) {
|
|
26
|
-
const msg =
|
|
27
|
+
const msg = errorMessage(err);
|
|
27
28
|
if (json) {
|
|
28
29
|
outputJsonError(msg);
|
|
29
30
|
}
|
|
@@ -32,20 +33,7 @@ function handleCommandError(err, json) {
|
|
|
32
33
|
}
|
|
33
34
|
process.exit(1);
|
|
34
35
|
}
|
|
35
|
-
const VERSION = (
|
|
36
|
-
try {
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
38
|
-
const fs = require('fs');
|
|
39
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
40
|
-
const path = require('path');
|
|
41
|
-
const pkgPath = path.join(path.dirname(process.argv[1]), '..', 'package.json');
|
|
42
|
-
return JSON.parse(fs.readFileSync(pkgPath, 'utf-8')).version;
|
|
43
|
-
}
|
|
44
|
-
catch (_err) {
|
|
45
|
-
// package.json may not be readable in all bundle/install configurations — fall back to safe default
|
|
46
|
-
return '0.0.0';
|
|
47
|
-
}
|
|
48
|
-
})();
|
|
36
|
+
const VERSION = getCLIVersion();
|
|
49
37
|
// Commands that skip the preAction GitHub token check.
|
|
50
38
|
// startup handles auth internally (returns authError in JSON instead of process.exit).
|
|
51
39
|
const LOCAL_ONLY_COMMANDS = [
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import { execFileSync } from 'child_process';
|
|
7
7
|
import { debug } from '../core/index.js';
|
|
8
|
+
import { errorMessage } from '../core/errors.js';
|
|
8
9
|
/** File extensions we consider "code" that should be imported/referenced */
|
|
9
10
|
const CODE_EXTENSIONS = new Set([
|
|
10
11
|
'.ts',
|
|
@@ -76,7 +77,7 @@ export async function runCheckIntegration(options) {
|
|
|
76
77
|
newFiles = output ? output.split('\n').filter(Boolean) : [];
|
|
77
78
|
}
|
|
78
79
|
catch (error) {
|
|
79
|
-
const msg =
|
|
80
|
+
const msg = errorMessage(error);
|
|
80
81
|
throw new Error(`Failed to run git diff: ${msg}`, { cause: error });
|
|
81
82
|
}
|
|
82
83
|
// Filter to code files, excluding tests, configs, etc.
|
|
@@ -133,9 +134,9 @@ export async function runCheckIntegration(options) {
|
|
|
133
134
|
}
|
|
134
135
|
catch (error) {
|
|
135
136
|
// git grep exit code 1 = no matches (expected), exit code 2+ = real error
|
|
136
|
-
const exitCode = error && typeof error === 'object' && 'status' in error ? error.status :
|
|
137
|
-
if (exitCode !==
|
|
138
|
-
const msg =
|
|
137
|
+
const exitCode = error && typeof error === 'object' && 'status' in error ? error.status : undefined;
|
|
138
|
+
if (exitCode !== undefined && exitCode !== 1) {
|
|
139
|
+
const msg = errorMessage(error);
|
|
139
140
|
debug('check-integration', `git grep failed for "${pattern}": ${msg}`);
|
|
140
141
|
}
|
|
141
142
|
}
|
|
@@ -18,30 +18,30 @@ export async function runComments(options) {
|
|
|
18
18
|
const { owner, repo, number: pull_number } = parsed;
|
|
19
19
|
// Get PR details
|
|
20
20
|
const { data: pr } = await octokit.pulls.get({ owner, repo, pull_number });
|
|
21
|
-
//
|
|
22
|
-
const reviewComments = await
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
+
]);
|
|
45
45
|
// Filter out own comments, optionally show bots
|
|
46
46
|
const username = stateManager.getState().config.githubUsername;
|
|
47
47
|
const filterComment = (c) => {
|
package/dist/commands/daily.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* orchestration layer that wires up the phases and handles I/O.
|
|
8
8
|
*/
|
|
9
9
|
import { getStateManager, PRMonitor, IssueConversationMonitor, requireGitHubToken, CRITICAL_STATUSES, computeRepoSignals, groupPRsByRepo, assessCapacity, collectActionableIssues, computeActionMenu, toShelvedPRRef, formatBriefSummary, formatSummary, } from '../core/index.js';
|
|
10
|
+
import { errorMessage } from '../core/errors.js';
|
|
10
11
|
import { deduplicateDigest, compactActionableIssues, compactRepoGroups, } from '../formatters/json.js';
|
|
11
12
|
// Re-export domain functions so existing consumers (tests, dashboard, startup)
|
|
12
13
|
// can continue importing from './daily.js' without changes.
|
|
@@ -33,15 +34,15 @@ async function fetchPRData(prMonitor, token) {
|
|
|
33
34
|
prMonitor.fetchUserMergedPRCounts(),
|
|
34
35
|
prMonitor.fetchUserClosedPRCounts(),
|
|
35
36
|
prMonitor.fetchRecentlyClosedPRs().catch((err) => {
|
|
36
|
-
console.error(`Warning: Failed to fetch recently closed PRs: ${err
|
|
37
|
+
console.error(`Warning: Failed to fetch recently closed PRs: ${errorMessage(err)}`);
|
|
37
38
|
return [];
|
|
38
39
|
}),
|
|
39
40
|
prMonitor.fetchRecentlyMergedPRs().catch((err) => {
|
|
40
|
-
console.error(`Warning: Failed to fetch recently merged PRs: ${err
|
|
41
|
+
console.error(`Warning: Failed to fetch recently merged PRs: ${errorMessage(err)}`);
|
|
41
42
|
return [];
|
|
42
43
|
}),
|
|
43
44
|
issueMonitor.fetchCommentedIssues().catch((error) => {
|
|
44
|
-
const msg =
|
|
45
|
+
const msg = errorMessage(error);
|
|
45
46
|
if (msg.includes('No GitHub username configured')) {
|
|
46
47
|
console.error(`[DAILY] Issue conversation tracking requires setup: ${msg}`);
|
|
47
48
|
}
|
|
@@ -103,7 +104,7 @@ async function updateRepoScores(prMonitor, prs, mergedCounts, closedCounts) {
|
|
|
103
104
|
}
|
|
104
105
|
catch (error) {
|
|
105
106
|
mergedCountFailures++;
|
|
106
|
-
console.error(`[DAILY] Failed to update merged count for ${repo}:`, error
|
|
107
|
+
console.error(`[DAILY] Failed to update merged count for ${repo}:`, errorMessage(error));
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
if (mergedCountFailures === mergedCounts.size && mergedCounts.size > 0) {
|
|
@@ -123,7 +124,7 @@ async function updateRepoScores(prMonitor, prs, mergedCounts, closedCounts) {
|
|
|
123
124
|
}
|
|
124
125
|
catch (error) {
|
|
125
126
|
closedCountFailures++;
|
|
126
|
-
console.error(`[DAILY] Failed to update closed count for ${repo}:`, error
|
|
127
|
+
console.error(`[DAILY] Failed to update closed count for ${repo}:`, errorMessage(error));
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
130
|
if (closedCountFailures === closedCounts.size && closedCounts.size > 0) {
|
|
@@ -142,7 +143,7 @@ async function updateRepoScores(prMonitor, prs, mergedCounts, closedCounts) {
|
|
|
142
143
|
}
|
|
143
144
|
catch (error) {
|
|
144
145
|
signalUpdateFailures++;
|
|
145
|
-
console.error(`[DAILY] Failed to update signals for ${repo}:`, error
|
|
146
|
+
console.error(`[DAILY] Failed to update signals for ${repo}:`, errorMessage(error));
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
149
|
if (signalUpdateFailures === repoSignals.size && repoSignals.size > 0) {
|
|
@@ -155,7 +156,7 @@ async function updateRepoScores(prMonitor, prs, mergedCounts, closedCounts) {
|
|
|
155
156
|
starCounts = await prMonitor.fetchRepoStarCounts(allRepos);
|
|
156
157
|
}
|
|
157
158
|
catch (error) {
|
|
158
|
-
console.error('[DAILY] Failed to fetch repo star counts:', error
|
|
159
|
+
console.error('[DAILY] Failed to fetch repo star counts:', errorMessage(error));
|
|
159
160
|
console.error('[DAILY] Dashboard minStars filter will use cached star counts (or be skipped for repos without cached data).');
|
|
160
161
|
starCounts = new Map();
|
|
161
162
|
}
|
|
@@ -166,7 +167,7 @@ async function updateRepoScores(prMonitor, prs, mergedCounts, closedCounts) {
|
|
|
166
167
|
}
|
|
167
168
|
catch (error) {
|
|
168
169
|
starUpdateFailures++;
|
|
169
|
-
console.error(`[DAILY] Failed to update star count for ${repo}:`, error
|
|
170
|
+
console.error(`[DAILY] Failed to update star count for ${repo}:`, errorMessage(error));
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
173
|
if (starUpdateFailures === starCounts.size && starCounts.size > 0) {
|
|
@@ -180,7 +181,7 @@ async function updateRepoScores(prMonitor, prs, mergedCounts, closedCounts) {
|
|
|
180
181
|
}
|
|
181
182
|
catch (error) {
|
|
182
183
|
trustSyncFailures++;
|
|
183
|
-
console.error(`[DAILY] Failed to sync trusted project ${repo}:`, error
|
|
184
|
+
console.error(`[DAILY] Failed to sync trusted project ${repo}:`, errorMessage(error));
|
|
184
185
|
}
|
|
185
186
|
}
|
|
186
187
|
if (trustSyncFailures === mergedCounts.size && mergedCounts.size > 0) {
|
|
@@ -199,13 +200,13 @@ function updateAnalytics(prs, monthlyCounts, monthlyClosedCounts, openedFromMerg
|
|
|
199
200
|
stateManager.setMonthlyMergedCounts(monthlyCounts);
|
|
200
201
|
}
|
|
201
202
|
catch (error) {
|
|
202
|
-
console.error('[DAILY] Failed to store monthly merged counts:', error
|
|
203
|
+
console.error('[DAILY] Failed to store monthly merged counts:', errorMessage(error));
|
|
203
204
|
}
|
|
204
205
|
try {
|
|
205
206
|
stateManager.setMonthlyClosedCounts(monthlyClosedCounts);
|
|
206
207
|
}
|
|
207
208
|
catch (error) {
|
|
208
|
-
console.error('[DAILY] Failed to store monthly closed counts:', error
|
|
209
|
+
console.error('[DAILY] Failed to store monthly closed counts:', errorMessage(error));
|
|
209
210
|
}
|
|
210
211
|
try {
|
|
211
212
|
// Build combined monthly opened counts from merged + closed + currently-open PRs
|
|
@@ -223,7 +224,7 @@ function updateAnalytics(prs, monthlyCounts, monthlyClosedCounts, openedFromMerg
|
|
|
223
224
|
stateManager.setMonthlyOpenedCounts(combinedOpenedCounts);
|
|
224
225
|
}
|
|
225
226
|
catch (error) {
|
|
226
|
-
console.error('[DAILY] Failed to compute/store monthly opened counts:', error
|
|
227
|
+
console.error('[DAILY] Failed to compute/store monthly opened counts:', errorMessage(error));
|
|
227
228
|
}
|
|
228
229
|
}
|
|
229
230
|
/**
|
|
@@ -246,7 +247,7 @@ function partitionPRs(prMonitor, prs, recentlyClosedPRs, recentlyMergedPRs) {
|
|
|
246
247
|
}
|
|
247
248
|
}
|
|
248
249
|
catch (error) {
|
|
249
|
-
console.error('[DAILY] Failed to expire/persist snoozes:', error
|
|
250
|
+
console.error('[DAILY] Failed to expire/persist snoozes:', errorMessage(error));
|
|
250
251
|
}
|
|
251
252
|
// Partition PRs into active vs shelved, auto-unshelving when maintainers engage
|
|
252
253
|
const shelvedPRs = [];
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Separates data concerns from template generation and command orchestration.
|
|
5
5
|
*/
|
|
6
6
|
import { getStateManager, PRMonitor, IssueConversationMonitor } from '../core/index.js';
|
|
7
|
+
import { errorMessage } from '../core/errors.js';
|
|
7
8
|
import { toShelvedPRRef } from './daily.js';
|
|
8
9
|
/**
|
|
9
10
|
* Fetch fresh dashboard data from GitHub.
|
|
@@ -17,17 +18,17 @@ export async function fetchDashboardData(token) {
|
|
|
17
18
|
const [{ prs, failures }, recentlyClosedPRs, recentlyMergedPRs, mergedResult, closedResult, fetchedIssues] = await Promise.all([
|
|
18
19
|
prMonitor.fetchUserOpenPRs(),
|
|
19
20
|
prMonitor.fetchRecentlyClosedPRs().catch((err) => {
|
|
20
|
-
console.error(`Warning: Failed to fetch recently closed PRs: ${err
|
|
21
|
+
console.error(`Warning: Failed to fetch recently closed PRs: ${errorMessage(err)}`);
|
|
21
22
|
return [];
|
|
22
23
|
}),
|
|
23
24
|
prMonitor.fetchRecentlyMergedPRs().catch((err) => {
|
|
24
|
-
console.error(`Warning: Failed to fetch recently merged PRs: ${err
|
|
25
|
+
console.error(`Warning: Failed to fetch recently merged PRs: ${errorMessage(err)}`);
|
|
25
26
|
return [];
|
|
26
27
|
}),
|
|
27
28
|
prMonitor.fetchUserMergedPRCounts(),
|
|
28
29
|
prMonitor.fetchUserClosedPRCounts(),
|
|
29
30
|
issueMonitor.fetchCommentedIssues().catch((error) => {
|
|
30
|
-
const msg =
|
|
31
|
+
const msg = errorMessage(error);
|
|
31
32
|
if (msg.includes('No GitHub username configured')) {
|
|
32
33
|
console.error(`[DASHBOARD] Issue conversation tracking requires setup: ${msg}`);
|
|
33
34
|
}
|
|
@@ -54,13 +55,13 @@ export async function fetchDashboardData(token) {
|
|
|
54
55
|
stateManager.setMonthlyMergedCounts(monthlyCounts);
|
|
55
56
|
}
|
|
56
57
|
catch (error) {
|
|
57
|
-
console.error('[DASHBOARD] Failed to store monthly merged counts:', error
|
|
58
|
+
console.error('[DASHBOARD] Failed to store monthly merged counts:', errorMessage(error));
|
|
58
59
|
}
|
|
59
60
|
try {
|
|
60
61
|
stateManager.setMonthlyClosedCounts(monthlyClosedCounts);
|
|
61
62
|
}
|
|
62
63
|
catch (error) {
|
|
63
|
-
console.error('[DASHBOARD] Failed to store monthly closed counts:', error
|
|
64
|
+
console.error('[DASHBOARD] Failed to store monthly closed counts:', errorMessage(error));
|
|
64
65
|
}
|
|
65
66
|
try {
|
|
66
67
|
const combinedOpenedCounts = { ...openedFromMerged };
|
|
@@ -76,7 +77,7 @@ export async function fetchDashboardData(token) {
|
|
|
76
77
|
stateManager.setMonthlyOpenedCounts(combinedOpenedCounts);
|
|
77
78
|
}
|
|
78
79
|
catch (error) {
|
|
79
|
-
console.error('[DASHBOARD] Failed to store monthly opened counts:', error
|
|
80
|
+
console.error('[DASHBOARD] Failed to store monthly opened counts:', errorMessage(error));
|
|
80
81
|
}
|
|
81
82
|
const digest = prMonitor.generateDigest(prs, recentlyClosedPRs, recentlyMergedPRs);
|
|
82
83
|
// Apply shelve partitioning for display (auto-unshelve only runs in daily check)
|
|
@@ -9,6 +9,7 @@ import * as http from 'http';
|
|
|
9
9
|
import * as fs from 'fs';
|
|
10
10
|
import * as path from 'path';
|
|
11
11
|
import { getStateManager, getGitHubToken } from '../core/index.js';
|
|
12
|
+
import { errorMessage } from '../core/errors.js';
|
|
12
13
|
import { fetchDashboardData, computePRsByRepo, computeTopRepos, getMonthlyData } from './dashboard-data.js';
|
|
13
14
|
import { buildDashboardStats } from './dashboard-templates.js';
|
|
14
15
|
// ── Constants ────────────────────────────────────────────────────────────────
|
|
@@ -203,7 +204,7 @@ export async function startDashboardServer(options) {
|
|
|
203
204
|
}
|
|
204
205
|
catch (error) {
|
|
205
206
|
console.error('Action failed:', body.action, body.url, error);
|
|
206
|
-
sendError(res, 500, `Action failed: ${
|
|
207
|
+
sendError(res, 500, `Action failed: ${errorMessage(error)}`);
|
|
207
208
|
return;
|
|
208
209
|
}
|
|
209
210
|
// Rebuild dashboard data from cached digest + updated state
|
|
@@ -229,7 +230,7 @@ export async function startDashboardServer(options) {
|
|
|
229
230
|
}
|
|
230
231
|
catch (error) {
|
|
231
232
|
console.error('Dashboard refresh failed:', error);
|
|
232
|
-
sendError(res, 500, `Refresh failed: ${
|
|
233
|
+
sendError(res, 500, `Refresh failed: ${errorMessage(error)}`);
|
|
233
234
|
}
|
|
234
235
|
}
|
|
235
236
|
// ── Static file serving ──────────────────────────────────────────────────
|
|
@@ -7,6 +7,7 @@ import * as fs from 'fs';
|
|
|
7
7
|
import * as path from 'path';
|
|
8
8
|
import { execFile } from 'child_process';
|
|
9
9
|
import { getStateManager, getDashboardPath, getGitHubToken } from '../core/index.js';
|
|
10
|
+
import { errorMessage } from '../core/errors.js';
|
|
10
11
|
import { outputJson } from '../formatters/json.js';
|
|
11
12
|
import { fetchDashboardData, computePRsByRepo, computeTopRepos, getMonthlyData } from './dashboard-data.js';
|
|
12
13
|
import { buildDashboardStats, generateDashboardHtml } from './dashboard-templates.js';
|
|
@@ -39,7 +40,7 @@ export async function runDashboard(options) {
|
|
|
39
40
|
commentedIssues = result.commentedIssues;
|
|
40
41
|
}
|
|
41
42
|
catch (error) {
|
|
42
|
-
console.error('Failed to fetch fresh data:', error
|
|
43
|
+
console.error('Failed to fetch fresh data:', errorMessage(error));
|
|
43
44
|
console.error('Falling back to cached data (issue conversations unavailable)...');
|
|
44
45
|
digest = stateManager.getState().lastDigest;
|
|
45
46
|
}
|
|
@@ -7,6 +7,7 @@ import * as path from 'path';
|
|
|
7
7
|
import * as os from 'os';
|
|
8
8
|
import { execFileSync } from 'child_process';
|
|
9
9
|
import { getStateManager, debug } from '../core/index.js';
|
|
10
|
+
import { errorMessage } from '../core/errors.js';
|
|
10
11
|
/** Default directories to scan for local clones */
|
|
11
12
|
const DEFAULT_SCAN_PATHS = [
|
|
12
13
|
path.join(os.homedir(), 'Documents', 'oss'),
|
|
@@ -115,7 +116,7 @@ export async function runLocalRepos(options) {
|
|
|
115
116
|
stateManager.save();
|
|
116
117
|
}
|
|
117
118
|
catch (error) {
|
|
118
|
-
const msg =
|
|
119
|
+
const msg = errorMessage(error);
|
|
119
120
|
debug('local-repos', `Failed to cache scan results: ${msg}`);
|
|
120
121
|
}
|
|
121
122
|
return {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import * as path from 'path';
|
|
7
|
+
import { errorMessage } from '../core/errors.js';
|
|
7
8
|
/** Extract GitHub issue/PR URLs from a markdown line */
|
|
8
9
|
function extractGitHubUrl(line) {
|
|
9
10
|
const match = line.match(/https:\/\/github\.com\/([^/]+\/[^/]+)\/issues\/(\d+)/);
|
|
@@ -100,7 +101,7 @@ export async function runParseList(options) {
|
|
|
100
101
|
content = fs.readFileSync(filePath, 'utf-8');
|
|
101
102
|
}
|
|
102
103
|
catch (error) {
|
|
103
|
-
const msg =
|
|
104
|
+
const msg = errorMessage(error);
|
|
104
105
|
throw new Error(`Failed to read file: ${msg}`, { cause: error });
|
|
105
106
|
}
|
|
106
107
|
return parseIssueList(content);
|
package/dist/commands/startup.js
CHANGED
|
@@ -7,21 +7,11 @@
|
|
|
7
7
|
* `node cli.bundle.cjs startup --json` call, reducing UI noise in Claude Code.
|
|
8
8
|
*/
|
|
9
9
|
import * as fs from 'fs';
|
|
10
|
-
import * as path from 'path';
|
|
11
10
|
import { execFile } from 'child_process';
|
|
12
|
-
import { getStateManager, getGitHubToken } from '../core/index.js';
|
|
11
|
+
import { getStateManager, getGitHubToken, getCLIVersion } from '../core/index.js';
|
|
12
|
+
import { errorMessage } from '../core/errors.js';
|
|
13
13
|
import { executeDailyCheck } from './daily.js';
|
|
14
14
|
import { writeDashboardFromState } from './dashboard.js';
|
|
15
|
-
function getVersion() {
|
|
16
|
-
try {
|
|
17
|
-
const pkgPath = path.join(path.dirname(process.argv[1]), '..', 'package.json');
|
|
18
|
-
return JSON.parse(fs.readFileSync(pkgPath, 'utf-8')).version;
|
|
19
|
-
}
|
|
20
|
-
catch (error) {
|
|
21
|
-
console.error('[STARTUP] Failed to detect CLI version:', error instanceof Error ? error.message : error);
|
|
22
|
-
return '0.0.0';
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
15
|
/**
|
|
26
16
|
* Parse issueListPath from a config file's YAML frontmatter.
|
|
27
17
|
* Returns the path string or undefined if not found.
|
|
@@ -75,7 +65,7 @@ export function detectIssueList() {
|
|
|
75
65
|
}
|
|
76
66
|
}
|
|
77
67
|
catch (error) {
|
|
78
|
-
console.error('[STARTUP] Failed to read config:', error
|
|
68
|
+
console.error('[STARTUP] Failed to read config:', errorMessage(error));
|
|
79
69
|
}
|
|
80
70
|
}
|
|
81
71
|
// 2. Probe known paths
|
|
@@ -98,7 +88,7 @@ export function detectIssueList() {
|
|
|
98
88
|
return { path: issueListPath, source, availableCount, completedCount };
|
|
99
89
|
}
|
|
100
90
|
catch (error) {
|
|
101
|
-
console.error(`[STARTUP] Failed to read issue list at ${issueListPath}:`, error
|
|
91
|
+
console.error(`[STARTUP] Failed to read issue list at ${issueListPath}:`, errorMessage(error));
|
|
102
92
|
return { path: issueListPath, source, availableCount: 0, completedCount: 0 };
|
|
103
93
|
}
|
|
104
94
|
}
|
|
@@ -122,7 +112,7 @@ function openInBrowser(filePath) {
|
|
|
122
112
|
* Errors from the daily check propagate to the caller.
|
|
123
113
|
*/
|
|
124
114
|
export async function runStartup() {
|
|
125
|
-
const version =
|
|
115
|
+
const version = getCLIVersion();
|
|
126
116
|
const stateManager = getStateManager();
|
|
127
117
|
// 1. Check setup
|
|
128
118
|
if (!stateManager.isSetupComplete()) {
|
|
@@ -151,7 +141,7 @@ export async function runStartup() {
|
|
|
151
141
|
}
|
|
152
142
|
}
|
|
153
143
|
catch (error) {
|
|
154
|
-
console.error('[STARTUP] Dashboard generation failed:', error
|
|
144
|
+
console.error('[STARTUP] Dashboard generation failed:', errorMessage(error));
|
|
155
145
|
}
|
|
156
146
|
// Append dashboard status to brief summary (only startup opens the browser, not daily)
|
|
157
147
|
if (dashboardOpened) {
|
|
@@ -21,7 +21,7 @@ export function validateGitHubUrl(url, pattern, entityType) {
|
|
|
21
21
|
if (pattern.test(url))
|
|
22
22
|
return;
|
|
23
23
|
const example = entityType === 'PR' ? 'https://github.com/owner/repo/pull/123' : 'https://github.com/owner/repo/issues/123';
|
|
24
|
-
throw new
|
|
24
|
+
throw new ValidationError(`Invalid ${entityType} URL: ${url}. Expected format: ${example}`);
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* Validate that a URL does not exceed the maximum allowed length.
|
|
@@ -29,7 +29,7 @@ export function validateGitHubUrl(url, pattern, entityType) {
|
|
|
29
29
|
*/
|
|
30
30
|
export function validateUrl(url) {
|
|
31
31
|
if (url.length > MAX_URL_LENGTH) {
|
|
32
|
-
throw new
|
|
32
|
+
throw new ValidationError(`URL exceeds maximum length of ${MAX_URL_LENGTH} characters`);
|
|
33
33
|
}
|
|
34
34
|
return url;
|
|
35
35
|
}
|
|
@@ -39,7 +39,7 @@ export function validateUrl(url) {
|
|
|
39
39
|
*/
|
|
40
40
|
export function validatePRNumber(num) {
|
|
41
41
|
if (!Number.isInteger(num) || num < 1 || num > MAX_PR_NUMBER) {
|
|
42
|
-
throw new
|
|
42
|
+
throw new ValidationError(`PR number must be a positive integer up to ${MAX_PR_NUMBER}`);
|
|
43
43
|
}
|
|
44
44
|
return num;
|
|
45
45
|
}
|
|
@@ -49,7 +49,7 @@ export function validatePRNumber(num) {
|
|
|
49
49
|
*/
|
|
50
50
|
export function validateMessage(message) {
|
|
51
51
|
if (message.length > MAX_MESSAGE_LENGTH) {
|
|
52
|
-
throw new
|
|
52
|
+
throw new ValidationError(`Message exceeds maximum length of ${MAX_MESSAGE_LENGTH} characters`);
|
|
53
53
|
}
|
|
54
54
|
return message;
|
|
55
55
|
}
|
|
@@ -59,7 +59,7 @@ export function validateMessage(message) {
|
|
|
59
59
|
*/
|
|
60
60
|
export function validateRepoIdentifier(repo) {
|
|
61
61
|
if (!REPO_PATTERN.test(repo)) {
|
|
62
|
-
throw new
|
|
62
|
+
throw new ValidationError(`Invalid repository format: "${repo}". Expected "owner/repo".`);
|
|
63
63
|
}
|
|
64
64
|
return repo;
|
|
65
65
|
}
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -22,3 +22,12 @@ export declare class ConfigurationError extends OssAutopilotError {
|
|
|
22
22
|
export declare class ValidationError extends OssAutopilotError {
|
|
23
23
|
constructor(message: string);
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Extract a human-readable message from an unknown error value.
|
|
27
|
+
*/
|
|
28
|
+
export declare function errorMessage(e: unknown): string;
|
|
29
|
+
/**
|
|
30
|
+
* Safely extract an HTTP status code from an unknown error (e.g. Octokit errors).
|
|
31
|
+
* Returns undefined if the error doesn't have a numeric `status` property.
|
|
32
|
+
*/
|
|
33
|
+
export declare function getHttpStatusCode(error: unknown): number | undefined;
|
package/dist/core/errors.js
CHANGED
|
@@ -32,3 +32,20 @@ export class ValidationError extends OssAutopilotError {
|
|
|
32
32
|
this.name = 'ValidationError';
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Extract a human-readable message from an unknown error value.
|
|
37
|
+
*/
|
|
38
|
+
export function errorMessage(e) {
|
|
39
|
+
return e instanceof Error ? e.message : String(e);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Safely extract an HTTP status code from an unknown error (e.g. Octokit errors).
|
|
43
|
+
* Returns undefined if the error doesn't have a numeric `status` property.
|
|
44
|
+
*/
|
|
45
|
+
export function getHttpStatusCode(error) {
|
|
46
|
+
if (error && typeof error === 'object' && 'status' in error) {
|
|
47
|
+
const status = error.status;
|
|
48
|
+
return typeof status === 'number' && Number.isFinite(status) ? status : undefined;
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
@@ -4,35 +4,28 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { Octokit } from '@octokit/rest';
|
|
6
6
|
import { ClosedPR, MergedPR } from './types.js';
|
|
7
|
+
/** TTL for cached PR count results (1 hour). */
|
|
8
|
+
export declare const PR_COUNTS_CACHE_TTL_MS: number;
|
|
9
|
+
/** Return type shared by both merged and closed PR count functions. */
|
|
10
|
+
export interface PRCountsResult<R> {
|
|
11
|
+
repos: Map<string, R>;
|
|
12
|
+
monthlyCounts: Record<string, number>;
|
|
13
|
+
monthlyOpenedCounts: Record<string, number>;
|
|
14
|
+
dailyActivityCounts: Record<string, number>;
|
|
15
|
+
}
|
|
7
16
|
/**
|
|
8
17
|
* Fetch merged PR counts and latest merge dates per repository for the configured user.
|
|
9
18
|
* Also builds a monthly histogram of all merges for the contribution timeline.
|
|
10
19
|
*/
|
|
11
|
-
export declare function fetchUserMergedPRCounts(octokit: Octokit, githubUsername: string): Promise<{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}>;
|
|
16
|
-
monthlyCounts: Record<string, number>;
|
|
17
|
-
monthlyOpenedCounts: Record<string, number>;
|
|
18
|
-
dailyActivityCounts: Record<string, number>;
|
|
19
|
-
}>;
|
|
20
|
+
export declare function fetchUserMergedPRCounts(octokit: Octokit, githubUsername: string): Promise<PRCountsResult<{
|
|
21
|
+
count: number;
|
|
22
|
+
lastMergedAt: string;
|
|
23
|
+
}>>;
|
|
20
24
|
/**
|
|
21
25
|
* Fetch closed-without-merge PR counts per repository for the configured user.
|
|
22
26
|
* Used to populate closedWithoutMergeCount in repo scores for accurate merge rate.
|
|
23
27
|
*/
|
|
24
|
-
export declare function fetchUserClosedPRCounts(octokit: Octokit, githubUsername: string): Promise<
|
|
25
|
-
repos: Map<string, number>;
|
|
26
|
-
monthlyCounts: Record<string, number>;
|
|
27
|
-
monthlyOpenedCounts: Record<string, number>;
|
|
28
|
-
dailyActivityCounts: Record<string, number>;
|
|
29
|
-
}>;
|
|
30
|
-
/**
|
|
31
|
-
* Fetch GitHub star counts for a list of repositories.
|
|
32
|
-
* Used to populate stargazersCount in repo scores for dashboard filtering by minStars.
|
|
33
|
-
* Fetches concurrently with per-repo error isolation (missing/private repos are skipped).
|
|
34
|
-
*/
|
|
35
|
-
export declare function fetchRepoStarCounts(octokit: Octokit, repos: string[]): Promise<Map<string, number>>;
|
|
28
|
+
export declare function fetchUserClosedPRCounts(octokit: Octokit, githubUsername: string): Promise<PRCountsResult<number>>;
|
|
36
29
|
/**
|
|
37
30
|
* Shared helper: search for recent PRs and filter out own repos, excluded repos/orgs.
|
|
38
31
|
* Returns parsed search results that pass all filters.
|