Skip to content

Commit 1bad87c

Browse files
committed
feat(npm): auto-install shell completion on
New npm postinstall script (scripts/postinstall.js) that runs after every changed 2 packages in 2s. It detects the user's shell from $SHELL (or defaults to PowerShell on Windows) and installs the right completion script to the standard auto-load location for that shell: bash -> ~/.local/share/bash-completion/completions/ado zsh -> ~/.zsh/completions/_ado (+ fpath/compinit in ~/.zshrc) fish -> ~/.config/fish/completions/ado.fish pwsh -> ~/.config/powershell/ado-completion.ps1 (+ . -source line in $PROFILE) The script is idempotent: re-running just refreshes the generated completion (regenerated on every ado upgrade, so new subcommands get auto-discovered). The zsh/pwsh config edits check for a marker line and skip if already configured. Opt out with: ADO_NO_COMPLETION=1 npm install -g @gilbertwong1996/ado For testing, the script honors ADO_BIN env var (point at a real binary) and falls back to the npm-resolved wrapper. Bugs fixed in the completion generator along the way: - Schema.build_tree/0 returns maps with atom keys; the generators used string keys. Added a normalize/1 helper that recurses through the tree, converting all keys to strings. Without this, the generated scripts had empty subcommand lists (matching nothing). - Powershell's @ado_top = @("") emitted an empty string instead of an empty array. Now emits @() for an empty subcommand list. Tests (scripts/test_postinstall.js, 5 cases): - bash detection + XDG path - zsh detection + .zshrc config edit - fish detection + standard path - ADO_NO_COMPLETION=1 skips cleanly - Second run is idempotent (no duplicate config lines)
1 parent 0f2023b commit 1bad87c

5 files changed

Lines changed: 511 additions & 7 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,4 @@ burrito/
3838
ado.tgz
3939
# Git worktrees for parallel agent work
4040
.worktrees/
41+
node_modules/

lib/ado_cli/cli/completion.ex

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,21 @@ defmodule AdoCli.CLI.Completion do
149149
@spec default_shell() :: String.t()
150150
def default_shell, do: @default_shell
151151

152+
# Schema.build_tree/0 returns a map with atom keys (because
153+
# node_to_map/1 builds the result with `Keyword.get` style
154+
# implicit keys). The subcommands are nested maps, also with
155+
# atom keys. For our string-keyed access below, normalize
156+
# each node to have string keys (and recurse into nested maps
157+
# and lists).
158+
defp normalize(tree) do
159+
tree
160+
|> Enum.into(%{}, fn {k, v} -> {to_string(k), normalize_value(v)} end)
161+
end
162+
163+
defp normalize_value(v) when is_map(v) and not is_struct(v), do: normalize(v)
164+
defp normalize_value(v) when is_list(v), do: Enum.map(v, &normalize/1)
165+
defp normalize_value(v), do: v
166+
152167
@doc """
153168
Returns the full completion script for the given shell.
154169
@@ -162,14 +177,13 @@ defmodule AdoCli.CLI.Completion do
162177
"""
163178
@spec generate(String.t(), map()) :: String.t()
164179
def generate(shell, tree) do
165-
tree = tree || %{}
166-
subcommands = tree["subcommands"] || []
180+
tree = normalize(tree || %{})
167181

168182
case shell do
169-
"bash" -> generate_bash(subcommands)
170-
"zsh" -> generate_zsh(subcommands)
171-
"fish" -> generate_fish(subcommands)
172-
"powershell" -> generate_powershell(subcommands)
183+
"bash" -> generate_bash(tree["subcommands"] || [])
184+
"zsh" -> generate_zsh(tree["subcommands"] || [])
185+
"fish" -> generate_fish(tree["subcommands"] || [])
186+
"powershell" -> generate_powershell(tree["subcommands"] || [])
173187
other -> raise ArgumentError, "Unknown shell: #{other}"
174188
end
175189
end
@@ -439,6 +453,12 @@ defmodule AdoCli.CLI.Completion do
439453
candidates_ps = powershell_candidates_block(flat_list)
440454
top_names = Enum.map(subcommands, &last_segment(&1["name"] || ""))
441455

456+
top_array =
457+
case top_names do
458+
[] -> "@()"
459+
names -> "@('" <> Enum.join(names, "', '") <> "')"
460+
end
461+
442462
"""
443463
# PowerShell completion for the ado CLI
444464
# Generated by: ado completion -s powershell
@@ -448,7 +468,7 @@ defmodule AdoCli.CLI.Completion do
448468
using namespace System.Management.Automation.Language
449469
450470
# Top-level candidates (also the fallback)
451-
$ado_top = @('#{Enum.join(top_names, "', '")}')
471+
$ado_top = #{top_array}
452472
453473
# Path -> candidates map for nested completion
454474
# Generated from the CliMate command tree

npm/@gilbertwong1996-ado/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@
2323
"bin": {
2424
"ado": "bin/ado"
2525
},
26+
"scripts": {
27+
"postinstall": "node scripts/postinstall.js"
28+
},
2629
"files": [
2730
"bin/ado",
31+
"scripts/postinstall.js",
2832
"README.md",
2933
"LICENSE"
3034
],

0 commit comments

Comments
 (0)