Skip to content

fix(hooks): sessionStart/sessionEnd hooks fire from bridge CWD, not session workingDirectory #233

Description

@raykao

Summary

onSessionStart (and other hooks that fire from the CLI subprocess) execute relative to the bridge process CWD, not the per-session workingDirectory passed to createSession.

Root Cause

CopilotBridge constructs CopilotClient once at startup with no cwd option:

// src/core/bridge.ts
this.client = new CopilotClient({
  autoStart: true,
  telemetry: options?.telemetry,
  env: options?.env,
  // no cwd: option
});

The SDK defaults cwd to process.cwd() (the bridge's launch directory):

// @github/copilot-sdk dist/client.js
cwd: options.cwd ?? process.cwd(),

The CLI subprocess is spawned once from that fixed CWD. workingDirectory is passed as a per-session RPC config, but the CLI process itself was already started from the bridge's launch directory.

Impact

Hook scripts are loaded correctly by the bridge's Node-side loadHooks(workingDirectory) (for preToolUse etc. which the bridge calls directly). But sessionStart/sessionEnd hooks are fired by the CLI subprocess via hooks.invoke RPC - that subprocess resolves hook paths relative to its own CWD, not the session's workingDirectory.

Result: workspace-scoped sessionStart hooks silently do nothing for sessions whose workingDirectory differs from the bridge's launch directory.

Affected hooks

  • sessionStart
  • sessionEnd
  • errorOccurred

Hooks dispatched directly by the bridge Node process (preToolUse, postToolUse, userPromptSubmitted) are unaffected because the bridge loads those scripts explicitly from workingDirectory before passing them to the SDK.

Expected behavior

The CLI subprocess should be spawned (or re-spawned) with the session's workingDirectory as its CWD, OR the SDK should support passing a per-session workingDirectory override for hook resolution.

Steps to reproduce

  1. Start the bridge from directory A
  2. Create a session with workingDirectory set to directory B
  3. Place a sessionStart hook in B/.github/hooks/hooks.json
  4. Hook does not fire

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions