zinkee 0.1.10 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,35 @@
10
10
  "Read(//home/guillermo/dev/z2-backend/**)",
11
11
  "Bash(grep *)",
12
12
  "Bash(npx vitest *)",
13
- "Bash(npx tsx *)"
13
+ "Bash(npx tsx *)",
14
+ "Bash(node dist/index.js --help)",
15
+ "Bash(gh repo *)",
16
+ "WebFetch(domain:github.com)",
17
+ "Bash(git config *)",
18
+ "Read(//home/guillermo/.config/**)",
19
+ "Read(//home/guillermo/**)",
20
+ "Bash(curl *)",
21
+ "Bash(node dist/index.js --show-completion zsh)",
22
+ "Bash(node *)",
23
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee\" COMP_CWORD=1 node *)",
24
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas\" COMP_CWORD=2 node *)",
25
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas fields\" COMP_CWORD=3 node dist/index.js)",
26
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas fields cr\" COMP_CWORD=3 node dist/index.js)",
27
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas list --j\" COMP_CWORD=3 node dist/index.js)",
28
+ "Bash(rm -rf /tmp/zinkee-install)",
29
+ "Bash(mkdir -p /tmp/zinkee-install)",
30
+ "Bash(HOME=/tmp/zinkee-install SHELL=/bin/zsh node dist/index.js --install-completion)",
31
+ "Read(//tmp/**)",
32
+ "Read(//tmp/zinkee-install/**)",
33
+ "Bash(rm -rf /tmp/zinkee-install-bash)",
34
+ "Bash(mkdir -p /tmp/zinkee-install-bash)",
35
+ "Bash(HOME=/tmp/zinkee-install-bash SHELL=/bin/bash node dist/index.js --install-completion)",
36
+ "Bash(rm -rf /tmp/zinkee-install-fish)",
37
+ "Bash(mkdir -p /tmp/zinkee-install-fish)",
38
+ "Bash(_ZINKEE_COMPLETE=zsh_complete node dist/index.js)",
39
+ "Bash(echo \"exit: $?\")",
40
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas\" COMP_CWORD=abc node dist/index.js)",
41
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee config show --foo --bar baz quux ?\" COMP_CWORD=10 node dist/index.js)"
14
42
  ]
15
43
  }
16
44
  }
package/AGENTS.md CHANGED
@@ -45,6 +45,7 @@ Use this order when reasoning about behavior:
45
45
  - JSON/table output helpers live in `src/utils/output.ts`
46
46
  - shared CLI error handling lives in `src/utils/errors.ts`
47
47
  - parsers live in `src/parsers`
48
+ - shell completion (engine, scripts, install, runtime) lives in `src/completion`
48
49
 
49
50
  ## Testing
50
51
 
package/README.md CHANGED
@@ -68,6 +68,18 @@ base_url = "https://api.zinkee.com"
68
68
  | `--read-only` | Run in read-only mode |
69
69
  | `--example` | Show examples for a command |
70
70
  | `--json` | Emit JSON output |
71
+ | `--install-completion [shell]` | Install shell completion (bash, zsh, fish, powershell) |
72
+ | `--show-completion [shell]` | Print the completion script to stdout |
73
+
74
+ ## Shell completion
75
+
76
+ ```bash
77
+ zinkee --install-completion # auto-detects $SHELL and installs
78
+ zinkee --install-completion zsh # force a specific shell
79
+ zinkee --show-completion zsh # print the script (for inspection)
80
+ ```
81
+
82
+ After installing, restart your shell.
71
83
 
72
84
  ## Runtime Resolution
73
85
 
package/dist/index.js CHANGED
@@ -10961,7 +10961,7 @@ var require2 = createRequire(import.meta.url);
10961
10961
  var { version } = require2("../package.json");
10962
10962
  function buildProgram(options = {}) {
10963
10963
  const program = new Command10();
10964
- program.name("zinkee").description("CLI for Zinkee API v2").version(version).enablePositionalOptions().showHelpAfterError().option("--profile <name>", "select a profile from config").option("--base-url <url>", "override the configured base URL").option("--api-key <token>", "override the configured API key").option("--read-only", "run in read-only mode").option("--example", "show examples for a command").option("--json", "emit JSON output");
10964
+ program.name("zinkee").description("CLI for Zinkee API v2").version(version).enablePositionalOptions().showHelpAfterError().option("--profile <name>", "select a profile from config").option("--base-url <url>", "override the configured base URL").option("--api-key <token>", "override the configured API key").option("--read-only", "run in read-only mode").option("--example", "show examples for a command").option("--json", "emit JSON output").option("--install-completion [shell]", "install shell completion (bash, zsh, fish, powershell)").option("--show-completion [shell]", "print shell completion script for the current shell");
10965
10965
  registerProfilesCommands(program, options);
10966
10966
  registerAutomationsCommands(program, options);
10967
10967
  registerConfigCommands(program, options);
@@ -10976,6 +10976,539 @@ function buildProgram(options = {}) {
10976
10976
  return program;
10977
10977
  }
10978
10978
 
10979
+ // src/completion/engine.ts
10980
+ function readProfileNamesFromConfig(configPath) {
10981
+ try {
10982
+ const config = readConfigIfExists(configPath);
10983
+ if (!config) {
10984
+ return [];
10985
+ }
10986
+ return Object.keys(config.profiles).sort();
10987
+ } catch {
10988
+ return [];
10989
+ }
10990
+ }
10991
+ function findSubcommand(command, name) {
10992
+ return command.commands.find((sub) => {
10993
+ if (sub.name() === name) {
10994
+ return true;
10995
+ }
10996
+ const aliases = sub.aliases();
10997
+ return aliases.includes(name);
10998
+ });
10999
+ }
11000
+ function collectFlagsThatTakeValues(root) {
11001
+ const flags = /* @__PURE__ */ new Set();
11002
+ const walk = (command) => {
11003
+ for (const option of command.options) {
11004
+ if (!option.required && !option.optional) {
11005
+ continue;
11006
+ }
11007
+ if (option.long) {
11008
+ flags.add(option.long);
11009
+ }
11010
+ if (option.short) {
11011
+ flags.add(option.short);
11012
+ }
11013
+ }
11014
+ for (const sub of command.commands) {
11015
+ walk(sub);
11016
+ }
11017
+ };
11018
+ walk(root);
11019
+ return flags;
11020
+ }
11021
+ function descend(root, words) {
11022
+ const flagsWithValues = collectFlagsThatTakeValues(root);
11023
+ let current = root;
11024
+ let index = 0;
11025
+ while (index < words.length) {
11026
+ const word = words[index];
11027
+ if (word.startsWith("-")) {
11028
+ const [flagPart] = word.split("=", 1);
11029
+ if (flagPart && flagsWithValues.has(flagPart) && !word.includes("=")) {
11030
+ index += 2;
11031
+ } else {
11032
+ index += 1;
11033
+ }
11034
+ continue;
11035
+ }
11036
+ const next = findSubcommand(current, word);
11037
+ if (!next) {
11038
+ break;
11039
+ }
11040
+ current = next;
11041
+ index += 1;
11042
+ }
11043
+ return current;
11044
+ }
11045
+ function collectVisibleSubcommands(command) {
11046
+ const names = [];
11047
+ for (const sub of command.commands) {
11048
+ if (sub.name().startsWith("__")) {
11049
+ continue;
11050
+ }
11051
+ names.push(sub.name());
11052
+ }
11053
+ return names;
11054
+ }
11055
+ function collectVisibleLongFlags(command) {
11056
+ const flags = [];
11057
+ let current = command;
11058
+ while (current) {
11059
+ for (const option of current.options) {
11060
+ if (option.hidden || !option.long) {
11061
+ continue;
11062
+ }
11063
+ if (!flags.includes(option.long)) {
11064
+ flags.push(option.long);
11065
+ }
11066
+ }
11067
+ current = current.parent;
11068
+ }
11069
+ if (!flags.includes("--help")) {
11070
+ flags.push("--help");
11071
+ }
11072
+ return flags;
11073
+ }
11074
+ function getCompletions(program, request, deps = {}) {
11075
+ const { words, cwordIndex } = request;
11076
+ const safeIndex = Math.max(0, Math.min(cwordIndex, words.length));
11077
+ const current = words[safeIndex] ?? "";
11078
+ const prevToken = safeIndex > 0 ? words[safeIndex - 1] : void 0;
11079
+ const readProfiles = deps.readProfileNames ?? readProfileNamesFromConfig;
11080
+ if (prevToken === "--profile" || prevToken === "-p") {
11081
+ try {
11082
+ return readProfiles(deps.configPath).filter((name) => name.startsWith(current)).slice().sort();
11083
+ } catch {
11084
+ return [];
11085
+ }
11086
+ }
11087
+ const tokensBeforeCurrent = words.slice(1, safeIndex);
11088
+ const command = descend(program, tokensBeforeCurrent);
11089
+ const candidates = /* @__PURE__ */ new Set();
11090
+ if (current.startsWith("-")) {
11091
+ for (const flag of collectVisibleLongFlags(command)) {
11092
+ if (flag.startsWith(current)) {
11093
+ candidates.add(flag);
11094
+ }
11095
+ }
11096
+ return [...candidates].sort();
11097
+ }
11098
+ for (const subcommand of collectVisibleSubcommands(command)) {
11099
+ if (subcommand.startsWith(current)) {
11100
+ candidates.add(subcommand);
11101
+ }
11102
+ }
11103
+ for (const flag of collectVisibleLongFlags(command)) {
11104
+ if (flag.startsWith(current)) {
11105
+ candidates.add(flag);
11106
+ }
11107
+ }
11108
+ return [...candidates].sort();
11109
+ }
11110
+
11111
+ // src/completion/install.ts
11112
+ import { execFileSync } from "child_process";
11113
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync10, writeFileSync as writeFileSync3 } from "fs";
11114
+ import { homedir as homedir2, platform } from "os";
11115
+ import { basename as basename2, dirname as dirname2, join as join2 } from "path";
11116
+
11117
+ // src/completion/scripts.ts
11118
+ var PROGRAM = "zinkee";
11119
+ var ENV_VAR = "_ZINKEE_COMPLETE";
11120
+ function renderBashScript() {
11121
+ return `_zinkee_completion() {
11122
+ local IFS=$'\\n'
11123
+ local response
11124
+
11125
+ response=$(env COMP_WORDS="\${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD ${ENV_VAR}=bash_complete ${PROGRAM} 2>/dev/null)
11126
+
11127
+ COMPREPLY=( \${response} )
11128
+ return 0
11129
+ }
11130
+
11131
+ complete -o default -F _zinkee_completion ${PROGRAM}
11132
+ `;
11133
+ }
11134
+ function renderZshScript() {
11135
+ return `#compdef ${PROGRAM}
11136
+
11137
+ _zinkee_completion() {
11138
+ local -a response
11139
+ (( ! $+commands[${PROGRAM}] )) && return 1
11140
+
11141
+ response=("\${(@f)$(env COMP_WORDS="\${words[*]}" COMP_CWORD=$((CURRENT - 1)) ${ENV_VAR}=zsh_complete ${PROGRAM} 2>/dev/null)}")
11142
+
11143
+ if [ -n "$response" ]; then
11144
+ compadd -U -V unsorted -a response
11145
+ fi
11146
+ }
11147
+
11148
+ if [[ $zsh_eval_context[-1] == loadautofunc ]]; then
11149
+ _zinkee_completion "$@"
11150
+ else
11151
+ compdef _zinkee_completion ${PROGRAM}
11152
+ fi
11153
+ `;
11154
+ }
11155
+ function renderFishScript() {
11156
+ return `function __zinkee_completion
11157
+ set -l tokens (commandline -opc) (commandline -ct)
11158
+ set -l cword (math (count $tokens) - 1)
11159
+ set -l joined (string join " " -- $tokens)
11160
+
11161
+ env COMP_WORDS="$joined" COMP_CWORD=$cword ${ENV_VAR}=fish_complete ${PROGRAM} 2>/dev/null
11162
+ end
11163
+
11164
+ complete --no-files --command ${PROGRAM} --arguments '(__zinkee_completion)'
11165
+ `;
11166
+ }
11167
+ function renderPowerShellScript() {
11168
+ return `Register-ArgumentCompleter -Native -CommandName ${PROGRAM} -ScriptBlock {
11169
+ param($wordToComplete, $commandAst, $cursorPosition)
11170
+
11171
+ $tokens = @($commandAst.CommandElements | ForEach-Object { $_.ToString() })
11172
+ $cword = [Math]::Max(0, $tokens.Count - 1)
11173
+
11174
+ $env:COMP_WORDS = ($tokens -join ' ')
11175
+ $env:COMP_CWORD = $cword
11176
+ $env:${ENV_VAR} = 'powershell_complete'
11177
+
11178
+ try {
11179
+ & ${PROGRAM} 2>$null | ForEach-Object {
11180
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
11181
+ }
11182
+ } finally {
11183
+ Remove-Item Env:COMP_WORDS -ErrorAction SilentlyContinue
11184
+ Remove-Item Env:COMP_CWORD -ErrorAction SilentlyContinue
11185
+ Remove-Item Env:${ENV_VAR} -ErrorAction SilentlyContinue
11186
+ }
11187
+ }
11188
+ `;
11189
+ }
11190
+ function renderScript(shell) {
11191
+ switch (shell) {
11192
+ case "bash":
11193
+ return renderBashScript();
11194
+ case "zsh":
11195
+ return renderZshScript();
11196
+ case "fish":
11197
+ return renderFishScript();
11198
+ case "powershell":
11199
+ return renderPowerShellScript();
11200
+ }
11201
+ }
11202
+
11203
+ // src/completion/install.ts
11204
+ var SUPPORTED_SHELLS = [
11205
+ "bash",
11206
+ "zsh",
11207
+ "fish",
11208
+ "powershell"
11209
+ ];
11210
+ var BLOCK_BEGIN = "# >>> zinkee completion >>>";
11211
+ var BLOCK_END = "# <<< zinkee completion <<<";
11212
+ var CompletionShellError = class extends Error {
11213
+ name = "CompletionShellError";
11214
+ };
11215
+ function defaultPowerShellProfile(env) {
11216
+ for (const exe of ["pwsh", "powershell.exe"]) {
11217
+ try {
11218
+ const out = execFileSync(exe, ["-NoProfile", "-Command", "$PROFILE"], {
11219
+ encoding: "utf8",
11220
+ stdio: ["ignore", "pipe", "ignore"]
11221
+ });
11222
+ const path = out.trim();
11223
+ if (path) {
11224
+ return path;
11225
+ }
11226
+ } catch {
11227
+ }
11228
+ }
11229
+ if (env.platform === "win32") {
11230
+ return join2(env.home, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1");
11231
+ }
11232
+ return join2(env.home, ".config", "powershell", "Microsoft.PowerShell_profile.ps1");
11233
+ }
11234
+ function detectShell(env) {
11235
+ const fromEnv = env.shellEnv;
11236
+ if (fromEnv) {
11237
+ const name = basename2(fromEnv).toLowerCase().replace(/\.exe$/, "");
11238
+ if (name === "bash") {
11239
+ return "bash";
11240
+ }
11241
+ if (name === "zsh") {
11242
+ return "zsh";
11243
+ }
11244
+ if (name === "fish") {
11245
+ return "fish";
11246
+ }
11247
+ if (name === "pwsh" || name === "powershell") {
11248
+ return "powershell";
11249
+ }
11250
+ }
11251
+ if (env.platform === "win32") {
11252
+ return "powershell";
11253
+ }
11254
+ throw new CompletionShellError(
11255
+ `Could not detect a supported shell from $SHELL=${fromEnv ?? ""}. Pass one of: ${SUPPORTED_SHELLS.join(", ")}.`
11256
+ );
11257
+ }
11258
+ function parseShell(value) {
11259
+ const normalized = value.toLowerCase();
11260
+ if (normalized === "bash" || normalized === "zsh" || normalized === "fish" || normalized === "powershell") {
11261
+ return normalized;
11262
+ }
11263
+ if (normalized === "pwsh") {
11264
+ return "powershell";
11265
+ }
11266
+ throw new CompletionShellError(
11267
+ `Unsupported shell "${value}". Supported: ${SUPPORTED_SHELLS.join(", ")}.`
11268
+ );
11269
+ }
11270
+ function resolveTarget(shell, env) {
11271
+ switch (shell) {
11272
+ case "bash":
11273
+ return {
11274
+ shell,
11275
+ scriptPath: join2(env.home, ".bash_completions", "zinkee.sh"),
11276
+ rcPath: join2(env.home, ".bashrc")
11277
+ };
11278
+ case "zsh":
11279
+ return {
11280
+ shell,
11281
+ scriptPath: join2(env.home, ".zfunc", "_zinkee"),
11282
+ rcPath: join2(env.home, ".zshrc")
11283
+ };
11284
+ case "fish":
11285
+ return {
11286
+ shell,
11287
+ scriptPath: join2(env.home, ".config", "fish", "completions", "zinkee.fish")
11288
+ };
11289
+ case "powershell": {
11290
+ const resolver = env.resolvePowerShellProfile ?? (() => defaultPowerShellProfile(env));
11291
+ const profilePath = resolver();
11292
+ if (!profilePath) {
11293
+ throw new CompletionShellError(
11294
+ "Could not resolve PowerShell $PROFILE path. Install PowerShell or use --show-completion."
11295
+ );
11296
+ }
11297
+ return {
11298
+ shell,
11299
+ scriptPath: profilePath,
11300
+ rcPath: profilePath
11301
+ };
11302
+ }
11303
+ }
11304
+ }
11305
+ function buildRcSnippet(shell, scriptPath) {
11306
+ switch (shell) {
11307
+ case "bash":
11308
+ return `source "${scriptPath}"`;
11309
+ case "zsh":
11310
+ return [
11311
+ `fpath=("${dirname2(scriptPath)}" $fpath)`,
11312
+ "autoload -Uz compinit && compinit"
11313
+ ].join("\n");
11314
+ default:
11315
+ return "";
11316
+ }
11317
+ }
11318
+ function applyBlock(existing, block) {
11319
+ const wrapped = `${BLOCK_BEGIN}
11320
+ ${block.trimEnd()}
11321
+ ${BLOCK_END}
11322
+ `;
11323
+ const blockPattern = new RegExp(
11324
+ `${BLOCK_BEGIN.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${BLOCK_END.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n?`,
11325
+ "m"
11326
+ );
11327
+ if (blockPattern.test(existing)) {
11328
+ return existing.replace(blockPattern, wrapped);
11329
+ }
11330
+ const separator = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
11331
+ return `${existing}${separator}${wrapped}`;
11332
+ }
11333
+ function readFileOrEmpty(path) {
11334
+ try {
11335
+ return readFileSync10(path, "utf8");
11336
+ } catch (error) {
11337
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
11338
+ return "";
11339
+ }
11340
+ throw error;
11341
+ }
11342
+ }
11343
+ function writeFileEnsuringDir(path, content) {
11344
+ mkdirSync2(dirname2(path), { recursive: true });
11345
+ writeFileSync3(path, content, "utf8");
11346
+ }
11347
+ function installCompletion(shell, env) {
11348
+ const target = resolveTarget(shell, env);
11349
+ const script = renderScript(shell);
11350
+ if (shell === "powershell") {
11351
+ const existing = readFileOrEmpty(target.scriptPath);
11352
+ const updated = applyBlock(existing, script);
11353
+ writeFileEnsuringDir(target.scriptPath, updated);
11354
+ return {
11355
+ shell,
11356
+ scriptPath: target.scriptPath,
11357
+ rcPath: target.scriptPath,
11358
+ rcUpdated: true
11359
+ };
11360
+ }
11361
+ writeFileEnsuringDir(target.scriptPath, script);
11362
+ if (!target.rcPath) {
11363
+ return {
11364
+ shell,
11365
+ scriptPath: target.scriptPath,
11366
+ rcUpdated: false
11367
+ };
11368
+ }
11369
+ const snippet = buildRcSnippet(shell, target.scriptPath);
11370
+ if (!snippet) {
11371
+ return {
11372
+ shell,
11373
+ scriptPath: target.scriptPath,
11374
+ rcPath: target.rcPath,
11375
+ rcUpdated: false
11376
+ };
11377
+ }
11378
+ const existingRc = readFileOrEmpty(target.rcPath);
11379
+ const updatedRc = applyBlock(existingRc, snippet);
11380
+ if (updatedRc !== existingRc) {
11381
+ writeFileEnsuringDir(target.rcPath, updatedRc);
11382
+ return {
11383
+ shell,
11384
+ scriptPath: target.scriptPath,
11385
+ rcPath: target.rcPath,
11386
+ rcUpdated: true
11387
+ };
11388
+ }
11389
+ return {
11390
+ shell,
11391
+ scriptPath: target.scriptPath,
11392
+ rcPath: target.rcPath,
11393
+ rcUpdated: false
11394
+ };
11395
+ }
11396
+ function currentEnvironment() {
11397
+ return {
11398
+ home: homedir2(),
11399
+ platform: platform(),
11400
+ shellEnv: process.env.SHELL
11401
+ };
11402
+ }
11403
+
11404
+ // src/completion/runtime.ts
11405
+ var COMPLETION_ENV_VAR = "_ZINKEE_COMPLETE";
11406
+ function getStream(stream, fallback) {
11407
+ return stream ?? fallback;
11408
+ }
11409
+ function parseEnvWords(env) {
11410
+ const raw = env.COMP_WORDS ?? "";
11411
+ if (raw.trim().length === 0) {
11412
+ return [];
11413
+ }
11414
+ return raw.split(/\s+/).filter((token) => token.length > 0);
11415
+ }
11416
+ function parseEnvCwordIndex(env) {
11417
+ const raw = env.COMP_CWORD ?? "0";
11418
+ const parsed = Number.parseInt(raw, 10);
11419
+ if (Number.isNaN(parsed) || parsed < 0) {
11420
+ return 0;
11421
+ }
11422
+ return parsed;
11423
+ }
11424
+ function isCompletionRequest(env = process.env) {
11425
+ return typeof env[COMPLETION_ENV_VAR] === "string" && env[COMPLETION_ENV_VAR].length > 0;
11426
+ }
11427
+ function runCompletionRequest(env = process.env, stdout) {
11428
+ const out = getStream(stdout, process.stdout);
11429
+ try {
11430
+ const program = buildProgram();
11431
+ const candidates = getCompletions(program, {
11432
+ words: parseEnvWords(env),
11433
+ cwordIndex: parseEnvCwordIndex(env)
11434
+ });
11435
+ if (candidates.length > 0) {
11436
+ out.write(`${candidates.join("\n")}
11437
+ `);
11438
+ }
11439
+ } catch {
11440
+ }
11441
+ }
11442
+ function extractCompletionFlag(argv) {
11443
+ for (let index = 0; index < argv.length; index += 1) {
11444
+ const token = argv[index];
11445
+ if (!token) {
11446
+ continue;
11447
+ }
11448
+ if (token === "--install-completion" || token === "--show-completion") {
11449
+ const mode = token === "--install-completion" ? "install" : "show";
11450
+ const next = argv[index + 1];
11451
+ const shellOverride = next && !next.startsWith("-") ? next : void 0;
11452
+ return { mode, shellOverride };
11453
+ }
11454
+ if (token.startsWith("--install-completion=")) {
11455
+ const value = token.slice("--install-completion=".length);
11456
+ return { mode: "install", shellOverride: value || void 0 };
11457
+ }
11458
+ if (token.startsWith("--show-completion=")) {
11459
+ const value = token.slice("--show-completion=".length);
11460
+ return { mode: "show", shellOverride: value || void 0 };
11461
+ }
11462
+ }
11463
+ return null;
11464
+ }
11465
+ function resolveShell(request, env) {
11466
+ if (request.shellOverride) {
11467
+ return parseShell(request.shellOverride);
11468
+ }
11469
+ return detectShell(env);
11470
+ }
11471
+ function handleCompletionFlag(request, deps = {}) {
11472
+ const env = deps.environment ?? currentEnvironment();
11473
+ const out = getStream(deps.stdout, process.stdout);
11474
+ const err = getStream(deps.stderr, process.stderr);
11475
+ let shell;
11476
+ try {
11477
+ shell = resolveShell(request, env);
11478
+ } catch (error) {
11479
+ const message = error instanceof CompletionShellError ? error.message : String(error);
11480
+ err.write(`${message}
11481
+ `);
11482
+ return 1;
11483
+ }
11484
+ if (request.mode === "show") {
11485
+ out.write(renderScript(shell));
11486
+ return 0;
11487
+ }
11488
+ try {
11489
+ const result = installCompletion(shell, env);
11490
+ err.write(`zinkee completion installed for ${shell}.
11491
+ `);
11492
+ err.write(` script: ${result.scriptPath}
11493
+ `);
11494
+ if (result.rcPath && result.rcPath !== result.scriptPath) {
11495
+ err.write(
11496
+ result.rcUpdated ? ` updated: ${result.rcPath}
11497
+ ` : ` unchanged: ${result.rcPath}
11498
+ `
11499
+ );
11500
+ }
11501
+ err.write(`Restart your shell or open a new session to enable completion.
11502
+ `);
11503
+ return 0;
11504
+ } catch (error) {
11505
+ const message = error instanceof Error ? error.message : String(error);
11506
+ err.write(`Failed to install zinkee completion: ${message}
11507
+ `);
11508
+ return 1;
11509
+ }
11510
+ }
11511
+
10979
11512
  // src/cli-runner.ts
10980
11513
  var ExampleDisplayed = class extends Error {
10981
11514
  name = "ExampleDisplayed";
@@ -10998,6 +11531,16 @@ function isExecutedAsEntry(argvEntry, moduleUrl) {
10998
11531
  }
10999
11532
  async function runCli(argv) {
11000
11533
  try {
11534
+ if (isCompletionRequest()) {
11535
+ runCompletionRequest();
11536
+ return;
11537
+ }
11538
+ const completionFlag = extractCompletionFlag(argv);
11539
+ if (completionFlag) {
11540
+ const exitCode = handleCompletionFlag(completionFlag);
11541
+ process.exitCode = exitCode;
11542
+ return;
11543
+ }
11001
11544
  const exampleRequest = extractExampleRequest(argv);
11002
11545
  if (exampleRequest) {
11003
11546
  await showExamples(