Extract paired source ref helpers
This commit is contained in:
@@ -11,12 +11,14 @@ import { logger } from './logger.js';
|
|||||||
import { markPairedTaskReviewReady } from './paired-workspace-manager.js';
|
import { markPairedTaskReviewReady } from './paired-workspace-manager.js';
|
||||||
import {
|
import {
|
||||||
applyPairedTaskPatch,
|
applyPairedTaskPatch,
|
||||||
hasCodeChangesSinceRef,
|
|
||||||
requestArbiterOrEscalate,
|
requestArbiterOrEscalate,
|
||||||
resolveCanonicalSourceRef,
|
|
||||||
transitionPairedTaskStatus,
|
transitionPairedTaskStatus,
|
||||||
} from './paired-execution-context-shared.js';
|
} from './paired-execution-context-shared.js';
|
||||||
import { resolveOwnerCompletionSignal } from './paired-completion-signals.js';
|
import { resolveOwnerCompletionSignal } from './paired-completion-signals.js';
|
||||||
|
import {
|
||||||
|
hasCodeChangesSinceRef,
|
||||||
|
resolveCanonicalSourceRef,
|
||||||
|
} from './paired-source-ref.js';
|
||||||
import { parseVisibleVerdict } from './paired-verdict.js';
|
import { parseVisibleVerdict } from './paired-verdict.js';
|
||||||
import type { PairedTask } from './types.js';
|
import type { PairedTask } from './types.js';
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import { getPairedWorkspace } from './db.js';
|
|||||||
import { logger } from './logger.js';
|
import { logger } from './logger.js';
|
||||||
import {
|
import {
|
||||||
requestArbiterOrEscalate,
|
requestArbiterOrEscalate,
|
||||||
resolveCanonicalSourceRef,
|
|
||||||
transitionPairedTaskStatus,
|
transitionPairedTaskStatus,
|
||||||
} from './paired-execution-context-shared.js';
|
} from './paired-execution-context-shared.js';
|
||||||
import {
|
import {
|
||||||
resolveReviewerCompletionSignal,
|
resolveReviewerCompletionSignal,
|
||||||
resolveReviewerFailureSignal,
|
resolveReviewerFailureSignal,
|
||||||
} from './paired-completion-signals.js';
|
} from './paired-completion-signals.js';
|
||||||
|
import { resolveCanonicalSourceRef } from './paired-source-ref.js';
|
||||||
import { parseVisibleVerdict } from './paired-verdict.js';
|
import { parseVisibleVerdict } from './paired-verdict.js';
|
||||||
import type { PairedTask } from './types.js';
|
import type { PairedTask } from './types.js';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { execFileSync } from 'child_process';
|
|
||||||
|
|
||||||
import { isArbiterEnabled } from './config.js';
|
import { isArbiterEnabled } from './config.js';
|
||||||
import { updatePairedTaskIfUnchanged } from './db.js';
|
import { updatePairedTaskIfUnchanged } from './db.js';
|
||||||
import { logger } from './logger.js';
|
import { logger } from './logger.js';
|
||||||
@@ -16,50 +14,10 @@ export {
|
|||||||
parseVisibleVerdict,
|
parseVisibleVerdict,
|
||||||
} from './paired-verdict.js';
|
} from './paired-verdict.js';
|
||||||
export type { ArbiterVerdictResult, VisibleVerdict } from './paired-verdict.js';
|
export type { ArbiterVerdictResult, VisibleVerdict } from './paired-verdict.js';
|
||||||
|
export {
|
||||||
export function resolveCanonicalSourceRef(workDir: string): string {
|
hasCodeChangesSinceRef,
|
||||||
const treeHash = resolveCanonicalTreeHash(workDir);
|
resolveCanonicalSourceRef,
|
||||||
return treeHash || 'HEAD';
|
} from './paired-source-ref.js';
|
||||||
}
|
|
||||||
|
|
||||||
function resolveCanonicalTreeHash(workDir: string): string | null {
|
|
||||||
try {
|
|
||||||
const treeHash = execFileSync('git', ['rev-parse', 'HEAD^{tree}'], {
|
|
||||||
cwd: workDir,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
stdio: ['ignore', 'pipe', 'pipe'],
|
|
||||||
}).trim();
|
|
||||||
return treeHash || null;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hasCodeChangesSinceRef(
|
|
||||||
workDir: string,
|
|
||||||
sourceRef: string | null | undefined,
|
|
||||||
): boolean | null {
|
|
||||||
if (!sourceRef) return null;
|
|
||||||
try {
|
|
||||||
execFileSync('git', ['diff', '--quiet', sourceRef, 'HEAD'], {
|
|
||||||
cwd: workDir,
|
|
||||||
stdio: ['ignore', 'pipe', 'pipe'],
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
} catch (error) {
|
|
||||||
const exitCode =
|
|
||||||
typeof error === 'object' &&
|
|
||||||
error !== null &&
|
|
||||||
'status' in error &&
|
|
||||||
typeof (error as { status?: unknown }).status === 'number'
|
|
||||||
? (error as { status: number }).status
|
|
||||||
: null;
|
|
||||||
if (exitCode === 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ALLOWED_PAIRED_STATUS_TRANSITIONS: Record<
|
const ALLOWED_PAIRED_STATUS_TRANSITIONS: Record<
|
||||||
PairedTaskStatus,
|
PairedTaskStatus,
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ import {
|
|||||||
} from './paired-execution-context-reviewer.js';
|
} from './paired-execution-context-reviewer.js';
|
||||||
import {
|
import {
|
||||||
applyPairedTaskPatch,
|
applyPairedTaskPatch,
|
||||||
resolveCanonicalSourceRef,
|
|
||||||
requestArbiterOrEscalate,
|
requestArbiterOrEscalate,
|
||||||
transitionPairedTaskStatus,
|
transitionPairedTaskStatus,
|
||||||
} from './paired-execution-context-shared.js';
|
} from './paired-execution-context-shared.js';
|
||||||
|
import { resolveCanonicalSourceRef } from './paired-source-ref.js';
|
||||||
import {
|
import {
|
||||||
isOwnerWorkspaceRepairNeededError,
|
isOwnerWorkspaceRepairNeededError,
|
||||||
markPairedTaskReviewReady,
|
markPairedTaskReviewReady,
|
||||||
|
|||||||
45
src/paired-source-ref.ts
Normal file
45
src/paired-source-ref.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { execFileSync } from 'child_process';
|
||||||
|
|
||||||
|
export function resolveCanonicalSourceRef(workDir: string): string {
|
||||||
|
const treeHash = resolveCanonicalTreeHash(workDir);
|
||||||
|
return treeHash || 'HEAD';
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveCanonicalTreeHash(workDir: string): string | null {
|
||||||
|
try {
|
||||||
|
const treeHash = execFileSync('git', ['rev-parse', 'HEAD^{tree}'], {
|
||||||
|
cwd: workDir,
|
||||||
|
encoding: 'utf-8',
|
||||||
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
|
}).trim();
|
||||||
|
return treeHash || null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasCodeChangesSinceRef(
|
||||||
|
workDir: string,
|
||||||
|
sourceRef: string | null | undefined,
|
||||||
|
): boolean | null {
|
||||||
|
if (!sourceRef) return null;
|
||||||
|
try {
|
||||||
|
execFileSync('git', ['diff', '--quiet', sourceRef, 'HEAD'], {
|
||||||
|
cwd: workDir,
|
||||||
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
} catch (error) {
|
||||||
|
const exitCode =
|
||||||
|
typeof error === 'object' &&
|
||||||
|
error !== null &&
|
||||||
|
'status' in error &&
|
||||||
|
typeof (error as { status?: unknown }).status === 'number'
|
||||||
|
? (error as { status: number }).status
|
||||||
|
: null;
|
||||||
|
if (exitCode === 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user