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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions