Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ export function RigSettingsPageClient({ townId, rigId, organizationId }: Props)
const [autoResolvePrFeedback, setAutoResolvePrFeedback] = useState<boolean | undefined>(
undefined
);
const [autoResolveMergeConflicts, setAutoResolveMergeConflicts] = useState<boolean | undefined>(
undefined
);
const [autoMergeDelayMinutes, setAutoMergeDelayMinutes] = useState<number | null | undefined>(
undefined
);
Expand All @@ -136,6 +139,7 @@ export function RigSettingsPageClient({ townId, rigId, organizationId }: Props)
setRefineryCodeReview(cfg.code_review);
setReviewMode(cfg.review_mode);
setAutoResolvePrFeedback(cfg.auto_resolve_pr_feedback);
setAutoResolveMergeConflicts(cfg.auto_resolve_merge_conflicts);
setAutoMergeDelayMinutes(cfg.auto_merge_delay_minutes);
setMergeStrategy(cfg.merge_strategy);
setConvoyMergeMode(cfg.convoy_merge_mode);
Expand Down Expand Up @@ -183,6 +187,7 @@ export function RigSettingsPageClient({ townId, rigId, organizationId }: Props)
code_review: refineryCodeReview,
review_mode: reviewMode,
auto_resolve_pr_feedback: autoResolvePrFeedback,
auto_resolve_merge_conflicts: autoResolveMergeConflicts,
auto_merge_delay_minutes: autoMergeDelayMinutes,
merge_strategy: mergeStrategy,
convoy_merge_mode: convoyMergeMode,
Expand Down Expand Up @@ -505,6 +510,46 @@ export function RigSettingsPageClient({ townId, rigId, organizationId }: Props)
</div>
</div>

<div className="rounded-lg border border-white/[0.06] bg-white/[0.02] px-4 py-3">
<div className="flex items-center gap-3">
<div className="flex-1">
<Label className="text-sm text-white/70">
Auto-resolve merge conflicts
</Label>
<p className="text-[11px] text-white/30">
When a PR has merge conflicts, automatically dispatch an agent to rebase
and resolve them.
{townCfg?.refinery?.auto_resolve_merge_conflicts !== undefined && (
<span className="ml-1 text-white/20">
(Town default:{' '}
{townCfg.refinery.auto_resolve_merge_conflicts ? 'on' : 'off'})
</span>
)}
</p>
</div>
<div className="flex items-center gap-2">
{autoResolveMergeConflicts !== undefined && (
<button
onClick={() => setAutoResolveMergeConflicts(undefined)}
className="rounded p-1 text-white/25 transition-colors hover:bg-white/[0.06] hover:text-white/50"
title="Inherit from town"
>
<X className="size-3" />
</button>
)}
<Switch
checked={
autoResolveMergeConflicts ??
townCfg?.refinery?.auto_resolve_merge_conflicts ??
true
}
onCheckedChange={v => setAutoResolveMergeConflicts(v)}
className={autoResolveMergeConflicts === undefined ? 'opacity-40' : ''}
/>
</div>
</div>
</div>

<div className="rounded-lg border border-white/[0.06] bg-white/[0.02] px-4 py-3">
<Label className="mb-1.5 block text-sm text-white/70">
Auto-merge delay (minutes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ export function TownSettingsPageClient({ townId, readOnly = false, organizationI
const [refineryCodeReview, setRefineryCodeReview] = useState(true);
const [reviewMode, setReviewMode] = useState<'rework' | 'comments'>('rework');
const [autoResolvePrFeedback, setAutoResolvePrFeedback] = useState(false);
const [autoResolveMergeConflicts, setAutoResolveMergeConflicts] = useState(true);
const [autoMergeDelayMinutes, setAutoMergeDelayMinutes] = useState<number | null>(null);
const [mergeStrategy, setMergeStrategy] = useState<'direct' | 'pr'>('direct');
const [stagedConvoysDefault, setStagedConvoysDefault] = useState(false);
Expand Down Expand Up @@ -315,6 +316,7 @@ export function TownSettingsPageClient({ townId, readOnly = false, organizationI
setRefineryCodeReview(cfg.refinery?.code_review ?? true);
setReviewMode(cfg.refinery?.review_mode === 'comments' ? 'comments' : 'rework');
setAutoResolvePrFeedback(cfg.refinery?.auto_resolve_pr_feedback ?? false);
setAutoResolveMergeConflicts(cfg.refinery?.auto_resolve_merge_conflicts ?? true);
setAutoMergeDelayMinutes(cfg.refinery?.auto_merge_delay_minutes ?? null);
setMergeStrategy(cfg.merge_strategy === 'pr' ? 'pr' : 'direct');
setStagedConvoysDefault(cfg.staged_convoys_default ?? false);
Expand Down Expand Up @@ -380,6 +382,7 @@ export function TownSettingsPageClient({ townId, readOnly = false, organizationI
review_mode: reviewMode,
require_clean_merge: true,
auto_resolve_pr_feedback: autoResolvePrFeedback,
auto_resolve_merge_conflicts: autoResolveMergeConflicts,
auto_merge_delay_minutes: autoMergeDelayMinutes,
},
convoy_merge_mode: convoyMergeMode,
Expand Down Expand Up @@ -1074,6 +1077,20 @@ export function TownSettingsPageClient({ townId, readOnly = false, organizationI
/>
</div>

<div className="mt-3 flex items-center gap-3 rounded-lg border border-white/[0.06] bg-white/[0.02] px-4 py-3">
<div className="flex-1">
<Label className="text-sm text-white/70">Auto-resolve merge conflicts</Label>
<p className="text-[11px] text-white/30">
When a PR has merge conflicts, automatically dispatch an agent to rebase and
resolve them.
</p>
</div>
<Switch
checked={autoResolveMergeConflicts}
onCheckedChange={setAutoResolveMergeConflicts}
/>
</div>

{autoResolvePrFeedback && (
<div className="mt-3 rounded-lg border border-white/[0.06] bg-white/[0.02] px-4 py-3">
<Label className="mb-1.5 block text-sm text-white/70">Auto-merge delay</Label>
Expand Down
9 changes: 9 additions & 0 deletions services/gastown/src/dos/town/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ export async function updateTownConfig(
update.refinery.auto_resolve_pr_feedback ??
current.refinery?.auto_resolve_pr_feedback ??
false,
auto_resolve_merge_conflicts:
update.refinery.auto_resolve_merge_conflicts ??
current.refinery?.auto_resolve_merge_conflicts ??
true,
auto_merge_delay_minutes:
update.refinery.auto_merge_delay_minutes !== undefined
? update.refinery.auto_merge_delay_minutes
Expand Down Expand Up @@ -191,6 +195,7 @@ export type EffectiveConfig = {
review_mode: 'rework' | 'comments';
code_review: boolean;
auto_resolve_pr_feedback: boolean;
auto_resolve_merge_conflicts: boolean;
auto_merge_delay_minutes: number | null;
merge_strategy: MergeStrategy;
convoy_merge_mode: 'review-then-land' | 'review-and-merge';
Expand Down Expand Up @@ -227,6 +232,10 @@ export function resolveRigConfig(
rigOverride?.auto_resolve_pr_feedback ??
townConfig.refinery?.auto_resolve_pr_feedback ??
false,
auto_resolve_merge_conflicts:
Comment thread
jrf0110 marked this conversation as resolved.
rigOverride?.auto_resolve_merge_conflicts ??
townConfig.refinery?.auto_resolve_merge_conflicts ??
true,
auto_merge_delay_minutes:
rigOverride?.auto_merge_delay_minutes !== undefined
? rigOverride.auto_merge_delay_minutes
Expand Down
5 changes: 5 additions & 0 deletions services/gastown/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ export const TownConfigSchema = z.object({
/** When enabled, a polecat is automatically dispatched to address
* unresolved review comments and failing CI checks on open PRs. */
auto_resolve_pr_feedback: z.boolean().default(false),
/** When enabled, a polecat is automatically dispatched to rebase and
* resolve merge conflicts on open PRs. */
auto_resolve_merge_conflicts: z.boolean().default(true).optional(),
/** After all CI checks pass and all review threads are resolved,
* automatically merge the PR after this many minutes.
* 0 = immediate, null = disabled (require manual merge). */
Expand Down Expand Up @@ -347,6 +350,7 @@ export const RigOverrideConfigSchema = z.object({
/** false = skip refinery entirely */
code_review: z.boolean().optional(),
auto_resolve_pr_feedback: z.boolean().optional(),
auto_resolve_merge_conflicts: z.boolean().optional(),
auto_merge_delay_minutes: z.number().int().min(0).nullable().optional(),

// Merge strategy
Expand Down Expand Up @@ -412,6 +416,7 @@ export const TownConfigUpdateSchema = z.object({
code_review: z.boolean().optional(),
review_mode: z.enum(['rework', 'comments']).optional(),
auto_resolve_pr_feedback: z.boolean().optional(),
auto_resolve_merge_conflicts: z.boolean().optional(),
auto_merge_delay_minutes: z.number().int().min(0).nullable().optional(),
})
.optional(),
Expand Down