Skip to content

Commit 4ad6a73

Browse files
committed
fix: run postcreate hook before tmux startup
1 parent 8143fce commit 4ad6a73

3 files changed

Lines changed: 17 additions & 10 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,12 @@ lifecycleHooks:
171171
| `startupEnvs.<KEY>` | string or boolean | no | Extra env vars materialized into worktree runtime env |
172172
| `auto_name.model` | string | no | Model used to generate the branch name when the branch field is left empty; supports Anthropic (`claude-*`), Gemini (`gemini-*`), and OpenAI (`gpt-*`, `chatgpt-*`, `o*`) models |
173173
| `auto_name.system_prompt` | string | no | System prompt sent to the auto-name model |
174-
| `lifecycleHooks.postCreate` | string | no | Shell command run after a managed worktree is created and its session is materialized |
174+
| `lifecycleHooks.postCreate` | string | no | Shell command run after a managed worktree is created and its runtime env is materialized, but before the tmux session/panes are started |
175175
| `lifecycleHooks.preRemove` | string | no | Shell command run before a managed worktree is removed |
176176

177177
</details>
178178

179-
Lifecycle hooks run with the worktree as `cwd` and receive the same computed runtime env as the managed panes, including `startupEnvs`, allocated service ports, and `WEBMUX_*` metadata.
179+
Lifecycle hooks run with the worktree as `cwd` and receive the same computed runtime env that the managed panes will use, including `startupEnvs`, allocated service ports, and `WEBMUX_*` metadata.
180180

181181
When `auto_name` is enabled, `webmux` calls the provider API directly with structured output and uses `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, or `OPENAI_API_KEY` based on the configured model.
182182

backend/src/__tests__/lifecycle-service.test.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,16 @@ class FakePortProbe implements PortProbe {
109109
class FakeHookRunner implements LifecycleHookRunner {
110110
readonly calls: RunLifecycleHookInput[] = [];
111111

112+
constructor(
113+
private readonly onRun?: (input: RunLifecycleHookInput) => void,
114+
) {}
115+
112116
async run(input: RunLifecycleHookInput): Promise<void> {
113117
this.calls.push({
114118
...input,
115119
env: { ...input.env },
116120
});
121+
this.onRun?.(input);
117122
}
118123
}
119124

@@ -277,7 +282,9 @@ describe("LifecycleService", () => {
277282
const repoRoot = await initRepo();
278283
const runtime = new ProjectRuntime();
279284
const tmux = new FakeTmuxGateway();
280-
const hooks = new FakeHookRunner();
285+
const hooks = new FakeHookRunner(() => {
286+
expect(tmux.listWindows()).toEqual([]);
287+
});
281288
const lifecycle = makeLifecycleService(repoRoot, tmux, runtime, new FakeDockerGateway(), hooks);
282289

283290
const created = await lifecycle.createWorktree({

backend/src/services/lifecycle-service.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ export class LifecycleService {
126126
worktreePath,
127127
});
128128

129+
await this.runLifecycleHook({
130+
name: "postCreate",
131+
command: this.deps.config.lifecycleHooks.postCreate,
132+
meta: initialized.meta,
133+
worktreePath,
134+
});
135+
129136
await this.materializeRuntimeSession({
130137
branch,
131138
profile,
@@ -135,13 +142,6 @@ export class LifecycleService {
135142
prompt: input.prompt,
136143
});
137144

138-
await this.runLifecycleHook({
139-
name: "postCreate",
140-
command: this.deps.config.lifecycleHooks.postCreate,
141-
meta: initialized.meta,
142-
worktreePath,
143-
});
144-
145145
await this.deps.reconciliation.reconcile(this.deps.projectRoot);
146146

147147
return {

0 commit comments

Comments
 (0)