diff --git a/CHANGELOG.md b/CHANGELOG.md index 5425a8d6..89814c6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,7 +43,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 the container boundary. The visible symptom is that the retry `status` itself recommends — `llm-test --provider anthropic-oauth` — fails with a missing-token error, because `llm-test` runs client-side in the helper - rather than on the server (#379). + rather than on the server. The PowerShell wrapper also trims trailing path + separators as individual characters, so Windows invocations reach Docker + instead of failing during path normalization (#379). ## [1.24.0] - 2026-08-04 diff --git a/bin/ai-memory.ps1 b/bin/ai-memory.ps1 index 4d35670a..f610ae86 100644 --- a/bin/ai-memory.ps1 +++ b/bin/ai-memory.ps1 @@ -44,7 +44,7 @@ $HomePath = (Resolve-Path -LiteralPath $HOME).Path $WorkPath = (Get-Location).Path $HookHostRoot = ($HomePath -replace '\\', '/') + "/.local/share/ai-memory/hooks" -$HomeRoot = $HomePath.TrimEnd([char[]]@('/', '\\')) +$HomeRoot = $HomePath.TrimEnd([char[]]@('/', '\')) $HomePrefix = $HomeRoot + [IO.Path]::DirectorySeparatorChar $InsideHome = $WorkPath.Equals($HomeRoot, [StringComparison]::OrdinalIgnoreCase) -or $WorkPath.StartsWith($HomePrefix, [StringComparison]::OrdinalIgnoreCase) @@ -64,7 +64,7 @@ if ($InsideHome) { $ScopeRoot = [IO.Path]::GetFullPath($DetectedScopeRoot.Trim()) } } - $ScopeRoot = $ScopeRoot.TrimEnd([char[]]@('/', '\\')) + $ScopeRoot = $ScopeRoot.TrimEnd([char[]]@('/', '\')) $ScopePrefix = $ScopeRoot + [IO.Path]::DirectorySeparatorChar if ($WorkPath.Equals($ScopeRoot, [StringComparison]::OrdinalIgnoreCase)) { $ScopeSuffix = "" diff --git a/crates/ai-memory-cli/tests/packaging.rs b/crates/ai-memory-cli/tests/packaging.rs index dda9d47a..4a52cf88 100644 --- a/crates/ai-memory-cli/tests/packaging.rs +++ b/crates/ai-memory-cli/tests/packaging.rs @@ -1365,6 +1365,21 @@ fn powershell_wrapper_lists_subscription_oauth_tokens_in_its_env_allowlist() { } } +#[test] +fn powershell_wrapper_trims_paths_with_single_character_separators() { + let wrapper = read_repo("bin/ai-memory.ps1"); + + assert_eq!( + wrapper.matches(r"TrimEnd([char[]]@('/', '\'))").count(), + 2, + "PowerShell TrimEnd arguments must contain individual characters" + ); + assert!( + !wrapper.contains(r"TrimEnd([char[]]@('/', '\\'))"), + "a multi-character backslash string cannot be converted to System.Char" + ); +} + #[cfg(windows)] #[test] fn powershell_wrapper_forwards_subscription_oauth_tokens_without_putting_values_in_argv() {