Skip to content

fix(cli): defer zsh compdef registration until compinit is available#56555

Merged
hydro13 merged 1 commit intoopenclaw:mainfrom
hydro13:fix/zsh-compdef-deferred-registration
Mar 28, 2026
Merged

fix(cli): defer zsh compdef registration until compinit is available#56555
hydro13 merged 1 commit intoopenclaw:mainfrom
hydro13:fix/zsh-compdef-deferred-registration

Conversation

@hydro13
Copy link
Copy Markdown
Member

@hydro13 hydro13 commented Mar 28, 2026

Summary

  • The generated zsh completion script called compdef at source time, which fails with command not found: compdef when loaded before compinit
  • Replace with deferred registration: tries immediately, if compdef not available queues a self-removing precmd hook that retries on first prompt
  • Handles repeated sourcing (deduped hook entry) and shells that never run compinit
  • Add real zsh integration test

Root Cause

getCompletionScript('zsh') in src/cli/completion-cli.ts emitted bare compdef _openclaw_root_completion openclaw at the top level. This runs at source time, before compinit in most plugin manager and manual setups.

Reference

gh and kubectl both document "run compinit first". We go one step further: defer registration so it works regardless of load order.

Change Type

  • Bug fix

Testing

4/4 tests pass including new zsh integration test that:

  1. Sources the script without compinit → no compdef error
  2. Runs compinit → completion registers correctly

Fixes #14289

@openclaw-barnacle openclaw-barnacle Bot added cli CLI command changes size: S maintainer Maintainer-authored PR labels Mar 28, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 28, 2026

Greptile Summary

This PR fixes a long-standing command not found: compdef error that occurs when the zsh completion script is sourced before compinit runs — the typical situation with most plugin managers and manual ~/.zshrc setups.

What changed:

  • src/cli/completion-cli.ts: Replaces the bare compdef _openclaw_root_completion openclaw at source time with a _openclaw_register_completion helper function. The helper checks $+functions[compdef]; if compdef is already loaded it registers immediately and cleans itself up (removes from precmd_functions, unfunctions itself). If not yet available, the main script queues the helper as a self-removing precmd hook so registration happens on the first shell prompt after compinit is called. A deduplication guard prevents double-registration on repeated sourcing.
  • src/cli/completion-cli.test.ts: Adds a real zsh integration test that sources the script without compinit (verifying no error), then loads compinit -C and manually calls the registration function, asserting _comps[openclaw] is set correctly.

One minor test-coverage gap: the integration test directly invokes _openclaw_register_completion rather than triggering it through the precmd_functions hook, so it does not verify that the hook is correctly queued after sourcing or that it self-removes after firing. The core logic is still sound.

Confidence Score: 5/5

Safe to merge — the deferred registration logic is correct and no runtime regressions were identified.

All findings are P2 (test coverage suggestion). The production zsh script change is logically sound: immediate registration when compdef is available, correct deferred precmd hook with deduplication and self-cleanup when it is not. No P0 or P1 issues found.

src/cli/completion-cli.test.ts — the integration test could be extended to assert hook queuing and self-removal, but this does not block merge.

Important Files Changed

Filename Overview
src/cli/completion-cli.ts Replaces bare compdef at source-time with a deferred _register_completion pattern. Logic is correct: checks $+functions[compdef], registers immediately if available, otherwise queues a self-removing precmd hook with deduplication guard. No issues found.
src/cli/completion-cli.test.ts Adds a zsh integration test with proper platform/binary guards and temp-dir cleanup. Core invariants are verified, but the test bypasses the precmd_functions hook mechanism and never asserts the hook is queued or self-cleans.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/cli/completion-cli.test.ts
Line: 52-76

Comment:
**Test bypasses the precmd hook path**

The test manually calls `_openclaw_register_completion` after `compinit -C` rather than letting the `precmd_functions` hook fire naturally. This means the test validates that the function *itself* works correctly, but never verifies:

1. That `_openclaw_register_completion` was actually added to `precmd_functions` after sourcing (when compdef isn't yet available).
2. That the hook self-removes from `precmd_functions` after it fires.

A more complete test could add assertions like:
```zsh
source ${scriptPath}
# Verify hook is queued
[[ "${precmd_functions[(r)_openclaw_register_completion]}" = "_openclaw_register_completion" ]] || exit 11
autoload -Uz compinit
compinit -C
_openclaw_register_completion
# Verify hook was removed after firing
[[ -z "${precmd_functions[(r)_openclaw_register_completion]}" ]] || exit 12
[[ "${_comps[openclaw]-}" = "_openclaw_root_completion" ]]
```

This won't affect production behavior, but the current test would pass even if the `precmd_functions` registration block were accidentally deleted.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(cli): defer zsh compdef registration..." | Re-trigger Greptile

Comment thread src/cli/completion-cli.test.ts
The generated zsh completion script called compdef at source time,
which fails with 'command not found: compdef' when loaded before
compinit. Replace with a deferred registration that tries immediately,
and if compdef is not yet available, queues a self-removing precmd hook
that retries on first prompt.

Handles repeated sourcing (deduped hook entry) and shells that never
run compinit (completion simply never registers, matching zsh model).

Add real zsh integration test verifying no compdef error on source and
successful registration after compinit.

Fixes openclaw#14289
@hydro13 hydro13 force-pushed the fix/zsh-compdef-deferred-registration branch from 54e7576 to e85ada9 Compare March 28, 2026 18:23
@hydro13 hydro13 merged commit 6be14ab into openclaw:main Mar 28, 2026
35 checks passed
hydro13 added a commit that referenced this pull request Mar 28, 2026
alexcode-cc pushed a commit to alexcode-cc/clawdbot that referenced this pull request Mar 30, 2026
…penclaw#56555)

The generated zsh completion script called compdef at source time,
which fails with 'command not found: compdef' when loaded before
compinit. Replace with a deferred registration that tries immediately,
and if compdef is not yet available, queues a self-removing precmd hook
that retries on first prompt.

Handles repeated sourcing (deduped hook entry) and shells that never
run compinit (completion simply never registers, matching zsh model).

Add real zsh integration test verifying no compdef error on source and
successful registration after compinit.

Fixes openclaw#14289
alexjiang1 pushed a commit to alexjiang1/openclaw that referenced this pull request Mar 31, 2026
…penclaw#56555)

The generated zsh completion script called compdef at source time,
which fails with 'command not found: compdef' when loaded before
compinit. Replace with a deferred registration that tries immediately,
and if compdef is not yet available, queues a self-removing precmd hook
that retries on first prompt.

Handles repeated sourcing (deduped hook entry) and shells that never
run compinit (completion simply never registers, matching zsh model).

Add real zsh integration test verifying no compdef error on source and
successful registration after compinit.

Fixes openclaw#14289
pgondhi987 pushed a commit to pgondhi987/openclaw that referenced this pull request Mar 31, 2026
…penclaw#56555)

The generated zsh completion script called compdef at source time,
which fails with 'command not found: compdef' when loaded before
compinit. Replace with a deferred registration that tries immediately,
and if compdef is not yet available, queues a self-removing precmd hook
that retries on first prompt.

Handles repeated sourcing (deduped hook entry) and shells that never
run compinit (completion simply never registers, matching zsh model).

Add real zsh integration test verifying no compdef error on source and
successful registration after compinit.

Fixes openclaw#14289
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
…penclaw#56555)

The generated zsh completion script called compdef at source time,
which fails with 'command not found: compdef' when loaded before
compinit. Replace with a deferred registration that tries immediately,
and if compdef is not yet available, queues a self-removing precmd hook
that retries on first prompt.

Handles repeated sourcing (deduped hook entry) and shells that never
run compinit (completion simply never registers, matching zsh model).

Add real zsh integration test verifying no compdef error on source and
successful registration after compinit.

Fixes openclaw#14289
Tardisyuan pushed a commit to Tardisyuan/openclaw that referenced this pull request Apr 30, 2026
…penclaw#56555)

The generated zsh completion script called compdef at source time,
which fails with 'command not found: compdef' when loaded before
compinit. Replace with a deferred registration that tries immediately,
and if compdef is not yet available, queues a self-removing precmd hook
that retries on first prompt.

Handles repeated sourcing (deduped hook entry) and shells that never
run compinit (completion simply never registers, matching zsh model).

Add real zsh integration test verifying no compdef error on source and
successful registration after compinit.

Fixes openclaw#14289
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
…penclaw#56555)

The generated zsh completion script called compdef at source time,
which fails with 'command not found: compdef' when loaded before
compinit. Replace with a deferred registration that tries immediately,
and if compdef is not yet available, queues a self-removing precmd hook
that retries on first prompt.

Handles repeated sourcing (deduped hook entry) and shells that never
run compinit (completion simply never registers, matching zsh model).

Add real zsh integration test verifying no compdef error on source and
successful registration after compinit.

Fixes openclaw#14289
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
…penclaw#56555)

The generated zsh completion script called compdef at source time,
which fails with 'command not found: compdef' when loaded before
compinit. Replace with a deferred registration that tries immediately,
and if compdef is not yet available, queues a self-removing precmd hook
that retries on first prompt.

Handles repeated sourcing (deduped hook entry) and shells that never
run compinit (completion simply never registers, matching zsh model).

Add real zsh integration test verifying no compdef error on source and
successful registration after compinit.

Fixes openclaw#14289
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes maintainer Maintainer-authored PR size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: zsh completion fails with command not found: compdef unless compinit is initialized first

1 participant