Skip to content

@effect/cli shell completions break for hyphenated command names #6114

@AndroAmater

Description

@AndroAmater

What version of @effect/cli are you using?

0.73.2

What is the problem this feature would solve?

Generated shell completion scripts appear to handle command names containing - inconsistently.

In my case, this breaks completions for hyphenated commands / subcommands like:

  • self-host
  • runners-start
  • webhook-restart
  • type-check
  • ide-helper
  • update-snapshots

Fish completions seem fine, but bash and zsh generation look wrong in different ways.

For bash, the generated matcher cases use sanitized names like self__host, type__check, ide__helper, etc., even though the actual CLI tokens are hyphenated.

Observed output from getBashCompletions(...):

cannon,api,ide__helper)
cannon,generator,update__snapshots)
cannon,self__host)
cannon,self__host,env)
cannon,self__host,start)
cannon,self__host,runners__start)
cannon,self__host,runners__stop)
cannon,self__host,runners__restart)
cannon,self__host,webhook__start)
cannon,self__host,webhook__stop)
cannon,self__host,webhook__restart)
cannon,type__check)

Expected relevant output:

cannon,api,ide-helper)
cannon,generator,update-snapshots)
cannon,self-host)
cannon,self-host,env)
cannon,self-host,start)
cannon,self-host,runners-start)
cannon,self-host,runners-stop)
cannon,self-host,runners-restart)
cannon,self-host,webhook-start)
cannon,self-host,webhook-stop)
cannon,self-host,webhook-restart)
cannon,type-check)

Without patching the generated script locally, completion after cannon self-host falls back to root suggestions instead of showing runners-start, webhook-start, etc.

For zsh, I also saw helper reference / helper definition naming get out of sync for hyphenated commands. Example shape:

":: :_cannon__self-host_commands"

while the generated helper function is named:

_cannon__self__host_commands() {

So the helper reference uses self-host while the generated function name uses self__host.

What is the feature you are proposing to solve the problem?

Fix completion generation so hyphenated command names are handled consistently across generated scripts:

  • bash command matcher cases should match the actual command tokens typed by the user (self-host, type-check, etc.)
  • zsh helper references should point to the same sanitized helper names that are actually defined

What alternatives have you considered?

For now I worked around it by post-processing the generated completion scripts locally, but it would be better if @effect/cli emitted correct scripts directly.

Minimal reproduction

A simple CLI with hyphenated command names is enough to reproduce it:

import { Command } from "@effect/cli"
import { Effect } from "effect"

const noop = () => Effect.void

const app = Command.make("cannon").pipe(
  Command.withSubcommands([
    Command.make("self-host").pipe(
      Command.withSubcommands([
        Command.make("env", {}, noop),
        Command.make("runners-start", {}, noop),
        Command.make("webhook-restart", {}, noop),
      ]),
    ),
    Command.make("type-check", {}, noop),
    Command.make("api").pipe(
      Command.withSubcommands([
        Command.make("ide-helper", {}, noop),
      ]),
    ),
    Command.make("generator").pipe(
      Command.withSubcommands([
        Command.make("update-snapshots", {}, noop),
      ]),
    ),
  ]),
)

const bash = await Effect.runPromise(Command.getBashCompletions(app, "cannon"))
console.log(bash.join("\n"))

Expected relevant bash output:

cannon,self-host)
cannon,self-host,runners-start)
cannon,type-check)

and zsh helper references / definitions should use a single consistent naming convention.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions