From 2b122a28c90547412593c0a8a7722d51147b6b69 Mon Sep 17 00:00:00 2001 From: Tomi Eckert Date: Wed, 4 Mar 2026 11:04:01 +0100 Subject: [PATCH] feat: Implement a user-approved shell command execution tool and a Windows installer script. --- AnchorCli.csproj | 6 ++++++ Program.cs | 3 ++- Tools/CommandTool.cs | 11 ++++++++++- installer.ps1 | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 installer.ps1 diff --git a/AnchorCli.csproj b/AnchorCli.csproj index 371ec96..366e3b8 100644 --- a/AnchorCli.csproj +++ b/AnchorCli.csproj @@ -12,6 +12,12 @@ anchor + + $(DefineConstants);WINDOWS + + false + + diff --git a/Program.cs b/Program.cs index f112982..5a8d1d2 100644 --- a/Program.cs +++ b/Program.cs @@ -145,7 +145,7 @@ if (modelInfo != null) // ── Chat history with system prompt ───────────────────────────────────── List history = [ - new(ChatRole.System, """ + new(ChatRole.System, $$""" You are anchor, a coding assistant that edits files using the Hashline technique. ## Reading files @@ -166,6 +166,7 @@ List history = 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. + You are running on: {{System.Runtime.InteropServices.RuntimeInformation.OSDescription}} """) ]; diff --git a/Tools/CommandTool.cs b/Tools/CommandTool.cs index d66f5be..87d9110 100644 --- a/Tools/CommandTool.cs +++ b/Tools/CommandTool.cs @@ -11,7 +11,11 @@ internal static class CommandTool { public static Action 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( [Description("The shell command to execute.")] string command) { @@ -41,8 +45,13 @@ internal static class CommandTool { var startInfo = new ProcessStartInfo { +#if WINDOWS + FileName = "powershell.exe", + Arguments = $"-NoProfile -Command \"{command}\"", +#else FileName = "/bin/bash", Arguments = $"-c \"{command}\"", +#endif UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/installer.ps1 b/installer.ps1 new file mode 100644 index 0000000..31fbcb7 --- /dev/null +++ b/installer.ps1 @@ -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