@seedcli/completions 0.1.7 → 0.1.10

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.
package/dist/bash.d.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  import type { CompletionInfo } from "./types.js";
2
2
  /**
3
3
  * Generate a bash completion script.
4
+ *
5
+ * Uses a lookup key built from all command tokens (words[1]..words[cword-1])
6
+ * joined with underscores so that nested subcommand completions are reachable.
7
+ * For example, `mycli db migrate <TAB>` builds the key "db_migrate" which
8
+ * matches the case pattern generated by generateCommandCase.
4
9
  */
5
10
  export declare function bash(info: CompletionInfo): string;
6
11
  //# sourceMappingURL=bash.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../src/bash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,YAAY,CAAC;AAyCpE;;GAEG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAiCjD"}
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../src/bash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,YAAY,CAAC;AAoDpE;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAgDjD"}
package/dist/bash.js CHANGED
@@ -1,20 +1,25 @@
1
- function generateCommandCase(brand, cmd, path) {
1
+ import { sanitizeShellToken } from "./types.js";
2
+ const MAX_COMPLETION_DEPTH = 20;
3
+ function generateCommandCase(brand, cmd, path, depth = 0) {
4
+ if (depth > MAX_COMPLETION_DEPTH)
5
+ return "";
2
6
  const lines = [];
3
- const casePattern = path ? `${path}_${cmd.name}` : cmd.name;
7
+ const safeName = sanitizeShellToken(cmd.name);
8
+ const casePattern = path ? `${path}_${safeName}` : safeName;
4
9
  // Gather completions for this command
5
10
  const words = [];
6
11
  // Add subcommands
7
12
  if (cmd.subcommands) {
8
13
  for (const sub of cmd.subcommands) {
9
- words.push(sub.name);
14
+ words.push(sanitizeShellToken(sub.name));
10
15
  }
11
16
  }
12
17
  // Add flags
13
18
  if (cmd.flags) {
14
19
  for (const f of cmd.flags) {
15
- words.push(`--${f.name}`);
20
+ words.push(`--${sanitizeShellToken(f.name)}`);
16
21
  if (f.alias)
17
- words.push(`-${f.alias}`);
22
+ words.push(`-${sanitizeShellToken(f.alias)}`);
18
23
  }
19
24
  }
20
25
  if (words.length > 0) {
@@ -26,25 +31,33 @@ function generateCommandCase(brand, cmd, path) {
26
31
  // Recurse for subcommands
27
32
  if (cmd.subcommands) {
28
33
  for (const sub of cmd.subcommands) {
29
- lines.push(generateCommandCase(brand, sub, casePattern));
34
+ lines.push(generateCommandCase(brand, sub, casePattern, depth + 1));
30
35
  }
31
36
  }
32
37
  return lines.join("\n");
33
38
  }
34
39
  /**
35
40
  * Generate a bash completion script.
41
+ *
42
+ * Uses a lookup key built from all command tokens (words[1]..words[cword-1])
43
+ * joined with underscores so that nested subcommand completions are reachable.
44
+ * For example, `mycli db migrate <TAB>` builds the key "db_migrate" which
45
+ * matches the case pattern generated by generateCommandCase.
36
46
  */
37
47
  export function bash(info) {
38
48
  const { brand, commands } = info;
39
- const topLevelWords = commands.flatMap((c) => [c.name, ...(c.aliases ?? [])]).join(" ");
49
+ const safeBrand = sanitizeShellToken(brand);
50
+ const topLevelWords = commands
51
+ .flatMap((c) => [sanitizeShellToken(c.name), ...(c.aliases ?? []).map(sanitizeShellToken)])
52
+ .join(" ");
40
53
  const caseClauses = [];
41
54
  for (const cmd of commands) {
42
- caseClauses.push(generateCommandCase(brand, cmd, ""));
55
+ caseClauses.push(generateCommandCase(safeBrand, cmd, ""));
43
56
  }
44
- return `# Bash completions for ${brand}
57
+ return `# Bash completions for ${safeBrand}
45
58
  # Generated by @seedcli/completions
46
59
 
47
- _${brand}_completions() {
60
+ _${safeBrand}_completions() {
48
61
  local cur prev words cword
49
62
  _init_completion || return
50
63
 
@@ -53,16 +66,28 @@ _${brand}_completions() {
53
66
  return 0
54
67
  fi
55
68
 
56
- local command="\${words[1]}"
69
+ # Build a lookup key from all command tokens before the cursor.
70
+ # e.g. "mycli db migrate <TAB>" → key="db_migrate"
71
+ local key=""
72
+ for ((i=1; i < cword; i++)); do
73
+ if [[ "\${words[i]}" == -* ]]; then
74
+ continue
75
+ fi
76
+ if [[ -n "$key" ]]; then
77
+ key="\${key}_\${words[i]}"
78
+ else
79
+ key="\${words[i]}"
80
+ fi
81
+ done
57
82
 
58
- case "\${command}" in
83
+ case "$key" in
59
84
  ${caseClauses.join("\n")}
60
85
  *)
61
86
  ;;
62
87
  esac
63
88
  }
64
89
 
65
- complete -F _${brand}_completions ${brand}
90
+ complete -F _${safeBrand}_completions ${safeBrand}
66
91
  `;
67
92
  }
68
93
  //# sourceMappingURL=bash.js.map
package/dist/bash.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bash.js","sourceRoot":"","sources":["../src/bash.ts"],"names":[],"mappings":"AAEA,SAAS,mBAAmB,CAAC,KAAa,EAAE,GAAsB,EAAE,IAAY;IAC/E,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;IAE5D,sCAAsC;IACtC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,kBAAkB;IAClB,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACrB,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;IACF,CAAC;IAED,YAAY;IACZ,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QACf,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC1B,IAAI,CAAC,CAAC,KAAK;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QACxC,CAAC;IACF,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,WAAW,WAAW,GAAG,CAAC,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC,yCAAyC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACxF,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACnC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC9B,CAAC;IAED,0BAA0B;IAC1B,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACrB,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;QAC1D,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,IAAI,CAAC,IAAoB;IACxC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAEjC,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAExF,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,WAAW,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,0BAA0B,KAAK;;;GAGpC,KAAK;;;;;oCAK4B,aAAa;;;;;;;EAO/C,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;eAMT,KAAK,gBAAgB,KAAK;CACxC,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../src/bash.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"fish.d.ts","sourceRoot":"","sources":["../src/fish.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,YAAY,CAAC;AAiDpE;;GAEG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAejD"}
1
+ {"version":3,"file":"fish.d.ts","sourceRoot":"","sources":["../src/fish.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,YAAY,CAAC;AAyDpE;;GAEG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAgBjD"}
package/dist/fish.js CHANGED
@@ -1,26 +1,32 @@
1
- function generateFishCompletions(brand, cmd, condition) {
1
+ import { escapeShellDescription, sanitizeShellToken } from "./types.js";
2
+ const MAX_COMPLETION_DEPTH = 20;
3
+ function generateFishCompletions(brand, cmd, condition, depth = 0) {
4
+ if (depth > MAX_COMPLETION_DEPTH)
5
+ return [];
2
6
  const lines = [];
3
- const desc = cmd.description ? ` -d '${cmd.description.replace(/'/g, "'\\''")}'` : "";
7
+ const safeName = sanitizeShellToken(cmd.name);
8
+ const desc = cmd.description ? ` -d '${escapeShellDescription(cmd.description)}'` : "";
4
9
  // Add the command itself as a completion
5
- lines.push(`complete -c ${brand} ${condition} -a '${cmd.name}'${desc}`);
10
+ lines.push(`complete -c ${brand} ${condition} -a '${safeName}'${desc}`);
6
11
  // Add aliases
7
12
  if (cmd.aliases) {
8
13
  for (const alias of cmd.aliases) {
9
- lines.push(`complete -c ${brand} ${condition} -a '${alias}'${desc}`);
14
+ lines.push(`complete -c ${brand} ${condition} -a '${sanitizeShellToken(alias)}'${desc}`);
10
15
  }
11
16
  }
12
17
  // Subcommand condition: we need the parent command in the args
13
- const subCondition = `-n '__fish_seen_subcommand_from ${cmd.name}'`;
18
+ const subCondition = `-n '__fish_seen_subcommand_from ${safeName}'`;
14
19
  // Add flags for this command
15
20
  if (cmd.flags) {
16
21
  for (const f of cmd.flags) {
17
- const flagDesc = f.description ? ` -d '${f.description.replace(/'/g, "'\\''")}'` : "";
18
- let line = `complete -c ${brand} ${subCondition} -l '${f.name}'`;
22
+ const safeFlagName = sanitizeShellToken(f.name);
23
+ const flagDesc = f.description ? ` -d '${escapeShellDescription(f.description)}'` : "";
24
+ let line = `complete -c ${brand} ${subCondition} -l '${safeFlagName}'`;
19
25
  if (f.alias) {
20
- line += ` -s '${f.alias}'`;
26
+ line += ` -s '${sanitizeShellToken(f.alias)}'`;
21
27
  }
22
28
  if (f.choices && f.choices.length > 0) {
23
- line += ` -r -a '${f.choices.join(" ")}'`;
29
+ line += ` -r -a '${f.choices.map(sanitizeShellToken).join(" ")}'`;
24
30
  }
25
31
  line += flagDesc;
26
32
  lines.push(line);
@@ -29,7 +35,7 @@ function generateFishCompletions(brand, cmd, condition) {
29
35
  // Recurse for subcommands
30
36
  if (cmd.subcommands) {
31
37
  for (const sub of cmd.subcommands) {
32
- lines.push(...generateFishCompletions(brand, sub, subCondition));
38
+ lines.push(...generateFishCompletions(brand, sub, subCondition, depth + 1));
33
39
  }
34
40
  }
35
41
  return lines;
@@ -39,14 +45,15 @@ function generateFishCompletions(brand, cmd, condition) {
39
45
  */
40
46
  export function fish(info) {
41
47
  const { brand, commands } = info;
48
+ const safeBrand = sanitizeShellToken(brand);
42
49
  const lines = [
43
- `# Fish completions for ${brand}`,
50
+ `# Fish completions for ${safeBrand}`,
44
51
  `# Generated by @seedcli/completions`,
45
52
  "",
46
53
  ];
47
- const topLevelCondition = `-n 'not __fish_seen_subcommand_from ${commands.map((c) => c.name).join(" ")}'`;
54
+ const topLevelCondition = `-n 'not __fish_seen_subcommand_from ${commands.map((c) => sanitizeShellToken(c.name)).join(" ")}'`;
48
55
  for (const cmd of commands) {
49
- lines.push(...generateFishCompletions(brand, cmd, topLevelCondition));
56
+ lines.push(...generateFishCompletions(safeBrand, cmd, topLevelCondition));
50
57
  }
51
58
  return `${lines.join("\n")}\n`;
52
59
  }
package/dist/fish.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"fish.js","sourceRoot":"","sources":["../src/fish.ts"],"names":[],"mappings":"AAEA,SAAS,uBAAuB,CAC/B,KAAa,EACb,GAAsB,EACtB,SAAiB;IAEjB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAEtF,yCAAyC;IACzC,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,IAAI,SAAS,QAAQ,GAAG,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;IAExE,cAAc;IACd,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,IAAI,SAAS,QAAQ,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC;QACtE,CAAC;IACF,CAAC;IAED,+DAA+D;IAC/D,MAAM,YAAY,GAAG,mCAAmC,GAAG,CAAC,IAAI,GAAG,CAAC;IAEpE,6BAA6B;IAC7B,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QACf,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACtF,IAAI,IAAI,GAAG,eAAe,KAAK,IAAI,YAAY,QAAQ,CAAC,CAAC,IAAI,GAAG,CAAC;YACjE,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;gBACb,IAAI,IAAI,QAAQ,CAAC,CAAC,KAAK,GAAG,CAAC;YAC5B,CAAC;YACD,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvC,IAAI,IAAI,WAAW,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAC3C,CAAC;YACD,IAAI,IAAI,QAAQ,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;IACF,CAAC;IAED,0BAA0B;IAC1B,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACrB,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,GAAG,uBAAuB,CAAC,KAAK,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;QAClE,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,IAAI,CAAC,IAAoB;IACxC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IACjC,MAAM,KAAK,GAAa;QACvB,0BAA0B,KAAK,EAAE;QACjC,qCAAqC;QACrC,EAAE;KACF,CAAC;IAEF,MAAM,iBAAiB,GAAG,uCAAuC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAE1G,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,GAAG,uBAAuB,CAAC,KAAK,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"fish.js","sourceRoot":"","sources":["../src/fish.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAExE,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEhC,SAAS,uBAAuB,CAC/B,KAAa,EACb,GAAsB,EACtB,SAAiB,EACjB,KAAK,GAAG,CAAC;IAET,IAAI,KAAK,GAAG,oBAAoB;QAAE,OAAO,EAAE,CAAC;IAE5C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,sBAAsB,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAEvF,yCAAyC;IACzC,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,IAAI,SAAS,QAAQ,QAAQ,IAAI,IAAI,EAAE,CAAC,CAAC;IAExE,cAAc;IACd,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,IAAI,SAAS,QAAQ,kBAAkB,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAC1F,CAAC;IACF,CAAC;IAED,+DAA+D;IAC/D,MAAM,YAAY,GAAG,mCAAmC,QAAQ,GAAG,CAAC;IAEpE,6BAA6B;IAC7B,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QACf,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YAC3B,MAAM,YAAY,GAAG,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChD,MAAM,QAAQ,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,sBAAsB,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACvF,IAAI,IAAI,GAAG,eAAe,KAAK,IAAI,YAAY,QAAQ,YAAY,GAAG,CAAC;YACvE,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;gBACb,IAAI,IAAI,QAAQ,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;YAChD,CAAC;YACD,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvC,IAAI,IAAI,WAAW,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YACnE,CAAC;YACD,IAAI,IAAI,QAAQ,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;IACF,CAAC;IAED,0BAA0B;IAC1B,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACrB,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,GAAG,uBAAuB,CAAC,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7E,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,IAAI,CAAC,IAAoB;IACxC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IACjC,MAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAa;QACvB,0BAA0B,SAAS,EAAE;QACrC,qCAAqC;QACrC,EAAE;KACF,CAAC;IAEF,MAAM,iBAAiB,GAAG,uCAAuC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAE9H,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,GAAG,uBAAuB,CAAC,SAAS,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAChC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -4,5 +4,6 @@ export { fish } from "./fish.js";
4
4
  export { install } from "./install.js";
5
5
  export { powershell } from "./powershell.js";
6
6
  export type { CompletionArg, CompletionCommand, CompletionFlag, CompletionInfo, ShellType, } from "./types.js";
7
+ export { escapeShellDescription, sanitizeShellToken } from "./types.js";
7
8
  export { zsh } from "./zsh.js";
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EACX,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,SAAS,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EACX,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,SAAS,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -3,5 +3,6 @@ export { detect } from "./detect.js";
3
3
  export { fish } from "./fish.js";
4
4
  export { install } from "./install.js";
5
5
  export { powershell } from "./powershell.js";
6
+ export { escapeShellDescription, sanitizeShellToken } from "./types.js";
6
7
  export { zsh } from "./zsh.js";
7
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAQ7C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAQ7C,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA8B5D;;GAEG;AACH,wBAAsB,OAAO,CAC5B,IAAI,EAAE,cAAc,EACpB,KAAK,CAAC,EAAE,SAAS,GACf,OAAO,CAAC;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAe7C"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA8B5D;;GAEG;AACH,wBAAsB,OAAO,CAC5B,IAAI,EAAE,cAAc,EACpB,KAAK,CAAC,EAAE,SAAS,GACf,OAAO,CAAC;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAwC7C"}
package/dist/install.js CHANGED
@@ -38,8 +38,31 @@ export async function install(info, shell) {
38
38
  const dir = join(homedir(), ".config", "fish", "completions");
39
39
  await mkdir(dir, { recursive: true });
40
40
  }
41
- const marker = `# ${info.brand} completions`;
42
- await appendFile(rcPath, `\n${marker}\n${script}\n`);
41
+ const markerStart = `# ${info.brand} completions`;
42
+ const markerEnd = `# end ${info.brand} completions`;
43
+ const block = `\n${markerStart}\n${script}\n${markerEnd}\n`;
44
+ // Check if completions are already installed — update if so
45
+ try {
46
+ const { readFile, writeFile } = await import("node:fs/promises");
47
+ const content = await readFile(rcPath, "utf-8");
48
+ const startIdx = content.indexOf(markerStart);
49
+ if (startIdx !== -1) {
50
+ const endIdx = content.indexOf(markerEnd, startIdx);
51
+ if (endIdx !== -1) {
52
+ // Replace existing block
53
+ const updated = content.slice(0, startIdx) +
54
+ `${markerStart}\n${script}\n${markerEnd}` +
55
+ content.slice(endIdx + markerEnd.length);
56
+ await writeFile(rcPath, updated);
57
+ }
58
+ // If no end marker found, leave as-is (legacy install)
59
+ return { shell: detectedShell, path: rcPath };
60
+ }
61
+ }
62
+ catch {
63
+ // File doesn't exist yet — proceed with install
64
+ }
65
+ await appendFile(rcPath, block);
43
66
  return { shell: detectedShell, path: rcPath };
44
67
  }
45
68
  //# sourceMappingURL=install.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;AAE/D,MAAM,UAAU,GAAwD;IACvE,IAAI;IACJ,GAAG;IACH,IAAI;IACJ,UAAU;CACV,CAAC;AAEF,SAAS,SAAS,CAAC,KAAgB,EAAE,KAAa;IACjD,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,QAAQ,KAAK,EAAE,CAAC;QACf,KAAK,MAAM;YACV,OAAO,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAC9B,KAAK,KAAK;YACT,OAAO,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC7B,KAAK,MAAM;YACV,OAAO,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC;QACtE,KAAK,YAAY;YAChB,OAAO,CACN,OAAO,CAAC,GAAG,CAAC,OAAO;gBACnB,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,kCAAkC,CAAC,CACvE,CAAC;IACJ,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC5B,IAAoB,EACpB,KAAiB;IAEjB,MAAM,aAAa,GAAG,KAAK,IAAI,MAAM,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,SAAS,CAAC,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAEpD,0CAA0C;IAC1C,IAAI,aAAa,KAAK,MAAM,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;QAC9D,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,IAAI,CAAC,KAAK,cAAc,CAAC;IAC7C,MAAM,UAAU,CAAC,MAAM,EAAE,KAAK,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC;IAErD,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC/C,CAAC"}
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,11 @@
1
1
  import type { CompletionInfo } from "./types.js";
2
2
  /**
3
3
  * Generate a PowerShell `Register-ArgumentCompleter` script.
4
+ *
5
+ * Uses a compound key built from all non-flag tokens (joined with underscores)
6
+ * so that nested subcommand completions are reachable. For example,
7
+ * `mycli db migrate <TAB>` builds the key "db_migrate" which matches the
8
+ * switch case generated by generateCommandCases.
4
9
  */
5
10
  export declare function powershell(info: CompletionInfo): string;
6
11
  //# sourceMappingURL=powershell.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"powershell.d.ts","sourceRoot":"","sources":["../src/powershell.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,YAAY,CAAC;AAiCpE;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAwCvD"}
1
+ {"version":3,"file":"powershell.d.ts","sourceRoot":"","sources":["../src/powershell.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,YAAY,CAAC;AA8EpE;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CA4CvD"}
@@ -1,48 +1,89 @@
1
+ import { sanitizeShellToken } from "./types.js";
2
+ const MAX_COMPLETION_DEPTH = 20;
3
+ /**
4
+ * Escape a string for safe use in PowerShell single-quoted strings.
5
+ * In PowerShell, single-quoted strings only need '' to represent a literal '.
6
+ * Also remove backticks and $ to prevent expression injection.
7
+ */
8
+ function escapePowerShellString(value) {
9
+ return value.replace(/'/g, "''").replace(/[`$]/g, "");
10
+ }
1
11
  function generateCommandCompletions(cmd, indent) {
2
12
  const lines = [];
3
13
  // Add subcommands
4
14
  if (cmd.subcommands) {
5
15
  for (const sub of cmd.subcommands) {
6
- const desc = sub.description ? sub.description.replace(/'/g, "''") : sub.name;
7
- lines.push(`${indent}[CompletionResult]::new('${sub.name}', '${desc}', [CompletionResultType]::ParameterValue, '${desc}')`);
16
+ const safeName = sanitizeShellToken(sub.name);
17
+ const desc = sub.description ? escapePowerShellString(sub.description) : safeName;
18
+ lines.push(`${indent}[CompletionResult]::new('${safeName}', '${desc}', [CompletionResultType]::ParameterValue, '${desc}')`);
8
19
  }
9
20
  }
10
21
  // Add flags
11
22
  if (cmd.flags) {
12
23
  for (const f of cmd.flags) {
13
- const desc = f.description ? f.description.replace(/'/g, "''") : `--${f.name}`;
14
- lines.push(`${indent}[CompletionResult]::new('--${f.name}', '${desc}', [CompletionResultType]::ParameterName, '${desc}')`);
24
+ const safeFlagName = sanitizeShellToken(f.name);
25
+ const desc = f.description ? escapePowerShellString(f.description) : `--${safeFlagName}`;
26
+ lines.push(`${indent}[CompletionResult]::new('--${safeFlagName}', '${desc}', [CompletionResultType]::ParameterName, '${desc}')`);
15
27
  if (f.alias) {
16
- lines.push(`${indent}[CompletionResult]::new('-${f.alias}', '${desc}', [CompletionResultType]::ParameterName, '${desc}')`);
28
+ const safeAlias = sanitizeShellToken(f.alias);
29
+ lines.push(`${indent}[CompletionResult]::new('-${safeAlias}', '${desc}', [CompletionResultType]::ParameterName, '${desc}')`);
17
30
  }
18
31
  }
19
32
  }
20
33
  return lines;
21
34
  }
35
+ /**
36
+ * Recursively generate switch cases for a command and all its subcommands.
37
+ * Uses an underscore-joined key path (e.g., "db_migrate") to match the
38
+ * compound key built from non-flag tokens at runtime.
39
+ */
40
+ function generateCommandCases(cmd, path, depth = 0) {
41
+ if (depth > MAX_COMPLETION_DEPTH)
42
+ return [];
43
+ const cases = [];
44
+ const safeName = sanitizeShellToken(cmd.name);
45
+ const key = path ? `${path}_${safeName}` : safeName;
46
+ const indent = " ";
47
+ const completions = generateCommandCompletions(cmd, indent);
48
+ if (completions.length > 0) {
49
+ cases.push(` '${key}' {
50
+ ${completions.join("\n")}
51
+ }`);
52
+ }
53
+ // Recurse for subcommands
54
+ if (cmd.subcommands) {
55
+ for (const sub of cmd.subcommands) {
56
+ cases.push(...generateCommandCases(sub, key, depth + 1));
57
+ }
58
+ }
59
+ return cases;
60
+ }
22
61
  /**
23
62
  * Generate a PowerShell `Register-ArgumentCompleter` script.
63
+ *
64
+ * Uses a compound key built from all non-flag tokens (joined with underscores)
65
+ * so that nested subcommand completions are reachable. For example,
66
+ * `mycli db migrate <TAB>` builds the key "db_migrate" which matches the
67
+ * switch case generated by generateCommandCases.
24
68
  */
25
69
  export function powershell(info) {
26
70
  const { brand, commands } = info;
71
+ const safeBrand = sanitizeShellToken(brand);
27
72
  const commandCases = [];
28
73
  for (const cmd of commands) {
29
- const completions = generateCommandCompletions(cmd, " ");
30
- if (completions.length > 0) {
31
- commandCases.push(` '${cmd.name}' {
32
- ${completions.join("\n")}
33
- }`);
34
- }
74
+ commandCases.push(...generateCommandCases(cmd, ""));
35
75
  }
36
76
  const topLevelCompletions = commands
37
77
  .map((c) => {
38
- const desc = c.description ? c.description.replace(/'/g, "''") : c.name;
39
- return ` [CompletionResult]::new('${c.name}', '${desc}', [CompletionResultType]::ParameterValue, '${desc}')`;
78
+ const safeName = sanitizeShellToken(c.name);
79
+ const desc = c.description ? escapePowerShellString(c.description) : safeName;
80
+ return ` [CompletionResult]::new('${safeName}', '${desc}', [CompletionResultType]::ParameterValue, '${desc}')`;
40
81
  })
41
82
  .join("\n");
42
- return `# PowerShell completions for ${brand}
83
+ return `# PowerShell completions for ${safeBrand}
43
84
  # Generated by @seedcli/completions
44
85
 
45
- Register-ArgumentCompleter -CommandName '${brand}' -ScriptBlock {
86
+ Register-ArgumentCompleter -CommandName '${safeBrand}' -ScriptBlock {
46
87
  param($wordToComplete, $commandAst, $cursorPosition)
47
88
 
48
89
  $tokens = $commandAst.ToString().Split(' ', [StringSplitOptions]::RemoveEmptyEntries)
@@ -52,9 +93,16 @@ ${topLevelCompletions}
52
93
  return
53
94
  }
54
95
 
55
- $command = $tokens[1]
96
+ # Build a compound key from all non-flag tokens after the command name.
97
+ # e.g. "mycli db migrate <TAB>" -> key = "db_migrate"
98
+ $key = ''
99
+ for ($i = 1; $i -lt $tokens.Length; $i++) {
100
+ if ($tokens[$i] -like '-*') { continue }
101
+ if ($key -ne '') { $key += '_' }
102
+ $key += $tokens[$i]
103
+ }
56
104
 
57
- switch ($command) {
105
+ switch ($key) {
58
106
  ${commandCases.join("\n")}
59
107
  }
60
108
  } | Where-Object { $_.CompletionText -like "$wordToComplete*" }
@@ -1 +1 @@
1
- {"version":3,"file":"powershell.js","sourceRoot":"","sources":["../src/powershell.ts"],"names":[],"mappings":"AAEA,SAAS,0BAA0B,CAAC,GAAsB,EAAE,MAAc;IACzE,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,kBAAkB;IAClB,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACrB,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;YAC9E,KAAK,CAAC,IAAI,CACT,GAAG,MAAM,4BAA4B,GAAG,CAAC,IAAI,OAAO,IAAI,+CAA+C,IAAI,IAAI,CAC/G,CAAC;QACH,CAAC;IACF,CAAC;IAED,YAAY;IACZ,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QACf,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;YAC/E,KAAK,CAAC,IAAI,CACT,GAAG,MAAM,8BAA8B,CAAC,CAAC,IAAI,OAAO,IAAI,8CAA8C,IAAI,IAAI,CAC9G,CAAC;YACF,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;gBACb,KAAK,CAAC,IAAI,CACT,GAAG,MAAM,6BAA6B,CAAC,CAAC,KAAK,OAAO,IAAI,8CAA8C,IAAI,IAAI,CAC9G,CAAC;YACH,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,IAAoB;IAC9C,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAEjC,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,WAAW,GAAG,0BAA0B,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;QACxE,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,YAAY,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,IAAI;EAC3C,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;cACV,CAAC,CAAC;QACd,CAAC;IACF,CAAC;IAED,MAAM,mBAAmB,GAAG,QAAQ;SAClC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACV,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACxE,OAAO,wCAAwC,CAAC,CAAC,IAAI,OAAO,IAAI,+CAA+C,IAAI,IAAI,CAAC;IACzH,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,OAAO,gCAAgC,KAAK;;;2CAGF,KAAK;;;;;;EAM9C,mBAAmB;;;;;;;EAOnB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;;;CAGxB,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"powershell.js","sourceRoot":"","sources":["../src/powershell.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -23,4 +23,14 @@ export interface CompletionInfo {
23
23
  brand: string;
24
24
  commands: CompletionCommand[];
25
25
  }
26
+ /**
27
+ * Sanitize a string for safe inclusion in a shell script.
28
+ * Strips any characters outside [a-zA-Z0-9_-].
29
+ */
30
+ export declare function sanitizeShellToken(value: string): string;
31
+ /**
32
+ * Escape a description string for shell scripts.
33
+ * Removes backticks, $, and other dangerous characters while preserving readability.
34
+ */
35
+ export declare function escapeShellDescription(value: string): string;
26
36
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,YAAY,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAClC,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC9B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,YAAY,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAClC,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5D"}
package/dist/types.js CHANGED
@@ -1,2 +1,15 @@
1
- export {};
1
+ /**
2
+ * Sanitize a string for safe inclusion in a shell script.
3
+ * Strips any characters outside [a-zA-Z0-9_-].
4
+ */
5
+ export function sanitizeShellToken(value) {
6
+ return value.replace(/[^a-zA-Z0-9_-]/g, "");
7
+ }
8
+ /**
9
+ * Escape a description string for shell scripts.
10
+ * Removes backticks, $, and other dangerous characters while preserving readability.
11
+ */
12
+ export function escapeShellDescription(value) {
13
+ return value.replace(/[`$\\!"]/g, "").replace(/'/g, "'\\''");
14
+ }
2
15
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA8BA;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC/C,OAAO,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAa;IACnD,OAAO,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC"}
package/dist/zsh.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"zsh.d.ts","sourceRoot":"","sources":["../src/zsh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,YAAY,CAAC;AAyDpE;;GAEG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAsChD"}
1
+ {"version":3,"file":"zsh.d.ts","sourceRoot":"","sources":["../src/zsh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,YAAY,CAAC;AAiEpE;;GAEG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAuChD"}
package/dist/zsh.js CHANGED
@@ -1,30 +1,36 @@
1
- function generateSubcommandFunction(brand, cmd, prefix) {
1
+ import { escapeShellDescription, sanitizeShellToken } from "./types.js";
2
+ const MAX_COMPLETION_DEPTH = 20;
3
+ function generateSubcommandFunction(brand, cmd, prefix, depth = 0) {
4
+ if (depth > MAX_COMPLETION_DEPTH)
5
+ return [];
2
6
  const blocks = [];
3
- const fnName = prefix ? `_${brand}_${prefix}_${cmd.name}` : `_${brand}_${cmd.name}`;
7
+ const safeName = sanitizeShellToken(cmd.name);
8
+ const fnName = prefix ? `_${brand}_${prefix}_${safeName}` : `_${brand}_${safeName}`;
4
9
  const args = [];
5
10
  // Add subcommand descriptions
6
11
  if (cmd.subcommands && cmd.subcommands.length > 0) {
7
12
  const subcmdDescs = cmd.subcommands
8
- .map((s) => `'${s.name}:${(s.description ?? "").replace(/'/g, "'\\''")}'`)
13
+ .map((s) => `'${sanitizeShellToken(s.name)}:${escapeShellDescription(s.description ?? "")}'`)
9
14
  .join(" ");
10
- args.push(`'1:command:(${cmd.subcommands.map((s) => s.name).join(" ")})'`);
15
+ args.push(`'1:command:(${cmd.subcommands.map((s) => sanitizeShellToken(s.name)).join(" ")})'`);
11
16
  blocks.push(`# Subcommands: ${subcmdDescs}`);
12
17
  }
13
18
  // Add flags
14
19
  if (cmd.flags) {
15
20
  for (const f of cmd.flags) {
16
- const desc = (f.description ?? "")
17
- .replace(/'/g, "'\\''")
21
+ const safeFlagName = sanitizeShellToken(f.name);
22
+ const desc = escapeShellDescription(f.description ?? "")
18
23
  .replace(/\[/g, "\\[")
19
24
  .replace(/\]/g, "\\]");
20
25
  if (f.choices && f.choices.length > 0) {
21
- args.push(`'--${f.name}[${desc}]:value:(${f.choices.join(" ")})'`);
26
+ const safeChoices = f.choices.map(sanitizeShellToken).join(" ");
27
+ args.push(`'--${safeFlagName}[${desc}]:value:(${safeChoices})'`);
22
28
  }
23
29
  else {
24
- args.push(`'--${f.name}[${desc}]'`);
30
+ args.push(`'--${safeFlagName}[${desc}]'`);
25
31
  }
26
32
  if (f.alias) {
27
- args.push(`'-${f.alias}[${desc}]'`);
33
+ args.push(`'-${sanitizeShellToken(f.alias)}[${desc}]'`);
28
34
  }
29
35
  }
30
36
  }
@@ -37,8 +43,8 @@ function generateSubcommandFunction(brand, cmd, prefix) {
37
43
  // Recurse for subcommands
38
44
  if (cmd.subcommands) {
39
45
  for (const sub of cmd.subcommands) {
40
- const nextPrefix = prefix ? `${prefix}_${cmd.name}` : cmd.name;
41
- blocks.push(...generateSubcommandFunction(brand, sub, nextPrefix));
46
+ const nextPrefix = prefix ? `${prefix}_${safeName}` : safeName;
47
+ blocks.push(...generateSubcommandFunction(brand, sub, nextPrefix, depth + 1));
42
48
  }
43
49
  }
44
50
  return blocks;
@@ -48,18 +54,19 @@ function generateSubcommandFunction(brand, cmd, prefix) {
48
54
  */
49
55
  export function zsh(info) {
50
56
  const { brand, commands } = info;
57
+ const safeBrand = sanitizeShellToken(brand);
51
58
  const functionBlocks = [];
52
59
  for (const cmd of commands) {
53
- functionBlocks.push(...generateSubcommandFunction(brand, cmd, ""));
60
+ functionBlocks.push(...generateSubcommandFunction(safeBrand, cmd, ""));
54
61
  }
55
- return `#compdef ${brand}
56
- # Zsh completions for ${brand}
62
+ return `#compdef ${safeBrand}
63
+ # Zsh completions for ${safeBrand}
57
64
  # Generated by @seedcli/completions
58
65
 
59
- _${brand}() {
66
+ _${safeBrand}() {
60
67
  local -a commands
61
68
  commands=(
62
- ${commands.map((c) => `'${c.name}:${(c.description ?? "").replace(/'/g, "'\\''")}'`).join("\n ")}
69
+ ${commands.map((c) => `'${sanitizeShellToken(c.name)}:${escapeShellDescription(c.description ?? "")}'`).join("\n ")}
63
70
  )
64
71
 
65
72
  _arguments \\
@@ -72,7 +79,7 @@ _${brand}() {
72
79
  ;;
73
80
  args)
74
81
  case "\${words[1]}" in
75
- ${commands.map((c) => `${c.name}) _${brand}_${c.name} ;;`).join("\n ")}
82
+ ${commands.map((c) => `${sanitizeShellToken(c.name)}) _${safeBrand}_${sanitizeShellToken(c.name)} ;;`).join("\n ")}
76
83
  esac
77
84
  ;;
78
85
  esac
@@ -80,7 +87,7 @@ _${brand}() {
80
87
 
81
88
  ${functionBlocks.join("\n\n")}
82
89
 
83
- _${brand} "$@"
90
+ _${safeBrand} "$@"
84
91
  `;
85
92
  }
86
93
  //# sourceMappingURL=zsh.js.map
package/dist/zsh.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"zsh.js","sourceRoot":"","sources":["../src/zsh.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"zsh.js","sourceRoot":"","sources":["../src/zsh.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seedcli/completions",
3
- "version": "0.1.7",
3
+ "version": "0.1.10",
4
4
  "description": "Shell completion generation for bash, zsh, and fish",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  "exports": {
31
31
  ".": {
32
32
  "import": "./dist/index.js",
33
- "types": "./dist/index.d.ts"
33
+ "types": "./dist/index.js"
34
34
  }
35
35
  },
36
36
  "files": [