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
8 changes: 8 additions & 0 deletions Codev.Avalonia.Tests/MainWindowTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3547,9 +3547,17 @@ public async Task Auto_mcp_approval_explains_unreadable_permissions_and_keeps_ru
await viewModel.SetProjectCommandPermissionModeAsync(ProjectCommandPermissionMode.Auto);
Assert.Equal(ProjectCommandPermissionMode.Auto, viewModel.ProjectCommandPermissionMode);
Assert.False(viewModel.CanPersistMcpToolPermissions);
Assert.Contains("MCP calls still require approval because saved MCP permission rules are unavailable", viewModel.ProjectCommandPermissionModeTooltip, StringComparison.Ordinal);
Assert.Contains(viewModel.McpToolPermissionLoadError!, viewModel.ProjectCommandPermissionModeTooltip, StringComparison.Ordinal);
Assert.NotNull(viewModel.ActiveConversation);
viewModel.ActiveConversation!.IsCodeTask = true;
Assert.Contains("MCP calls still require approval because saved MCP permission rules are unavailable", viewModel.CodeTaskTooltip, StringComparison.Ordinal);

window = new MainWindow { DataContext = viewModel };
window.Show();
var modeButton = Assert.IsType<Button>(window.FindControl<Button>("ProjectCommandModeButton"));
Assert.Equal("Auto ▾", modeButton.Content?.ToString());
Assert.Equal(viewModel.ProjectCommandPermissionModeTooltip, modeButton.GetValue(ToolTip.TipProperty)?.ToString());
using var schema = JsonDocument.Parse("""{"type":"object","properties":{"query":{"type":"string"}},"required":["query"],"additionalProperties":false}""");
using var arguments = JsonDocument.Parse("""{"query":"codev"}""");
var tool = new McpCodeTaskTool("mcp_github_search_0123456789abcdef", "github", "GitHub", "search",
Expand Down
15 changes: 14 additions & 1 deletion Codev.Avalonia/ViewModels/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,19 @@ public Codev.ProjectCommandPermissionMode GetProjectCommandPermissionMode(string
Codev.ProjectCommandPermissionMode.ReadOnly => "Read-only ▾",
_ => "Ask every time ▾"
};
public string ProjectCommandPermissionModeTooltip
{
get
{
const string description = "With a project attached, this mode is saved for that project. Without one, it sets the default for new projects and Code task workspaces. Auto runs shell commands and calls configured MCP tools without approval unless an exact saved project deny rule blocks that command or MCP server/tool. Shell commands use your account permissions and are not sandboxed to the project folder; MCP tools may affect external services.";
return McpPermissionFallbackNotice is { Length: > 0 } notice
? $"{description} {notice}."
: description;
}
}
private string McpPermissionFallbackNotice => _projectMcpPermissions.LoadError is { } loadError
? $"MCP calls still require approval because saved MCP permission rules are unavailable: {loadError}"
: "";
public IReadOnlyList<Codev.ProjectCommandPermissionRule> ProjectCommandPermissionRules => ActiveConversation?.ProjectPath is { Length: > 0 } path
? _projectCommandPermissions.GetRules(path) : [];
public bool CanPersistProjectCommandPermissions => _projectCommandPermissions.CanPersist;
Expand Down Expand Up @@ -575,7 +588,7 @@ reason is not "Start or select a conversation first." &&
public string CodeTaskTooltip => IsCodeTask
? $"Code task is on. {(IsOpenAIModel && ActiveConversation?.AllowHostedCodeTask != true ? "The first prompt asks permission to send prompts and tool results to OpenAI. " : "")}{(IsOpenAIModel ? Codev.OpenAiCodeTaskLimits.Description + " " : "")}{ProjectCommandPermissionMode switch
{
Codev.ProjectCommandPermissionMode.Auto => "Auto applies ordinary file changes with checkpoints, runs shell commands, and calls configured MCP tools without approval unless an exact saved project deny rule blocks that command or MCP server/tool. Shell commands use your account permissions and are not sandboxed to the project folder; MCP tools may affect external services.",
Codev.ProjectCommandPermissionMode.Auto => $"Auto applies ordinary file changes with checkpoints, runs shell commands, and calls configured MCP tools without approval unless an exact saved project deny rule blocks that command or MCP server/tool.{(McpPermissionFallbackNotice.Length > 0 ? $" {McpPermissionFallbackNotice}." : "")} Shell commands use your account permissions and are not sandboxed to the project folder; MCP tools may affect external services.",
Codev.ProjectCommandPermissionMode.Allowlist => "Exact saved allow rules can skip approval; unlisted commands still ask.",
Codev.ProjectCommandPermissionMode.ReadOnly => "Only recognized read-only inspections can skip approval; other commands ask.",
_ => "Commands ask every time."
Expand Down
2 changes: 1 addition & 1 deletion Codev.Avalonia/Views/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@
</MenuFlyout>
</Button.Flyout>
</Button>
<Button x:Name="ProjectCommandModeButton" Classes="soft" Content="{Binding ProjectCommandPermissionModeLabel}" Padding="8,4" FontSize="10" IsEnabled="{Binding CanPersistProjectCommandPermissions}" ToolTip.Tip="With a project attached, this mode is saved for that project. Without one, it sets the default for new projects and Code task workspaces. Auto runs shell commands and calls configured MCP tools without approval unless an exact saved project deny rule blocks that command or MCP server/tool. Shell commands use your account permissions and are not sandboxed to the project folder; MCP tools may affect external services.">
<Button x:Name="ProjectCommandModeButton" Classes="soft" Content="{Binding ProjectCommandPermissionModeLabel}" Padding="8,4" FontSize="10" IsEnabled="{Binding CanPersistProjectCommandPermissions}" ToolTip.Tip="{Binding ProjectCommandPermissionModeTooltip}">
<Button.Flyout>
<MenuFlyout>
<MenuItem Header="Auto · approve unless denied" Tag="Auto" Click="ProjectCommandMode_Click" />
Expand Down
2 changes: 1 addition & 1 deletion DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ X-items are from section 7. Items in phase 1 to 3 do not depend on the Avalonia

| ID | Feature | Size | Depends on | Status / tier |
|---|---|---|---|---|
| B1 | Permission modes and allowlist | M | none | Core · implemented in Avalonia. Auto resolves all command approvals as allow, including verification, destructive shell commands, and compound Git writes; exact saved deny rules still block their matching command, following OpenCode's published Auto rule. Persistent exact allow rules remain unavailable for protected Git/.git/Codev-data commands and shell commands with indirect path expansion, only in Ask/Allowlist; the disabled control now says `Protected · no saved allow`. Avalonia uses the tested Core approval policy; executor integration tests run verification, protected Git, and compound shell commands while proving the approval callback is not invoked, Ask invokes it, and exact denies still block. On 2026-10-02, 53 focused Auto policy/executor tests passed locally at the current checkout. Opt-in live Ollama integration exercises real MCP and `verify_command` tool calls through Codev's schemas and executor; both installed Qwen models passed verification under Auto, and Qwen3.6 passed live MCP/exact-deny and verification 2/2 on 2026-10-02 and again 2/2 on the current working tree. On 2026-10-02, two opt-in Avalonia live-app tests also passed with Qwen3.6: Auto applied a requested file edit with a rollback checkpoint and no review callback, and ran `verify_command` (`dotnet --version`) with no command-approval callback. On this checkout, the local Release suites passed `Codev.Tests` 922 with the two opt-in live tests skipped, `Codev.Avalonia.Tests` 30/30, and `Codev.Windows.Tests` 8/8. Hosted CI run [#36831396270](https://github.com/jay23606/codev/actions/runs/36831396270) passed on Windows, Linux, and macOS, including Avalonia headless UI tests; matching package/launch run [#36831396292](https://github.com/jay23606/codev/actions/runs/36831396292) passed for win-x64, linux-x64, osx-arm64, and osx-x64. End-to-end desktop Auto interaction and cross-platform security review remain |
| B1 | Permission modes and allowlist | M | none | Core · implemented in Avalonia. Auto resolves all command approvals as allow, including verification, destructive shell commands, and compound Git writes; exact saved deny rules still block their matching command, following OpenCode's published Auto rule. Persistent exact allow rules remain unavailable for protected Git/.git/Codev-data commands and shell commands with indirect path expansion, only in Ask/Allowlist; the disabled control now says `Protected · no saved allow`. Avalonia uses the tested Core approval policy; executor integration tests run verification, protected Git, and compound shell commands while proving the approval callback is not invoked, Ask invokes it, and exact denies still block. On 2026-10-02, 53 focused Auto policy/executor tests passed locally at the current checkout. Opt-in live Ollama integration exercises real MCP and `verify_command` tool calls through Codev's schemas and executor; both installed Qwen models passed verification under Auto, and Qwen3.6 passed live MCP/exact-deny and verification 2/2 on 2026-10-02 and again 2/2 on the current working tree. On 2026-10-02, two opt-in Avalonia live-app tests also passed with Qwen3.6: Auto applied a requested file edit with a rollback checkpoint and no review callback, and ran `verify_command` (`dotnet --version`) with no command-approval callback. When saved MCP permission data is unavailable, MCP calls intentionally fail closed to per-call approval so a saved Deny cannot be bypassed; the Auto footer and Code task tooltips now explain this exception and its cause. The focused headless UI regression passes. On this checkout, the local Release suites passed `Codev.Tests` 922 with the two opt-in live tests skipped, `Codev.Avalonia.Tests` 30/30, and `Codev.Windows.Tests` 8/8. Hosted CI run [#36831396270](https://github.com/jay23606/codev/actions/runs/36831396270) passed on Windows, Linux, and macOS, including Avalonia headless UI tests; matching package/launch run [#36831396292](https://github.com/jay23606/codev/actions/runs/36831396292) passed for win-x64, linux-x64, osx-arm64, and osx-x64. End-to-end desktop Auto interaction and cross-platform security review remain |
| B2 | Structured tool calls | M | none | Core · Ollama compaction and Avalonia local Plan use validated JSON Schema with bounded text fallbacks; five focused tests and an opt-in live Qwen3.6 Plan workflow pass; cross-model and native UI QA remain |
| B15 | Keep a conversation's model warm between turns | S | none | Core · Avalonia Ollama requests set a 30-minute keep-alive; current V5 selected-file chat stayed resident after six minutes and follow-up load was 1.97 ms; manual desktop smoke remains |
| B16 | Best-of-N attempts, picked by the verification loop | M | B5, B1 | Later · Implemented in Avalonia; current-build V5 again found no completed task at N=1 or N=3, while N=3 cost 12 minutes; keep N=1 by default |
Expand Down
Loading