feat(ui): Listen-Einstellungen — Checkbox fuer serialize_on_file_overlap
Das Flag war bisher nur ueber MCP set_list_config erreichbar. UpdateListConfigDto fuehrt es tri-state (null = gespeicherten Wert behalten), damit nur das Listen-Modal es setzen/loeschen kann und kein anderer Aufrufer es per Omission verliert.
This commit is contained in:
@@ -94,11 +94,14 @@ public record MergeSegmentDto(bool IsConflict, string Text, string Ours, string?
|
||||
|
||||
public record UpdateListDto(string Id, string Name, string? WorkingDir, string DefaultCommitType, bool IsManual = false, bool FindingsTracked = false);
|
||||
|
||||
public record UpdateListConfigDto(string ListId, string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? VerifyCommand = null);
|
||||
// SerializeOnFileOverlap is tri-state on purpose: null = leave the stored flag alone. A caller that
|
||||
// doesn't own the field (anything but the list-settings modal) must not be able to clear it by
|
||||
// omission — SetConfigAsync copies the entity verbatim.
|
||||
public record UpdateListConfigDto(string ListId, string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? VerifyCommand = null, bool? SerializeOnFileOverlap = null);
|
||||
|
||||
public record UpdateTaskAgentSettingsDto(string TaskId, string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null);
|
||||
|
||||
public record ListConfigDto(string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? VerifyCommand = null);
|
||||
public record ListConfigDto(string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? VerifyCommand = null, bool SerializeOnFileOverlap = false);
|
||||
|
||||
public record SeedResultDto(int Copied, int Skipped);
|
||||
|
||||
|
||||
@@ -371,6 +371,8 @@
|
||||
"manualListHint": "Neue Aufgaben in dieser Liste sind zunächst manuell: kein Einreihen, Ausführen oder Verfeinern, und die Automatik überspringt sie. Eine handgesteuerte Sitzung kannst du weiterhin öffnen.",
|
||||
"findingsTracked": "Findings-Ordner .claudedo einchecken",
|
||||
"findingsTrackedHint": "Aus: der Ordner bleibt über .git/info/exclude aus git heraus. An: Findings reisen mit dem Repo.",
|
||||
"serializeOnFileOverlap": "Tasks mit gleichen Dateien serialisieren",
|
||||
"serializeOnFileOverlapHint": "Aus: Tasks dieser Liste laufen parallel. An: ein wartender Task, dessen deklarierter Datei-Scope einen laufenden oder review-wartenden Nachbarn überlappt, wartet statt zu starten.",
|
||||
"sectionAgent": "AGENT",
|
||||
"resetAgentSettings": "Agent-Einstellungen zurücksetzen",
|
||||
"sectionVerify": "VERIFIKATION",
|
||||
|
||||
@@ -371,6 +371,8 @@
|
||||
"manualListHint": "New tasks in this list start out manual: no queueing, running or refining, and automation skips them. You can still open a hand-driven session.",
|
||||
"findingsTracked": "Commit the .claudedo findings folder",
|
||||
"findingsTrackedHint": "Off: the folder stays out of git via .git/info/exclude. On: findings travel with the repo.",
|
||||
"serializeOnFileOverlap": "Serialize tasks that touch the same files",
|
||||
"serializeOnFileOverlapHint": "Off: tasks in this list run in parallel. On: a queued task whose declared file scope overlaps a running or awaiting-review sibling waits instead of starting.",
|
||||
"sectionAgent": "AGENT",
|
||||
"resetAgentSettings": "Reset agent settings",
|
||||
"sectionVerify": "VERIFICATION",
|
||||
|
||||
@@ -189,10 +189,12 @@ public sealed partial class AgentConfigEditorViewModel : ViewModelBase, IDisposa
|
||||
catch { }
|
||||
}
|
||||
|
||||
// verifyCommand is a List-only field owned by ListSettingsModalViewModel (not this editor,
|
||||
// which is also reused for Task scope); the caller passes it through so the single
|
||||
// UpdateListConfig call carries the full desired row instead of clobbering it.
|
||||
public async System.Threading.Tasks.Task SaveAsync(string? verifyCommand = null)
|
||||
// verifyCommand and serializeOnFileOverlap are List-only fields owned by
|
||||
// ListSettingsModalViewModel (not this editor, which is also reused for Task scope); the caller
|
||||
// passes them through so the single UpdateListConfig call carries the full desired row instead
|
||||
// of clobbering it.
|
||||
public async System.Threading.Tasks.Task SaveAsync(
|
||||
string? verifyCommand = null, bool? serializeOnFileOverlap = null)
|
||||
{
|
||||
if (TargetId is null) return;
|
||||
var model = string.IsNullOrWhiteSpace(Model) ? null : Model;
|
||||
@@ -204,7 +206,7 @@ public sealed partial class AgentConfigEditorViewModel : ViewModelBase, IDisposa
|
||||
if (_scope == AgentConfigScope.Task)
|
||||
await _worker.UpdateTaskAgentSettingsAsync(new UpdateTaskAgentSettingsDto(TargetId, model, sp, ap, turns, skills));
|
||||
else
|
||||
await _worker.UpdateListConfigAsync(new UpdateListConfigDto(TargetId, model, sp, ap, turns, skills, verifyCommand));
|
||||
await _worker.UpdateListConfigAsync(new UpdateListConfigDto(TargetId, model, sp, ap, turns, skills, verifyCommand, serializeOnFileOverlap));
|
||||
}
|
||||
|
||||
private List<string>? SelectedSessionSkillNames()
|
||||
|
||||
@@ -36,6 +36,9 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
|
||||
// Optional post-merge verification command (build/test), run in WorkingDir after a merge
|
||||
// lands; a non-zero exit keeps the task out of Done instead of silently reporting merged.
|
||||
[ObservableProperty] private string _verifyCommand = "";
|
||||
// When on, the queue picker holds back a queued task whose declared scope globs overlap a
|
||||
// running/awaiting-merge sibling in this list (ListConfigEntity.SerializeOnFileOverlap).
|
||||
[ObservableProperty] private bool _serializeOnFileOverlap;
|
||||
|
||||
public ObservableCollection<string> CommitTypeOptions { get; } = new(CommitTypeRegistry.Types);
|
||||
|
||||
@@ -71,6 +74,7 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
|
||||
await Agent.LoadForListAsync(listId, ct);
|
||||
var cfg = await _worker.GetListConfigAsync(listId);
|
||||
VerifyCommand = cfg?.VerifyCommand ?? "";
|
||||
SerializeOnFileOverlap = cfg?.SerializeOnFileOverlap ?? false;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -84,7 +88,9 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
|
||||
IsManual,
|
||||
FindingsTracked));
|
||||
|
||||
await Agent.SaveAsync(string.IsNullOrWhiteSpace(VerifyCommand) ? null : VerifyCommand);
|
||||
await Agent.SaveAsync(
|
||||
string.IsNullOrWhiteSpace(VerifyCommand) ? null : VerifyCommand,
|
||||
SerializeOnFileOverlap);
|
||||
|
||||
CloseAction?.Invoke();
|
||||
}
|
||||
|
||||
@@ -74,6 +74,13 @@
|
||||
<TextBlock Text="{loc:Tr modals.listSettings.findingsTrackedHint}"
|
||||
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<CheckBox IsChecked="{Binding SerializeOnFileOverlap, Mode=TwoWay}"
|
||||
Content="{loc:Tr modals.listSettings.serializeOnFileOverlap}"/>
|
||||
<TextBlock Text="{loc:Tr modals.listSettings.serializeOnFileOverlapHint}"
|
||||
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
+2
-2
@@ -104,8 +104,8 @@ public sealed class ConfigMcpTools
|
||||
|
||||
// Fields this tool doesn't expose but that live on the same row. They must survive every
|
||||
// write here — ListRepository.SetConfigAsync copies the entity verbatim, so anything left
|
||||
// at its default would silently reset (SerializeOnFileOverlap in particular has no UI
|
||||
// affordance at all, so a reset is invisible until tasks stop serializing).
|
||||
// at its default would silently reset (a SerializeOnFileOverlap reset only shows up as
|
||||
// tasks no longer serializing, long after this write).
|
||||
var hasUnrelatedSettings = existing is not null
|
||||
&& (existing.SessionSkills is not null || existing.SerializeOnFileOverlap);
|
||||
|
||||
|
||||
@@ -545,13 +545,13 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
||||
var sessionSkills = SkillsToJson(dto.SessionSkills);
|
||||
var verifyCommand = dto.VerifyCommand.NullIfBlank();
|
||||
|
||||
// Preserve SerializeOnFileOverlap: it has no UI/hub affordance yet (set via
|
||||
// set_list_config or directly against ListConfigEntity), so a save from this path
|
||||
// must not silently drop it -- neither by deleting the row nor by overwriting it.
|
||||
// A null SerializeOnFileOverlap means "leave it as stored" — only the list-settings modal
|
||||
// owns that field, so every other caller must not drop it (neither by deleting the row nor
|
||||
// by overwriting it: SetConfigAsync copies the entity verbatim).
|
||||
var existing = await repo.GetConfigAsync(dto.ListId);
|
||||
var hasUnrelatedSettings = existing?.SerializeOnFileOverlap ?? false;
|
||||
var serializeOnFileOverlap = dto.SerializeOnFileOverlap ?? existing?.SerializeOnFileOverlap ?? false;
|
||||
|
||||
if (model is null && systemPrompt is null && agentPath is null && dto.MaxTurns is null && sessionSkills is null && verifyCommand is null && !hasUnrelatedSettings)
|
||||
if (model is null && systemPrompt is null && agentPath is null && dto.MaxTurns is null && sessionSkills is null && verifyCommand is null && !serializeOnFileOverlap)
|
||||
{
|
||||
await repo.DeleteConfigAsync(dto.ListId);
|
||||
}
|
||||
@@ -566,7 +566,7 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
||||
MaxTurns = dto.MaxTurns,
|
||||
SessionSkills = sessionSkills,
|
||||
VerifyCommand = verifyCommand,
|
||||
SerializeOnFileOverlap = existing?.SerializeOnFileOverlap ?? false,
|
||||
SerializeOnFileOverlap = serializeOnFileOverlap,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -579,7 +579,7 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
||||
var repo = new ListRepository(ctx);
|
||||
var config = await repo.GetConfigAsync(listId);
|
||||
if (config is null) return null;
|
||||
return new ListConfigDto(config.Model, config.SystemPrompt, config.AgentPath, config.MaxTurns, SkillsFromJson(config.SessionSkills), config.VerifyCommand);
|
||||
return new ListConfigDto(config.Model, config.SystemPrompt, config.AgentPath, config.MaxTurns, SkillsFromJson(config.SessionSkills), config.VerifyCommand, config.SerializeOnFileOverlap);
|
||||
}
|
||||
|
||||
public async Task<SetTaskStatusResultDto> SetTaskStatus(string taskId, string status)
|
||||
|
||||
Reference in New Issue
Block a user