google-gemini / google-gemini/gemini-cli
hooks: `migrate` copies Claude's `timeout` across a seconds → milliseconds unit change
- Dominant language
- TypeScript
- Stars
- 107k
- Forks
- 14.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 45
Description
### Description
`gemini hooks migrate` copies a Claude Code hook's `timeout` value straight through, but the two products measure it in different units, so an explicitly-set timeout is reduced by a factor of 1000.
In `packages/cli/src/commands/hooks/migrate.ts`:
```js
if ("timeout" in hook && typeof hook["timeout"] === "number") {
migrated["timeout"] = hook["timeout"];
}
```
The units differ:
- **Claude Code** — `hooks[].hooks[].timeout` is in **seconds** (default 60).
- **Gemini CLI** — `packages/core/src/hooks/hookRunner.ts` treats it as **milliseconds**:
```js
var DEFAULT_HOOK_TIMEOUT = 6e4;
...
const timeout = hookConfig.timeout ?? DEFAULT_HOOK_TIMEOUT;
timeoutHandle = setTimeout(
() => reject(new Error(`Hook timed out after ${timeout}ms`)),
timeout
);
```
So a migrated hook carrying `"timeout": 30` — 30 seconds under Claude Code — becomes **30 milliseconds** under Gemini. Almost any real hook command exceeds that, so it fails with `Hook timed out after 30ms`.
The defaults happen to agree (Claude 60 s, Gemini 60000 ms), which is why this only bites users who set `timeout` explicitly — and why it is easy to miss in testing.
### Expected behaviour
`migrateClaudeHook` converts the unit, e.g. `migrated["timeout"] = hook["timeout"] * 1000`.
### Steps to reproduce
1. In `~/.claude/settings.json`, define a hook with `"timeout": 30`.
2. Run `gemini hooks migrate`.
3. Inspect the generated Gemini settings: `timeout` is `30`, not `30000`.
4. Trigger the hook — it fails with `Hook timed out after 30ms`.
### Version
`gemini-cli` 0.57.0 (installed via Homebrew). Verified against the shipped bundle: `bundle/gemini-OYYGXMHL.js` for the migrator, `bundle/chunk-S3MXVTTY.js` for `hookRunner`.
Contributor guide
Research direction
Start in packages/cli/src/commands/hooks/migrate.ts, then compare the migrated timeout with the millisecond handling in packages/core/src/hooks/hookRunner.ts. Verify the migration using the 30-second example from the issue and confirm the generated Gemini settings express the equivalent timeout in milliseconds without changing other hook fields.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 85/100