@humanbased/crosscheck 1.7.2-beta.9 → 1.8.0-beta.20
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/crosscheck.config.example.yml +23 -0
- package/dist/__tests__/author-attribution.test.d.ts +2 -0
- package/dist/__tests__/author-attribution.test.d.ts.map +1 -0
- package/dist/__tests__/author-attribution.test.js +89 -0
- package/dist/__tests__/author-attribution.test.js.map +1 -0
- package/dist/__tests__/comment-bodies.test.js +42 -0
- package/dist/__tests__/comment-bodies.test.js.map +1 -1
- package/dist/__tests__/conflict-resolve.test.js +91 -1
- package/dist/__tests__/conflict-resolve.test.js.map +1 -1
- package/dist/__tests__/onboard-preservation.test.js +15 -0
- package/dist/__tests__/onboard-preservation.test.js.map +1 -1
- package/dist/__tests__/opencode-policy.test.d.ts +2 -0
- package/dist/__tests__/opencode-policy.test.d.ts.map +1 -0
- package/dist/__tests__/opencode-policy.test.js +60 -0
- package/dist/__tests__/opencode-policy.test.js.map +1 -0
- package/dist/__tests__/optimize.test.js +1 -0
- package/dist/__tests__/optimize.test.js.map +1 -1
- package/dist/__tests__/review-comment-body.test.js +22 -0
- package/dist/__tests__/review-comment-body.test.js.map +1 -1
- package/dist/__tests__/runner.test.js +65 -21
- package/dist/__tests__/runner.test.js.map +1 -1
- package/dist/commands/issue.d.ts.map +1 -1
- package/dist/commands/issue.js +5 -3
- package/dist/commands/issue.js.map +1 -1
- package/dist/commands/onboard.d.ts +3 -0
- package/dist/commands/onboard.d.ts.map +1 -1
- package/dist/commands/onboard.js +92 -12
- package/dist/commands/onboard.js.map +1 -1
- package/dist/commands/optimize.d.ts.map +1 -1
- package/dist/commands/optimize.js +5 -3
- package/dist/commands/optimize.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +2 -1
- package/dist/commands/review.js.map +1 -1
- package/dist/config/schema.d.ts +37 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +14 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/github/client.d.ts +4 -1
- package/dist/github/client.d.ts.map +1 -1
- package/dist/github/client.js +5 -3
- package/dist/github/client.js.map +1 -1
- package/dist/lib/author-attribution.d.ts +10 -0
- package/dist/lib/author-attribution.d.ts.map +1 -0
- package/dist/lib/author-attribution.js +94 -0
- package/dist/lib/author-attribution.js.map +1 -0
- package/dist/lib/comment-bodies.d.ts +10 -0
- package/dist/lib/comment-bodies.d.ts.map +1 -1
- package/dist/lib/comment-bodies.js +45 -9
- package/dist/lib/comment-bodies.js.map +1 -1
- package/dist/lib/runner.d.ts +1 -0
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/runner.js +123 -67
- package/dist/lib/runner.js.map +1 -1
- package/dist/reviewers/conflict-resolve.d.ts +7 -3
- package/dist/reviewers/conflict-resolve.d.ts.map +1 -1
- package/dist/reviewers/conflict-resolve.js +199 -11
- package/dist/reviewers/conflict-resolve.js.map +1 -1
- package/dist/reviewers/fix.d.ts.map +1 -1
- package/dist/reviewers/fix.js +4 -2
- package/dist/reviewers/fix.js.map +1 -1
- package/dist/reviewers/opencode.d.ts +3 -2
- package/dist/reviewers/opencode.d.ts.map +1 -1
- package/dist/reviewers/opencode.js +31 -16
- package/dist/reviewers/opencode.js.map +1 -1
- package/get-started.md +21 -1
- package/package.json +1 -1
package/dist/lib/runner.js
CHANGED
|
@@ -9,7 +9,7 @@ import { runCodexReview } from '../reviewers/codex.js';
|
|
|
9
9
|
import { runClaudeReview } from '../reviewers/claude.js';
|
|
10
10
|
import { runOpenCodeReview } from '../reviewers/opencode.js';
|
|
11
11
|
import { runFixStep, runCodexFixStep, runOpenCodeFixStep } from '../reviewers/fix.js';
|
|
12
|
-
import {
|
|
12
|
+
import { runConflictResolveForVendor, findConflictedFiles } from '../reviewers/conflict-resolve.js';
|
|
13
13
|
import { parseVerdict, prependVerdictToComment, NULL_VERDICT_WARNING, applySeverityGate, SEVERITY_GATE_NOTE, DOC_ONLY_GATE_NOTE, detectInconclusiveReview, reviewHasNoFindings } from '../lib/verdict.js';
|
|
14
14
|
import { createGithubClient, postReviewComment, getLastCrossCheckCommentId, getLastCrossCheckReviewComment } from '../github/client.js';
|
|
15
15
|
import { fetchCommentsAfter, selectHumanFeedback, formatHumanFeedback } from '../lib/human-feedback.js';
|
|
@@ -37,6 +37,7 @@ import { tierTimeoutMs } from '../reviewers/tier-timeouts.js';
|
|
|
37
37
|
import { loadSkillCatalog } from '../skills/catalog.js';
|
|
38
38
|
import { createSkillActivationSession } from '../skills/broker.js';
|
|
39
39
|
import { formatSkillAttribution } from '../skills/attribution.js';
|
|
40
|
+
import { parseAuthorAttribution } from './author-attribution.js';
|
|
40
41
|
import { CompromisedCloneError, runGitWithoutHooks, changedFilesVsBase } from './clone.js';
|
|
41
42
|
const MAX_CROSSCHECK_COMMITS = 5;
|
|
42
43
|
const FIX_RETRY_DELAY_MS = 2 * 60 * 1000;
|
|
@@ -249,36 +250,85 @@ function countComments(reviewText) {
|
|
|
249
250
|
const numbered = (reviewText.match(/^\d+\.\s/gm) ?? []).length;
|
|
250
251
|
return bullets + numbered;
|
|
251
252
|
}
|
|
252
|
-
function
|
|
253
|
+
function priorityTaskForStep(stepType) {
|
|
254
|
+
if (stepType === 'conflict-resolve')
|
|
255
|
+
return 'conflict_resolve';
|
|
256
|
+
if (stepType === 'fix')
|
|
257
|
+
return 'fix';
|
|
258
|
+
return 'review';
|
|
259
|
+
}
|
|
260
|
+
function originVendorOf(origin) {
|
|
261
|
+
return origin === 'claude' || origin === 'codex' || origin === 'opencode' ? origin : null;
|
|
262
|
+
}
|
|
263
|
+
// Configured order first, then any other enabled/capable vendor so a newly
|
|
264
|
+
// enabled agent is still usable without re-running onboard. An empty configured
|
|
265
|
+
// list returns [] — callers then use the legacy codex-first order, which keeps
|
|
266
|
+
// pre-priority configs byte-for-byte behaviourally identical.
|
|
267
|
+
function priorityOrder(task, config, stepType) {
|
|
268
|
+
const configured = config.agent_priority?.[task] ?? [];
|
|
269
|
+
if (configured.length === 0)
|
|
270
|
+
return [];
|
|
271
|
+
const usable = (vendor) => config.vendors[vendor].enabled && supportsStep(vendor, stepType);
|
|
272
|
+
const ordered = configured.filter(usable);
|
|
273
|
+
for (const vendor of ['claude', 'codex', 'opencode']) {
|
|
274
|
+
if (usable(vendor) && !ordered.includes(vendor))
|
|
275
|
+
ordered.push(vendor);
|
|
276
|
+
}
|
|
277
|
+
return ordered;
|
|
278
|
+
}
|
|
279
|
+
function legacyAutoReviewer(origin, config) {
|
|
280
|
+
if (origin === 'claude' && config.vendors.codex.enabled)
|
|
281
|
+
return 'codex';
|
|
282
|
+
if (origin === 'claude' && config.vendors.opencode.enabled)
|
|
283
|
+
return 'opencode';
|
|
284
|
+
if (origin === 'codex' && config.vendors.claude.enabled)
|
|
285
|
+
return 'claude';
|
|
286
|
+
if (origin === 'codex' && config.vendors.opencode.enabled)
|
|
287
|
+
return 'opencode';
|
|
288
|
+
if (origin === 'opencode' && config.vendors.claude.enabled)
|
|
289
|
+
return 'claude';
|
|
290
|
+
if (origin === 'opencode' && config.vendors.codex.enabled)
|
|
291
|
+
return 'codex';
|
|
292
|
+
if (config.vendors.codex.enabled)
|
|
293
|
+
return 'codex';
|
|
294
|
+
if (config.vendors.claude.enabled)
|
|
295
|
+
return 'claude';
|
|
296
|
+
if (config.vendors.opencode.enabled)
|
|
297
|
+
return 'opencode';
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
function resolveReviewer(reviewer, origin, config, fallback, stepType = 'review') {
|
|
301
|
+
const originVendor = originVendorOf(origin);
|
|
302
|
+
const task = priorityTaskForStep(stepType);
|
|
303
|
+
const writesCode = stepType === 'fix' || stepType === 'conflict-resolve';
|
|
253
304
|
if (reviewer === 'origin') {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
305
|
+
// Fix and conflict-resolve deliberately start from the PR author's own
|
|
306
|
+
// agent — it has the most context on the change. The configured order only
|
|
307
|
+
// decides who runs when the author is human or that agent is unavailable.
|
|
308
|
+
if (originVendor && config.vendors[originVendor].enabled && supportsStep(originVendor, stepType))
|
|
309
|
+
return originVendor;
|
|
310
|
+
if (writesCode) {
|
|
311
|
+
const preferred = priorityOrder(task, config, stepType)[0];
|
|
312
|
+
if (preferred)
|
|
313
|
+
return preferred;
|
|
314
|
+
}
|
|
260
315
|
return fallback && config.vendors[fallback].enabled ? fallback : null;
|
|
261
316
|
}
|
|
262
317
|
if (reviewer === 'auto') {
|
|
263
|
-
if (
|
|
264
|
-
return
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
if (
|
|
268
|
-
return
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
if (config.vendors.claude.enabled)
|
|
278
|
-
return 'claude';
|
|
279
|
-
if (config.vendors.opencode.enabled)
|
|
280
|
-
return 'opencode';
|
|
281
|
-
return null;
|
|
318
|
+
if (writesCode && originVendor && config.vendors[originVendor].enabled && supportsStep(originVendor, stepType)) {
|
|
319
|
+
return originVendor;
|
|
320
|
+
}
|
|
321
|
+
let ordered = priorityOrder(task, config, stepType);
|
|
322
|
+
if (ordered.length === 0)
|
|
323
|
+
return legacyAutoReviewer(origin, config);
|
|
324
|
+
// Review is cross-vendor even when the author's agent tops the list. Fall
|
|
325
|
+
// back to it only when it is the sole enabled/capable vendor.
|
|
326
|
+
if (!writesCode && ordered.length > 1 && originVendor) {
|
|
327
|
+
const crossVendor = ordered.filter(vendor => vendor !== originVendor);
|
|
328
|
+
if (crossVendor.length > 0)
|
|
329
|
+
ordered = crossVendor;
|
|
330
|
+
}
|
|
331
|
+
return ordered[0] ?? null;
|
|
282
332
|
}
|
|
283
333
|
if (reviewer === 'claude')
|
|
284
334
|
return config.vendors.claude.enabled ? 'claude' : (fallback && config.vendors[fallback].enabled ? fallback : null);
|
|
@@ -288,13 +338,19 @@ function resolveReviewer(reviewer, origin, config, fallback) {
|
|
|
288
338
|
return config.vendors.opencode.enabled ? 'opencode' : (fallback && config.vendors[fallback].enabled ? fallback : null);
|
|
289
339
|
return null;
|
|
290
340
|
}
|
|
341
|
+
// Exported for tests and for review call sites that need the cross-vendor rule.
|
|
342
|
+
export function resolveReviewVendor(stepReviewer, origin, config, fallback) {
|
|
343
|
+
return resolveReviewer(stepReviewer, origin, config, fallback, 'review');
|
|
344
|
+
}
|
|
291
345
|
function supportsStep(vendor, stepType) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
// Conflict resolution is Claude-only until Codex/OpenCode conflict resolution exists.
|
|
295
|
-
return vendor === 'claude';
|
|
346
|
+
void vendor;
|
|
347
|
+
return stepType === 'review' || stepType === 'recheck' || stepType === 'fix' || stepType === 'conflict-resolve';
|
|
296
348
|
}
|
|
297
349
|
function resolveLimitFallbackVendor(failedVendor, stepType, config) {
|
|
350
|
+
const ordered = priorityOrder(priorityTaskForStep(stepType), config, stepType)
|
|
351
|
+
.filter(vendor => vendor !== failedVendor);
|
|
352
|
+
if (ordered.length > 0)
|
|
353
|
+
return ordered[0];
|
|
298
354
|
const candidates = failedVendor === 'claude'
|
|
299
355
|
? ['codex', 'opencode']
|
|
300
356
|
: failedVendor === 'codex'
|
|
@@ -339,16 +395,12 @@ export function conflictResolveCommitSubject(conflictCount, vendor) {
|
|
|
339
395
|
// unsupported-step skip instead of silently substituting a different vendor.
|
|
340
396
|
// null disables the fallback entirely.
|
|
341
397
|
function resolveStepVendor(stepType, stepReviewer, origin, config, fallback) {
|
|
342
|
-
const vendor = resolveReviewer(stepReviewer, origin, config, fallback);
|
|
343
|
-
//
|
|
344
|
-
//
|
|
345
|
-
//
|
|
346
|
-
//
|
|
347
|
-
//
|
|
348
|
-
// and the auto fallback picked Claude.) Substitute a capable, enabled vendor.
|
|
349
|
-
// Scoped to origin-derived assignment only — an explicit reviewer: claude|codex,
|
|
350
|
-
// reviewer: auto, or routing.fallback_reviewer is an operator decision, left as
|
|
351
|
-
// written so the caller can report the precise unsupported-step skip.
|
|
398
|
+
const vendor = resolveReviewer(stepReviewer, origin, config, fallback, stepType);
|
|
399
|
+
// Every current step supports every vendor, so this substitution is a guard
|
|
400
|
+
// for future step capabilities rather than a live path. It stays scoped to
|
|
401
|
+
// origin-derived assignment: an explicit reviewer choice or
|
|
402
|
+
// routing.fallback_reviewer is an operator decision and must be reported
|
|
403
|
+
// precisely instead of silently swapped.
|
|
352
404
|
if (stepReviewer === 'origin' &&
|
|
353
405
|
(origin === 'claude' || origin === 'codex' || origin === 'opencode') &&
|
|
354
406
|
vendor !== null &&
|
|
@@ -358,6 +410,13 @@ function resolveStepVendor(stepType, stepReviewer, origin, config, fallback) {
|
|
|
358
410
|
return { vendor: capable, usedHumanFallback: false, substitutedOriginVendor: vendor };
|
|
359
411
|
}
|
|
360
412
|
}
|
|
413
|
+
// A configured task order is the human-origin fallback now, so report it as
|
|
414
|
+
// one: the fix/conflict-resolve callers use this flag for their fallback log.
|
|
415
|
+
const humanOriginPriority = stepReviewer === 'origin' && origin === 'human'
|
|
416
|
+
&& priorityOrder(priorityTaskForStep(stepType), config, stepType).length > 0;
|
|
417
|
+
if (vendor !== null && humanOriginPriority) {
|
|
418
|
+
return { vendor, usedHumanFallback: true };
|
|
419
|
+
}
|
|
361
420
|
if (vendor !== null || origin !== 'human' || stepReviewer !== 'origin') {
|
|
362
421
|
return { vendor, usedHumanFallback: false };
|
|
363
422
|
}
|
|
@@ -370,10 +429,12 @@ function resolveStepVendor(stepType, stepReviewer, origin, config, fallback) {
|
|
|
370
429
|
else if (fb === 'opencode')
|
|
371
430
|
humanFallback = config.vendors.opencode.enabled ? 'opencode' : null;
|
|
372
431
|
else if (fb !== null) {
|
|
373
|
-
// 'auto':
|
|
374
|
-
//
|
|
432
|
+
// 'auto': the configured task order wins; with no order configured, keep
|
|
433
|
+
// the legacy codex-first preference. Either way, narrow to vendors that
|
|
434
|
+
// support this step type.
|
|
375
435
|
const usable = (v) => config.vendors[v].enabled && supportsStep(v, stepType);
|
|
376
|
-
humanFallback =
|
|
436
|
+
humanFallback = priorityOrder(priorityTaskForStep(stepType), config, stepType)[0]
|
|
437
|
+
?? (usable('codex') ? 'codex' : usable('claude') ? 'claude' : usable('opencode') ? 'opencode' : null);
|
|
377
438
|
}
|
|
378
439
|
if (!humanFallback)
|
|
379
440
|
return { vendor: null, usedHumanFallback: false };
|
|
@@ -741,6 +802,9 @@ export async function pushWithNonFastForwardHandling(params) {
|
|
|
741
802
|
export async function runWorkflow(ctx) {
|
|
742
803
|
const { owner, repoName, prNumber, pr, tmpDir, token, config, origin, log, onPhaseChange, trigger } = ctx;
|
|
743
804
|
const triggerField = trigger !== undefined ? { trigger } : {};
|
|
805
|
+
// The author's declaration lives in the PR body. Parsing it once here means
|
|
806
|
+
// every card this run posts names the same author, model and effort.
|
|
807
|
+
const authorAttribution = parseAuthorAttribution(pr.body ?? '');
|
|
744
808
|
const configuredSteps = (ctx.steps ?? loadWorkflow(process.cwd())).map(step => {
|
|
745
809
|
if (!step.harness || step.instructions)
|
|
746
810
|
return step;
|
|
@@ -946,7 +1010,7 @@ export async function runWorkflow(ctx) {
|
|
|
946
1010
|
}
|
|
947
1011
|
if (effectiveType === 'review' || effectiveType === 'recheck') {
|
|
948
1012
|
const isRecheck = effectiveType === 'recheck';
|
|
949
|
-
let reviewer =
|
|
1013
|
+
let reviewer = resolveReviewVendor(step.reviewer, origin, config, ctx.smartSwitchFallback);
|
|
950
1014
|
if (!reviewer) {
|
|
951
1015
|
fileLog({ level: 'info', event: 'step_skipped', repo: `${owner}/${repoName}`, pr: prNumber, step: step.name, reason: 'no_reviewer' });
|
|
952
1016
|
results[step.name] = { skipped: true, skipReason: 'no_reviewer' };
|
|
@@ -1201,7 +1265,7 @@ export async function runWorkflow(ctx) {
|
|
|
1201
1265
|
// Withheld when an explicit vendors.*.model overrode the tier map:
|
|
1202
1266
|
// citing a tier the run did not use would assert a routing decision
|
|
1203
1267
|
// that never happened.
|
|
1204
|
-
strategyCitation(reviewer === 'codex' ? config.vendors.codex : reviewer === 'opencode' ? config.vendors.opencode : config.vendors.claude, strategy, roundStrategy, model));
|
|
1268
|
+
strategyCitation(reviewer === 'codex' ? config.vendors.codex : reviewer === 'opencode' ? config.vendors.opencode : config.vendors.claude, strategy, roundStrategy, model), authorAttribution ?? undefined);
|
|
1205
1269
|
if (memoryPlan && structured?.snapshot) {
|
|
1206
1270
|
// The review is already posted; a memory write failure only costs the next review its delta.
|
|
1207
1271
|
try {
|
|
@@ -1473,6 +1537,7 @@ export async function runWorkflow(ctx) {
|
|
|
1473
1537
|
vendor: activeVendor,
|
|
1474
1538
|
model: activeVendor === 'codex' ? codexFixModel : activeVendor === 'opencode' ? opencodeFixModel : claudeFixModel,
|
|
1475
1539
|
effort: fixEffort,
|
|
1540
|
+
author: authorAttribution ?? undefined,
|
|
1476
1541
|
skills: activatedSkills,
|
|
1477
1542
|
}),
|
|
1478
1543
|
});
|
|
@@ -1559,6 +1624,7 @@ export async function runWorkflow(ctx) {
|
|
|
1559
1624
|
reviewCommentBody,
|
|
1560
1625
|
model: activeVendor === 'codex' ? codexFixModel : activeVendor === 'opencode' ? opencodeFixModel : claudeFixModel,
|
|
1561
1626
|
effort: fixEffort,
|
|
1627
|
+
author: authorAttribution ?? undefined,
|
|
1562
1628
|
skills: activatedSkills,
|
|
1563
1629
|
});
|
|
1564
1630
|
await octokit.rest.issues.createComment({ owner, repo: repoName, issue_number: prNumber, body });
|
|
@@ -1632,6 +1698,7 @@ export async function runWorkflow(ctx) {
|
|
|
1632
1698
|
reviewCommentBody,
|
|
1633
1699
|
model: activeVendor === 'codex' ? codexFixModel : activeVendor === 'opencode' ? opencodeFixModel : claudeFixModel,
|
|
1634
1700
|
effort: fixEffort,
|
|
1701
|
+
author: authorAttribution ?? undefined,
|
|
1635
1702
|
skills: activatedSkills,
|
|
1636
1703
|
});
|
|
1637
1704
|
await octokit.rest.issues.createComment({ owner, repo: repoName, issue_number: prNumber, body });
|
|
@@ -1956,27 +2023,14 @@ export async function runWorkflow(ctx) {
|
|
|
1956
2023
|
skipConflictResolve('no_vendor');
|
|
1957
2024
|
continue;
|
|
1958
2025
|
}
|
|
1959
|
-
if (vendor === 'codex') {
|
|
1960
|
-
try {
|
|
1961
|
-
runGitWithoutHooks(tmpDir, ['merge', '--abort']);
|
|
1962
|
-
}
|
|
1963
|
-
catch { /* ignore */ }
|
|
1964
|
-
;
|
|
1965
|
-
skipConflictResolve('codex_conflict_resolve_unsupported');
|
|
1966
|
-
continue;
|
|
1967
|
-
}
|
|
1968
|
-
if (vendor === 'opencode') {
|
|
1969
|
-
try {
|
|
1970
|
-
runGitWithoutHooks(tmpDir, ['merge', '--abort']);
|
|
1971
|
-
}
|
|
1972
|
-
catch { /* ignore */ }
|
|
1973
|
-
;
|
|
1974
|
-
skipConflictResolve('opencode_conflict_resolve_unsupported');
|
|
1975
|
-
continue;
|
|
1976
|
-
}
|
|
1977
2026
|
// Conflict-resolve is mechanical text surgery bounded by the markers —
|
|
1978
2027
|
// measured at 37s against ~643s for a review — so it always runs fast.
|
|
1979
|
-
const
|
|
2028
|
+
const conflictResolveQuality = { ...config.quality, tier: config.quality.mode === 'smart' ? 'fast' : config.quality.tier };
|
|
2029
|
+
const conflictResolveModel = vendor === 'claude'
|
|
2030
|
+
? resolveClaudeModel(conflictResolveQuality, config.vendors.claude)
|
|
2031
|
+
: vendor === 'codex'
|
|
2032
|
+
? resolveCodexModel(conflictResolveQuality, config.vendors.codex)
|
|
2033
|
+
: resolveOpenCodeModel(conflictResolveQuality, config.vendors.opencode);
|
|
1980
2034
|
const isFork = pr.head.repo?.full_name !== pr.base.repo.full_name;
|
|
1981
2035
|
if (isFork) {
|
|
1982
2036
|
try {
|
|
@@ -2009,7 +2063,7 @@ export async function runWorkflow(ctx) {
|
|
|
2009
2063
|
const skillSession = skillSessionFor(step.name, effectiveType);
|
|
2010
2064
|
try {
|
|
2011
2065
|
;
|
|
2012
|
-
({ appliedCount, resolvedPaths, tokensUsed: resolveTokensUsed, effort: resolveEffort } = await
|
|
2066
|
+
({ appliedCount, resolvedPaths, tokensUsed: resolveTokensUsed, effort: resolveEffort } = await runConflictResolveForVendor(vendor, tmpDir, pr.title, step.instructions ?? '', conflictResolveModel, ctx.overrideTimeoutMs ?? vendorTimeoutMs(config.vendors[vendor].timeout_sec), skillSession, config.vendors[vendor].effort, config.skills.codex_full_access));
|
|
2013
2067
|
}
|
|
2014
2068
|
catch (err) {
|
|
2015
2069
|
logError({ repo: `${owner}/${repoName}`, pr: prNumber, phase: 'conflict-resolve', attempt: 1 }, err);
|
|
@@ -2099,7 +2153,7 @@ export async function runWorkflow(ctx) {
|
|
|
2099
2153
|
'-m',
|
|
2100
2154
|
conflictResolveCommitSubject(conflictedFiles.length, vendor),
|
|
2101
2155
|
'-m',
|
|
2102
|
-
buildCommitTrailers({ reviewer: vendor, model: conflictResolveModel, step: 'conflict-resolve', service: 'crosscheck' }),
|
|
2156
|
+
buildCommitTrailers({ reviewer: vendor, model: conflictResolveModel ?? 'default', step: 'conflict-resolve', service: 'crosscheck' }),
|
|
2103
2157
|
]);
|
|
2104
2158
|
const newSha = execSync('git rev-parse HEAD', { cwd: tmpDir, encoding: 'utf8' }).trim();
|
|
2105
2159
|
await pushWithNonFastForwardHandling({
|
|
@@ -2140,7 +2194,9 @@ export async function runWorkflow(ctx) {
|
|
|
2140
2194
|
files: resolvedPaths.length > 0 ? resolvedPaths : conflictedFiles,
|
|
2141
2195
|
model: conflictResolveModel,
|
|
2142
2196
|
effort: resolveEffort,
|
|
2197
|
+
author: authorAttribution ?? undefined,
|
|
2143
2198
|
skills: activatedSkills,
|
|
2199
|
+
vendor,
|
|
2144
2200
|
});
|
|
2145
2201
|
await octokit.rest.issues.createComment({ owner, repo: repoName, issue_number: prNumber, body });
|
|
2146
2202
|
fileLog({ level: 'info', event: 'conflict_resolved_comment_posted', repo: `${owner}/${repoName}`, pr: prNumber, sha: newSha });
|