Skip to content

fix(hooks): the Copilot skip guard changes with bundler renames #1356

Closed

Description

@SaulMoro

Summary

src/claude-hook-host.ts builds the Copilot skip guard of every Claude team hook from copilotRunsEntries.toString(). In the published CLI that is the bundled source, and the bundler is free to rename the function's locals when another module in the same chunk declares the same name at top level. When it does, the hook command teamai writes changes even though no hook changed:

  • teamai pull sees a different command and rewrites every Claude team hook.
  • The hook hashes change too: the Copilot guard embeds them, and tools that trust hooks by hash (Codex) see new hooks.
  • Tests that compare against the unbundled text fail.

Evidence

#1297 adds a top-level async function entries() in src/workflow/scoring.ts. In its CI the bundled guard reads flatMap(([event, entries2]) => …) instead of flatMap(([event, entries]) => …). Four e2e tests then fail on the command text: hooks-team-e2e, hooks-project-isolation-issue373 (2) and scope-isolation-issue85. See https://github.com/Tencent/teamai-cli/actions/runs/40060685552.

Suggested fix

Do not derive hook command text from Function.prototype.toString() of bundled code. Keep the guard as one string constant, and have copilotRunsEntries and the guard share a test that runs both on the same inputs. Any rename-sensitive toString() elsewhere in hook rendering has the same problem.

Introduced with the Copilot user-scope built-ins (#1038).

Activity

  1. added a commit that references this issue on Oct 24, 2026
    afdfe35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions