@oss-scout/core 0.1.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 (66) hide show
  1. package/dist/cli.bundle.cjs +114 -0
  2. package/dist/cli.d.ts +5 -0
  3. package/dist/cli.js +341 -0
  4. package/dist/commands/config.d.ts +22 -0
  5. package/dist/commands/config.js +169 -0
  6. package/dist/commands/results.d.ts +8 -0
  7. package/dist/commands/results.js +13 -0
  8. package/dist/commands/search.d.ts +39 -0
  9. package/dist/commands/search.js +50 -0
  10. package/dist/commands/setup.d.ts +17 -0
  11. package/dist/commands/setup.js +104 -0
  12. package/dist/commands/validation.d.ts +6 -0
  13. package/dist/commands/validation.js +17 -0
  14. package/dist/commands/vet-list.d.ts +9 -0
  15. package/dist/commands/vet-list.js +16 -0
  16. package/dist/commands/vet.d.ts +25 -0
  17. package/dist/commands/vet.js +29 -0
  18. package/dist/core/bootstrap.d.ts +14 -0
  19. package/dist/core/bootstrap.js +122 -0
  20. package/dist/core/category-mapping.d.ts +19 -0
  21. package/dist/core/category-mapping.js +58 -0
  22. package/dist/core/concurrency.d.ts +6 -0
  23. package/dist/core/concurrency.js +25 -0
  24. package/dist/core/errors.d.ts +22 -0
  25. package/dist/core/errors.js +69 -0
  26. package/dist/core/gist-state-store.d.ts +96 -0
  27. package/dist/core/gist-state-store.js +302 -0
  28. package/dist/core/github.d.ts +16 -0
  29. package/dist/core/github.js +58 -0
  30. package/dist/core/http-cache.d.ts +108 -0
  31. package/dist/core/http-cache.js +314 -0
  32. package/dist/core/issue-discovery.d.ts +93 -0
  33. package/dist/core/issue-discovery.js +475 -0
  34. package/dist/core/issue-eligibility.d.ts +33 -0
  35. package/dist/core/issue-eligibility.js +151 -0
  36. package/dist/core/issue-filtering.d.ts +51 -0
  37. package/dist/core/issue-filtering.js +103 -0
  38. package/dist/core/issue-scoring.d.ts +43 -0
  39. package/dist/core/issue-scoring.js +97 -0
  40. package/dist/core/issue-vetting.d.ts +44 -0
  41. package/dist/core/issue-vetting.js +270 -0
  42. package/dist/core/local-state.d.ts +16 -0
  43. package/dist/core/local-state.js +56 -0
  44. package/dist/core/logger.d.ts +11 -0
  45. package/dist/core/logger.js +25 -0
  46. package/dist/core/pagination.d.ts +7 -0
  47. package/dist/core/pagination.js +16 -0
  48. package/dist/core/repo-health.d.ts +19 -0
  49. package/dist/core/repo-health.js +179 -0
  50. package/dist/core/schemas.d.ts +315 -0
  51. package/dist/core/schemas.js +137 -0
  52. package/dist/core/search-budget.d.ts +62 -0
  53. package/dist/core/search-budget.js +129 -0
  54. package/dist/core/search-phases.d.ts +69 -0
  55. package/dist/core/search-phases.js +238 -0
  56. package/dist/core/types.d.ts +124 -0
  57. package/dist/core/types.js +9 -0
  58. package/dist/core/utils.d.ts +18 -0
  59. package/dist/core/utils.js +106 -0
  60. package/dist/formatters/json.d.ts +6 -0
  61. package/dist/formatters/json.js +20 -0
  62. package/dist/index.d.ts +23 -0
  63. package/dist/index.js +25 -0
  64. package/dist/scout.d.ts +125 -0
  65. package/dist/scout.js +391 -0
  66. package/package.json +70 -0
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Lightweight debug logger for oss-scout.
3
+ * Activated by the global --debug CLI flag.
4
+ *
5
+ * All debug/warn output goes to stderr so it never contaminates
6
+ * the --json stdout contract.
7
+ */
8
+ export declare function enableDebug(): void;
9
+ export declare function debug(module: string, message: string, ...args: unknown[]): void;
10
+ export declare function info(module: string, message: string, ...args: unknown[]): void;
11
+ export declare function warn(module: string, message: string, ...args: unknown[]): void;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Lightweight debug logger for oss-scout.
3
+ * Activated by the global --debug CLI flag.
4
+ *
5
+ * All debug/warn output goes to stderr so it never contaminates
6
+ * the --json stdout contract.
7
+ */
8
+ let debugEnabled = false;
9
+ export function enableDebug() {
10
+ debugEnabled = true;
11
+ }
12
+ export function debug(module, message, ...args) {
13
+ if (!debugEnabled)
14
+ return;
15
+ const timestamp = new Date().toISOString();
16
+ console.error(`[${timestamp}] [DEBUG] [${module}] ${message}`, ...args);
17
+ }
18
+ export function info(module, message, ...args) {
19
+ const timestamp = new Date().toISOString();
20
+ console.error(`[${timestamp}] [INFO] [${module}] ${message}`, ...args);
21
+ }
22
+ export function warn(module, message, ...args) {
23
+ const timestamp = new Date().toISOString();
24
+ console.error(`[${timestamp}] [WARN] [${module}] ${message}`, ...args);
25
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Auto-paginate an Octokit list endpoint. Fetches additional pages when
3
+ * the result count equals per_page (indicating more data may exist).
4
+ */
5
+ export declare function paginateAll<T>(fetchPage: (page: number) => Promise<{
6
+ data: T[];
7
+ }>, perPage?: number, maxPages?: number): Promise<T[]>;
@@ -0,0 +1,16 @@
1
+ /** Maximum pages to fetch to prevent runaway pagination */
2
+ const MAX_PAGES = 10;
3
+ /**
4
+ * Auto-paginate an Octokit list endpoint. Fetches additional pages when
5
+ * the result count equals per_page (indicating more data may exist).
6
+ */
7
+ export async function paginateAll(fetchPage, perPage = 100, maxPages = MAX_PAGES) {
8
+ const allItems = [];
9
+ for (let page = 1; page <= maxPages; page++) {
10
+ const { data } = await fetchPage(page);
11
+ allItems.push(...data);
12
+ if (data.length < perPage)
13
+ break;
14
+ }
15
+ return allItems;
16
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Repo Health — project health checks and contribution guidelines fetching.
3
+ *
4
+ * Extracted from issue-vetting.ts to isolate repo-level checks
5
+ * from issue-level eligibility logic.
6
+ */
7
+ import { Octokit } from '@octokit/rest';
8
+ import { type ContributionGuidelines, type ProjectHealth } from './types.js';
9
+ /**
10
+ * Check the health of a GitHub project: recent commits, CI status, star/fork counts.
11
+ * Results are cached for HEALTH_CACHE_TTL_MS (4 hours).
12
+ */
13
+ export declare function checkProjectHealth(octokit: Octokit, owner: string, repo: string): Promise<ProjectHealth>;
14
+ /**
15
+ * Fetch and parse CONTRIBUTING.md (or variants) from a GitHub repo.
16
+ * Probes multiple paths in parallel: CONTRIBUTING.md, .github/CONTRIBUTING.md,
17
+ * docs/CONTRIBUTING.md, contributing.md. Results are cached for CACHE_TTL_MS.
18
+ */
19
+ export declare function fetchContributionGuidelines(octokit: Octokit, owner: string, repo: string): Promise<ContributionGuidelines | undefined>;
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Repo Health — project health checks and contribution guidelines fetching.
3
+ *
4
+ * Extracted from issue-vetting.ts to isolate repo-level checks
5
+ * from issue-level eligibility logic.
6
+ */
7
+ import { daysBetween } from './utils.js';
8
+ import { errorMessage } from './errors.js';
9
+ import { warn } from './logger.js';
10
+ import { getHttpCache, cachedRequest, cachedTimeBased } from './http-cache.js';
11
+ const MODULE = 'repo-health';
12
+ // ── Cache for contribution guidelines ──
13
+ const guidelinesCache = new Map();
14
+ /** TTL for cached contribution guidelines (1 hour). */
15
+ const CACHE_TTL_MS = 60 * 60 * 1000;
16
+ /** TTL for cached project health results (4 hours). Health data (stars, commits, CI) changes slowly. */
17
+ const HEALTH_CACHE_TTL_MS = 4 * 60 * 60 * 1000;
18
+ /** Max entries in the guidelines cache before pruning. */
19
+ const CACHE_MAX_SIZE = 100;
20
+ /** Remove expired and excess entries from the guidelines cache. */
21
+ function pruneCache() {
22
+ const now = Date.now();
23
+ // First, remove expired entries (older than CACHE_TTL_MS)
24
+ for (const [key, value] of guidelinesCache.entries()) {
25
+ if (now - value.fetchedAt > CACHE_TTL_MS) {
26
+ guidelinesCache.delete(key);
27
+ }
28
+ }
29
+ // Then, if still over size limit, remove oldest entries
30
+ if (guidelinesCache.size > CACHE_MAX_SIZE) {
31
+ const entries = Array.from(guidelinesCache.entries()).sort((a, b) => a[1].fetchedAt - b[1].fetchedAt);
32
+ const toRemove = entries.slice(0, guidelinesCache.size - CACHE_MAX_SIZE);
33
+ for (const [key] of toRemove) {
34
+ guidelinesCache.delete(key);
35
+ }
36
+ }
37
+ }
38
+ // ── Project health ──
39
+ /**
40
+ * Check the health of a GitHub project: recent commits, CI status, star/fork counts.
41
+ * Results are cached for HEALTH_CACHE_TTL_MS (4 hours).
42
+ */
43
+ export async function checkProjectHealth(octokit, owner, repo) {
44
+ const cache = getHttpCache();
45
+ const healthCacheKey = `health:${owner}/${repo}`;
46
+ try {
47
+ return await cachedTimeBased(cache, healthCacheKey, HEALTH_CACHE_TTL_MS, async () => {
48
+ // Get repo info (with ETag caching — repo metadata changes infrequently)
49
+ const url = `/repos/${owner}/${repo}`;
50
+ const repoData = await cachedRequest(cache, url, (headers) => octokit.repos.get({ owner, repo, headers }));
51
+ // Get recent commits
52
+ const { data: commits } = await octokit.repos.listCommits({
53
+ owner,
54
+ repo,
55
+ per_page: 1,
56
+ });
57
+ const lastCommit = commits[0];
58
+ const lastCommitAt = lastCommit?.commit?.author?.date || repoData.pushed_at;
59
+ const daysSinceLastCommit = daysBetween(new Date(lastCommitAt));
60
+ const ciStatus = 'unknown';
61
+ return {
62
+ repo: `${owner}/${repo}`,
63
+ lastCommitAt,
64
+ daysSinceLastCommit,
65
+ openIssuesCount: repoData.open_issues_count,
66
+ avgIssueResponseDays: 0, // Would need more API calls to calculate
67
+ ciStatus,
68
+ isActive: daysSinceLastCommit < 30,
69
+ stargazersCount: repoData.stargazers_count,
70
+ forksCount: repoData.forks_count,
71
+ language: repoData.language,
72
+ };
73
+ });
74
+ }
75
+ catch (error) {
76
+ const errMsg = errorMessage(error);
77
+ warn(MODULE, `Error checking project health for ${owner}/${repo}: ${errMsg}`);
78
+ return {
79
+ repo: `${owner}/${repo}`,
80
+ lastCommitAt: '',
81
+ daysSinceLastCommit: 999,
82
+ openIssuesCount: 0,
83
+ avgIssueResponseDays: 0,
84
+ ciStatus: 'unknown',
85
+ isActive: false,
86
+ checkFailed: true,
87
+ failureReason: errMsg,
88
+ };
89
+ }
90
+ }
91
+ // ── Contribution guidelines ──
92
+ /**
93
+ * Fetch and parse CONTRIBUTING.md (or variants) from a GitHub repo.
94
+ * Probes multiple paths in parallel: CONTRIBUTING.md, .github/CONTRIBUTING.md,
95
+ * docs/CONTRIBUTING.md, contributing.md. Results are cached for CACHE_TTL_MS.
96
+ */
97
+ export async function fetchContributionGuidelines(octokit, owner, repo) {
98
+ const cacheKey = `${owner}/${repo}`;
99
+ // Check cache first
100
+ const cached = guidelinesCache.get(cacheKey);
101
+ if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
102
+ return cached.guidelines;
103
+ }
104
+ const filesToCheck = ['CONTRIBUTING.md', '.github/CONTRIBUTING.md', 'docs/CONTRIBUTING.md', 'contributing.md'];
105
+ // Probe all paths in parallel — take the first success in priority order
106
+ const results = await Promise.allSettled(filesToCheck.map((file) => octokit.repos.getContent({ owner, repo, path: file }).then(({ data }) => {
107
+ if ('content' in data) {
108
+ return Buffer.from(data.content, 'base64').toString('utf-8');
109
+ }
110
+ return null;
111
+ })));
112
+ for (let i = 0; i < results.length; i++) {
113
+ const result = results[i];
114
+ if (result.status === 'fulfilled' && result.value) {
115
+ const guidelines = parseContributionGuidelines(result.value);
116
+ guidelinesCache.set(cacheKey, { guidelines, fetchedAt: Date.now() });
117
+ pruneCache();
118
+ return guidelines;
119
+ }
120
+ if (result.status === 'rejected') {
121
+ const msg = result.reason instanceof Error ? result.reason.message : String(result.reason);
122
+ if (!msg.includes('404') && !msg.includes('Not Found')) {
123
+ warn(MODULE, `Unexpected error fetching ${filesToCheck[i]} from ${owner}/${repo}: ${msg}`);
124
+ }
125
+ }
126
+ }
127
+ // Cache the negative result too and prune if needed
128
+ guidelinesCache.set(cacheKey, { guidelines: undefined, fetchedAt: Date.now() });
129
+ pruneCache();
130
+ return undefined;
131
+ }
132
+ /**
133
+ * Parse the raw content of a CONTRIBUTING.md file to extract structured guidelines:
134
+ * branch naming, commit format, test framework, linter, formatter, CLA requirement.
135
+ */
136
+ function parseContributionGuidelines(content) {
137
+ const guidelines = {
138
+ rawContent: content,
139
+ };
140
+ const lowerContent = content.toLowerCase();
141
+ // Detect branch naming conventions
142
+ if (lowerContent.includes('branch')) {
143
+ const branchMatch = content.match(/branch[^\n]*(?:named?|format|convention)[^\n]*[`"]([^`"]+)[`"]/i);
144
+ if (branchMatch) {
145
+ guidelines.branchNamingConvention = branchMatch[1];
146
+ }
147
+ }
148
+ // Detect commit message format
149
+ if (lowerContent.includes('conventional commit')) {
150
+ guidelines.commitMessageFormat = 'conventional commits';
151
+ }
152
+ else if (lowerContent.includes('commit message')) {
153
+ const commitMatch = content.match(/commit message[^\n]*[`"]([^`"]+)[`"]/i);
154
+ if (commitMatch) {
155
+ guidelines.commitMessageFormat = commitMatch[1];
156
+ }
157
+ }
158
+ // Detect test framework
159
+ if (lowerContent.includes('jest'))
160
+ guidelines.testFramework = 'Jest';
161
+ else if (lowerContent.includes('rspec'))
162
+ guidelines.testFramework = 'RSpec';
163
+ else if (lowerContent.includes('pytest'))
164
+ guidelines.testFramework = 'pytest';
165
+ else if (lowerContent.includes('mocha'))
166
+ guidelines.testFramework = 'Mocha';
167
+ // Detect linter
168
+ if (lowerContent.includes('eslint'))
169
+ guidelines.linter = 'ESLint';
170
+ else if (lowerContent.includes('rubocop'))
171
+ guidelines.linter = 'RuboCop';
172
+ else if (lowerContent.includes('prettier'))
173
+ guidelines.formatter = 'Prettier';
174
+ // Detect CLA requirement
175
+ if (lowerContent.includes('cla') || lowerContent.includes('contributor license agreement')) {
176
+ guidelines.claRequired = true;
177
+ }
178
+ return guidelines;
179
+ }
@@ -0,0 +1,315 @@
1
+ /**
2
+ * Zod schemas for all types persisted in oss-scout state.
3
+ *
4
+ * This file is the single source of truth for persisted type shapes.
5
+ * Types are inferred via `z.infer<>` at the bottom.
6
+ */
7
+ import { z } from 'zod';
8
+ export declare const IssueStatusSchema: z.ZodEnum<{
9
+ candidate: "candidate";
10
+ claimed: "claimed";
11
+ in_progress: "in_progress";
12
+ pr_submitted: "pr_submitted";
13
+ }>;
14
+ export declare const ProjectCategorySchema: z.ZodEnum<{
15
+ nonprofit: "nonprofit";
16
+ devtools: "devtools";
17
+ infrastructure: "infrastructure";
18
+ "web-frameworks": "web-frameworks";
19
+ "data-ml": "data-ml";
20
+ education: "education";
21
+ }>;
22
+ export declare const IssueScopeSchema: z.ZodEnum<{
23
+ advanced: "advanced";
24
+ beginner: "beginner";
25
+ intermediate: "intermediate";
26
+ }>;
27
+ export declare const SearchStrategySchema: z.ZodEnum<{
28
+ all: "all";
29
+ merged: "merged";
30
+ orgs: "orgs";
31
+ starred: "starred";
32
+ broad: "broad";
33
+ maintained: "maintained";
34
+ }>;
35
+ /** All concrete strategies (excludes 'all' meta-strategy). */
36
+ export declare const CONCRETE_STRATEGIES: readonly ["merged", "orgs", "starred", "broad", "maintained"];
37
+ export declare const RepoSignalsSchema: z.ZodObject<{
38
+ hasActiveMaintainers: z.ZodBoolean;
39
+ isResponsive: z.ZodBoolean;
40
+ hasHostileComments: z.ZodBoolean;
41
+ }, z.core.$strip>;
42
+ export declare const RepoScoreSchema: z.ZodObject<{
43
+ repo: z.ZodString;
44
+ score: z.ZodNumber;
45
+ mergedPRCount: z.ZodNumber;
46
+ closedWithoutMergeCount: z.ZodNumber;
47
+ avgResponseDays: z.ZodNullable<z.ZodNumber>;
48
+ lastMergedAt: z.ZodOptional<z.ZodString>;
49
+ lastEvaluatedAt: z.ZodString;
50
+ signals: z.ZodObject<{
51
+ hasActiveMaintainers: z.ZodBoolean;
52
+ isResponsive: z.ZodBoolean;
53
+ hasHostileComments: z.ZodBoolean;
54
+ }, z.core.$strip>;
55
+ stargazersCount: z.ZodOptional<z.ZodNumber>;
56
+ language: z.ZodOptional<z.ZodNullable<z.ZodString>>;
57
+ }, z.core.$strip>;
58
+ export declare const StoredMergedPRSchema: z.ZodObject<{
59
+ url: z.ZodString;
60
+ title: z.ZodString;
61
+ mergedAt: z.ZodString;
62
+ }, z.core.$strip>;
63
+ export declare const StoredClosedPRSchema: z.ZodObject<{
64
+ url: z.ZodString;
65
+ title: z.ZodString;
66
+ closedAt: z.ZodString;
67
+ }, z.core.$strip>;
68
+ export declare const ContributionGuidelinesSchema: z.ZodObject<{
69
+ branchNamingConvention: z.ZodOptional<z.ZodString>;
70
+ commitMessageFormat: z.ZodOptional<z.ZodString>;
71
+ prTitleFormat: z.ZodOptional<z.ZodString>;
72
+ requiredChecks: z.ZodOptional<z.ZodArray<z.ZodString>>;
73
+ testFramework: z.ZodOptional<z.ZodString>;
74
+ testCoverageRequired: z.ZodOptional<z.ZodBoolean>;
75
+ testFileNaming: z.ZodOptional<z.ZodString>;
76
+ linter: z.ZodOptional<z.ZodString>;
77
+ formatter: z.ZodOptional<z.ZodString>;
78
+ styleGuideUrl: z.ZodOptional<z.ZodString>;
79
+ issueClaimProcess: z.ZodOptional<z.ZodString>;
80
+ reviewProcess: z.ZodOptional<z.ZodString>;
81
+ claRequired: z.ZodOptional<z.ZodBoolean>;
82
+ rawContent: z.ZodOptional<z.ZodString>;
83
+ }, z.core.$strip>;
84
+ export declare const IssueVettingResultSchema: z.ZodObject<{
85
+ passedAllChecks: z.ZodBoolean;
86
+ checks: z.ZodObject<{
87
+ noExistingPR: z.ZodBoolean;
88
+ notClaimed: z.ZodBoolean;
89
+ projectActive: z.ZodBoolean;
90
+ clearRequirements: z.ZodBoolean;
91
+ contributionGuidelinesFound: z.ZodBoolean;
92
+ }, z.core.$strip>;
93
+ contributionGuidelines: z.ZodOptional<z.ZodObject<{
94
+ branchNamingConvention: z.ZodOptional<z.ZodString>;
95
+ commitMessageFormat: z.ZodOptional<z.ZodString>;
96
+ prTitleFormat: z.ZodOptional<z.ZodString>;
97
+ requiredChecks: z.ZodOptional<z.ZodArray<z.ZodString>>;
98
+ testFramework: z.ZodOptional<z.ZodString>;
99
+ testCoverageRequired: z.ZodOptional<z.ZodBoolean>;
100
+ testFileNaming: z.ZodOptional<z.ZodString>;
101
+ linter: z.ZodOptional<z.ZodString>;
102
+ formatter: z.ZodOptional<z.ZodString>;
103
+ styleGuideUrl: z.ZodOptional<z.ZodString>;
104
+ issueClaimProcess: z.ZodOptional<z.ZodString>;
105
+ reviewProcess: z.ZodOptional<z.ZodString>;
106
+ claRequired: z.ZodOptional<z.ZodBoolean>;
107
+ rawContent: z.ZodOptional<z.ZodString>;
108
+ }, z.core.$strip>>;
109
+ notes: z.ZodArray<z.ZodString>;
110
+ }, z.core.$strip>;
111
+ export declare const TrackedIssueSchema: z.ZodObject<{
112
+ id: z.ZodNumber;
113
+ url: z.ZodString;
114
+ repo: z.ZodString;
115
+ number: z.ZodNumber;
116
+ title: z.ZodString;
117
+ status: z.ZodEnum<{
118
+ candidate: "candidate";
119
+ claimed: "claimed";
120
+ in_progress: "in_progress";
121
+ pr_submitted: "pr_submitted";
122
+ }>;
123
+ labels: z.ZodArray<z.ZodString>;
124
+ createdAt: z.ZodString;
125
+ updatedAt: z.ZodString;
126
+ vetted: z.ZodBoolean;
127
+ vettingResult: z.ZodOptional<z.ZodObject<{
128
+ passedAllChecks: z.ZodBoolean;
129
+ checks: z.ZodObject<{
130
+ noExistingPR: z.ZodBoolean;
131
+ notClaimed: z.ZodBoolean;
132
+ projectActive: z.ZodBoolean;
133
+ clearRequirements: z.ZodBoolean;
134
+ contributionGuidelinesFound: z.ZodBoolean;
135
+ }, z.core.$strip>;
136
+ contributionGuidelines: z.ZodOptional<z.ZodObject<{
137
+ branchNamingConvention: z.ZodOptional<z.ZodString>;
138
+ commitMessageFormat: z.ZodOptional<z.ZodString>;
139
+ prTitleFormat: z.ZodOptional<z.ZodString>;
140
+ requiredChecks: z.ZodOptional<z.ZodArray<z.ZodString>>;
141
+ testFramework: z.ZodOptional<z.ZodString>;
142
+ testCoverageRequired: z.ZodOptional<z.ZodBoolean>;
143
+ testFileNaming: z.ZodOptional<z.ZodString>;
144
+ linter: z.ZodOptional<z.ZodString>;
145
+ formatter: z.ZodOptional<z.ZodString>;
146
+ styleGuideUrl: z.ZodOptional<z.ZodString>;
147
+ issueClaimProcess: z.ZodOptional<z.ZodString>;
148
+ reviewProcess: z.ZodOptional<z.ZodString>;
149
+ claRequired: z.ZodOptional<z.ZodBoolean>;
150
+ rawContent: z.ZodOptional<z.ZodString>;
151
+ }, z.core.$strip>>;
152
+ notes: z.ZodArray<z.ZodString>;
153
+ }, z.core.$strip>>;
154
+ }, z.core.$strip>;
155
+ export declare const SavedCandidateSchema: z.ZodObject<{
156
+ issueUrl: z.ZodString;
157
+ repo: z.ZodString;
158
+ number: z.ZodNumber;
159
+ title: z.ZodString;
160
+ labels: z.ZodArray<z.ZodString>;
161
+ recommendation: z.ZodEnum<{
162
+ approve: "approve";
163
+ skip: "skip";
164
+ needs_review: "needs_review";
165
+ }>;
166
+ viabilityScore: z.ZodNumber;
167
+ searchPriority: z.ZodString;
168
+ firstSeenAt: z.ZodString;
169
+ lastSeenAt: z.ZodString;
170
+ lastScore: z.ZodNumber;
171
+ }, z.core.$strip>;
172
+ export declare const PersistenceModeSchema: z.ZodEnum<{
173
+ local: "local";
174
+ gist: "gist";
175
+ }>;
176
+ export declare const ScoutPreferencesSchema: z.ZodObject<{
177
+ githubUsername: z.ZodDefault<z.ZodString>;
178
+ languages: z.ZodDefault<z.ZodArray<z.ZodString>>;
179
+ labels: z.ZodDefault<z.ZodArray<z.ZodString>>;
180
+ scope: z.ZodOptional<z.ZodArray<z.ZodEnum<{
181
+ advanced: "advanced";
182
+ beginner: "beginner";
183
+ intermediate: "intermediate";
184
+ }>>>;
185
+ excludeRepos: z.ZodDefault<z.ZodArray<z.ZodString>>;
186
+ aiPolicyBlocklist: z.ZodDefault<z.ZodArray<z.ZodString>>;
187
+ preferredOrgs: z.ZodDefault<z.ZodArray<z.ZodString>>;
188
+ projectCategories: z.ZodDefault<z.ZodArray<z.ZodEnum<{
189
+ nonprofit: "nonprofit";
190
+ devtools: "devtools";
191
+ infrastructure: "infrastructure";
192
+ "web-frameworks": "web-frameworks";
193
+ "data-ml": "data-ml";
194
+ education: "education";
195
+ }>>>;
196
+ minStars: z.ZodDefault<z.ZodNumber>;
197
+ maxIssueAgeDays: z.ZodDefault<z.ZodNumber>;
198
+ includeDocIssues: z.ZodDefault<z.ZodBoolean>;
199
+ minRepoScoreThreshold: z.ZodDefault<z.ZodNumber>;
200
+ persistence: z.ZodDefault<z.ZodEnum<{
201
+ local: "local";
202
+ gist: "gist";
203
+ }>>;
204
+ defaultStrategy: z.ZodOptional<z.ZodArray<z.ZodEnum<{
205
+ all: "all";
206
+ merged: "merged";
207
+ orgs: "orgs";
208
+ starred: "starred";
209
+ broad: "broad";
210
+ maintained: "maintained";
211
+ }>>>;
212
+ }, z.core.$strip>;
213
+ export declare const ScoutStateSchema: z.ZodObject<{
214
+ version: z.ZodLiteral<1>;
215
+ preferences: z.ZodDefault<z.ZodObject<{
216
+ githubUsername: z.ZodDefault<z.ZodString>;
217
+ languages: z.ZodDefault<z.ZodArray<z.ZodString>>;
218
+ labels: z.ZodDefault<z.ZodArray<z.ZodString>>;
219
+ scope: z.ZodOptional<z.ZodArray<z.ZodEnum<{
220
+ advanced: "advanced";
221
+ beginner: "beginner";
222
+ intermediate: "intermediate";
223
+ }>>>;
224
+ excludeRepos: z.ZodDefault<z.ZodArray<z.ZodString>>;
225
+ aiPolicyBlocklist: z.ZodDefault<z.ZodArray<z.ZodString>>;
226
+ preferredOrgs: z.ZodDefault<z.ZodArray<z.ZodString>>;
227
+ projectCategories: z.ZodDefault<z.ZodArray<z.ZodEnum<{
228
+ nonprofit: "nonprofit";
229
+ devtools: "devtools";
230
+ infrastructure: "infrastructure";
231
+ "web-frameworks": "web-frameworks";
232
+ "data-ml": "data-ml";
233
+ education: "education";
234
+ }>>>;
235
+ minStars: z.ZodDefault<z.ZodNumber>;
236
+ maxIssueAgeDays: z.ZodDefault<z.ZodNumber>;
237
+ includeDocIssues: z.ZodDefault<z.ZodBoolean>;
238
+ minRepoScoreThreshold: z.ZodDefault<z.ZodNumber>;
239
+ persistence: z.ZodDefault<z.ZodEnum<{
240
+ local: "local";
241
+ gist: "gist";
242
+ }>>;
243
+ defaultStrategy: z.ZodOptional<z.ZodArray<z.ZodEnum<{
244
+ all: "all";
245
+ merged: "merged";
246
+ orgs: "orgs";
247
+ starred: "starred";
248
+ broad: "broad";
249
+ maintained: "maintained";
250
+ }>>>;
251
+ }, z.core.$strip>>;
252
+ repoScores: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
253
+ repo: z.ZodString;
254
+ score: z.ZodNumber;
255
+ mergedPRCount: z.ZodNumber;
256
+ closedWithoutMergeCount: z.ZodNumber;
257
+ avgResponseDays: z.ZodNullable<z.ZodNumber>;
258
+ lastMergedAt: z.ZodOptional<z.ZodString>;
259
+ lastEvaluatedAt: z.ZodString;
260
+ signals: z.ZodObject<{
261
+ hasActiveMaintainers: z.ZodBoolean;
262
+ isResponsive: z.ZodBoolean;
263
+ hasHostileComments: z.ZodBoolean;
264
+ }, z.core.$strip>;
265
+ stargazersCount: z.ZodOptional<z.ZodNumber>;
266
+ language: z.ZodOptional<z.ZodNullable<z.ZodString>>;
267
+ }, z.core.$strip>>>;
268
+ starredRepos: z.ZodDefault<z.ZodArray<z.ZodString>>;
269
+ starredReposLastFetched: z.ZodOptional<z.ZodString>;
270
+ mergedPRs: z.ZodDefault<z.ZodArray<z.ZodObject<{
271
+ url: z.ZodString;
272
+ title: z.ZodString;
273
+ mergedAt: z.ZodString;
274
+ }, z.core.$strip>>>;
275
+ closedPRs: z.ZodDefault<z.ZodArray<z.ZodObject<{
276
+ url: z.ZodString;
277
+ title: z.ZodString;
278
+ closedAt: z.ZodString;
279
+ }, z.core.$strip>>>;
280
+ savedResults: z.ZodDefault<z.ZodArray<z.ZodObject<{
281
+ issueUrl: z.ZodString;
282
+ repo: z.ZodString;
283
+ number: z.ZodNumber;
284
+ title: z.ZodString;
285
+ labels: z.ZodArray<z.ZodString>;
286
+ recommendation: z.ZodEnum<{
287
+ approve: "approve";
288
+ skip: "skip";
289
+ needs_review: "needs_review";
290
+ }>;
291
+ viabilityScore: z.ZodNumber;
292
+ searchPriority: z.ZodString;
293
+ firstSeenAt: z.ZodString;
294
+ lastSeenAt: z.ZodString;
295
+ lastScore: z.ZodNumber;
296
+ }, z.core.$strip>>>;
297
+ lastSearchAt: z.ZodOptional<z.ZodString>;
298
+ lastRunAt: z.ZodDefault<z.ZodString>;
299
+ gistId: z.ZodOptional<z.ZodString>;
300
+ }, z.core.$strip>;
301
+ export type IssueStatus = z.infer<typeof IssueStatusSchema>;
302
+ export type ProjectCategory = z.infer<typeof ProjectCategorySchema>;
303
+ export type IssueScope = z.infer<typeof IssueScopeSchema>;
304
+ export type SearchStrategy = z.infer<typeof SearchStrategySchema>;
305
+ export type RepoSignals = z.infer<typeof RepoSignalsSchema>;
306
+ export type RepoScore = z.infer<typeof RepoScoreSchema>;
307
+ export type StoredMergedPR = z.infer<typeof StoredMergedPRSchema>;
308
+ export type StoredClosedPR = z.infer<typeof StoredClosedPRSchema>;
309
+ export type ContributionGuidelines = z.infer<typeof ContributionGuidelinesSchema>;
310
+ export type IssueVettingResult = z.infer<typeof IssueVettingResultSchema>;
311
+ export type TrackedIssue = z.infer<typeof TrackedIssueSchema>;
312
+ export type PersistenceMode = z.infer<typeof PersistenceModeSchema>;
313
+ export type ScoutPreferences = z.infer<typeof ScoutPreferencesSchema>;
314
+ export type SavedCandidate = z.infer<typeof SavedCandidateSchema>;
315
+ export type ScoutState = z.infer<typeof ScoutStateSchema>;