Skip to content

Commit bf270f3

Browse files
committed
Added Windows editor arg quoting and git status refresh after worktree bootstrap
Adapted from upstream t3code #1805 and #2005. launchDetached now quotes each arg with double quotes on Windows (shell: true) to handle paths with spaces. Added refreshGitStatus call after worktree creation in wsBootstrap and after branch rename in ProviderCommandReactorSessionOps. Updated ProviderCommandReactor test to include GitStatusBroadcaster mock.
1 parent 21a1b21 commit bf270f3

4 files changed

Lines changed: 48 additions & 6 deletions

File tree

apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ import {
2727
type ProviderServiceShape,
2828
} from "../../provider/Services/ProviderService.ts";
2929
import { GitCore, type GitCoreShape } from "../../git/Services/GitCore.ts";
30+
import {
31+
GitStatusBroadcaster,
32+
type GitStatusBroadcasterShape,
33+
} from "../../git/Services/GitStatusBroadcaster.ts";
3034
import { TextGeneration, type TextGenerationShape } from "../../git/Services/TextGeneration.ts";
3135
import { OrchestrationEngineLive } from "./OrchestrationEngine.ts";
3236
import { OrchestrationProjectionPipelineLive } from "./ProjectionPipeline.ts";
@@ -180,6 +184,24 @@ describe("ProviderCommandReactor", () => {
180184
: "renamed-branch",
181185
}),
182186
);
187+
const refreshLocalStatus = vi.fn((_: string) =>
188+
Effect.succeed({
189+
isRepo: true,
190+
hasOriginRemote: true,
191+
isDefaultBranch: false,
192+
branch: "renamed-branch",
193+
hasWorkingTreeChanges: false,
194+
workingTree: {
195+
files: [],
196+
insertions: 0,
197+
deletions: 0,
198+
},
199+
hasUpstream: true,
200+
aheadCount: 0,
201+
behindCount: 0,
202+
pr: null,
203+
}),
204+
);
183205
const generateBranchName = vi.fn<TextGenerationShape["generateBranchName"]>((_) =>
184206
Effect.fail(
185207
new TextGenerationError({
@@ -235,6 +257,11 @@ describe("ProviderCommandReactor", () => {
235257
}),
236258
),
237259
Layer.provideMerge(Layer.succeed(GitCore, { renameBranch } as unknown as GitCoreShape)),
260+
Layer.provideMerge(
261+
Layer.succeed(GitStatusBroadcaster, {
262+
refreshLocalStatus,
263+
} as unknown as GitStatusBroadcasterShape),
264+
),
238265
Layer.provideMerge(
239266
Layer.mock(TextGeneration, {
240267
generateBranchName,
@@ -290,6 +317,7 @@ describe("ProviderCommandReactor", () => {
290317
respondToUserInput,
291318
stopSession,
292319
renameBranch,
320+
refreshLocalStatus,
293321
generateBranchName,
294322
generateThreadTitle,
295323
stateDir,

apps/server/src/utils/open.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,16 @@ export const launchDetached = (launch: EditorLaunch) =>
293293
yield* Effect.callback<void, OpenError>((resume) => {
294294
let child;
295295
try {
296-
child = spawn(launch.command, [...launch.args], {
297-
detached: true,
298-
stdio: "ignore",
299-
shell: process.platform === "win32",
300-
});
296+
const isWin32 = process.platform === "win32";
297+
child = spawn(
298+
launch.command,
299+
isWin32 ? launch.args.map((a) => `"${a}"`) : [...launch.args],
300+
{
301+
detached: true,
302+
stdio: "ignore",
303+
shell: isWin32,
304+
},
305+
);
301306
} catch (error) {
302307
return resume(
303308
Effect.fail(new OpenError({ message: "failed to spawn detached process", cause: error })),

apps/server/src/ws/ws.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,21 @@ const WsRpcLayer = WsRpcGroup.toLayer(
109109
cause,
110110
});
111111

112+
const refreshGitStatusEffect = (cwd: string) =>
113+
gitManager.invalidateStatus(cwd).pipe(
114+
Effect.flatMap(() => gitStatusBroadcaster.invalidateLocal(cwd)),
115+
Effect.flatMap(() => gitStatusBroadcaster.invalidateRemote(cwd)),
116+
);
117+
112118
const dispatchBootstrapTurnStart = makeDispatchBootstrapTurnStart(
113119
orchestrationEngine,
114120
git,
115121
projectSetupScriptRunner,
122+
refreshGitStatusEffect,
116123
appendSetupScriptActivity,
117124
serverCommandId,
118125
);
119126

120-
/** Fire-and-forget helper to invalidate + re-broadcast git status for a cwd. */
121127
const refreshGitStatus = (cwd: string) =>
122128
gitManager.invalidateStatus(cwd).pipe(
123129
Effect.flatMap(() => gitStatusBroadcaster.invalidateLocal(cwd)),

apps/server/src/ws/wsBootstrap.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@ export type BootstrapServices = {
3636
input: ProjectSetupScriptRunnerInput,
3737
) => Effect.Effect<ProjectSetupScriptRunnerResult, Error>;
3838
};
39+
readonly refreshGitStatus: (cwd: string) => Effect.Effect<void>;
3940
};
4041

4142
export function makeDispatchBootstrapTurnStart(
4243
orchestrationEngine: BootstrapServices["orchestrationEngine"],
4344
git: BootstrapServices["git"],
4445
projectSetupScriptRunner: BootstrapServices["projectSetupScriptRunner"],
46+
refreshGitStatus: BootstrapServices["refreshGitStatus"],
4547
appendSetupScriptActivity: (input: {
4648
readonly threadId: ThreadId;
4749
readonly kind: "setup-script.requested" | "setup-script.started" | "setup-script.failed";
@@ -197,6 +199,7 @@ export function makeDispatchBootstrapTurnStart(
197199
branch: worktree.worktree.branch,
198200
worktreePath: targetWorktreePath,
199201
});
202+
yield* refreshGitStatus(targetWorktreePath).pipe(Effect.ignoreCause({ log: true }));
200203
}
201204

202205
yield* runSetupProgram();

0 commit comments

Comments
 (0)