fix(worker): keep interactive & planning prompts intact past Windows Terminal
wt.exe treats ';' as a command/tab delimiter in every argument, with no escape that survives quoting (microsoft/terminal#13264), so a task description containing ';' spawned extra terminals on "Run interactively" and planning start. Route the launch as wt -> powershell -> claude and pass the free-text prompt via $env:CLAUDEDO_LAUNCH_PROMPT so it never reaches the wt command line; PowerShell binds the variable as a single argument (embedded quotes escaped for PS 5.1). Also clarify the launcher, which serves interactive runs too (not just planning): IPlanningTerminalLauncher -> ITerminalLauncher, WindowsTerminalPlanningLauncher -> WindowsTerminalLauncher, LaunchStart/Resume -> LaunchPlanning{Start,Resume}Async.
This commit is contained in:
@@ -24,7 +24,7 @@ public sealed class PlanningHubTests : IDisposable
|
||||
private readonly ListRepository _lists;
|
||||
private readonly string _rootDir;
|
||||
private readonly PlanningSessionManager _planning;
|
||||
private readonly FakePlanningLauncher _launcher;
|
||||
private readonly FakeTerminalLauncher _launcher;
|
||||
private readonly RecordingClientProxy _proxy;
|
||||
|
||||
public PlanningHubTests()
|
||||
@@ -40,7 +40,7 @@ public sealed class PlanningHubTests : IDisposable
|
||||
var built = TaskStateServiceBuilder.Build(_db.CreateFactory());
|
||||
_planning = new PlanningSessionManager(
|
||||
_tasks, _lists, settingsRepo, git, cfg, _rootDir, built.State, built.Chain);
|
||||
_launcher = new FakePlanningLauncher();
|
||||
_launcher = new FakeTerminalLauncher();
|
||||
_proxy = new RecordingClientProxy();
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ public sealed class PlanningHubTests : IDisposable
|
||||
_launcher.ShouldThrow = true;
|
||||
var hub = CreateHub();
|
||||
|
||||
await Assert.ThrowsAsync<PlanningLaunchException>(() =>
|
||||
await Assert.ThrowsAsync<TerminalLaunchException>(() =>
|
||||
hub.StartPlanningSessionAsync(taskId));
|
||||
|
||||
var loaded = await _tasks.GetByIdAsync(taskId);
|
||||
@@ -173,21 +173,21 @@ public sealed class PlanningHubTests : IDisposable
|
||||
// Fakes
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
internal sealed class FakePlanningLauncher : IPlanningTerminalLauncher
|
||||
internal sealed class FakeTerminalLauncher : ITerminalLauncher
|
||||
{
|
||||
public bool ShouldThrow { get; set; }
|
||||
public int LaunchStartCalls { get; private set; }
|
||||
public int LaunchResumeCalls { get; private set; }
|
||||
public int LaunchInteractiveCalls { get; private set; }
|
||||
|
||||
public Task LaunchStartAsync(PlanningSessionStartContext ctx, CancellationToken cancellationToken)
|
||||
public Task LaunchPlanningStartAsync(PlanningSessionStartContext ctx, CancellationToken cancellationToken)
|
||||
{
|
||||
if (ShouldThrow) throw new PlanningLaunchException("fake launch failure");
|
||||
if (ShouldThrow) throw new TerminalLaunchException("fake launch failure");
|
||||
LaunchStartCalls++;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task LaunchResumeAsync(PlanningSessionResumeContext ctx, CancellationToken cancellationToken)
|
||||
public Task LaunchPlanningResumeAsync(PlanningSessionResumeContext ctx, CancellationToken cancellationToken)
|
||||
{
|
||||
LaunchResumeCalls++;
|
||||
return Task.CompletedTask;
|
||||
@@ -195,7 +195,7 @@ internal sealed class FakePlanningLauncher : IPlanningTerminalLauncher
|
||||
|
||||
public Task LaunchInteractiveAsync(InteractiveLaunchContext ctx, CancellationToken cancellationToken)
|
||||
{
|
||||
if (ShouldThrow) throw new PlanningLaunchException("fake launch failure");
|
||||
if (ShouldThrow) throw new TerminalLaunchException("fake launch failure");
|
||||
LaunchInteractiveCalls++;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user