@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
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
* v2: Fetches fresh data from GitHub if token available, otherwise uses cached lastDigest.
|
|
5
5
|
*/
|
|
6
6
|
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
7
8
|
import { execFile } from 'child_process';
|
|
8
9
|
import { getStateManager, getDashboardPath, getGitHubToken } from '../core/index.js';
|
|
10
|
+
import { errorMessage } from '../core/errors.js';
|
|
9
11
|
import { outputJson } from '../formatters/json.js';
|
|
10
12
|
import { fetchDashboardData, computePRsByRepo, computeTopRepos, getMonthlyData } from './dashboard-data.js';
|
|
11
13
|
import { buildDashboardStats, generateDashboardHtml } from './dashboard-templates.js';
|
|
@@ -38,7 +40,7 @@ export async function runDashboard(options) {
|
|
|
38
40
|
commentedIssues = result.commentedIssues;
|
|
39
41
|
}
|
|
40
42
|
catch (error) {
|
|
41
|
-
console.error('Failed to fetch fresh data:', error
|
|
43
|
+
console.error('Failed to fetch fresh data:', errorMessage(error));
|
|
42
44
|
console.error('Falling back to cached data (issue conversations unavailable)...');
|
|
43
45
|
digest = stateManager.getState().lastDigest;
|
|
44
46
|
}
|
|
@@ -132,3 +134,51 @@ export function writeDashboardFromState() {
|
|
|
132
134
|
fs.chmodSync(dashboardPath, 0o644);
|
|
133
135
|
return dashboardPath;
|
|
134
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Resolve the SPA assets directory from packages/dashboard/dist/.
|
|
139
|
+
* Tries multiple strategies to locate it across dev (tsx) and bundled (cjs) modes.
|
|
140
|
+
*/
|
|
141
|
+
function resolveAssetsDir() {
|
|
142
|
+
// Strategy 1: relative to this source file (works in dev with tsx)
|
|
143
|
+
const devPath = path.resolve(__dirname, '../../dashboard/dist');
|
|
144
|
+
if (fs.existsSync(path.join(devPath, 'index.html'))) {
|
|
145
|
+
return devPath;
|
|
146
|
+
}
|
|
147
|
+
// Strategy 2: relative to the CLI bundle location (packages/core/dist/cli.bundle.cjs)
|
|
148
|
+
const bundlePath = path.resolve(path.dirname(process.argv[1]), '../../dashboard/dist');
|
|
149
|
+
if (fs.existsSync(path.join(bundlePath, 'index.html'))) {
|
|
150
|
+
return bundlePath;
|
|
151
|
+
}
|
|
152
|
+
// Strategy 3: resolve the dashboard package via require.resolve
|
|
153
|
+
try {
|
|
154
|
+
const dashboardPkgPath = require.resolve('@oss-autopilot/dashboard/package.json');
|
|
155
|
+
const dashboardDist = path.join(path.dirname(dashboardPkgPath), 'dist');
|
|
156
|
+
if (fs.existsSync(path.join(dashboardDist, 'index.html'))) {
|
|
157
|
+
return dashboardDist;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
const code = error.code;
|
|
162
|
+
if (code !== 'MODULE_NOT_FOUND') {
|
|
163
|
+
console.error('Error resolving dashboard package:', error);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
export async function serveDashboard(options) {
|
|
169
|
+
const assetsDir = resolveAssetsDir();
|
|
170
|
+
if (!assetsDir) {
|
|
171
|
+
console.error('Could not find dashboard SPA assets.');
|
|
172
|
+
console.error('Make sure packages/dashboard has been built:');
|
|
173
|
+
console.error(' cd packages/dashboard && pnpm run build');
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
const token = getGitHubToken();
|
|
177
|
+
const { startDashboardServer } = await import('./dashboard-server.js');
|
|
178
|
+
await startDashboardServer({
|
|
179
|
+
port: options.port,
|
|
180
|
+
assetsDir,
|
|
181
|
+
token,
|
|
182
|
+
open: options.open,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
@@ -4,10 +4,18 @@
|
|
|
4
4
|
* Dismissed issues resurface automatically when new responses arrive after the dismiss timestamp.
|
|
5
5
|
*/
|
|
6
6
|
import { ISSUE_URL_PATTERN } from './validation.js';
|
|
7
|
-
interface
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
export interface DismissOutput {
|
|
8
|
+
dismissed: boolean;
|
|
9
|
+
url: string;
|
|
10
|
+
}
|
|
11
|
+
export interface UndismissOutput {
|
|
12
|
+
undismissed: boolean;
|
|
13
|
+
url: string;
|
|
10
14
|
}
|
|
11
15
|
export { ISSUE_URL_PATTERN };
|
|
12
|
-
export declare function runDismiss(options:
|
|
13
|
-
|
|
16
|
+
export declare function runDismiss(options: {
|
|
17
|
+
issueUrl: string;
|
|
18
|
+
}): Promise<DismissOutput>;
|
|
19
|
+
export declare function runUndismiss(options: {
|
|
20
|
+
issueUrl: string;
|
|
21
|
+
}): Promise<UndismissOutput>;
|
package/dist/commands/dismiss.js
CHANGED
|
@@ -4,46 +4,26 @@
|
|
|
4
4
|
* Dismissed issues resurface automatically when new responses arrive after the dismiss timestamp.
|
|
5
5
|
*/
|
|
6
6
|
import { getStateManager } from '../core/index.js';
|
|
7
|
-
import { outputJson } from '../formatters/json.js';
|
|
8
7
|
import { ISSUE_URL_PATTERN, validateGitHubUrl, validateUrl } from './validation.js';
|
|
9
8
|
// Re-export for backward compatibility with tests
|
|
10
9
|
export { ISSUE_URL_PATTERN };
|
|
11
10
|
export async function runDismiss(options) {
|
|
12
11
|
validateUrl(options.issueUrl);
|
|
13
|
-
validateGitHubUrl(options.issueUrl, ISSUE_URL_PATTERN, 'issue'
|
|
12
|
+
validateGitHubUrl(options.issueUrl, ISSUE_URL_PATTERN, 'issue');
|
|
14
13
|
const stateManager = getStateManager();
|
|
15
14
|
const added = stateManager.dismissIssue(options.issueUrl, new Date().toISOString());
|
|
16
15
|
if (added) {
|
|
17
16
|
stateManager.save();
|
|
18
17
|
}
|
|
19
|
-
|
|
20
|
-
outputJson({ dismissed: added, url: options.issueUrl });
|
|
21
|
-
}
|
|
22
|
-
else if (added) {
|
|
23
|
-
console.log(`Dismissed: ${options.issueUrl}`);
|
|
24
|
-
console.log('Issue reply notifications are now muted.');
|
|
25
|
-
console.log('New responses after this point will resurface automatically.');
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
console.log('Issue is already dismissed.');
|
|
29
|
-
}
|
|
18
|
+
return { dismissed: added, url: options.issueUrl };
|
|
30
19
|
}
|
|
31
20
|
export async function runUndismiss(options) {
|
|
32
21
|
validateUrl(options.issueUrl);
|
|
33
|
-
validateGitHubUrl(options.issueUrl, ISSUE_URL_PATTERN, 'issue'
|
|
22
|
+
validateGitHubUrl(options.issueUrl, ISSUE_URL_PATTERN, 'issue');
|
|
34
23
|
const stateManager = getStateManager();
|
|
35
24
|
const removed = stateManager.undismissIssue(options.issueUrl);
|
|
36
25
|
if (removed) {
|
|
37
26
|
stateManager.save();
|
|
38
27
|
}
|
|
39
|
-
|
|
40
|
-
outputJson({ undismissed: removed, url: options.issueUrl });
|
|
41
|
-
}
|
|
42
|
-
else if (removed) {
|
|
43
|
-
console.log(`Undismissed: ${options.issueUrl}`);
|
|
44
|
-
console.log('Issue reply notifications are active again.');
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
console.log('Issue was not dismissed.');
|
|
48
|
-
}
|
|
28
|
+
return { undismissed: removed, url: options.issueUrl };
|
|
49
29
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel export for all command functions and their output types.
|
|
3
|
+
* Used by @oss-autopilot/mcp to import command functions directly.
|
|
4
|
+
*/
|
|
5
|
+
export { runDaily, runDailyForDisplay, executeDailyCheck } from './daily.js';
|
|
6
|
+
export { runStatus } from './status.js';
|
|
7
|
+
export { runSearch } from './search.js';
|
|
8
|
+
export { runVet } from './vet.js';
|
|
9
|
+
export { runTrack, runUntrack } from './track.js';
|
|
10
|
+
export { runRead } from './read.js';
|
|
11
|
+
export { runComments, runPost, runClaim } from './comments.js';
|
|
12
|
+
export { runConfig } from './config.js';
|
|
13
|
+
export { runInit } from './init.js';
|
|
14
|
+
export { runSetup, runCheckSetup } from './setup.js';
|
|
15
|
+
export { runShelve, runUnshelve } from './shelve.js';
|
|
16
|
+
export { runDismiss, runUndismiss } from './dismiss.js';
|
|
17
|
+
export { runSnooze, runUnsnooze } from './snooze.js';
|
|
18
|
+
export { runStartup } from './startup.js';
|
|
19
|
+
export { runParseList } from './parse-list.js';
|
|
20
|
+
export { runCheckIntegration } from './check-integration.js';
|
|
21
|
+
export { runLocalRepos } from './local-repos.js';
|
|
22
|
+
export type { DailyOutput, SearchOutput, StartupOutput, StatusOutput, TrackOutput } from '../formatters/json.js';
|
|
23
|
+
export type { VetOutput, CommentsOutput, PostOutput, ClaimOutput } from '../formatters/json.js';
|
|
24
|
+
export type { ConfigOutput, ParseIssueListOutput, CheckIntegrationOutput, LocalReposOutput, } from '../formatters/json.js';
|
|
25
|
+
export type { ReadOutput } from './read.js';
|
|
26
|
+
export type { ShelveOutput, UnshelveOutput } from './shelve.js';
|
|
27
|
+
export type { DismissOutput, UndismissOutput } from './dismiss.js';
|
|
28
|
+
export type { SnoozeOutput, UnsnoozeOutput } from './snooze.js';
|
|
29
|
+
export type { UntrackOutput } from './track.js';
|
|
30
|
+
export type { InitOutput } from './init.js';
|
|
31
|
+
export type { ConfigSetOutput, ConfigCommandOutput } from './config.js';
|
|
32
|
+
export type { SetupSetOutput, SetupCompleteOutput, SetupRequiredOutput, SetupOutput, CheckSetupOutput, } from './setup.js';
|
|
33
|
+
export type { DailyCheckResult } from './daily.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel export for all command functions and their output types.
|
|
3
|
+
* Used by @oss-autopilot/mcp to import command functions directly.
|
|
4
|
+
*/
|
|
5
|
+
// Command functions
|
|
6
|
+
export { runDaily, runDailyForDisplay, executeDailyCheck } from './daily.js';
|
|
7
|
+
export { runStatus } from './status.js';
|
|
8
|
+
export { runSearch } from './search.js';
|
|
9
|
+
export { runVet } from './vet.js';
|
|
10
|
+
export { runTrack, runUntrack } from './track.js';
|
|
11
|
+
export { runRead } from './read.js';
|
|
12
|
+
export { runComments, runPost, runClaim } from './comments.js';
|
|
13
|
+
export { runConfig } from './config.js';
|
|
14
|
+
export { runInit } from './init.js';
|
|
15
|
+
export { runSetup, runCheckSetup } from './setup.js';
|
|
16
|
+
export { runShelve, runUnshelve } from './shelve.js';
|
|
17
|
+
export { runDismiss, runUndismiss } from './dismiss.js';
|
|
18
|
+
export { runSnooze, runUnsnooze } from './snooze.js';
|
|
19
|
+
export { runStartup } from './startup.js';
|
|
20
|
+
export { runParseList } from './parse-list.js';
|
|
21
|
+
export { runCheckIntegration } from './check-integration.js';
|
|
22
|
+
export { runLocalRepos } from './local-repos.js';
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Init command
|
|
3
3
|
* Initialize with GitHub username. In v2, PRs are fetched fresh on each daily run.
|
|
4
4
|
*/
|
|
5
|
-
interface
|
|
5
|
+
export interface InitOutput {
|
|
6
6
|
username: string;
|
|
7
|
-
|
|
7
|
+
message: string;
|
|
8
8
|
}
|
|
9
|
-
export declare function runInit(options:
|
|
10
|
-
|
|
9
|
+
export declare function runInit(options: {
|
|
10
|
+
username: string;
|
|
11
|
+
}): Promise<InitOutput>;
|
package/dist/commands/init.js
CHANGED
|
@@ -3,25 +3,15 @@
|
|
|
3
3
|
* Initialize with GitHub username. In v2, PRs are fetched fresh on each daily run.
|
|
4
4
|
*/
|
|
5
5
|
import { getStateManager } from '../core/index.js';
|
|
6
|
-
import { outputJson } from '../formatters/json.js';
|
|
7
6
|
import { validateGitHubUsername } from './validation.js';
|
|
8
7
|
export async function runInit(options) {
|
|
9
8
|
validateGitHubUsername(options.username);
|
|
10
9
|
const stateManager = getStateManager();
|
|
11
|
-
if (!options.json) {
|
|
12
|
-
console.log(`\nš Initializing for @${options.username}...\n`);
|
|
13
|
-
}
|
|
14
10
|
// Set username in config
|
|
15
11
|
stateManager.updateConfig({ githubUsername: options.username });
|
|
16
12
|
stateManager.save();
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
console.log(`Username set to @${options.username}.`);
|
|
25
|
-
console.log('Run `oss-autopilot daily` to fetch your open PRs from GitHub.');
|
|
26
|
-
}
|
|
13
|
+
return {
|
|
14
|
+
username: options.username,
|
|
15
|
+
message: 'Username saved. Run `daily` to fetch your open PRs from GitHub.',
|
|
16
|
+
};
|
|
27
17
|
}
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
* Local repos command (#84)
|
|
3
3
|
* Scans configurable directories for local git clones and caches results
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import type { LocalReposOutput, LocalRepoInfo } from '../formatters/json.js';
|
|
6
6
|
interface LocalReposOptions {
|
|
7
7
|
scan?: boolean;
|
|
8
8
|
paths?: string[];
|
|
9
|
-
json?: boolean;
|
|
10
9
|
}
|
|
11
|
-
|
|
10
|
+
export type { LocalReposOutput, LocalRepoInfo };
|
|
11
|
+
/** Scan directories for git repos, returning a map of owner/repo -> local path */
|
|
12
12
|
export declare function scanForRepos(scanPaths: string[]): Record<string, LocalRepoInfo>;
|
|
13
|
-
export declare function runLocalRepos(options: LocalReposOptions): Promise<
|
|
14
|
-
export {};
|
|
13
|
+
export declare function runLocalRepos(options: LocalReposOptions): Promise<LocalReposOutput>;
|
|
@@ -7,7 +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 {
|
|
10
|
+
import { errorMessage } from '../core/errors.js';
|
|
11
11
|
/** Default directories to scan for local clones */
|
|
12
12
|
const DEFAULT_SCAN_PATHS = [
|
|
13
13
|
path.join(os.homedir(), 'Documents', 'oss'),
|
|
@@ -56,7 +56,7 @@ function getCurrentBranch(repoPath) {
|
|
|
56
56
|
return null;
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
/** Scan directories for git repos, returning a map of owner/repo
|
|
59
|
+
/** Scan directories for git repos, returning a map of owner/repo -> local path */
|
|
60
60
|
export function scanForRepos(scanPaths) {
|
|
61
61
|
const repos = {};
|
|
62
62
|
for (const scanPath of scanPaths) {
|
|
@@ -101,26 +101,14 @@ export async function runLocalRepos(options) {
|
|
|
101
101
|
// Use cached data unless --scan is specified
|
|
102
102
|
if (!options.scan && state.localRepoCache) {
|
|
103
103
|
const cache = state.localRepoCache;
|
|
104
|
-
|
|
104
|
+
return {
|
|
105
105
|
repos: cache.repos,
|
|
106
106
|
scanPaths: cache.scanPaths,
|
|
107
107
|
cachedAt: cache.cachedAt,
|
|
108
108
|
fromCache: true,
|
|
109
109
|
};
|
|
110
|
-
if (options.json) {
|
|
111
|
-
outputJson(result);
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
console.log(`\nš Local Repos (cached ${cache.cachedAt})\n`);
|
|
115
|
-
printRepos(cache.repos);
|
|
116
|
-
}
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
if (!options.json) {
|
|
120
|
-
console.log(`\nš Scanning for local repos in ${scanPaths.length} directories...\n`);
|
|
121
110
|
}
|
|
122
111
|
const repos = scanForRepos(scanPaths);
|
|
123
|
-
const repoCount = Object.keys(repos).length;
|
|
124
112
|
// Cache the results in state
|
|
125
113
|
const cachedAt = new Date().toISOString();
|
|
126
114
|
try {
|
|
@@ -128,28 +116,13 @@ export async function runLocalRepos(options) {
|
|
|
128
116
|
stateManager.save();
|
|
129
117
|
}
|
|
130
118
|
catch (error) {
|
|
131
|
-
const msg =
|
|
132
|
-
|
|
119
|
+
const msg = errorMessage(error);
|
|
120
|
+
debug('local-repos', `Failed to cache scan results: ${msg}`);
|
|
133
121
|
}
|
|
134
|
-
|
|
122
|
+
return {
|
|
135
123
|
repos,
|
|
136
124
|
scanPaths,
|
|
137
125
|
cachedAt,
|
|
138
126
|
fromCache: false,
|
|
139
127
|
};
|
|
140
|
-
if (options.json) {
|
|
141
|
-
outputJson(result);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
console.log(`Found ${repoCount} repos:\n`);
|
|
145
|
-
printRepos(repos);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
function printRepos(repos) {
|
|
149
|
-
const entries = Object.entries(repos).sort(([a], [b]) => a.localeCompare(b));
|
|
150
|
-
for (const [remote, info] of entries) {
|
|
151
|
-
const branch = info.currentBranch ? ` (${info.currentBranch})` : '';
|
|
152
|
-
console.log(` ${remote}${branch}`);
|
|
153
|
-
console.log(` ${info.path}`);
|
|
154
|
-
}
|
|
155
128
|
}
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
* Parse issue list command (#82)
|
|
3
3
|
* Parses markdown issue lists into structured JSON with tier classification
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import type { ParseIssueListOutput, ParsedIssueItem } from '../formatters/json.js';
|
|
6
6
|
interface ParseListOptions {
|
|
7
7
|
filePath: string;
|
|
8
|
-
json?: boolean;
|
|
9
8
|
}
|
|
9
|
+
export type { ParseIssueListOutput, ParsedIssueItem };
|
|
10
10
|
/** Parse a markdown string into structured issue items */
|
|
11
11
|
export declare function parseIssueList(content: string): ParseIssueListOutput;
|
|
12
|
-
export declare function runParseList(options: ParseListOptions): Promise<
|
|
13
|
-
export {};
|
|
12
|
+
export declare function runParseList(options: ParseListOptions): Promise<ParseIssueListOutput>;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import * as path from 'path';
|
|
7
|
-
import {
|
|
7
|
+
import { errorMessage } from '../core/errors.js';
|
|
8
8
|
/** Extract GitHub issue/PR URLs from a markdown line */
|
|
9
9
|
function extractGitHubUrl(line) {
|
|
10
10
|
const match = line.match(/https:\/\/github\.com\/([^/]+\/[^/]+)\/issues\/(\d+)/);
|
|
@@ -19,7 +19,7 @@ function extractGitHubUrl(line) {
|
|
|
19
19
|
}
|
|
20
20
|
/** Extract issue title from a markdown line (text after URL or checkbox) */
|
|
21
21
|
function extractTitle(line) {
|
|
22
|
-
// Remove markdown link syntax: [title](url)
|
|
22
|
+
// Remove markdown link syntax: [title](url) -> title
|
|
23
23
|
let cleaned = line.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1');
|
|
24
24
|
// Remove bare URLs
|
|
25
25
|
cleaned = cleaned.replace(/https?:\/\/\S+/g, '');
|
|
@@ -32,7 +32,7 @@ function extractTitle(line) {
|
|
|
32
32
|
// Remove "Done" markers
|
|
33
33
|
cleaned = cleaned.replace(/\b(Done|DONE|done)\b/g, '');
|
|
34
34
|
// Remove leading/trailing punctuation and whitespace
|
|
35
|
-
cleaned = cleaned.replace(/^[\s
|
|
35
|
+
cleaned = cleaned.replace(/^[\s\-\u2013\u2014:]+/, '').replace(/[\s\-\u2013\u2014:]+$/, '');
|
|
36
36
|
return cleaned.trim();
|
|
37
37
|
}
|
|
38
38
|
/** Determine if a line represents a completed item */
|
|
@@ -65,7 +65,7 @@ export function parseIssueList(content) {
|
|
|
65
65
|
if (!line.trim() || !/^\s*[-*+]|\s*\d+\.|\s*\[[ xX]\]/.test(line)) {
|
|
66
66
|
continue;
|
|
67
67
|
}
|
|
68
|
-
// Extract GitHub URL
|
|
68
|
+
// Extract GitHub URL -- skip lines without one
|
|
69
69
|
const ghUrl = extractGitHubUrl(line);
|
|
70
70
|
if (!ghUrl)
|
|
71
71
|
continue;
|
|
@@ -94,46 +94,15 @@ export function parseIssueList(content) {
|
|
|
94
94
|
export async function runParseList(options) {
|
|
95
95
|
const filePath = path.resolve(options.filePath);
|
|
96
96
|
if (!fs.existsSync(filePath)) {
|
|
97
|
-
|
|
98
|
-
outputJsonError(`File not found: ${filePath}`);
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
console.error(`Error: File not found: ${filePath}`);
|
|
102
|
-
}
|
|
103
|
-
process.exit(1);
|
|
97
|
+
throw new Error(`File not found: ${filePath}`);
|
|
104
98
|
}
|
|
105
99
|
let content;
|
|
106
100
|
try {
|
|
107
101
|
content = fs.readFileSync(filePath, 'utf-8');
|
|
108
102
|
}
|
|
109
103
|
catch (error) {
|
|
110
|
-
const msg =
|
|
111
|
-
|
|
112
|
-
outputJsonError(`Failed to read file: ${msg}`);
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
console.error(`Error: Failed to read file: ${msg}`);
|
|
116
|
-
}
|
|
117
|
-
process.exit(1);
|
|
118
|
-
}
|
|
119
|
-
const result = parseIssueList(content);
|
|
120
|
-
if (options.json) {
|
|
121
|
-
outputJson(result);
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
console.log(`\nš Issue List: ${filePath}\n`);
|
|
125
|
-
console.log(`Available: ${result.availableCount} | Completed: ${result.completedCount}\n`);
|
|
126
|
-
if (result.available.length > 0) {
|
|
127
|
-
console.log('--- Available ---');
|
|
128
|
-
for (const item of result.available) {
|
|
129
|
-
console.log(` [${item.tier}] ${item.repo}#${item.number}: ${item.title}`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
if (result.completed.length > 0) {
|
|
133
|
-
console.log('\n--- Completed ---');
|
|
134
|
-
for (const item of result.completed) {
|
|
135
|
-
console.log(` [${item.tier}] ${item.repo}#${item.number}: ${item.title}`);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
104
|
+
const msg = errorMessage(error);
|
|
105
|
+
throw new Error(`Failed to read file: ${msg}`, { cause: error });
|
|
138
106
|
}
|
|
107
|
+
return parseIssueList(content);
|
|
139
108
|
}
|
package/dist/commands/read.d.ts
CHANGED
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
* In v2, PR read/unread state is not tracked locally.
|
|
4
4
|
* This command is a no-op preserved for backward compatibility.
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
export type ReadOutput = {
|
|
7
|
+
markedAsRead: number;
|
|
8
|
+
all: true;
|
|
9
|
+
message: string;
|
|
10
|
+
} | {
|
|
11
|
+
marked: boolean;
|
|
12
|
+
url: string | undefined;
|
|
13
|
+
message: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function runRead(options: {
|
|
7
16
|
prUrl?: string;
|
|
8
17
|
all?: boolean;
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
export declare function runRead(options: ReadOptions): Promise<void>;
|
|
12
|
-
export {};
|
|
18
|
+
}): Promise<ReadOutput>;
|
package/dist/commands/read.js
CHANGED
|
@@ -3,31 +3,17 @@
|
|
|
3
3
|
* In v2, PR read/unread state is not tracked locally.
|
|
4
4
|
* This command is a no-op preserved for backward compatibility.
|
|
5
5
|
*/
|
|
6
|
-
import { outputJson, outputJsonError } from '../formatters/json.js';
|
|
7
6
|
import { validateUrl } from './validation.js';
|
|
8
7
|
export async function runRead(options) {
|
|
9
8
|
if (!options.all && !options.prUrl) {
|
|
10
|
-
|
|
11
|
-
outputJsonError('PR URL or --all flag required');
|
|
12
|
-
}
|
|
13
|
-
else {
|
|
14
|
-
console.error('Usage: oss-autopilot read <pr-url> or oss-autopilot read --all');
|
|
15
|
-
}
|
|
16
|
-
process.exit(1);
|
|
9
|
+
throw new Error('PR URL or --all flag required');
|
|
17
10
|
}
|
|
18
11
|
if (options.prUrl) {
|
|
19
12
|
validateUrl(options.prUrl);
|
|
20
13
|
}
|
|
21
14
|
// In v2, unread state is not tracked locally ā PRs are fetched fresh each run.
|
|
22
|
-
if (options.
|
|
23
|
-
|
|
24
|
-
outputJson({ markedAsRead: 0, all: true, message: 'In v2, PR read state is not tracked locally.' });
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
outputJson({ marked: false, url: options.prUrl, message: 'In v2, PR read state is not tracked locally.' });
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
console.log('Note: In v2, PR read state is not tracked locally. PRs are fetched fresh on each daily run.');
|
|
15
|
+
if (options.all) {
|
|
16
|
+
return { markedAsRead: 0, all: true, message: 'In v2, PR read state is not tracked locally.' };
|
|
32
17
|
}
|
|
18
|
+
return { marked: false, url: options.prUrl, message: 'In v2, PR read state is not tracked locally.' };
|
|
33
19
|
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Search command
|
|
3
3
|
* Searches for new issues to work on
|
|
4
4
|
*/
|
|
5
|
+
import { type SearchOutput } from '../formatters/json.js';
|
|
6
|
+
export { type SearchOutput } from '../formatters/json.js';
|
|
5
7
|
interface SearchOptions {
|
|
6
8
|
maxResults: number;
|
|
7
|
-
json?: boolean;
|
|
8
9
|
}
|
|
9
|
-
export declare function runSearch(options: SearchOptions): Promise<
|
|
10
|
-
export {};
|
|
10
|
+
export declare function runSearch(options: SearchOptions): Promise<SearchOutput>;
|
package/dist/commands/search.js
CHANGED
|
@@ -2,73 +2,47 @@
|
|
|
2
2
|
* Search command
|
|
3
3
|
* Searches for new issues to work on
|
|
4
4
|
*/
|
|
5
|
-
import { IssueDiscovery,
|
|
6
|
-
import { outputJson } from '../formatters/json.js';
|
|
5
|
+
import { IssueDiscovery, requireGitHubToken, getStateManager, DEFAULT_CONFIG } from '../core/index.js';
|
|
7
6
|
export async function runSearch(options) {
|
|
8
|
-
|
|
9
|
-
const token = getGitHubToken();
|
|
7
|
+
const token = requireGitHubToken();
|
|
10
8
|
const discovery = new IssueDiscovery(token);
|
|
11
|
-
if (!options.json) {
|
|
12
|
-
console.log(`\nš Searching for issues (max ${options.maxResults})...\n`);
|
|
13
|
-
}
|
|
14
9
|
const candidates = await discovery.searchIssues({ maxResults: options.maxResults });
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
searchOutput.rateLimitWarning = discovery.rateLimitWarning;
|
|
52
|
-
}
|
|
53
|
-
outputJson(searchOutput);
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
if (candidates.length === 0) {
|
|
57
|
-
if (discovery.rateLimitWarning) {
|
|
58
|
-
console.warn(`\nā ${discovery.rateLimitWarning}\n`);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
console.log('No matching issues found.');
|
|
62
|
-
}
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
if (discovery.rateLimitWarning) {
|
|
66
|
-
console.warn(`\nā ${discovery.rateLimitWarning}\n`);
|
|
67
|
-
}
|
|
68
|
-
console.log(`Found ${candidates.length} candidates:\n`);
|
|
69
|
-
for (const candidate of candidates) {
|
|
70
|
-
console.log(discovery.formatCandidate(candidate));
|
|
71
|
-
console.log('---');
|
|
72
|
-
}
|
|
10
|
+
const stateManager = getStateManager();
|
|
11
|
+
const { config } = stateManager.getState();
|
|
12
|
+
const excludedRepos = config.excludeRepos || [];
|
|
13
|
+
const aiPolicyBlocklist = config.aiPolicyBlocklist ?? DEFAULT_CONFIG.aiPolicyBlocklist ?? [];
|
|
14
|
+
const searchOutput = {
|
|
15
|
+
candidates: candidates.map((c) => {
|
|
16
|
+
const repoScoreRecord = stateManager.getRepoScore(c.issue.repo);
|
|
17
|
+
return {
|
|
18
|
+
issue: {
|
|
19
|
+
repo: c.issue.repo,
|
|
20
|
+
number: c.issue.number,
|
|
21
|
+
title: c.issue.title,
|
|
22
|
+
url: c.issue.url,
|
|
23
|
+
labels: c.issue.labels,
|
|
24
|
+
},
|
|
25
|
+
recommendation: c.recommendation,
|
|
26
|
+
reasonsToApprove: c.reasonsToApprove,
|
|
27
|
+
reasonsToSkip: c.reasonsToSkip,
|
|
28
|
+
searchPriority: c.searchPriority,
|
|
29
|
+
viabilityScore: c.viabilityScore,
|
|
30
|
+
repoScore: repoScoreRecord
|
|
31
|
+
? {
|
|
32
|
+
score: repoScoreRecord.score,
|
|
33
|
+
mergedPRCount: repoScoreRecord.mergedPRCount,
|
|
34
|
+
closedWithoutMergeCount: repoScoreRecord.closedWithoutMergeCount,
|
|
35
|
+
isResponsive: repoScoreRecord.signals?.isResponsive ?? false,
|
|
36
|
+
lastMergedAt: repoScoreRecord.lastMergedAt,
|
|
37
|
+
}
|
|
38
|
+
: undefined,
|
|
39
|
+
};
|
|
40
|
+
}),
|
|
41
|
+
excludedRepos,
|
|
42
|
+
aiPolicyBlocklist,
|
|
43
|
+
};
|
|
44
|
+
if (discovery.rateLimitWarning) {
|
|
45
|
+
searchOutput.rateLimitWarning = discovery.rateLimitWarning;
|
|
73
46
|
}
|
|
47
|
+
return searchOutput;
|
|
74
48
|
}
|