Skip to content

feat(cli): cached shell completion (bash/zsh/fish)#78

Merged
Sootopolis merged 1 commit into
mainfrom
feat/shell-completions
Jun 12, 2026
Merged

feat(cli): cached shell completion (bash/zsh/fish)#78
Sootopolis merged 1 commit into
mainfrom
feat/shell-completions

Conversation

@Sootopolis

Copy link
Copy Markdown
Owner

What

ccas completion <bash|zsh|fish> emits a self-contained, pure-shell completion script. The JVM boots once at install; at <TAB> the script runs entirely in the shell (no JVM, no network) → instant, all three shells. Completes subcommands, flags, club slugs (at slug positions) and recent job ids (ccas logs).

Why this shape (deviates from the issue's literal design)

#49 specified a hidden ccas __complete <argv> subcommand the shell calls per <TAB>. On a JavaAppPackaging binary that boots a JVM (~1.5s) every <TAB> — breaking the issue's own <50ms / cache-only acceptance. So instead:

  • One CompletionSpec mirrors the CliCommand tree (single source of truth); CompletionEmitter generates all three shells from it.
  • Committed completions/ccas.bash is the emitter's bash output (regenerate: ccas completion bash > completions/ccas.bash).
  • Also retires the ~1.5s-per-<TAB> zio-cli dynamic script previously used for zsh/fish.

Dynamic sources

${XDG_CACHE_HOME:-~/.cache}/ccas/{clubs.txt,recent-jobs.txt}, written best-effort by normal commands (never alter exit code): staleness-gated GET /api/clubs refresh after a successful command; each submitted job id appended on submit.

Tests / guards (TestCcasCompletion)

  • completions/ccas.bash == bash emitter output
  • each emitted script passes <shell> -n (skips absent shells; @@ flaky to absorb fork-pressure flakes without masking real syntax errors)
  • CompletionSpec ⊇ tree commands + flags, and value-vs-boolean flag classification matches the tree
  • positional kinds pinned

Verification

  • Full suite 791 green (4 new completion tests + completion parser case).
  • Bash completion driven across 15 scenarios (subcommands, flags, variadic-vs-single slug positional gating, value-flag guard, nested blacklist/schedule, empty-cache no-op).
  • Live end-to-end: real ccas-server (isolated schema) → ccas jobs refreshed clubs.txtccas stats … team-alpha submit wrote the real ULID to recent-jobs.txt (job Completed) → sourced completion served slugs + the ULID with prefix filtering.

Scoped out / notes

  • Empty-cache default_clubs fallback → CLI config file resolution #43 (no CLI config yet).
  • Hidden __complete JVM subcommand intentionally not built.
  • fish offers slugs at every positional of single-slug commands (no portable positional-count); cosmetic, documented in CompletionEmitter. bash/zsh gate correctly.
  • Drive-by: Main's serve branch now logs the crash cause (foldCauseZIO) instead of the error-swallowing fold (body of the deprecated ZIO#exitCode).

Closes #49. Part of epic #40.

🤖 Generated with Claude Code

`ccas completion <bash|zsh|fish>` emits a self-contained, pure-shell
completion script. The JVM boots once at install; at <TAB> the script
runs entirely in the shell (no JVM, no network), meeting the <50ms bar
for all three shells — and retiring the ~1.5s-per-<TAB> zio-cli dynamic
script used for zsh/fish.

This replaces issue #49's hidden `ccas __complete` design: that would
boot the JVM on every <TAB> (~1.5s on a JavaAppPackaging binary),
breaking its own <50ms / cache-only acceptance. Instead the scripts are
generated from a single `CompletionSpec` (mirrors the CliCommand tree)
via `CompletionEmitter`; the committed `completions/ccas.bash` is the
emitter's output, and TestCcasCompletion guards file==emitter,
per-shell `-n` validity, spec⊇tree coverage, and value-vs-boolean flag
classification.

Dynamic candidates — club slugs at slug positions, recent job ids for
`logs` — come from `${XDG_CACHE_HOME:-~/.cache}/ccas/{clubs.txt,
recent-jobs.txt}`, written best-effort by normal commands
(staleness-gated `GET /api/clubs` refresh after a successful command;
each submitted job id appended on submit). The empty-cache
`default_clubs` fallback is deferred to #43 (no CLI config yet).

Drive-by: `Main`'s `serve` branch now logs the server crash cause via
`foldCauseZIO` instead of the error-swallowing
`fold(_ => ExitCode.failure, …)` (the body of the deprecated
`ZIO#exitCode`).

Closes #49.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Sootopolis Sootopolis merged commit ffb1458 into main Jun 12, 2026
1 check passed
@Sootopolis Sootopolis deleted the feat/shell-completions branch June 12, 2026 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shell completions for ccas

1 participant