@oss-autopilot/core 0.41.0 → 0.42.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.
Files changed (46) hide show
  1. package/dist/cli.bundle.cjs +1300 -1020
  2. package/dist/cli.js +591 -55
  3. package/dist/commands/check-integration.d.ts +3 -3
  4. package/dist/commands/check-integration.js +5 -39
  5. package/dist/commands/comments.d.ts +6 -9
  6. package/dist/commands/comments.js +78 -228
  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 +19 -32
  11. package/dist/commands/dashboard-server.d.ts +14 -0
  12. package/dist/commands/dashboard-server.js +361 -0
  13. package/dist/commands/dashboard.d.ts +5 -0
  14. package/dist/commands/dashboard.js +49 -0
  15. package/dist/commands/dismiss.d.ts +13 -5
  16. package/dist/commands/dismiss.js +4 -24
  17. package/dist/commands/index.d.ts +33 -0
  18. package/dist/commands/index.js +22 -0
  19. package/dist/commands/init.d.ts +5 -4
  20. package/dist/commands/init.js +4 -14
  21. package/dist/commands/local-repos.d.ts +4 -5
  22. package/dist/commands/local-repos.js +4 -32
  23. package/dist/commands/parse-list.d.ts +3 -4
  24. package/dist/commands/parse-list.js +6 -38
  25. package/dist/commands/read.d.ts +11 -5
  26. package/dist/commands/read.js +4 -18
  27. package/dist/commands/search.d.ts +3 -3
  28. package/dist/commands/search.js +39 -65
  29. package/dist/commands/setup.d.ts +34 -5
  30. package/dist/commands/setup.js +75 -166
  31. package/dist/commands/shelve.d.ts +13 -5
  32. package/dist/commands/shelve.js +4 -24
  33. package/dist/commands/snooze.d.ts +15 -9
  34. package/dist/commands/snooze.js +16 -59
  35. package/dist/commands/startup.d.ts +11 -6
  36. package/dist/commands/startup.js +39 -67
  37. package/dist/commands/status.d.ts +3 -3
  38. package/dist/commands/status.js +10 -29
  39. package/dist/commands/track.d.ts +10 -9
  40. package/dist/commands/track.js +17 -39
  41. package/dist/commands/validation.d.ts +2 -2
  42. package/dist/commands/validation.js +3 -11
  43. package/dist/commands/vet.d.ts +3 -3
  44. package/dist/commands/vet.js +16 -26
  45. package/dist/formatters/json.d.ts +58 -0
  46. package/package.json +5 -1
@@ -3,7 +3,6 @@
3
3
  * Shows current status and stats
4
4
  */
5
5
  import { getStateManager } from '../core/index.js';
6
- import { outputJson } from '../formatters/json.js';
7
6
  export async function runStatus(options) {
8
7
  const stateManager = getStateManager();
9
8
  const stats = stateManager.getStats();
@@ -11,33 +10,15 @@ export async function runStatus(options) {
11
10
  // Status always reads from local state (no API calls), so offline mode
12
11
  // simply adds metadata about cache freshness.
13
12
  const lastUpdated = state.lastDigestAt || state.lastRunAt;
14
- if (options.json) {
15
- // Extract only the stats we want to output (exclude totalTracked)
16
- const { totalTracked: _totalTracked, ...outputStats } = stats;
17
- const output = {
18
- stats: outputStats,
19
- lastRunAt: state.lastRunAt,
20
- };
21
- if (options.offline) {
22
- output.offline = true;
23
- output.lastUpdated = lastUpdated;
24
- }
25
- outputJson(output);
26
- }
27
- else {
28
- // Simple console output
29
- console.log('\nšŸ“Š OSS Status\n');
30
- console.log(`Merged PRs: ${stats.mergedPRs}`);
31
- console.log(`Closed PRs: ${stats.closedPRs}`);
32
- console.log(`Merge Rate: ${stats.mergeRate}`);
33
- console.log(`Needs Response: ${stats.needsResponse}`);
34
- if (options.offline) {
35
- console.log(`\nLast Updated: ${lastUpdated || 'Never'}`);
36
- console.log('(Offline mode: showing cached data)');
37
- }
38
- else {
39
- console.log(`\nLast Run: ${state.lastRunAt || 'Never'}`);
40
- }
41
- console.log('\nRun with --json for structured output');
13
+ // Extract only the stats we want to output (exclude totalTracked)
14
+ const { totalTracked: _totalTracked, ...outputStats } = stats;
15
+ const output = {
16
+ stats: outputStats,
17
+ lastRunAt: state.lastRunAt,
18
+ };
19
+ if (options.offline) {
20
+ output.offline = true;
21
+ output.lastUpdated = lastUpdated;
42
22
  }
23
+ return output;
43
24
  }
@@ -3,14 +3,15 @@
3
3
  * In v2, PRs are fetched fresh from GitHub on each `daily` run.
4
4
  * These commands are preserved for backward compatibility.
5
5
  */
6
- interface TrackOptions {
7
- prUrl: string;
8
- json?: boolean;
6
+ import type { TrackOutput } from '../formatters/json.js';
7
+ export interface UntrackOutput {
8
+ removed: boolean;
9
+ url: string;
10
+ message: string;
9
11
  }
10
- interface UntrackOptions {
12
+ export declare function runTrack(options: {
11
13
  prUrl: string;
12
- json?: boolean;
13
- }
14
- export declare function runTrack(options: TrackOptions): Promise<void>;
15
- export declare function runUntrack(options: UntrackOptions): Promise<void>;
16
- export {};
14
+ }): Promise<TrackOutput>;
15
+ export declare function runUntrack(options: {
16
+ prUrl: string;
17
+ }): Promise<UntrackOutput>;
@@ -3,57 +3,35 @@
3
3
  * In v2, PRs are fetched fresh from GitHub on each `daily` run.
4
4
  * These commands are preserved for backward compatibility.
5
5
  */
6
- import { getOctokit, getGitHubToken } from '../core/index.js';
7
- import { outputJson, outputJsonError } from '../formatters/json.js';
6
+ import { getOctokit, requireGitHubToken } from '../core/index.js';
8
7
  import { validateUrl, PR_URL_PATTERN, validateGitHubUrl } from './validation.js';
9
8
  import { parseGitHubUrl } from '../core/utils.js';
10
9
  export async function runTrack(options) {
11
10
  validateUrl(options.prUrl);
12
- validateGitHubUrl(options.prUrl, PR_URL_PATTERN, 'PR', options.json);
13
- // Token is guaranteed by the preAction hook in cli.ts for non-LOCAL_ONLY_COMMANDS.
14
- const token = getGitHubToken();
11
+ validateGitHubUrl(options.prUrl, PR_URL_PATTERN, 'PR');
12
+ const token = requireGitHubToken();
15
13
  const octokit = getOctokit(token);
16
14
  const parsed = parseGitHubUrl(options.prUrl);
17
15
  if (!parsed || parsed.type !== 'pull') {
18
- if (options.json) {
19
- outputJsonError(`Invalid PR URL: ${options.prUrl}`);
20
- }
21
- else {
22
- console.error(`Error: Invalid PR URL: ${options.prUrl}`);
23
- }
24
- process.exit(1);
16
+ throw new Error(`Invalid PR URL: ${options.prUrl}`);
25
17
  }
26
18
  const { owner, repo, number } = parsed;
27
- if (!options.json) {
28
- console.log(`\nšŸ“Œ Fetching PR: ${options.prUrl}\n`);
29
- }
30
19
  const { data: ghPR } = await octokit.pulls.get({ owner, repo, pull_number: number });
31
- const pr = {
32
- repo: `${owner}/${repo}`,
33
- number,
34
- title: ghPR.title,
35
- url: options.prUrl,
20
+ return {
21
+ pr: {
22
+ repo: `${owner}/${repo}`,
23
+ number,
24
+ title: ghPR.title,
25
+ url: options.prUrl,
26
+ },
36
27
  };
37
- if (options.json) {
38
- outputJson({ pr });
39
- }
40
- else {
41
- console.log(`PR: ${pr.repo}#${pr.number} - ${pr.title}`);
42
- console.log('Note: In v2, PRs are tracked automatically via the daily run.');
43
- }
44
28
  }
45
29
  export async function runUntrack(options) {
46
30
  validateUrl(options.prUrl);
47
- validateGitHubUrl(options.prUrl, PR_URL_PATTERN, 'PR', options.json);
48
- if (options.json) {
49
- outputJson({
50
- removed: false,
51
- url: options.prUrl,
52
- message: 'In v2, PRs are fetched fresh on each daily run — there is no local tracking list to remove from.',
53
- });
54
- }
55
- else {
56
- console.log('Note: In v2, PRs are fetched fresh on each daily run — there is no local tracking list to remove from.');
57
- console.log('Use `shelve` to temporarily hide a PR from the daily summary.');
58
- }
31
+ validateGitHubUrl(options.prUrl, PR_URL_PATTERN, 'PR');
32
+ return {
33
+ removed: false,
34
+ url: options.prUrl,
35
+ message: 'In v2, PRs are fetched fresh on each daily run — there is no local tracking list to remove from.',
36
+ };
59
37
  }
@@ -6,9 +6,9 @@ export declare const PR_URL_PATTERN: RegExp;
6
6
  /** Matches GitHub issue URLs: https://github.com/owner/repo/issues/123 */
7
7
  export declare const ISSUE_URL_PATTERN: RegExp;
8
8
  /**
9
- * Validate a GitHub URL against a pattern. Exits with error if invalid.
9
+ * Validate a GitHub URL against a pattern. Throws if invalid.
10
10
  */
11
- export declare function validateGitHubUrl(url: string, pattern: RegExp, entityType: 'PR' | 'issue', json?: boolean): void;
11
+ export declare function validateGitHubUrl(url: string, pattern: RegExp, entityType: 'PR' | 'issue'): void;
12
12
  /**
13
13
  * Validate that a URL does not exceed the maximum allowed length.
14
14
  * Returns the URL if valid, throws if too long.
@@ -2,7 +2,6 @@
2
2
  * Shared validation patterns and helpers for CLI commands.
3
3
  */
4
4
  import { ValidationError } from '../core/errors.js';
5
- import { outputJsonError } from '../formatters/json.js';
6
5
  /** Matches GitHub PR URLs: https://github.com/owner/repo/pull/123 */
7
6
  export const PR_URL_PATTERN = /^https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/\d+$/;
8
7
  /** Matches GitHub issue URLs: https://github.com/owner/repo/issues/123 */
@@ -16,20 +15,13 @@ const MAX_MESSAGE_LENGTH = 1000;
16
15
  /** Pattern for valid GitHub repository identifiers */
17
16
  const REPO_PATTERN = /^[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+$/;
18
17
  /**
19
- * Validate a GitHub URL against a pattern. Exits with error if invalid.
18
+ * Validate a GitHub URL against a pattern. Throws if invalid.
20
19
  */
21
- export function validateGitHubUrl(url, pattern, entityType, json) {
20
+ export function validateGitHubUrl(url, pattern, entityType) {
22
21
  if (pattern.test(url))
23
22
  return;
24
23
  const example = entityType === 'PR' ? 'https://github.com/owner/repo/pull/123' : 'https://github.com/owner/repo/issues/123';
25
- const msg = `Invalid ${entityType} URL: ${url}. Expected format: ${example}`;
26
- if (json) {
27
- outputJsonError(msg);
28
- }
29
- else {
30
- console.error(`Error: ${msg}`);
31
- }
32
- process.exit(1);
24
+ throw new Error(`Invalid ${entityType} URL: ${url}. Expected format: ${example}`);
33
25
  }
34
26
  /**
35
27
  * Validate that a URL does not exceed the maximum allowed length.
@@ -2,9 +2,9 @@
2
2
  * Vet command
3
3
  * Vets a specific issue before working on it
4
4
  */
5
+ import { type VetOutput } from '../formatters/json.js';
6
+ export { type VetOutput } from '../formatters/json.js';
5
7
  interface VetOptions {
6
8
  issueUrl: string;
7
- json?: boolean;
8
9
  }
9
- export declare function runVet(options: VetOptions): Promise<void>;
10
- export {};
10
+ export declare function runVet(options: VetOptions): Promise<VetOutput>;
@@ -2,35 +2,25 @@
2
2
  * Vet command
3
3
  * Vets a specific issue before working on it
4
4
  */
5
- import { IssueDiscovery, getGitHubToken } from '../core/index.js';
6
- import { outputJson } from '../formatters/json.js';
5
+ import { IssueDiscovery, requireGitHubToken } from '../core/index.js';
7
6
  import { validateUrl } from './validation.js';
8
7
  export async function runVet(options) {
9
8
  validateUrl(options.issueUrl);
10
- // Token is guaranteed by the preAction hook in cli.ts for non-LOCAL_ONLY_COMMANDS.
11
- const token = getGitHubToken();
9
+ const token = requireGitHubToken();
12
10
  const discovery = new IssueDiscovery(token);
13
- if (!options.json) {
14
- console.log(`\nšŸ” Vetting issue: ${options.issueUrl}\n`);
15
- }
16
11
  const candidate = await discovery.vetIssue(options.issueUrl);
17
- if (options.json) {
18
- outputJson({
19
- issue: {
20
- repo: candidate.issue.repo,
21
- number: candidate.issue.number,
22
- title: candidate.issue.title,
23
- url: candidate.issue.url,
24
- labels: candidate.issue.labels,
25
- },
26
- recommendation: candidate.recommendation,
27
- reasonsToApprove: candidate.reasonsToApprove,
28
- reasonsToSkip: candidate.reasonsToSkip,
29
- projectHealth: candidate.projectHealth,
30
- vettingResult: candidate.vettingResult,
31
- });
32
- }
33
- else {
34
- console.log(discovery.formatCandidate(candidate));
35
- }
12
+ return {
13
+ issue: {
14
+ repo: candidate.issue.repo,
15
+ number: candidate.issue.number,
16
+ title: candidate.issue.title,
17
+ url: candidate.issue.url,
18
+ labels: candidate.issue.labels,
19
+ },
20
+ recommendation: candidate.recommendation,
21
+ reasonsToApprove: candidate.reasonsToApprove,
22
+ reasonsToSkip: candidate.reasonsToSkip,
23
+ projectHealth: candidate.projectHealth,
24
+ vettingResult: candidate.vettingResult,
25
+ };
36
26
  }
@@ -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.0",
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": [