Skip to content

feat(completion): add shell autocompletion#141

Open
nicknisi wants to merge 8 commits intomainfrom
feat/shell-completion
Open

feat(completion): add shell autocompletion#141
nicknisi wants to merge 8 commits intomainfrom
feat/shell-completion

Conversation

@nicknisi
Copy link
Copy Markdown
Member

@nicknisi nicknisi commented May 4, 2026

Summary

  • Add workos completion <shell> command supporting bash, zsh, fish, and powershell
  • Add hidden --get-yargs-completions fast path intercepted before yargs parses, avoiding validation errors on partial tab input
  • Completion engine walks the existing help-json.ts command registry with normalization to handle the mixed flat/nested naming (e.g. auth login vs skills > install)
  • Descriptions appear alongside candidates in shells that support them (zsh with fzf-tab, fish, powershell)
  • Add README setup instructions for session and persistent shell completion installation
  • Address review findings:
    • Use BSD/macOS-portable bash parsing instead of head -n-1
    • Escape : in zsh descriptions before passing candidates to _describe
    • Split PowerShell completion output on a real tab character using `t
    • Exclude completion from unclaimed-environment warning middleware
    • Avoid mutating the original help-json command registry during normalization
  • Add unit coverage for command/subcommand/option completion, compound name normalization, shell script generation, and the review fixes above

Review & Testing Checklist for Human

  • Verify eval "$(workos completion bash)", eval "$(workos completion zsh)", fish, and PowerShell setup each produce usable completions in a real shell session
  • On macOS/BSD bash, confirm completion still works and no head: illegal line count error appears
  • In zsh, confirm completion descriptions containing : render correctly and do not break candidate parsing
  • In PowerShell, confirm accepting a completion inserts only the command/flag name, not the tab-separated description text
  • Confirm workos completion <shell> does not show an unclaimed-environment warning

Notes

Usage examples:

eval "$(workos completion zsh)"   # load into current session
workos completion bash > /etc/bash_completion.d/workos  # permanent

Local validation run:

  • pnpm test -- src/utils/completion.spec.ts — full Vitest suite passed, 125 files / 1675 tests
  • pnpm lint
  • pnpm typecheck
  • pnpm format:check
  • pnpm build
  • Smoke test generated bash/zsh/PowerShell scripts and workos --get-yargs-completions auth ""

Open in Devin Review

Summary by CodeRabbit

  • New Features

    • Adds a new workos completion command to generate shell autocompletion scripts for Bash, Zsh, Fish, and PowerShell; validates the shell argument and writes the script to stdout.
    • Provides smarter tab-completion: suggests subcommands and options, handles nested commands, respects hidden/used options, and suppresses file completions when appropriate.
  • Documentation

    • Adds a "Shell Completion" README section with usage and session vs. permanent installation examples.
  • Tests

    • Adds unit tests covering completion generation, suggestion behavior, and shell script output for supported shells.

Link to Devin session: https://app.devin.ai/sessions/d1f3c75f768e47d49b8fa040482284bd
Requested by: @nicknisi

nicknisi added 2 commits May 4, 2026 15:32
…owershell

Add `workos completion <shell>` command that generates shell-specific
completion scripts. A hidden `--get-yargs-completions` fast path is
intercepted before yargs parses to avoid validation errors on partial
tab input.

The completion engine walks the existing help-json.ts command registry,
normalizing its mixed flat/nested naming into a uniform tree so both
`auth login` style entries and `skills > install` style entries resolve
correctly for subcommand drilling.

Supports descriptions alongside candidates in shells that render them
(zsh with fzf-tab, fish, powershell).
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds shell autocompletion: a completion engine that normalizes the command registry, computes completions for commands and options, emits a server-format response, and generates Bash/Zsh/Fish/PowerShell scripts. Adds an early CLI fast-path for yargs completion requests and a workos completion <shell> command; tests and README docs added.

Changes

Shell Completion Engine

Layer / File(s) Summary
Help registry (data shape)
src/utils/help-json.ts
Adds a completion top-level command with a required shell positional and exports commands/globalOptions as commandRegistry/globalOptionRegistry.
Completion Engine (core API & behavior)
src/utils/completion.ts
Adds generateCompletions(args) and completeHandler(args), normalization/caching of the command registry, command-tree walking, option-use detection, completion filtering (skip hidden/already-used options), and returns a no-file-completion directive. Exports SUPPORTED_SHELLS, SupportedShell, and generateShellScript.
Registry normalization & caching
src/utils/completion.ts
Normalize mixed flat/compound command names into a virtual-parent tree and cache cloned normalized registry for traversal.
Command tree traversal & option tracking
src/utils/completion.ts
Walk input tokens to find active command node and collect used option flags (skipping option values when appropriate).
Completion generation helpers
src/utils/completion.ts
Produce subcommand and option candidates, filter hidden/already-used options, and package results with a no-file-completion directive.
Shell Script Generators
src/utils/completion.ts
Implement Bash, Zsh, Fish, and PowerShell script generators and generateShellScript(shell, binaryName) that invoke --get-yargs-completions and parse the returned lines.
CLI Fast Path & Command
src/bin.ts
Add top-level rawArgs fast-path intercepting --get-yargs-completions (dynamic import + completeHandler + exit) and a workos completion [shell] command that prints the generated script.
Tests
src/utils/completion.spec.ts, src/utils/help-json.spec.ts
Adds Vitest suites for generateCompletions (many completion cases) and generateShellScript (per-shell output and escaping), and registry-parity assertions in help-json tests.
Documentation
README.md
Add "Shell Completion" section with session and permanent install examples for Bash, Zsh, Fish, and PowerShell and workos completion <shell> usage.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat(completion): add shell autocompletion' directly and clearly describes the main change: adding shell completion functionality to the workos CLI.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/shell-completion

Comment @coderabbitai help to get the list of available commands and usage tips.

nicknisi added 2 commits May 4, 2026 15:34
- Hoist completion intercept above heavy imports (yargs, clack, semver)
  so Tab presses skip ~150ms of module loading
- Export raw command/option arrays from help-json.ts, eliminating double
  buildCommandTree() call and 'in' type narrowing in completion.ts
- Remove dead DIRECTIVE.DEFAULT constant
- Remove unused _resetCache export
- Remove duplicate shell validation in bin.ts (yargs choices +
  generateShellScript throw already cover it)
- Add 7 new tests (option value skipping, empty args, partial prefix
  filtering, hidden commands, descriptions)
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3311d846-0107-405b-8cfa-5f37121338ed

📥 Commits

Reviewing files that changed from the base of the PR and between 9179874 and af85f34.

📒 Files selected for processing (5)
  • README.md
  • src/bin.ts
  • src/utils/completion.spec.ts
  • src/utils/completion.ts
  • src/utils/help-json.ts

Comment thread src/utils/completion.ts
Comment thread src/utils/completion.ts
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 4, 2026

Greptile Summary

This PR adds workos completion <shell> to generate autocompletion scripts for bash, zsh, fish, and PowerShell, along with a hidden --get-yargs-completions fast-path intercepted before yargs loads to keep tab latency low. All three issues raised in prior review threads are addressed in this version: BSD-portable sed '$d' output trimming, escaped colons in zsh _describe specs, PowerShell `t tab literal, and non-mutating registry normalization via cloneCommand.

  • Adds src/utils/completion.ts with a completion engine that normalizes the mixed flat/nested help-json registry, walks the command tree, tracks used options/aliases, and emits per-shell scripts.
  • Inserts the --get-yargs-completions fast-path at the very top of src/bin.ts before dotenv, clack, or yargs load, with completion added to the unclaimed-environment middleware exclusion list.
  • Adds 125 unit tests covering completion generation, shell script content assertions, and the review fixes.

Confidence Score: 5/5

Safe to merge — the change is additive (new command + fast-path exit), the three bugs raised in prior review rounds are all corrected, and the completion engine cannot affect existing command behavior.

The completion fast-path exits before any existing yargs/clack/middleware code runs, so there is no regression risk for any current command. All three prior findings (BSD head portability, zsh colon-escaping, PowerShell tab literal) are fixed and covered by explicit test assertions. Registry normalization no longer mutates the original commandRegistry objects. The new middleware exclusion for completion is a one-liner addition to an existing allowlist.

No files require special attention.

Important Files Changed

Filename Overview
src/utils/completion.ts New completion engine and shell script generators. All three previously flagged bugs (head portability, zsh colon escaping, PowerShell tab literal) are correctly fixed.
src/bin.ts Fast-path for --get-yargs-completions added before yargs/clack load; completion command registered; exclusion list in unclaimed-env middleware updated.
src/utils/completion.spec.ts Comprehensive test coverage for completion engine and shell script generators, including regression tests for all three review-fix items.
src/utils/help-json.ts Exports commandRegistry and globalOptionRegistry; adds completion command entry. Clean change.
src/utils/help-json.spec.ts Adds registry-parity tests ensuring every public top-level command in bin.ts has a matching help-json entry.
README.md Adds Shell Completion section with session and persistent installation examples for all four shells.

Sequence Diagram

sequenceDiagram
    participant Shell as Shell (bash/zsh/fish/PS)
    participant Bin as workos bin.ts
    participant CE as completion.ts
    participant Reg as help-json registry

    Note over Shell: User presses Tab
    Shell->>Bin: workos --get-yargs-completions [words...]
    Note over Bin: Fast-path: intercepted before yargs/clack load
    Bin->>CE: completeHandler(args)
    CE->>Reg: commandRegistry / globalOptionRegistry
    Reg-->>CE: CommandSchema[], OptionSchema[]
    CE->>CE: normalizeRegistry() — flat→nested
    CE->>CE: walkCommandTree() — resolve command + usedOptions
    CE->>CE: completeSubcommands() + completeOptions()
    CE-->>Bin: name\tdescription lines + :directive
    Bin-->>Shell: stdout output
    Note over Shell: Parse tab-separated lines, offer completions

    Note over Shell: User runs workos completion zsh
    Shell->>Bin: workos completion zsh
    Bin->>CE: generateShellScript('zsh', 'workos')
    CE-->>Bin: zsh script string
    Bin-->>Shell: stdout (pipe to eval or file)
Loading

Reviews (4): Last reviewed commit: "Handle inline option values" | Re-trigger Greptile

Comment thread src/utils/completion.ts Outdated
Comment thread src/utils/completion.ts
Comment thread src/utils/completion.ts Outdated
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment thread src/bin.ts
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 completion command not excluded from unclaimed-env middleware

The completion command is missing from the middleware exclusion list at src/bin.ts:200. The middleware comment explicitly states that utility commands like skills, doctor, env, and debug are excluded because the warning is unnecessary — completion is also a utility command but was not added. When completion runs through the middleware, maybeWarnUnclaimed() may make an API call (adding latency) and emit a stderr warning. While it won't corrupt the stdout script output, running eval "$(workos completion bash)" could flash a confusing "Unclaimed environment" warning.

(Refers to lines 200-202)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread src/utils/completion.ts Outdated
if ($line -match '^:(\\d+)$') {
$directive = [int]$matches[1]
} elseif ($line.Trim()) {
$parts = $line.Split("\\t", 2)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 PowerShell completion script splits on literal \t instead of tab character

The generated PowerShell completion script uses $line.Split("\t", 2) to parse tab-separated completions. However, in PowerShell, "\t" is the literal two-character string backslash-t — PowerShell uses backtick escapes ("`t") for tab characters, not backslash escapes. The .Split() method is not regex-based, so it won't interpret \t as a tab.

Impact on different PowerShell versions

On PowerShell 7+ (.NET 6+): .Split("\t", 2) matches String.Split(String, Int32) and looks for the literal two-character string \t, which never appears in the output (the actual output uses real tab characters from src/utils/completion.ts:29). The entire line becomes $comp, including the tab and description text.

On PowerShell 5 (.NET Framework): .Split("\t", 2) resolves to Split(Char[], Int32), splitting on either \ or t as individual characters. This incorrectly splits any completion containing the letter t (e.g., --git-check splits into --gi and -check...).

Prompt for agents
In src/utils/completion.ts, the generatePowershell function at line 364 outputs `$parts = $line.Split("\\t", 2)` which generates PowerShell code `$parts = $line.Split("\t", 2)`. In PowerShell, `"\t"` is a literal backslash-t, not a tab character. PowerShell uses backtick escapes for special characters.

The fix needs to produce PowerShell code that splits on an actual tab character. Two options:

1. Use PowerShell's [char]9 for a tab: change the line to produce `$parts = $line.Split([char]9, 2)` — this works on both PowerShell 5 and 7.

2. Use PowerShell's backtick escape: change to produce `$parts = $line.Split("`t", 2)` — but this requires careful escaping in the JavaScript template literal since backtick is the template delimiter.

Option 1 is simpler and avoids JS escaping complexity. In the JS template literal, the line should be: `$parts = $line.Split([char]9, 2)`
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Add parameterized test that asserts every public bin.ts command has a
matching entry in the help-json registry. Catches forgotten registry
updates at CI time (which would cause missing tab completions and
missing --help --json entries).

Also add 7 completion edge case tests: option value skipping, empty
args, partial prefix filtering, hidden commands, descriptions.
Comment thread src/utils/completion.ts Outdated
devin-ai-integration Bot and others added 2 commits May 7, 2026 16:55
Co-Authored-By: nick.nisi@workos.com <nick.nisi@workos.com>
Co-Authored-By: nick.nisi@workos.com <nick.nisi@workos.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1178ac09-8af7-4e1f-b019-2d396251ab1b

📥 Commits

Reviewing files that changed from the base of the PR and between 0ba7d77 and 16bba52.

📒 Files selected for processing (2)
  • src/utils/completion.spec.ts
  • src/utils/completion.ts

Comment thread src/utils/completion.ts
Co-Authored-By: nick.nisi@workos.com <nick.nisi@workos.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant