@oss-autopilot/core 0.41.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 (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +85 -0
  3. package/dist/cli.bundle.cjs +17657 -0
  4. package/dist/cli.d.ts +12 -0
  5. package/dist/cli.js +325 -0
  6. package/dist/commands/check-integration.d.ts +10 -0
  7. package/dist/commands/check-integration.js +192 -0
  8. package/dist/commands/comments.d.ts +24 -0
  9. package/dist/commands/comments.js +311 -0
  10. package/dist/commands/config.d.ts +11 -0
  11. package/dist/commands/config.js +82 -0
  12. package/dist/commands/daily.d.ts +29 -0
  13. package/dist/commands/daily.js +433 -0
  14. package/dist/commands/dashboard-data.d.ts +45 -0
  15. package/dist/commands/dashboard-data.js +132 -0
  16. package/dist/commands/dashboard-templates.d.ts +23 -0
  17. package/dist/commands/dashboard-templates.js +1627 -0
  18. package/dist/commands/dashboard.d.ts +18 -0
  19. package/dist/commands/dashboard.js +134 -0
  20. package/dist/commands/dismiss.d.ts +13 -0
  21. package/dist/commands/dismiss.js +49 -0
  22. package/dist/commands/init.d.ts +10 -0
  23. package/dist/commands/init.js +27 -0
  24. package/dist/commands/local-repos.d.ts +14 -0
  25. package/dist/commands/local-repos.js +155 -0
  26. package/dist/commands/parse-list.d.ts +13 -0
  27. package/dist/commands/parse-list.js +139 -0
  28. package/dist/commands/read.d.ts +12 -0
  29. package/dist/commands/read.js +33 -0
  30. package/dist/commands/search.d.ts +10 -0
  31. package/dist/commands/search.js +74 -0
  32. package/dist/commands/setup.d.ts +15 -0
  33. package/dist/commands/setup.js +276 -0
  34. package/dist/commands/shelve.d.ts +13 -0
  35. package/dist/commands/shelve.js +49 -0
  36. package/dist/commands/snooze.d.ts +18 -0
  37. package/dist/commands/snooze.js +83 -0
  38. package/dist/commands/startup.d.ts +33 -0
  39. package/dist/commands/startup.js +197 -0
  40. package/dist/commands/status.d.ts +10 -0
  41. package/dist/commands/status.js +43 -0
  42. package/dist/commands/track.d.ts +16 -0
  43. package/dist/commands/track.js +59 -0
  44. package/dist/commands/validation.d.ts +43 -0
  45. package/dist/commands/validation.js +112 -0
  46. package/dist/commands/vet.d.ts +10 -0
  47. package/dist/commands/vet.js +36 -0
  48. package/dist/core/checklist-analysis.d.ts +17 -0
  49. package/dist/core/checklist-analysis.js +39 -0
  50. package/dist/core/ci-analysis.d.ts +78 -0
  51. package/dist/core/ci-analysis.js +163 -0
  52. package/dist/core/comment-utils.d.ts +15 -0
  53. package/dist/core/comment-utils.js +52 -0
  54. package/dist/core/concurrency.d.ts +5 -0
  55. package/dist/core/concurrency.js +15 -0
  56. package/dist/core/daily-logic.d.ts +77 -0
  57. package/dist/core/daily-logic.js +512 -0
  58. package/dist/core/display-utils.d.ts +10 -0
  59. package/dist/core/display-utils.js +100 -0
  60. package/dist/core/errors.d.ts +24 -0
  61. package/dist/core/errors.js +34 -0
  62. package/dist/core/github-stats.d.ts +73 -0
  63. package/dist/core/github-stats.js +272 -0
  64. package/dist/core/github.d.ts +19 -0
  65. package/dist/core/github.js +60 -0
  66. package/dist/core/http-cache.d.ts +97 -0
  67. package/dist/core/http-cache.js +269 -0
  68. package/dist/core/index.d.ts +15 -0
  69. package/dist/core/index.js +15 -0
  70. package/dist/core/issue-conversation.d.ts +29 -0
  71. package/dist/core/issue-conversation.js +231 -0
  72. package/dist/core/issue-discovery.d.ts +85 -0
  73. package/dist/core/issue-discovery.js +589 -0
  74. package/dist/core/issue-filtering.d.ts +51 -0
  75. package/dist/core/issue-filtering.js +103 -0
  76. package/dist/core/issue-scoring.d.ts +40 -0
  77. package/dist/core/issue-scoring.js +92 -0
  78. package/dist/core/issue-vetting.d.ts +49 -0
  79. package/dist/core/issue-vetting.js +536 -0
  80. package/dist/core/logger.d.ts +21 -0
  81. package/dist/core/logger.js +49 -0
  82. package/dist/core/maintainer-analysis.d.ts +10 -0
  83. package/dist/core/maintainer-analysis.js +59 -0
  84. package/dist/core/pagination.d.ts +11 -0
  85. package/dist/core/pagination.js +20 -0
  86. package/dist/core/pr-monitor.d.ts +109 -0
  87. package/dist/core/pr-monitor.js +594 -0
  88. package/dist/core/review-analysis.d.ts +72 -0
  89. package/dist/core/review-analysis.js +163 -0
  90. package/dist/core/state.d.ts +371 -0
  91. package/dist/core/state.js +1089 -0
  92. package/dist/core/types.d.ts +507 -0
  93. package/dist/core/types.js +34 -0
  94. package/dist/core/utils.d.ts +249 -0
  95. package/dist/core/utils.js +422 -0
  96. package/dist/formatters/json.d.ts +269 -0
  97. package/dist/formatters/json.js +88 -0
  98. package/package.json +67 -0
package/dist/cli.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OSS Autopilot CLI
4
+ * Entry point with commander for argument parsing
5
+ *
6
+ * Supports --json flag for structured output (used by Claude Code plugin)
7
+ *
8
+ * Performance: Command modules are lazy-loaded via dynamic import() so that
9
+ * only the invoked command's code is evaluated. The preAction hook uses an
10
+ * async token fetch to avoid blocking the event loop on `gh auth token`.
11
+ */
12
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,325 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OSS Autopilot CLI
4
+ * Entry point with commander for argument parsing
5
+ *
6
+ * Supports --json flag for structured output (used by Claude Code plugin)
7
+ *
8
+ * Performance: Command modules are lazy-loaded via dynamic import() so that
9
+ * only the invoked command's code is evaluated. The preAction hook uses an
10
+ * async token fetch to avoid blocking the event loop on `gh auth token`.
11
+ */
12
+ import { Command } from 'commander';
13
+ import { getGitHubTokenAsync, enableDebug, debug } from './core/index.js';
14
+ const VERSION = (() => {
15
+ try {
16
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
17
+ const fs = require('fs');
18
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
19
+ const path = require('path');
20
+ const pkgPath = path.join(path.dirname(process.argv[1]), '..', 'package.json');
21
+ return JSON.parse(fs.readFileSync(pkgPath, 'utf-8')).version;
22
+ }
23
+ catch (_err) {
24
+ // package.json may not be readable in all bundle/install configurations — fall back to safe default
25
+ return '0.0.0';
26
+ }
27
+ })();
28
+ // Commands that skip the preAction GitHub token check.
29
+ // startup handles auth internally (returns authError in JSON instead of process.exit).
30
+ const LOCAL_ONLY_COMMANDS = [
31
+ 'help',
32
+ 'status',
33
+ 'config',
34
+ 'read',
35
+ 'untrack',
36
+ 'version',
37
+ 'setup',
38
+ 'checkSetup',
39
+ 'dashboard',
40
+ 'parse-issue-list',
41
+ 'check-integration',
42
+ 'local-repos',
43
+ 'startup',
44
+ 'shelve',
45
+ 'unshelve',
46
+ 'dismiss',
47
+ 'undismiss',
48
+ 'snooze',
49
+ 'unsnooze',
50
+ ];
51
+ const program = new Command();
52
+ program
53
+ .name('oss-autopilot')
54
+ .description('AI-powered autopilot for managing open source contributions')
55
+ .version(VERSION)
56
+ .option('--debug', 'Enable debug logging');
57
+ // Daily check command
58
+ program
59
+ .command('daily')
60
+ .description('Run daily check on all tracked PRs')
61
+ .option('--json', 'Output as JSON')
62
+ .action(async (options) => {
63
+ const { runDaily } = await import('./commands/daily.js');
64
+ await runDaily({ json: options.json });
65
+ });
66
+ // Status command
67
+ program
68
+ .command('status')
69
+ .description('Show current status and stats')
70
+ .option('--json', 'Output as JSON')
71
+ .option('--offline', 'Use cached data only (no GitHub API calls)')
72
+ .action(async (options) => {
73
+ const { runStatus } = await import('./commands/status.js');
74
+ await runStatus({ json: options.json, offline: options.offline });
75
+ });
76
+ // Search command
77
+ program
78
+ .command('search [count]')
79
+ .description('Search for new issues to work on')
80
+ .option('--json', 'Output as JSON')
81
+ .action(async (count, options) => {
82
+ const { runSearch } = await import('./commands/search.js');
83
+ await runSearch({ maxResults: parseInt(count) || 5, json: options.json });
84
+ });
85
+ // Vet command
86
+ program
87
+ .command('vet <issue-url>')
88
+ .description('Vet a specific issue before working on it')
89
+ .option('--json', 'Output as JSON')
90
+ .action(async (issueUrl, options) => {
91
+ const { runVet } = await import('./commands/vet.js');
92
+ await runVet({ issueUrl, json: options.json });
93
+ });
94
+ // Track command
95
+ program
96
+ .command('track <pr-url>')
97
+ .description('Add a PR to track')
98
+ .option('--json', 'Output as JSON')
99
+ .action(async (prUrl, options) => {
100
+ const { runTrack } = await import('./commands/track.js');
101
+ await runTrack({ prUrl, json: options.json });
102
+ });
103
+ // Untrack command
104
+ program
105
+ .command('untrack <pr-url>')
106
+ .description('Stop tracking a PR')
107
+ .option('--json', 'Output as JSON')
108
+ .action(async (prUrl, options) => {
109
+ const { runUntrack } = await import('./commands/track.js');
110
+ await runUntrack({ prUrl, json: options.json });
111
+ });
112
+ // Read command (mark as read)
113
+ program
114
+ .command('read [pr-url]')
115
+ .description('Mark PR comments as read')
116
+ .option('--all', 'Mark all PRs as read')
117
+ .option('--json', 'Output as JSON')
118
+ .action(async (prUrl, options) => {
119
+ const { runRead } = await import('./commands/read.js');
120
+ await runRead({ prUrl, all: options.all, json: options.json });
121
+ });
122
+ // Comments command
123
+ program
124
+ .command('comments <pr-url>')
125
+ .description('Show all comments on a PR')
126
+ .option('--bots', 'Include bot comments')
127
+ .option('--json', 'Output as JSON')
128
+ .action(async (prUrl, options) => {
129
+ const { runComments } = await import('./commands/comments.js');
130
+ await runComments({ prUrl, showBots: options.bots, json: options.json });
131
+ });
132
+ // Post command
133
+ program
134
+ .command('post <url> [message...]')
135
+ .description('Post a comment to a PR or issue')
136
+ .option('--stdin', 'Read message from stdin')
137
+ .option('--json', 'Output as JSON')
138
+ .action(async (url, messageParts, options) => {
139
+ const { runPost } = await import('./commands/comments.js');
140
+ const message = options.stdin ? undefined : messageParts.join(' ');
141
+ await runPost({ url, message, stdin: options.stdin, json: options.json });
142
+ });
143
+ // Claim command
144
+ program
145
+ .command('claim <issue-url> [message...]')
146
+ .description('Claim an issue by posting a comment')
147
+ .option('--json', 'Output as JSON')
148
+ .action(async (issueUrl, messageParts, options) => {
149
+ const { runClaim } = await import('./commands/comments.js');
150
+ const message = messageParts.length > 0 ? messageParts.join(' ') : undefined;
151
+ await runClaim({ issueUrl, message, json: options.json });
152
+ });
153
+ // Config command
154
+ program
155
+ .command('config [key] [value]')
156
+ .description('Show or update configuration')
157
+ .option('--json', 'Output as JSON')
158
+ .action(async (key, value, options) => {
159
+ const { runConfig } = await import('./commands/config.js');
160
+ await runConfig({ key, value, json: options.json });
161
+ });
162
+ // Init command
163
+ program
164
+ .command('init <username>')
165
+ .description('Initialize with your GitHub username and import open PRs')
166
+ .option('--json', 'Output as JSON')
167
+ .action(async (username, options) => {
168
+ const { runInit } = await import('./commands/init.js');
169
+ await runInit({ username, json: options.json });
170
+ });
171
+ // Setup command
172
+ program
173
+ .command('setup')
174
+ .description('Interactive setup / configuration')
175
+ .option('--reset', 'Re-run setup even if already complete')
176
+ .option('--set <settings...>', 'Set specific values (key=value)')
177
+ .option('--json', 'Output as JSON')
178
+ .action(async (options) => {
179
+ const { runSetup } = await import('./commands/setup.js');
180
+ await runSetup({ reset: options.reset, set: options.set, json: options.json });
181
+ });
182
+ // Check setup command
183
+ program
184
+ .command('checkSetup')
185
+ .description('Check if setup is complete')
186
+ .option('--json', 'Output as JSON')
187
+ .action(async (options) => {
188
+ const { runCheckSetup } = await import('./commands/setup.js');
189
+ await runCheckSetup({ json: options.json });
190
+ });
191
+ // Dashboard command
192
+ program
193
+ .command('dashboard')
194
+ .description('Generate HTML stats dashboard')
195
+ .option('--open', 'Open in browser')
196
+ .option('--json', 'Output as JSON')
197
+ .option('--offline', 'Use cached data only (no GitHub API calls)')
198
+ .action(async (options) => {
199
+ const { runDashboard } = await import('./commands/dashboard.js');
200
+ await runDashboard({ open: options.open, json: options.json, offline: options.offline });
201
+ });
202
+ // Parse issue list command (#82)
203
+ program
204
+ .command('parse-issue-list <path>')
205
+ .description('Parse a markdown issue list into structured JSON')
206
+ .option('--json', 'Output as JSON')
207
+ .action(async (filePath, options) => {
208
+ const { runParseList } = await import('./commands/parse-list.js');
209
+ await runParseList({ filePath, json: options.json });
210
+ });
211
+ // Check integration command (#83)
212
+ program
213
+ .command('check-integration')
214
+ .description('Detect new files not referenced by the codebase')
215
+ .option('--base <branch>', 'Base branch to compare against', 'main')
216
+ .option('--json', 'Output as JSON')
217
+ .action(async (options) => {
218
+ const { runCheckIntegration } = await import('./commands/check-integration.js');
219
+ await runCheckIntegration({ base: options.base, json: options.json });
220
+ });
221
+ // Local repos command (#84)
222
+ program
223
+ .command('local-repos')
224
+ .description('Scan filesystem for local git clones')
225
+ .option('--scan', 'Force re-scan (ignores cache)')
226
+ .option('--paths <dirs...>', 'Directories to scan')
227
+ .option('--json', 'Output as JSON')
228
+ .action(async (options) => {
229
+ const { runLocalRepos } = await import('./commands/local-repos.js');
230
+ await runLocalRepos({ scan: options.scan, paths: options.paths, json: options.json });
231
+ });
232
+ // Startup command (combines auth, setup, daily, dashboard, issue list)
233
+ program
234
+ .command('startup')
235
+ .description('Run all pre-flight checks and daily fetch in one call')
236
+ .option('--json', 'Output as JSON')
237
+ .action(async (options) => {
238
+ const { runStartup } = await import('./commands/startup.js');
239
+ await runStartup({ json: options.json });
240
+ });
241
+ // Shelve command
242
+ program
243
+ .command('shelve <pr-url>')
244
+ .description('Shelve a PR (exclude from capacity and actionable issues)')
245
+ .option('--json', 'Output as JSON')
246
+ .action(async (prUrl, options) => {
247
+ const { runShelve } = await import('./commands/shelve.js');
248
+ await runShelve({ prUrl, json: options.json });
249
+ });
250
+ // Unshelve command
251
+ program
252
+ .command('unshelve <pr-url>')
253
+ .description('Unshelve a PR (include in capacity and actionable issues again)')
254
+ .option('--json', 'Output as JSON')
255
+ .action(async (prUrl, options) => {
256
+ const { runUnshelve } = await import('./commands/shelve.js');
257
+ await runUnshelve({ prUrl, json: options.json });
258
+ });
259
+ // Dismiss command
260
+ program
261
+ .command('dismiss <issue-url>')
262
+ .description('Dismiss issue reply notifications (resurfaces on new activity)')
263
+ .option('--json', 'Output as JSON')
264
+ .action(async (issueUrl, options) => {
265
+ const { runDismiss } = await import('./commands/dismiss.js');
266
+ await runDismiss({ issueUrl, json: options.json });
267
+ });
268
+ // Undismiss command
269
+ program
270
+ .command('undismiss <issue-url>')
271
+ .description('Undismiss an issue (re-enable reply notifications)')
272
+ .option('--json', 'Output as JSON')
273
+ .action(async (issueUrl, options) => {
274
+ const { runUndismiss } = await import('./commands/dismiss.js');
275
+ await runUndismiss({ issueUrl, json: options.json });
276
+ });
277
+ // Snooze command
278
+ program
279
+ .command('snooze <pr-url>')
280
+ .description('Snooze CI failure notifications for a PR')
281
+ .requiredOption('--reason <reason>', 'Reason for snoozing (e.g., "upstream infrastructure issue")')
282
+ .option('--days <days>', 'Number of days to snooze (default: 7)', '7')
283
+ .option('--json', 'Output as JSON')
284
+ .action(async (prUrl, options) => {
285
+ const { runSnooze } = await import('./commands/snooze.js');
286
+ await runSnooze({ prUrl, reason: options.reason, days: parseInt(options.days, 10), json: options.json });
287
+ });
288
+ // Unsnooze command
289
+ program
290
+ .command('unsnooze <pr-url>')
291
+ .description('Unsnooze a PR (re-enable CI failure notifications)')
292
+ .option('--json', 'Output as JSON')
293
+ .action(async (prUrl, options) => {
294
+ const { runUnsnooze } = await import('./commands/snooze.js');
295
+ await runUnsnooze({ prUrl, json: options.json });
296
+ });
297
+ // Validate GitHub token before running commands that need it
298
+ program.hook('preAction', async (thisCommand, actionCommand) => {
299
+ // Enable debug logging if --debug flag is set
300
+ const globalOpts = thisCommand.opts();
301
+ if (globalOpts.debug) {
302
+ enableDebug();
303
+ debug('cli', `Running command: ${actionCommand.name()}`);
304
+ }
305
+ // actionCommand is the command being executed (e.g., 'status', 'daily')
306
+ const commandName = actionCommand.name();
307
+ if (!LOCAL_ONLY_COMMANDS.includes(commandName)) {
308
+ const token = await getGitHubTokenAsync();
309
+ if (!token) {
310
+ console.error('Error: GitHub authentication required.');
311
+ console.error('');
312
+ console.error('Option 1 (Recommended): Install and authenticate GitHub CLI');
313
+ console.error(' Install: https://cli.github.com/');
314
+ console.error(' Then run: gh auth login');
315
+ console.error('');
316
+ console.error('Option 2: Set GITHUB_TOKEN environment variable');
317
+ console.error(' export GITHUB_TOKEN="your-github-token-here"');
318
+ console.error('');
319
+ console.error('Then run your command again.');
320
+ process.exit(1);
321
+ }
322
+ }
323
+ });
324
+ // Parse and execute
325
+ program.parse();
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Check integration command (#83)
3
+ * Detects new files in the current branch that aren't referenced elsewhere
4
+ */
5
+ interface CheckIntegrationOptions {
6
+ base: string;
7
+ json?: boolean;
8
+ }
9
+ export declare function runCheckIntegration(options: CheckIntegrationOptions): Promise<void>;
10
+ export {};
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Check integration command (#83)
3
+ * Detects new files in the current branch that aren't referenced elsewhere
4
+ */
5
+ import * as path from 'path';
6
+ import { execFileSync } from 'child_process';
7
+ import { outputJson, outputJsonError } from '../formatters/json.js';
8
+ import { debug } from '../core/index.js';
9
+ /** File extensions we consider "code" that should be imported/referenced */
10
+ const CODE_EXTENSIONS = new Set([
11
+ '.ts',
12
+ '.tsx',
13
+ '.js',
14
+ '.jsx',
15
+ '.mjs',
16
+ '.cjs',
17
+ '.py',
18
+ '.rb',
19
+ '.go',
20
+ '.rs',
21
+ '.java',
22
+ '.kt',
23
+ '.vue',
24
+ '.svelte',
25
+ ]);
26
+ /** Files that are typically entry points or config, not expected to be imported */
27
+ const IGNORED_PATTERNS = [
28
+ /^\./, // dotfiles
29
+ /\.(test|spec|e2e)\.[^.]+$/, // test files
30
+ /\.(config|rc)\.[^.]+$/, // config files
31
+ /__tests__\//, // test directories
32
+ /\.d\.ts$/, // type declarations
33
+ /\.md$/, // documentation
34
+ /\.json$/, // json files
35
+ /\.ya?ml$/, // yaml files
36
+ ];
37
+ /** Get the basename without extension for import matching (TS/JS) */
38
+ function getImportName(filePath) {
39
+ const ext = path.extname(filePath);
40
+ const base = path.basename(filePath, ext);
41
+ // index files are imported by their directory name
42
+ if (base === 'index') {
43
+ return path.basename(path.dirname(filePath));
44
+ }
45
+ return base;
46
+ }
47
+ /** Suggest likely entry points for a new file based on its location */
48
+ function suggestEntryPoints(newFile, existingFiles) {
49
+ const dir = path.dirname(newFile);
50
+ const suggestions = [];
51
+ // Look for index files in the same directory
52
+ for (const ext of ['.ts', '.tsx', '.js', '.jsx']) {
53
+ const indexFile = path.join(dir, `index${ext}`);
54
+ if (existingFiles.includes(indexFile)) {
55
+ suggestions.push(indexFile);
56
+ }
57
+ }
58
+ // Look for barrel/index in parent directory
59
+ const parentDir = path.dirname(dir);
60
+ for (const ext of ['.ts', '.tsx', '.js', '.jsx']) {
61
+ const parentIndex = path.join(parentDir, `index${ext}`);
62
+ if (existingFiles.includes(parentIndex)) {
63
+ suggestions.push(parentIndex);
64
+ }
65
+ }
66
+ return [...new Set(suggestions)];
67
+ }
68
+ export async function runCheckIntegration(options) {
69
+ const base = options.base;
70
+ // Get new files added in this branch vs base
71
+ let newFiles;
72
+ try {
73
+ const output = execFileSync('git', ['diff', '--name-only', '--diff-filter=A', `${base}...HEAD`], {
74
+ encoding: 'utf-8',
75
+ timeout: 10000,
76
+ }).trim();
77
+ newFiles = output ? output.split('\n').filter(Boolean) : [];
78
+ }
79
+ catch (error) {
80
+ const msg = error instanceof Error ? error.message : String(error);
81
+ if (options.json) {
82
+ outputJsonError(`Failed to run git diff: ${msg}`);
83
+ }
84
+ else {
85
+ console.error(`Error: Failed to run git diff: ${msg}`);
86
+ }
87
+ process.exit(1);
88
+ }
89
+ // Filter to code files, excluding tests, configs, etc.
90
+ const codeFiles = newFiles.filter((f) => {
91
+ const ext = path.extname(f);
92
+ if (!CODE_EXTENSIONS.has(ext))
93
+ return false;
94
+ return !IGNORED_PATTERNS.some((p) => p.test(f));
95
+ });
96
+ if (codeFiles.length === 0) {
97
+ const result = { newFiles: [], unreferencedCount: 0 };
98
+ if (options.json) {
99
+ outputJson(result);
100
+ }
101
+ else {
102
+ console.log('\nNo new code files to check.');
103
+ }
104
+ return;
105
+ }
106
+ // Get all tracked files in the repo for reference checking
107
+ let allFiles;
108
+ try {
109
+ allFiles = execFileSync('git', ['ls-files'], {
110
+ encoding: 'utf-8',
111
+ timeout: 10000,
112
+ })
113
+ .trim()
114
+ .split('\n')
115
+ .filter(Boolean);
116
+ }
117
+ catch (err) {
118
+ // git ls-files failed (e.g. not a git repo) — proceed without reference list
119
+ debug('check-integration', 'git ls-files failed, reference checking will be skipped', err);
120
+ allFiles = [];
121
+ }
122
+ // For each new file, search for references in the repo
123
+ const results = [];
124
+ for (const newFile of codeFiles) {
125
+ const importName = getImportName(newFile);
126
+ const fileWithoutExt = newFile.replace(/\.[^.]+$/, '');
127
+ // Search for references using git grep (fast, respects .gitignore)
128
+ let referencedBy = [];
129
+ // Search for: import from './filename', require('./filename'), or just the filename stem
130
+ const patterns = [
131
+ importName, // bare name (covers most import patterns)
132
+ ];
133
+ // Also search for path-based imports (relative path without extension)
134
+ if (fileWithoutExt.includes('/')) {
135
+ patterns.push(fileWithoutExt);
136
+ }
137
+ for (const pattern of patterns) {
138
+ try {
139
+ const grepOutput = execFileSync('git', ['grep', '-l', '--', pattern], {
140
+ encoding: 'utf-8',
141
+ timeout: 10000,
142
+ }).trim();
143
+ if (grepOutput) {
144
+ const matches = grepOutput.split('\n').filter((f) => f !== newFile);
145
+ referencedBy.push(...matches);
146
+ }
147
+ }
148
+ catch (error) {
149
+ // git grep exit code 1 = no matches (expected), exit code 2+ = real error
150
+ const exitCode = error && typeof error === 'object' && 'status' in error ? error.status : null;
151
+ if (exitCode !== null && exitCode !== 1) {
152
+ const msg = error instanceof Error ? error.message : String(error);
153
+ console.error(`Warning: git grep failed for "${pattern}": ${msg}`);
154
+ }
155
+ }
156
+ }
157
+ // Deduplicate
158
+ referencedBy = [...new Set(referencedBy)];
159
+ const isIntegrated = referencedBy.length > 0;
160
+ const info = {
161
+ path: newFile,
162
+ referencedBy,
163
+ isIntegrated,
164
+ };
165
+ if (!isIntegrated) {
166
+ info.suggestedEntryPoints = suggestEntryPoints(newFile, allFiles);
167
+ }
168
+ results.push(info);
169
+ }
170
+ const unreferencedCount = results.filter((r) => !r.isIntegrated).length;
171
+ const output = { newFiles: results, unreferencedCount };
172
+ if (options.json) {
173
+ outputJson(output);
174
+ }
175
+ else {
176
+ console.log(`\nšŸ” Integration Check (base: ${base})\n`);
177
+ console.log(`New files: ${results.length} | Unreferenced: ${unreferencedCount}\n`);
178
+ for (const file of results) {
179
+ const status = file.isIntegrated ? 'āœ…' : 'āš ļø';
180
+ console.log(`${status} ${file.path}`);
181
+ if (file.isIntegrated) {
182
+ console.log(` Referenced by: ${file.referencedBy.join(', ')}`);
183
+ }
184
+ else {
185
+ console.log(' Not referenced by any file');
186
+ if (file.suggestedEntryPoints && file.suggestedEntryPoints.length > 0) {
187
+ console.log(` Suggested entry points: ${file.suggestedEntryPoints.join(', ')}`);
188
+ }
189
+ }
190
+ }
191
+ }
192
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Comments, Post, and Claim commands
3
+ * Handles GitHub comment interactions
4
+ */
5
+ interface CommentsOptions {
6
+ prUrl: string;
7
+ showBots?: boolean;
8
+ json?: boolean;
9
+ }
10
+ interface PostOptions {
11
+ url: string;
12
+ message?: string;
13
+ stdin?: boolean;
14
+ json?: boolean;
15
+ }
16
+ interface ClaimOptions {
17
+ issueUrl: string;
18
+ message?: string;
19
+ json?: boolean;
20
+ }
21
+ export declare function runComments(options: CommentsOptions): Promise<void>;
22
+ export declare function runPost(options: PostOptions): Promise<void>;
23
+ export declare function runClaim(options: ClaimOptions): Promise<void>;
24
+ export {};