1
0

feat: Implement a user-approved shell command execution tool and a Windows installer script.

This commit is contained in:
2026-03-04 11:04:01 +01:00
parent b05e905dc4
commit 2b122a28c9
4 changed files with 57 additions and 2 deletions

View File

@@ -12,6 +12,12 @@
<AssemblyName>anchor</AssemblyName> <AssemblyName>anchor</AssemblyName>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Windows'))">
<DefineConstants>$(DefineConstants);WINDOWS</DefineConstants>
<!-- Windows requires Desktop C++ Workload for NativeAOT, so we compile a standard self-contained portable executable instead -->
<PublishAot>false</PublishAot>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.AI" Version="10.3.0" /> <PackageReference Include="Microsoft.Extensions.AI" Version="10.3.0" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="10.3.0" /> <PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="10.3.0" />

View File

@@ -145,7 +145,7 @@ if (modelInfo != null)
// ── Chat history with system prompt ───────────────────────────────────── // ── Chat history with system prompt ─────────────────────────────────────
List<ChatMessage> history = List<ChatMessage> history =
[ [
new(ChatRole.System, """ new(ChatRole.System, $$"""
You are anchor, a coding assistant that edits files using the Hashline technique. You are anchor, a coding assistant that edits files using the Hashline technique.
## Reading files ## Reading files
@@ -166,6 +166,7 @@ List<ChatMessage> history =
4. If an anchor fails validation, re-read the file to get fresh anchors. 4. If an anchor fails validation, re-read the file to get fresh anchors.
Keep responses concise. You have access to the current working directory. Keep responses concise. You have access to the current working directory.
You are running on: {{System.Runtime.InteropServices.RuntimeInformation.OSDescription}}
""") """)
]; ];

View File

@@ -11,7 +11,11 @@ internal static class CommandTool
{ {
public static Action<string> Log { get; set; } = Console.WriteLine; public static Action<string> Log { get; set; } = Console.WriteLine;
[Description("Execute a shell command after user approval. Prompts with [Y/n] before running. Note: For file editing and operations, use the built-in file tools (ReadFile, ReplaceLines, InsertAfter, DeleteRange, CreateFile, etc.) instead of shell commands.")] #if WINDOWS
[Description("Execute a PowerShell command after user approval. Prompts with [Y/n] before running. Note: For file editing and operations, use the built-in file tools (ReadFile, ReplaceLines, InsertAfter, DeleteRange, CreateFile, etc.) instead of shell commands.")]
#else
[Description("Execute a Bash shell command after user approval. Prompts with [Y/n] before running. Note: For file editing and operations, use the built-in file tools (ReadFile, ReplaceLines, InsertAfter, DeleteRange, CreateFile, etc.) instead of shell commands.")]
#endif
public static string ExecuteCommand( public static string ExecuteCommand(
[Description("The shell command to execute.")] string command) [Description("The shell command to execute.")] string command)
{ {
@@ -41,8 +45,13 @@ internal static class CommandTool
{ {
var startInfo = new ProcessStartInfo var startInfo = new ProcessStartInfo
{ {
#if WINDOWS
FileName = "powershell.exe",
Arguments = $"-NoProfile -Command \"{command}\"",
#else
FileName = "/bin/bash", FileName = "/bin/bash",
Arguments = $"-c \"{command}\"", Arguments = $"-c \"{command}\"",
#endif
UseShellExecute = false, UseShellExecute = false,
RedirectStandardOutput = true, RedirectStandardOutput = true,
RedirectStandardError = true, RedirectStandardError = true,

39
installer.ps1 Normal file
View File

@@ -0,0 +1,39 @@
$ErrorActionPreference = "Stop"
Write-Host "Publishing project..."
dotnet publish -c Release -r win-x64 -p:PublishSingleFile=true -o ./publish
Write-Host "Finding binary..."
$binary = Get-ChildItem -Path ./publish -Filter "anchor.exe" -File | Select-Object -First 1
if (-not $binary) {
Write-Host "Error: Could not find anchor.exe in ./publish" -ForegroundColor Red
exit 1
}
Write-Host "Found binary: $($binary.FullName)"
# Define the installation directory in the user's profile
$installDir = Join-Path $env:USERPROFILE ".anchor\bin"
if (-not (Test-Path $installDir)) {
Write-Host "Creating installation directory: $installDir"
New-Item -ItemType Directory -Path $installDir | Out-Null
}
Write-Host "Copying to $installDir..."
Copy-Item -Path $binary.FullName -Destination $installDir -Force
# Check if the installation directory is in the User PATH
$userPath = [Environment]::GetEnvironmentVariable("PATH", "User")
if ($userPath -split ';' -notcontains $installDir) {
Write-Host "Adding $installDir to User PATH..."
$newPath = if ($userPath) { "$userPath;$installDir" } else { $installDir }
[Environment]::SetEnvironmentVariable("PATH", $newPath, "User")
Write-Host "PATH updated. You may need to restart your terminal for changes to take effect." -ForegroundColor Yellow
}
else {
Write-Host "$installDir is already in the PATH."
}
Write-Host "Installation complete!" -ForegroundColor Green