@humanbased/crosscheck 0.14.0 → 0.15.0-beta.103

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 (145) hide show
  1. package/README.md +147 -4
  2. package/crosscheck.config.example.yml +3 -1
  3. package/dist/__tests__/backtrace.test.js +1 -1
  4. package/dist/__tests__/backtrace.test.js.map +1 -1
  5. package/dist/__tests__/durations.test.js +5 -1
  6. package/dist/__tests__/durations.test.js.map +1 -1
  7. package/dist/__tests__/fix.test.js +48 -1
  8. package/dist/__tests__/fix.test.js.map +1 -1
  9. package/dist/__tests__/kickass.test.js +362 -69
  10. package/dist/__tests__/kickass.test.js.map +1 -1
  11. package/dist/__tests__/optimize.test.js +3 -3
  12. package/dist/__tests__/optimize.test.js.map +1 -1
  13. package/dist/__tests__/pr-picker.test.js +8 -7
  14. package/dist/__tests__/pr-picker.test.js.map +1 -1
  15. package/dist/__tests__/pr-status.test.js +41 -20
  16. package/dist/__tests__/pr-status.test.js.map +1 -1
  17. package/dist/__tests__/pr-workflow-state.test.d.ts +2 -0
  18. package/dist/__tests__/pr-workflow-state.test.d.ts.map +1 -0
  19. package/dist/__tests__/pr-workflow-state.test.js +184 -0
  20. package/dist/__tests__/pr-workflow-state.test.js.map +1 -0
  21. package/dist/__tests__/review-models.test.js +1 -0
  22. package/dist/__tests__/review-models.test.js.map +1 -1
  23. package/dist/__tests__/run.test.d.ts +2 -0
  24. package/dist/__tests__/run.test.d.ts.map +1 -0
  25. package/dist/__tests__/run.test.js +81 -0
  26. package/dist/__tests__/run.test.js.map +1 -0
  27. package/dist/__tests__/runner.test.js +117 -1
  28. package/dist/__tests__/runner.test.js.map +1 -1
  29. package/dist/__tests__/smart-switch.test.js +1 -1
  30. package/dist/__tests__/smart-switch.test.js.map +1 -1
  31. package/dist/__tests__/tier-timeouts.test.d.ts +2 -0
  32. package/dist/__tests__/tier-timeouts.test.d.ts.map +1 -0
  33. package/dist/__tests__/tier-timeouts.test.js +23 -0
  34. package/dist/__tests__/tier-timeouts.test.js.map +1 -0
  35. package/dist/__tests__/webhook.test.d.ts +2 -0
  36. package/dist/__tests__/webhook.test.d.ts.map +1 -0
  37. package/dist/__tests__/webhook.test.js +197 -0
  38. package/dist/__tests__/webhook.test.js.map +1 -0
  39. package/dist/cli.js +38 -5
  40. package/dist/cli.js.map +1 -1
  41. package/dist/commands/detect-step.d.ts +5 -0
  42. package/dist/commands/detect-step.d.ts.map +1 -0
  43. package/dist/commands/detect-step.js +124 -0
  44. package/dist/commands/detect-step.js.map +1 -0
  45. package/dist/commands/kickass.d.ts +18 -10
  46. package/dist/commands/kickass.d.ts.map +1 -1
  47. package/dist/commands/kickass.js +234 -63
  48. package/dist/commands/kickass.js.map +1 -1
  49. package/dist/commands/review.d.ts.map +1 -1
  50. package/dist/commands/review.js +14 -5
  51. package/dist/commands/review.js.map +1 -1
  52. package/dist/commands/run.d.ts +16 -1
  53. package/dist/commands/run.d.ts.map +1 -1
  54. package/dist/commands/run.js +347 -44
  55. package/dist/commands/run.js.map +1 -1
  56. package/dist/commands/serve.d.ts.map +1 -1
  57. package/dist/commands/serve.js +41 -3
  58. package/dist/commands/serve.js.map +1 -1
  59. package/dist/commands/watch.d.ts.map +1 -1
  60. package/dist/commands/watch.js +200 -6
  61. package/dist/commands/watch.js.map +1 -1
  62. package/dist/config/schema.d.ts +52 -0
  63. package/dist/config/schema.d.ts.map +1 -1
  64. package/dist/config/schema.js +24 -1
  65. package/dist/config/schema.js.map +1 -1
  66. package/dist/github/client.d.ts +40 -1
  67. package/dist/github/client.d.ts.map +1 -1
  68. package/dist/github/client.js +69 -9
  69. package/dist/github/client.js.map +1 -1
  70. package/dist/github/review-status.d.ts.map +1 -1
  71. package/dist/github/review-status.js +7 -4
  72. package/dist/github/review-status.js.map +1 -1
  73. package/dist/github/webhook.d.ts +25 -1
  74. package/dist/github/webhook.d.ts.map +1 -1
  75. package/dist/github/webhook.js +37 -1
  76. package/dist/github/webhook.js.map +1 -1
  77. package/dist/lib/annotation.d.ts +4 -0
  78. package/dist/lib/annotation.d.ts.map +1 -1
  79. package/dist/lib/annotation.js +5 -1
  80. package/dist/lib/annotation.js.map +1 -1
  81. package/dist/lib/comment-bodies.d.ts.map +1 -1
  82. package/dist/lib/comment-bodies.js +3 -2
  83. package/dist/lib/comment-bodies.js.map +1 -1
  84. package/dist/lib/durations.d.ts.map +1 -1
  85. package/dist/lib/durations.js +5 -3
  86. package/dist/lib/durations.js.map +1 -1
  87. package/dist/lib/logger.d.ts +3 -0
  88. package/dist/lib/logger.d.ts.map +1 -1
  89. package/dist/lib/logger.js +29 -3
  90. package/dist/lib/logger.js.map +1 -1
  91. package/dist/lib/pr-picker.d.ts.map +1 -1
  92. package/dist/lib/pr-picker.js +5 -1
  93. package/dist/lib/pr-picker.js.map +1 -1
  94. package/dist/lib/pr-status.d.ts +4 -3
  95. package/dist/lib/pr-status.d.ts.map +1 -1
  96. package/dist/lib/pr-status.js +19 -13
  97. package/dist/lib/pr-status.js.map +1 -1
  98. package/dist/lib/pr-workflow-state.d.ts +68 -0
  99. package/dist/lib/pr-workflow-state.d.ts.map +1 -0
  100. package/dist/lib/pr-workflow-state.js +328 -0
  101. package/dist/lib/pr-workflow-state.js.map +1 -0
  102. package/dist/lib/product.d.ts +3 -0
  103. package/dist/lib/product.d.ts.map +1 -0
  104. package/dist/lib/product.js +5 -0
  105. package/dist/lib/product.js.map +1 -0
  106. package/dist/lib/repo-picker.d.ts +1 -0
  107. package/dist/lib/repo-picker.d.ts.map +1 -1
  108. package/dist/lib/repo-picker.js +50 -33
  109. package/dist/lib/repo-picker.js.map +1 -1
  110. package/dist/lib/runner.d.ts +19 -1
  111. package/dist/lib/runner.d.ts.map +1 -1
  112. package/dist/lib/runner.js +337 -54
  113. package/dist/lib/runner.js.map +1 -1
  114. package/dist/lib/smart-switch.js +1 -1
  115. package/dist/lib/smart-switch.js.map +1 -1
  116. package/dist/lib/vendor.d.ts +4 -0
  117. package/dist/lib/vendor.d.ts.map +1 -0
  118. package/dist/lib/vendor.js +14 -0
  119. package/dist/lib/vendor.js.map +1 -0
  120. package/dist/lib/workflow.d.ts +5 -0
  121. package/dist/lib/workflow.d.ts.map +1 -1
  122. package/dist/lib/workflow.js.map +1 -1
  123. package/dist/reviewers/claude.d.ts +3 -1
  124. package/dist/reviewers/claude.d.ts.map +1 -1
  125. package/dist/reviewers/claude.js +14 -9
  126. package/dist/reviewers/claude.js.map +1 -1
  127. package/dist/reviewers/codex.d.ts +1 -1
  128. package/dist/reviewers/codex.d.ts.map +1 -1
  129. package/dist/reviewers/codex.js +7 -10
  130. package/dist/reviewers/codex.js.map +1 -1
  131. package/dist/reviewers/conflict-resolve.d.ts +1 -1
  132. package/dist/reviewers/conflict-resolve.d.ts.map +1 -1
  133. package/dist/reviewers/conflict-resolve.js +3 -2
  134. package/dist/reviewers/conflict-resolve.js.map +1 -1
  135. package/dist/reviewers/fix.d.ts +5 -1
  136. package/dist/reviewers/fix.d.ts.map +1 -1
  137. package/dist/reviewers/fix.js +68 -2
  138. package/dist/reviewers/fix.js.map +1 -1
  139. package/dist/reviewers/tier-timeouts.d.ts +5 -0
  140. package/dist/reviewers/tier-timeouts.d.ts.map +1 -0
  141. package/dist/reviewers/tier-timeouts.js +14 -0
  142. package/dist/reviewers/tier-timeouts.js.map +1 -0
  143. package/get-started.md +56 -5
  144. package/get-started.zh.md +7 -1
  145. package/package.json +1 -1
@@ -0,0 +1,328 @@
1
+ import { parseAnnotation, parseAnnotationFields } from './annotation.js';
2
+ import { evaluateWhen, DEFAULT_RECHECK_INSTRUCTIONS } from './workflow.js';
3
+ import { parseVerdict } from './verdict.js';
4
+ import { fetchPRCommentPage, fetchPRCommitPage } from '../github/client.js';
5
+ const VALID_STEP_TYPES = new Set(['review', 'recheck', 'fix', 'conflict-resolve']);
6
+ function commentToRecord(comment) {
7
+ const fields = parseAnnotationFields(comment.body);
8
+ if (!fields) {
9
+ // No annotation at all — detect legacy review comments by header pattern
10
+ if (comment.body.includes('### Code Review by') && !comment.body.startsWith('> Recheck of')) {
11
+ const { verdict } = parseVerdict(comment.body);
12
+ return {
13
+ type: 'review',
14
+ ...(verdict !== null && { verdict }),
15
+ round: 1,
16
+ commentId: comment.id,
17
+ commentBody: comment.body,
18
+ createdAt: comment.created_at,
19
+ };
20
+ }
21
+ return null;
22
+ }
23
+ // Bareword markers: fix_applied and conflict_resolved have no origin/reviewer fields
24
+ const marker = fields.get('__marker__');
25
+ if (marker === 'fix_applied') {
26
+ // The fix comment body embeds the pushed SHA as a full commit URL — extract it
27
+ // so identifyNextWorkflowStep can verify the fix commit before routing to recheck.
28
+ const shaMatch = comment.body.match(/\/commit\/([0-9a-f]{40})/i);
29
+ const pushedSha = shaMatch ? shaMatch[1] : undefined;
30
+ return { type: 'fix', round: 1, commentId: comment.id, commentBody: comment.body, createdAt: comment.created_at, ...(pushedSha !== undefined && { pushedSha }) };
31
+ }
32
+ if (marker === 'conflict_resolved') {
33
+ return { type: 'conflict-resolve', round: 1, commentId: comment.id, commentBody: comment.body, createdAt: comment.created_at };
34
+ }
35
+ // Full annotation (requires origin + reviewer)
36
+ const parsed = parseAnnotation(comment.body);
37
+ if (!parsed)
38
+ return null;
39
+ const type = parsed.type;
40
+ if (!VALID_STEP_TYPES.has(type))
41
+ return null;
42
+ const verdict = parsed.verdict && parsed.verdict !== 'UNKNOWN' ? parsed.verdict : undefined;
43
+ return {
44
+ type,
45
+ ...(verdict !== undefined && { verdict }),
46
+ ...(parsed.sha !== undefined && { sha: parsed.sha }),
47
+ round: parsed.round,
48
+ commentId: comment.id,
49
+ commentBody: comment.body,
50
+ createdAt: comment.created_at,
51
+ reviewer: parsed.reviewer,
52
+ ...(parsed.model !== 'default' && { model: parsed.model }),
53
+ ...(parsed.next_step !== undefined && { next_step: parsed.next_step }),
54
+ };
55
+ }
56
+ export function commitToRecord(commit) {
57
+ const trailers = parseCommitTrailers(commit.commit.message);
58
+ const step = trailers.get('crosscheck-step');
59
+ if (step !== 'fix' && step !== 'conflict-resolve')
60
+ return null;
61
+ const createdAt = commit.commit.committer?.date ?? commit.commit.author?.date;
62
+ if (!createdAt)
63
+ return null;
64
+ return {
65
+ type: step,
66
+ pushedSha: commit.sha,
67
+ round: 1,
68
+ commentId: 0,
69
+ commentBody: commit.commit.message,
70
+ createdAt,
71
+ source: 'commit',
72
+ ...(trailers.has('crosscheck-reviewer') && { reviewer: trailers.get('crosscheck-reviewer') }),
73
+ ...(trailers.has('crosscheck-model') && { model: trailers.get('crosscheck-model') }),
74
+ };
75
+ }
76
+ function parseCommitTrailers(message) {
77
+ const trailers = new Map();
78
+ for (const line of message.split('\n')) {
79
+ const match = line.match(/^\s*(Crosscheck-[A-Za-z-]+):\s*(.*?)\s*$/);
80
+ if (match)
81
+ trailers.set(match[1].toLowerCase(), match[2]);
82
+ }
83
+ return trailers;
84
+ }
85
+ async function fetchCommitHistory(owner, repo, prNumber, token) {
86
+ const records = [];
87
+ let page = 1;
88
+ while (true) {
89
+ const commits = await fetchPRCommitPage(owner, repo, prNumber, token, page);
90
+ if (commits.length === 0)
91
+ break;
92
+ for (const commit of commits) {
93
+ const record = commitToRecord(commit);
94
+ if (record)
95
+ records.push(record);
96
+ }
97
+ if (commits.length < 100)
98
+ break;
99
+ page++;
100
+ }
101
+ return records;
102
+ }
103
+ function mergeStepHistory(commentRecords, commitRecords) {
104
+ const commentedStepShas = new Set(commentRecords
105
+ .filter(r => (r.type === 'fix' || r.type === 'conflict-resolve') && r.pushedSha)
106
+ .map(r => r.pushedSha));
107
+ const uniqueCommitRecords = commitRecords.filter(r => !r.pushedSha || !commentedStepShas.has(r.pushedSha));
108
+ return [...commentRecords, ...uniqueCommitRecords]
109
+ .sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
110
+ }
111
+ /**
112
+ * Fetch all crosscheck step records from PR comments and crosscheck commit
113
+ * trailers in chronological order.
114
+ * All HTTP calls go through github/client.ts.
115
+ *
116
+ * Fast path (new annotations with next_step):
117
+ * 1. Fetch the last page to find the most recent review/recheck annotation.
118
+ * 2. If it carries next_step, fetch only comments after it (?since=) to check for
119
+ * trailing fix markers — skipping the entire earlier thread.
120
+ *
121
+ * Full scan fallback (legacy annotations without next_step):
122
+ * Read all pages from page 1.
123
+ */
124
+ export async function fetchStepHistory(owner, repo, prNumber, token) {
125
+ // Fetch the first page to discover total pagination
126
+ const { comments: firstPage, lastPage } = await fetchPRCommentPage(owner, repo, prNumber, token);
127
+ const commitHistory = await fetchCommitHistory(owner, repo, prNumber, token);
128
+ if (firstPage.length === 0)
129
+ return mergeStepHistory([], commitHistory);
130
+ // ── Fast path ──────────────────────────────────────────────────────────────
131
+ if (lastPage !== null && lastPage > 1) {
132
+ const { comments: tailPage } = await fetchPRCommentPage(owner, repo, prNumber, token, { page: lastPage });
133
+ const anchor = [...tailPage].reverse().find(c => {
134
+ const r = commentToRecord(c);
135
+ return r !== null && (r.type === 'review' || r.type === 'recheck') && r.next_step !== undefined;
136
+ });
137
+ if (anchor) {
138
+ const anchorRecord = commentToRecord(anchor);
139
+ const { comments: sinceComments } = await fetchPRCommentPage(owner, repo, prNumber, token, { since: anchor.created_at });
140
+ const seen = new Set([anchorRecord.commentId]);
141
+ const trailing = [];
142
+ for (const c of sinceComments) {
143
+ if (seen.has(c.id))
144
+ continue;
145
+ seen.add(c.id);
146
+ const r = commentToRecord(c);
147
+ if (r)
148
+ trailing.push(r);
149
+ }
150
+ return mergeStepHistory([anchorRecord, ...trailing], commitHistory);
151
+ }
152
+ }
153
+ // ── Full scan fallback ─────────────────────────────────────────────────────
154
+ const allComments = [...firstPage];
155
+ let page = 2;
156
+ while (true) {
157
+ const { comments } = await fetchPRCommentPage(owner, repo, prNumber, token, { page });
158
+ if (comments.length === 0)
159
+ break;
160
+ allComments.push(...comments);
161
+ if (comments.length < 100)
162
+ break;
163
+ page++;
164
+ }
165
+ const records = [];
166
+ for (const comment of allComments) {
167
+ const record = commentToRecord(comment);
168
+ if (record)
169
+ records.push(record);
170
+ }
171
+ return mergeStepHistory(records, commitHistory);
172
+ }
173
+ /**
174
+ * Given the PR's step history and the current HEAD SHA, determine which workflow
175
+ * step should run next.
176
+ *
177
+ * The algorithm replays the history from the end:
178
+ * 1. No review/recheck on record → start from the first workflow step.
179
+ * 2. Any non-APPROVE review/recheck without a later fix → fix is next.
180
+ * 3. A fix after the last review/recheck → recheck is next.
181
+ * 4. Current SHA has not been analyzed after the initial review → recheck is next.
182
+ * 5. Current SHA already reviewed → walk the workflow steps that follow
183
+ * and return the first whose `when` condition evaluates to true and
184
+ * that hasn't already been completed in history.
185
+ */
186
+ export function identifyNextWorkflowStep(history, steps, currentSha) {
187
+ const reviewHistory = history.filter(r => r.type === 'review' || r.type === 'recheck');
188
+ const hasExistingReview = reviewHistory.length > 0;
189
+ if (!hasExistingReview) {
190
+ const firstStep = firstIncompleteInitialStep(history, steps);
191
+ return { step: firstStep, hasExistingReview: false, round: 1, history };
192
+ }
193
+ const lastReview = reviewHistory[reviewHistory.length - 1];
194
+ const lastReviewIdx = history.lastIndexOf(lastReview);
195
+ const historyAfterReview = history.slice(lastReviewIdx + 1);
196
+ // Only check for explicit fix/conflict-resolve markers after the last review.
197
+ // Do NOT short-circuit based on lastReview.type === 'recheck': after a BLOCK or
198
+ // NEEDS_WORK recheck, fix still needs to run. The fix step's `when` condition
199
+ // (e.g. "review.verdict != 'APPROVE'") correctly gates it on APPROVE alone.
200
+ const lastFixAfterReview = historyAfterReview.filter(r => r.type === 'fix').at(-1);
201
+ const conflictAfterReview = historyAfterReview.some(r => r.type === 'conflict-resolve');
202
+ const fixAfterReview = lastFixAfterReview !== undefined || conflictAfterReview;
203
+ // Build synthetic results so evaluateWhen works correctly for downstream steps.
204
+ // Always populate under the literal key 'review' so conditions like
205
+ // "review.verdict != 'APPROVE'" work regardless of the step's name in the workflow.
206
+ const syntheticResults = {
207
+ review: { verdict: lastReview.verdict },
208
+ };
209
+ const reviewStepDef = steps.find(s => s.type === 'review' || s.type === 'recheck');
210
+ if (reviewStepDef && reviewStepDef.name !== 'review') {
211
+ syntheticResults[reviewStepDef.name] = { verdict: lastReview.verdict };
212
+ }
213
+ if (fixAfterReview) {
214
+ syntheticResults['fix'] = { applied_count: 1 };
215
+ const fixStepDef = steps.find(s => s.type === 'fix');
216
+ if (fixStepDef && fixStepDef.name !== 'fix')
217
+ syntheticResults[fixStepDef.name] = { applied_count: 1 };
218
+ }
219
+ const reviewComment = { id: lastReview.commentId, body: lastReview.commentBody };
220
+ const reviewedCurrentSha = lastReview.sha !== undefined && lastReview.sha === currentSha;
221
+ const fixedCurrentSha = lastFixAfterReview?.pushedSha !== undefined && lastFixAfterReview.pushedSha === currentSha;
222
+ if (fixedCurrentSha) {
223
+ return {
224
+ step: effectiveRecheckStep(steps),
225
+ reviewComment,
226
+ hasExistingReview: true,
227
+ round: lastReview.round,
228
+ history,
229
+ };
230
+ }
231
+ if (lastFixAfterReview !== undefined && !fixedCurrentSha) {
232
+ const reviewStep = steps.find(s => s.type === 'review') ?? steps[0] ?? null;
233
+ return {
234
+ step: reviewStep,
235
+ hasExistingReview: true,
236
+ round: lastReview.round + 1,
237
+ history,
238
+ };
239
+ }
240
+ const fixStep = firstRunnableFixStep(steps, syntheticResults);
241
+ if (fixStep) {
242
+ return {
243
+ step: fixStep,
244
+ reviewComment,
245
+ hasExistingReview: true,
246
+ round: lastReview.round,
247
+ history,
248
+ };
249
+ }
250
+ if (!reviewedCurrentSha) {
251
+ const reviewStep = steps.find(s => s.type === 'review') ?? steps[0] ?? null;
252
+ return {
253
+ step: reviewStep,
254
+ hasExistingReview: true,
255
+ round: lastReview.round + 1,
256
+ history,
257
+ };
258
+ }
259
+ // Current SHA has been reviewed — find the first incomplete step that follows
260
+ let passedReview = false;
261
+ for (const step of steps) {
262
+ if (step.type === 'review' || step.type === 'recheck') {
263
+ passedReview = true;
264
+ continue; // done for this sha
265
+ }
266
+ if (!passedReview)
267
+ continue;
268
+ if (step.when && !evaluateWhen(step.when, syntheticResults))
269
+ continue;
270
+ if (step.type === 'fix') {
271
+ if (fixAfterReview) {
272
+ syntheticResults[step.name] = { applied_count: 1 };
273
+ syntheticResults['fix'] = { applied_count: 1 };
274
+ continue; // already ran
275
+ }
276
+ return {
277
+ step,
278
+ reviewComment: { id: lastReview.commentId, body: lastReview.commentBody },
279
+ hasExistingReview: true,
280
+ round: lastReview.round,
281
+ history,
282
+ };
283
+ }
284
+ if (step.type === 'conflict-resolve') {
285
+ const conflictDone = historyAfterReview.some(r => r.type === 'conflict-resolve');
286
+ if (conflictDone)
287
+ continue;
288
+ return { step, hasExistingReview: true, round: lastReview.round, history };
289
+ }
290
+ }
291
+ return { step: null, hasExistingReview: true, round: lastReview.round, history };
292
+ }
293
+ function firstIncompleteInitialStep(history, steps) {
294
+ for (const step of steps) {
295
+ if (step.type === 'conflict-resolve') {
296
+ const conflictDone = history.some(r => r.type === 'conflict-resolve');
297
+ if (!conflictDone)
298
+ return step;
299
+ continue;
300
+ }
301
+ return step;
302
+ }
303
+ return null;
304
+ }
305
+ function firstRunnableFixStep(steps, syntheticResults) {
306
+ for (const step of steps) {
307
+ if (step.type !== 'fix')
308
+ continue;
309
+ if (step.when && !evaluateWhen(step.when, syntheticResults))
310
+ continue;
311
+ return step;
312
+ }
313
+ return null;
314
+ }
315
+ function effectiveRecheckStep(steps) {
316
+ const recheckStep = steps.find(s => s.type === 'recheck');
317
+ if (recheckStep)
318
+ return recheckStep;
319
+ const reviewBase = steps.find(s => s.type === 'review');
320
+ return {
321
+ ...(reviewBase ?? { reviewer: 'auto', max_rounds: 1 }),
322
+ name: 'recheck',
323
+ type: 'recheck',
324
+ when: undefined,
325
+ instructions: DEFAULT_RECHECK_INSTRUCTIONS,
326
+ };
327
+ }
328
+ //# sourceMappingURL=pr-workflow-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-workflow-state.js","sourceRoot":"","sources":["../../src/lib/pr-workflow-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const CROSSCHECK_REPO_URL = "https://github.com/humanbased-ai/crosscheck";
2
+ export declare const CROSSCHECK_ISSUES_URL = "https://github.com/humanbased-ai/crosscheck/issues";
3
+ //# sourceMappingURL=product.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product.d.ts","sourceRoot":"","sources":["../../src/lib/product.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,mBAAmB,gDAAgD,CAAA;AAChF,eAAO,MAAM,qBAAqB,uDAAkC,CAAA"}
@@ -0,0 +1,5 @@
1
+ // Single source of truth for crosscheck's own project URLs.
2
+ // Update here if the project moves to a different org or repo name.
3
+ export const CROSSCHECK_REPO_URL = 'https://github.com/humanbased-ai/crosscheck';
4
+ export const CROSSCHECK_ISSUES_URL = `${CROSSCHECK_REPO_URL}/issues`;
5
+ //# sourceMappingURL=product.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product.js","sourceRoot":"","sources":["../../src/lib/product.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,oEAAoE;AACpE,MAAM,CAAC,MAAM,mBAAmB,GAAG,6CAA6C,CAAA;AAChF,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,mBAAmB,SAAS,CAAA"}
@@ -17,6 +17,7 @@ export interface PickerOptions {
17
17
  title?: string;
18
18
  initialSelected?: string[];
19
19
  pageSize?: number;
20
+ selectAllLabel?: string;
20
21
  getDescription?: (item: string) => string;
21
22
  }
22
23
  export declare function promptRepoPicker(items: string[], opts?: PickerOptions): Promise<string[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"repo-picker.d.ts","sourceRoot":"","sources":["../../src/lib/repo-picker.ts"],"names":[],"mappings":"AAuBA,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQtE;AAID,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,MAAM,CAOR;AAGD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAK9F;AAKD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK5D;AAOD,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,GAChB,MAAM,CAIR;AAID,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAID,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,UAAU,EAAE,EACnB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GACtE,OAAO,CAAC,MAAM,CAAC,CA2GjB;AAID,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAC1C;AASD,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC,CAsOnB"}
1
+ {"version":3,"file":"repo-picker.d.ts","sourceRoot":"","sources":["../../src/lib/repo-picker.ts"],"names":[],"mappings":"AAuBA,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQtE;AAID,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,MAAM,CAOR;AAGD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAK9F;AAKD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK5D;AAOD,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,GAChB,MAAM,CAIR;AAID,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAID,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,UAAU,EAAE,EACnB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GACtE,OAAO,CAAC,MAAM,CAAC,CA2GjB;AAID,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAC1C;AASD,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC,CAsPnB"}
@@ -188,25 +188,39 @@ export async function promptRepoPicker(items, opts = {}) {
188
188
  if (items.length === 0)
189
189
  return [];
190
190
  return new Promise((resolve, reject) => {
191
+ const allRow = -1;
191
192
  const selected = new Set(opts.initialSelected
192
193
  ? opts.initialSelected.map(s => items.indexOf(s)).filter(i => i !== -1)
193
194
  : []);
194
195
  let filterText = '';
195
196
  let filterMode = false;
196
197
  let filtered = filterIndices(items, '');
197
- let cursorPos = 0; // index into `filtered`
198
+ let cursorPos = opts.selectAllLabel && items.length > 0 ? 1 : 0; // index into `filtered`
198
199
  let windowStart = 0; // index into `filtered`
199
200
  let lastLineCount = 0;
200
201
  const viewport = () => resolveViewport(opts.pageSize, process.stdout.rows);
202
+ const displayIndices = () => (opts.selectAllLabel && filtered.length > 0 ? [allRow, ...filtered] : filtered);
203
+ const allVisibleSelected = () => filtered.length > 0 && filtered.every(i => selected.has(i));
204
+ const toggleAllVisible = () => {
205
+ const allOn = allVisibleSelected();
206
+ if (allOn)
207
+ for (const i of filtered)
208
+ selected.delete(i);
209
+ else
210
+ for (const i of filtered)
211
+ selected.add(i);
212
+ };
201
213
  function recomputeFiltered() {
202
214
  filtered = filterIndices(items, filterText);
203
- if (cursorPos >= filtered.length)
204
- cursorPos = Math.max(0, filtered.length - 1);
205
- windowStart = adjustWindowStart(windowStart, cursorPos, viewport(), filtered.length);
215
+ const displayed = displayIndices();
216
+ if (cursorPos >= displayed.length)
217
+ cursorPos = Math.max(0, displayed.length - 1);
218
+ windowStart = adjustWindowStart(windowStart, cursorPos, viewport(), displayed.length);
206
219
  }
207
220
  function render(firstRender = false) {
208
221
  const vp = viewport();
209
- windowStart = adjustWindowStart(windowStart, cursorPos, vp, filtered.length);
222
+ const displayed = displayIndices();
223
+ windowStart = adjustWindowStart(windowStart, cursorPos, vp, displayed.length);
210
224
  if (!firstRender) {
211
225
  process.stdout.write(`\x1b[${lastLineCount}A`);
212
226
  // Erase leftover content from the previous (possibly taller) render so a
@@ -215,8 +229,8 @@ export async function promptRepoPicker(items, opts = {}) {
215
229
  }
216
230
  // Render exactly as many item rows as we have items, capped at the
217
231
  // viewport. Empty filter result → one "(no matches)" hint row instead.
218
- const visibleRows = Math.min(vp, filtered.length);
219
- const emptyHint = filtered.length === 0;
232
+ const visibleRows = Math.min(vp, displayed.length);
233
+ const emptyHint = displayed.length === 0;
220
234
  const itemRows = emptyHint ? 1 : visibleRows;
221
235
  lastLineCount = (opts.title ? 1 : 0) + 1 + itemRows + 1 + 1;
222
236
  if (opts.title) {
@@ -246,12 +260,13 @@ export async function promptRepoPicker(items, opts = {}) {
246
260
  else {
247
261
  for (let row = 0; row < visibleRows; row++) {
248
262
  const fi = windowStart + row;
249
- const origIdx = filtered[fi];
250
- const item = items[origIdx];
251
- const isSelected = selected.has(origIdx);
263
+ const origIdx = displayed[fi];
264
+ const isAllRow = origIdx === allRow;
265
+ const item = isAllRow ? opts.selectAllLabel ?? 'all' : items[origIdx];
266
+ const isSelected = isAllRow ? allVisibleSelected() : selected.has(origIdx);
252
267
  const isFocused = cursorPos === fi;
253
268
  const checkStr = isSelected ? `${CYAN}[x]${RESET}` : '[ ]';
254
- const desc = opts.getDescription ? opts.getDescription(item) : '';
269
+ const desc = isAllRow ? `${filtered.length} PRs` : opts.getDescription ? opts.getDescription(item) : '';
255
270
  // Budget: cols - 2 (indent) - 4 ("[x] ") - (desc.length + 2 spaces if desc).
256
271
  const descBudget = desc ? desc.length + 2 : 0;
257
272
  const labelMax = Math.max(1, cols - 6 - descBudget);
@@ -262,15 +277,16 @@ export async function promptRepoPicker(items, opts = {}) {
262
277
  }
263
278
  }
264
279
  const total = filtered.length;
265
- const pos = total === 0 ? 0 : cursorPos + 1;
280
+ const displayedTotal = displayed.length;
281
+ const pos = displayedTotal === 0 ? 0 : cursorPos + 1;
266
282
  const selCount = selected.size;
267
283
  const filterNote = filterText ? ` · filter: "${filterText}"` : '';
268
284
  const selNote = selCount > 0 ? ` · ${selCount} selected` : '';
269
- const statusLine = truncate(`${pos}/${total}${filterNote}${selNote}`, innerWidth);
285
+ const statusLine = truncate(`${pos}/${displayedTotal}${filterNote}${selNote}`, innerWidth);
270
286
  process.stdout.write(`${ERASE_LINE}${DIM} ${statusLine}${RESET}\n`);
271
287
  // PgUp/PgDn only when the *current* visible list overflows the viewport.
272
288
  // After a filter narrows the list, the hint shrinks accordingly.
273
- const navHint = filtered.length > vp ? '↑↓ PgUp/PgDn move' : '↑↓ move';
289
+ const navHint = displayed.length > vp ? '↑↓ PgUp/PgDn move' : '↑↓ move';
274
290
  const footerLine = filterMode
275
291
  ? `${navHint} · type to filter · backspace · esc clear · enter done`
276
292
  : `${navHint} · space select · a all · / filter · enter confirm`;
@@ -303,16 +319,18 @@ export async function promptRepoPicker(items, opts = {}) {
303
319
  }
304
320
  // Navigation keys work in both modes — let the user scroll while filtering.
305
321
  if (key === '\x1b[A') {
306
- if (filtered.length === 0)
322
+ const displayed = displayIndices();
323
+ if (displayed.length === 0)
307
324
  return;
308
- cursorPos = cursorPos > 0 ? cursorPos - 1 : filtered.length - 1;
325
+ cursorPos = cursorPos > 0 ? cursorPos - 1 : displayed.length - 1;
309
326
  render();
310
327
  return;
311
328
  }
312
329
  if (key === '\x1b[B') {
313
- if (filtered.length === 0)
330
+ const displayed = displayIndices();
331
+ if (displayed.length === 0)
314
332
  return;
315
- cursorPos = cursorPos < filtered.length - 1 ? cursorPos + 1 : 0;
333
+ cursorPos = cursorPos < displayed.length - 1 ? cursorPos + 1 : 0;
316
334
  render();
317
335
  return;
318
336
  }
@@ -320,21 +338,23 @@ export async function promptRepoPicker(items, opts = {}) {
320
338
  // PageUp — advance window AND cursor by one viewport so the page
321
339
  // actually flips. Without the windowStart bump, adjustWindowStart would
322
340
  // only scroll far enough to keep the cursor visible (one row).
323
- if (filtered.length === 0)
341
+ const displayed = displayIndices();
342
+ if (displayed.length === 0)
324
343
  return;
325
344
  const vp = viewport();
326
345
  cursorPos = Math.max(0, cursorPos - vp);
327
- windowStart = advancePageStart(windowStart, vp, filtered.length, -1);
346
+ windowStart = advancePageStart(windowStart, vp, displayed.length, -1);
328
347
  render();
329
348
  return;
330
349
  }
331
350
  if (key === '\x1b[6~') {
332
351
  // PageDown — see PageUp comment.
333
- if (filtered.length === 0)
352
+ const displayed = displayIndices();
353
+ if (displayed.length === 0)
334
354
  return;
335
355
  const vp = viewport();
336
- cursorPos = Math.min(filtered.length - 1, cursorPos + vp);
337
- windowStart = advancePageStart(windowStart, vp, filtered.length, 1);
356
+ cursorPos = Math.min(displayed.length - 1, cursorPos + vp);
357
+ windowStart = advancePageStart(windowStart, vp, displayed.length, 1);
338
358
  render();
339
359
  return;
340
360
  }
@@ -376,10 +396,13 @@ export async function promptRepoPicker(items, opts = {}) {
376
396
  render();
377
397
  }
378
398
  else if (key === ' ') {
379
- if (filtered.length === 0)
399
+ const displayed = displayIndices();
400
+ if (displayed.length === 0)
380
401
  return;
381
- const origIdx = filtered[cursorPos];
382
- if (selected.has(origIdx))
402
+ const origIdx = displayed[cursorPos];
403
+ if (origIdx === allRow)
404
+ toggleAllVisible();
405
+ else if (selected.has(origIdx))
383
406
  selected.delete(origIdx);
384
407
  else
385
408
  selected.add(origIdx);
@@ -387,13 +410,7 @@ export async function promptRepoPicker(items, opts = {}) {
387
410
  }
388
411
  else if (key === 'a') {
389
412
  // Toggle every item in the current filtered view.
390
- const allOn = filtered.every(i => selected.has(i));
391
- if (allOn)
392
- for (const i of filtered)
393
- selected.delete(i);
394
- else
395
- for (const i of filtered)
396
- selected.add(i);
413
+ toggleAllVisible();
397
414
  render();
398
415
  }
399
416
  else if (key === '\r' || key === '\n') {