@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.
Files changed (63) hide show
  1. package/dist/cli.bundle.cjs +1552 -1318
  2. package/dist/cli.js +593 -69
  3. package/dist/commands/check-integration.d.ts +3 -3
  4. package/dist/commands/check-integration.js +10 -43
  5. package/dist/commands/comments.d.ts +6 -9
  6. package/dist/commands/comments.js +102 -252
  7. package/dist/commands/config.d.ts +8 -2
  8. package/dist/commands/config.js +6 -28
  9. package/dist/commands/daily.d.ts +28 -4
  10. package/dist/commands/daily.js +33 -45
  11. package/dist/commands/dashboard-data.js +7 -6
  12. package/dist/commands/dashboard-server.d.ts +14 -0
  13. package/dist/commands/dashboard-server.js +362 -0
  14. package/dist/commands/dashboard.d.ts +5 -0
  15. package/dist/commands/dashboard.js +51 -1
  16. package/dist/commands/dismiss.d.ts +13 -5
  17. package/dist/commands/dismiss.js +4 -24
  18. package/dist/commands/index.d.ts +33 -0
  19. package/dist/commands/index.js +22 -0
  20. package/dist/commands/init.d.ts +5 -4
  21. package/dist/commands/init.js +4 -14
  22. package/dist/commands/local-repos.d.ts +4 -5
  23. package/dist/commands/local-repos.js +6 -33
  24. package/dist/commands/parse-list.d.ts +3 -4
  25. package/dist/commands/parse-list.js +8 -39
  26. package/dist/commands/read.d.ts +11 -5
  27. package/dist/commands/read.js +4 -18
  28. package/dist/commands/search.d.ts +3 -3
  29. package/dist/commands/search.js +39 -65
  30. package/dist/commands/setup.d.ts +34 -5
  31. package/dist/commands/setup.js +75 -166
  32. package/dist/commands/shelve.d.ts +13 -5
  33. package/dist/commands/shelve.js +4 -24
  34. package/dist/commands/snooze.d.ts +15 -9
  35. package/dist/commands/snooze.js +16 -59
  36. package/dist/commands/startup.d.ts +11 -6
  37. package/dist/commands/startup.js +44 -82
  38. package/dist/commands/status.d.ts +3 -3
  39. package/dist/commands/status.js +10 -29
  40. package/dist/commands/track.d.ts +10 -9
  41. package/dist/commands/track.js +17 -39
  42. package/dist/commands/validation.d.ts +2 -2
  43. package/dist/commands/validation.js +7 -15
  44. package/dist/commands/vet.d.ts +3 -3
  45. package/dist/commands/vet.js +16 -26
  46. package/dist/core/errors.d.ts +9 -0
  47. package/dist/core/errors.js +17 -0
  48. package/dist/core/github-stats.d.ts +14 -21
  49. package/dist/core/github-stats.js +84 -138
  50. package/dist/core/http-cache.d.ts +6 -0
  51. package/dist/core/http-cache.js +16 -4
  52. package/dist/core/index.d.ts +2 -1
  53. package/dist/core/index.js +2 -1
  54. package/dist/core/issue-conversation.js +4 -4
  55. package/dist/core/issue-discovery.js +14 -14
  56. package/dist/core/issue-vetting.js +17 -17
  57. package/dist/core/pr-monitor.d.ts +6 -20
  58. package/dist/core/pr-monitor.js +11 -52
  59. package/dist/core/state.js +4 -5
  60. package/dist/core/utils.d.ts +11 -0
  61. package/dist/core/utils.js +21 -0
  62. package/dist/formatters/json.d.ts +58 -0
  63. package/package.json +5 -1
@@ -15,7 +15,7 @@ import { getOctokit } from './github.js';
15
15
  import { getStateManager } from './state.js';
16
16
  import { daysBetween, parseGitHubUrl, extractOwnerRepo } from './utils.js';
17
17
  import { runWorkerPool } from './concurrency.js';
18
- import { ConfigurationError, ValidationError } from './errors.js';
18
+ import { ConfigurationError, ValidationError, errorMessage, getHttpStatusCode } from './errors.js';
19
19
  import { paginateAll } from './pagination.js';
20
20
  import { debug, warn, timed } from './logger.js';
21
21
  import { getHttpCache, cachedRequest } from './http-cache.js';
@@ -114,9 +114,9 @@ export class PRMonitor {
114
114
  prs.push(pr);
115
115
  }
116
116
  catch (error) {
117
- const errorMessage = error instanceof Error ? error.message : String(error);
118
- warn('pr-monitor', `Error fetching ${item.html_url}: ${errorMessage}`);
119
- failures.push({ prUrl: item.html_url, error: errorMessage });
117
+ const errMsg = errorMessage(error);
118
+ warn('pr-monitor', `Error fetching ${item.html_url}: ${errMsg}`);
119
+ failures.push({ prUrl: item.html_url, error: errMsg });
120
120
  }
121
121
  }, MAX_CONCURRENT_REQUESTS);
122
122
  });
@@ -162,14 +162,14 @@ export class PRMonitor {
162
162
  paginateAll((page) => this.octokit.issues.listComments({ owner, repo, issue_number: number, per_page: 100, page })),
163
163
  this.octokit.pulls.listReviews({ owner, repo, pull_number: number }),
164
164
  paginateAll((page) => this.octokit.pulls.listReviewComments({ owner, repo, pull_number: number, per_page: 100, page })).catch((err) => {
165
- const status = err?.status;
165
+ const status = getHttpStatusCode(err);
166
166
  // Rate limit errors must propagate — silently swallowing them hides
167
167
  // a systemic problem and produces misleading results (#229).
168
168
  if (status === 429) {
169
169
  throw err;
170
170
  }
171
171
  if (status === 403) {
172
- const msg = (err?.message ?? '').toLowerCase();
172
+ const msg = errorMessage(err).toLowerCase();
173
173
  if (msg.includes('rate limit') || msg.includes('abuse detection')) {
174
174
  throw err;
175
175
  }
@@ -349,7 +349,7 @@ export class PRMonitor {
349
349
  this.octokit.repos.getCombinedStatusForRef({ owner, repo, ref: sha }),
350
350
  // 404 is expected for repos without check runs configured; log other errors for debugging
351
351
  this.octokit.checks.listForRef({ owner, repo, ref: sha }).catch((err) => {
352
- const status = err?.status;
352
+ const status = getHttpStatusCode(err);
353
353
  if (status === 404) {
354
354
  debug('pr-monitor', `Check runs 404 for ${owner}/${repo}@${sha.slice(0, 7)} (no checks configured)`);
355
355
  }
@@ -378,8 +378,8 @@ export class PRMonitor {
378
378
  return mergeStatuses(checkRunAnalysis, combinedAnalysis, checkRuns.length);
379
379
  }
380
380
  catch (error) {
381
- const statusCode = error.status;
382
- const errorMessage = error instanceof Error ? error.message : String(error);
381
+ const statusCode = getHttpStatusCode(error);
382
+ const errMsg = errorMessage(error);
383
383
  if (statusCode === 401) {
384
384
  warn('pr-monitor', `CI check failed for ${owner}/${repo}: Invalid token`);
385
385
  }
@@ -392,7 +392,7 @@ export class PRMonitor {
392
392
  return { status: 'unknown', failingCheckNames: [], failingCheckConclusions: new Map() };
393
393
  }
394
394
  else {
395
- warn('pr-monitor', `Failed to check CI for ${owner}/${repo}@${sha.slice(0, 7)}: ${errorMessage}`);
395
+ warn('pr-monitor', `Failed to check CI for ${owner}/${repo}@${sha.slice(0, 7)}: ${errMsg}`);
396
396
  }
397
397
  return { status: 'unknown', failingCheckNames: [], failingCheckConclusions: new Map() };
398
398
  }
@@ -451,7 +451,7 @@ export class PRMonitor {
451
451
  }
452
452
  else {
453
453
  chunkFailures++;
454
- warn(MODULE, `Failed to fetch stars for ${chunk[j]}: ${result.reason instanceof Error ? result.reason.message : result.reason}`);
454
+ warn(MODULE, `Failed to fetch stars for ${chunk[j]}: ${errorMessage(result.reason)}`);
455
455
  }
456
456
  }
457
457
  // If entire chunk failed, likely a systemic issue (rate limit, auth, outage) — abort remaining
@@ -466,47 +466,6 @@ export class PRMonitor {
466
466
  debug(MODULE, `Fetched star counts for ${results.size}/${repos.length} repos`);
467
467
  return results;
468
468
  }
469
- /**
470
- * Shared helper: search for recent PRs and filter out own repos, excluded repos/orgs.
471
- * Returns parsed search results that pass all filters.
472
- */
473
- async fetchRecentPRs(query, label, days, mapItem) {
474
- const config = this.stateManager.getState().config;
475
- if (!config.githubUsername) {
476
- warn(MODULE, `Skipping recently ${label} PRs fetch: no githubUsername configured. Run /setup-oss to configure.`);
477
- return [];
478
- }
479
- const sinceDate = new Date();
480
- sinceDate.setDate(sinceDate.getDate() - days);
481
- const since = sinceDate.toISOString().split('T')[0]; // YYYY-MM-DD
482
- debug(MODULE, `Fetching recently ${label} PRs for @${config.githubUsername} (since ${since})...`);
483
- const { data } = await this.octokit.search.issuesAndPullRequests({
484
- q: query.replace('{username}', config.githubUsername).replace('{since}', since),
485
- sort: 'updated',
486
- order: 'desc',
487
- per_page: 100,
488
- });
489
- const results = [];
490
- for (const item of data.items) {
491
- const parsed = parseGitHubUrl(item.html_url);
492
- if (!parsed) {
493
- warn(MODULE, `Could not parse GitHub URL from API response: ${item.html_url}`);
494
- continue;
495
- }
496
- const repo = `${parsed.owner}/${parsed.repo}`;
497
- // Skip own repos
498
- if (parsed.owner.toLowerCase() === config.githubUsername.toLowerCase())
499
- continue;
500
- // Skip excluded repos and orgs
501
- if (config.excludeRepos.includes(repo))
502
- continue;
503
- if (config.excludeOrgs?.some((org) => parsed.owner.toLowerCase() === org.toLowerCase()))
504
- continue;
505
- results.push(mapItem(item, { owner: parsed.owner, repo, number: parsed.number }));
506
- }
507
- debug(MODULE, `Found ${results.length} recently ${label} PRs`);
508
- return results;
509
- }
510
469
  /**
511
470
  * Fetch PRs closed without merge in the last N days.
512
471
  * Delegates to github-stats module.
@@ -6,7 +6,7 @@ import * as fs from 'fs';
6
6
  import * as path from 'path';
7
7
  import { INITIAL_STATE, } from './types.js';
8
8
  import { getStatePath, getBackupDir, getDataDir } from './utils.js';
9
- import { ValidationError } from './errors.js';
9
+ import { ValidationError, errorMessage } from './errors.js';
10
10
  import { debug, warn } from './logger.js';
11
11
  const MODULE = 'state';
12
12
  // Current state version
@@ -272,8 +272,7 @@ export class StateManager {
272
272
  return true;
273
273
  }
274
274
  catch (error) {
275
- const errorMessage = error instanceof Error ? error.message : String(error);
276
- warn(MODULE, `Failed to migrate state: ${errorMessage}`);
275
+ warn(MODULE, `Failed to migrate state: ${errorMessage(error)}`);
277
276
  // Clean up partial migration to avoid inconsistent state
278
277
  const newStatePath = getStatePath();
279
278
  if (fs.existsSync(newStatePath) && fs.existsSync(LEGACY_STATE_FILE)) {
@@ -471,12 +470,12 @@ export class StateManager {
471
470
  fs.unlinkSync(path.join(backupDir, file));
472
471
  }
473
472
  catch (error) {
474
- warn(MODULE, `Could not delete old backup ${file}:`, error instanceof Error ? error.message : error);
473
+ warn(MODULE, `Could not delete old backup ${file}:`, errorMessage(error));
475
474
  }
476
475
  }
477
476
  }
478
477
  catch (error) {
479
- warn(MODULE, 'Could not clean up backups:', error instanceof Error ? error.message : error);
478
+ warn(MODULE, 'Could not clean up backups:', errorMessage(error));
480
479
  }
481
480
  }
482
481
  /**
@@ -157,6 +157,17 @@ export declare function splitRepo(repoFullName: string): {
157
157
  owner: string;
158
158
  repo: string;
159
159
  };
160
+ /**
161
+ * Case-insensitive check whether a repo owner matches the given GitHub username.
162
+ * Used to skip a user's own repos (PRs to your own repos aren't OSS contributions).
163
+ */
164
+ export declare function isOwnRepo(owner: string, username: string): boolean;
165
+ /**
166
+ * Read the CLI package version from package.json relative to the running CLI bundle.
167
+ * Resolves `../package.json` from `process.argv[1]` (the bundle entry point).
168
+ * Falls back to '0.0.0' if the file is unreadable.
169
+ */
170
+ export declare function getCLIVersion(): string;
160
171
  /**
161
172
  * Formats a timestamp as a human-readable relative time string.
162
173
  *
@@ -228,6 +228,27 @@ export function splitRepo(repoFullName) {
228
228
  const [owner, repo] = repoFullName.split('/');
229
229
  return { owner, repo };
230
230
  }
231
+ /**
232
+ * Case-insensitive check whether a repo owner matches the given GitHub username.
233
+ * Used to skip a user's own repos (PRs to your own repos aren't OSS contributions).
234
+ */
235
+ export function isOwnRepo(owner, username) {
236
+ return owner.toLowerCase() === username.toLowerCase();
237
+ }
238
+ /**
239
+ * Read the CLI package version from package.json relative to the running CLI bundle.
240
+ * Resolves `../package.json` from `process.argv[1]` (the bundle entry point).
241
+ * Falls back to '0.0.0' if the file is unreadable.
242
+ */
243
+ export function getCLIVersion() {
244
+ try {
245
+ const pkgPath = path.join(path.dirname(process.argv[1]), '..', 'package.json');
246
+ return JSON.parse(fs.readFileSync(pkgPath, 'utf-8')).version;
247
+ }
248
+ catch {
249
+ return '0.0.0';
250
+ }
251
+ }
231
252
  /**
232
253
  * Formats a timestamp as a human-readable relative time string.
233
254
  *
@@ -238,6 +238,64 @@ export interface CheckIntegrationOutput {
238
238
  newFiles: NewFileInfo[];
239
239
  unreferencedCount: number;
240
240
  }
241
+ /** Output of the vet command */
242
+ export interface VetOutput {
243
+ issue: {
244
+ repo: string;
245
+ number: number;
246
+ title: string;
247
+ url: string;
248
+ labels: string[];
249
+ };
250
+ recommendation: 'approve' | 'skip' | 'needs_review';
251
+ reasonsToApprove: string[];
252
+ reasonsToSkip: string[];
253
+ projectHealth: unknown;
254
+ vettingResult: unknown;
255
+ }
256
+ /** Output of the comments command */
257
+ export interface CommentsOutput {
258
+ pr: {
259
+ title: string;
260
+ state: string;
261
+ mergeable: boolean | null;
262
+ head: string;
263
+ base: string;
264
+ url: string;
265
+ };
266
+ reviews: Array<{
267
+ user: string | undefined;
268
+ state: string;
269
+ body: string | null;
270
+ submittedAt: string | null;
271
+ }>;
272
+ reviewComments: Array<{
273
+ user: string | undefined;
274
+ body: string;
275
+ path: string;
276
+ createdAt: string;
277
+ }>;
278
+ issueComments: Array<{
279
+ user: string | undefined;
280
+ body: string | undefined;
281
+ createdAt: string;
282
+ }>;
283
+ summary: {
284
+ reviewCount: number;
285
+ inlineCommentCount: number;
286
+ discussionCommentCount: number;
287
+ };
288
+ }
289
+ /** Output of the post command */
290
+ export interface PostOutput {
291
+ commentUrl: string;
292
+ url: string;
293
+ }
294
+ /** Output of the claim command */
295
+ export interface ClaimOutput {
296
+ commentUrl: string;
297
+ issueUrl: string;
298
+ }
241
299
  /** Info about a local git clone (#84) */
242
300
  export interface LocalRepoInfo {
243
301
  path: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-autopilot/core",
3
- "version": "0.41.0",
3
+ "version": "0.42.1",
4
4
  "description": "CLI and core library for managing open source contributions",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,6 +14,10 @@
14
14
  "./types": {
15
15
  "import": "./dist/core/types.js",
16
16
  "types": "./dist/core/types.d.ts"
17
+ },
18
+ "./commands": {
19
+ "import": "./dist/commands/index.js",
20
+ "types": "./dist/commands/index.d.ts"
17
21
  }
18
22
  },
19
23
  "files": [