chrome-proc 1.0.0 → 1.0.1

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.
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.linuxProvider = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const os_1 = require("os");
6
+ const fs_1 = require("fs");
7
+ const completion_helpers_1 = require("./completion-helpers");
8
+ const CHROME_CANDIDATES = [
9
+ "/usr/bin/google-chrome",
10
+ "/usr/bin/google-chrome-stable",
11
+ "/usr/bin/chromium",
12
+ "/usr/bin/chromium-browser",
13
+ ];
14
+ function getChromePids(exact = false) {
15
+ const names = ["chrome", "google-chrome", "google-chrome-stable", "chromium", "chromium-browser"];
16
+ const pids = [];
17
+ for (const name of names) {
18
+ try {
19
+ const flag = exact ? "-x" : "-f";
20
+ const output = (0, child_process_1.execSync)(`pgrep ${flag} "${name}"`, { encoding: "utf-8" });
21
+ output
22
+ .trim()
23
+ .split("\n")
24
+ .filter((line) => line.trim() !== "")
25
+ .map((line) => parseInt(line.trim(), 10))
26
+ .filter((pid) => !isNaN(pid) && !pids.includes(pid))
27
+ .forEach((pid) => pids.push(pid));
28
+ }
29
+ catch {
30
+ // pgrep exits with code 1 when no matches found
31
+ }
32
+ }
33
+ return pids;
34
+ }
35
+ function getProcessArgs(pid) {
36
+ try {
37
+ return (0, child_process_1.execSync)(`ps -p "${pid}" -o args=`, { encoding: "utf-8" }).trim();
38
+ }
39
+ catch {
40
+ return "?";
41
+ }
42
+ }
43
+ function getProcessName(pid) {
44
+ try {
45
+ return (0, child_process_1.execSync)(`ps -p "${pid}" -o comm=`, { encoding: "utf-8" }).trim();
46
+ }
47
+ catch {
48
+ return "?";
49
+ }
50
+ }
51
+ function killPid(pid, signal) {
52
+ try {
53
+ (0, child_process_1.execSync)(`kill -${signal} "${pid}"`, { stdio: "pipe" });
54
+ return true;
55
+ }
56
+ catch {
57
+ return false;
58
+ }
59
+ }
60
+ function isChromeRunning() {
61
+ return getChromePids(true).length > 0;
62
+ }
63
+ const processManager = {
64
+ getChromePids,
65
+ getProcessArgs,
66
+ getProcessName,
67
+ killPid,
68
+ isChromeRunning,
69
+ };
70
+ function findChrome() {
71
+ for (const candidate of CHROME_CANDIDATES) {
72
+ if ((0, fs_1.existsSync)(candidate)) {
73
+ return candidate;
74
+ }
75
+ }
76
+ return CHROME_CANDIDATES[0];
77
+ }
78
+ exports.linuxProvider = {
79
+ name: "linux",
80
+ getChromeExecutablePath() {
81
+ return findChrome();
82
+ },
83
+ getDefaultChromeDataDir() {
84
+ return `${(0, os_1.homedir)()}/.config/google-chrome`;
85
+ },
86
+ getProcessManager() {
87
+ return processManager;
88
+ },
89
+ supportedShells() {
90
+ return ["bash", "zsh"];
91
+ },
92
+ generateCompletion(shell, profileDirs) {
93
+ switch (shell) {
94
+ case "bash":
95
+ return (0, completion_helpers_1.generateBashCompletion)(profileDirs);
96
+ case "zsh":
97
+ return (0, completion_helpers_1.generateZshCompletion)(profileDirs);
98
+ default:
99
+ throw new Error(`Unsupported shell: ${shell}`);
100
+ }
101
+ },
102
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.win32Provider = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const fs_1 = require("fs");
6
+ const completion_helpers_1 = require("./completion-helpers");
7
+ function getChromePids(_exact = false) {
8
+ try {
9
+ const output = (0, child_process_1.execSync)(`tasklist /FI "IMAGENAME eq chrome.exe" /FO CSV /NH`, { encoding: "utf-8" }).trim();
10
+ if (!output || output.startsWith("INFO:"))
11
+ return [];
12
+ return output
13
+ .split("\n")
14
+ .map((line) => {
15
+ const match = line.match(/^"[^"]+","(\d+)"/);
16
+ return match ? parseInt(match[1], 10) : NaN;
17
+ })
18
+ .filter((pid) => !isNaN(pid));
19
+ }
20
+ catch {
21
+ return [];
22
+ }
23
+ }
24
+ function getProcessArgs(pid) {
25
+ try {
26
+ const output = (0, child_process_1.execSync)(`powershell.exe -NoProfile -Command "(Get-CimInstance Win32_Process -Filter \\"ProcessId=${pid}\\").CommandLine"`, { encoding: "utf-8" }).trim();
27
+ return output || "?";
28
+ }
29
+ catch {
30
+ return "?";
31
+ }
32
+ }
33
+ function getProcessName(pid) {
34
+ try {
35
+ const output = (0, child_process_1.execSync)(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`, { encoding: "utf-8" }).trim();
36
+ if (!output || output.startsWith("INFO:"))
37
+ return "?";
38
+ const match = output.match(/^"([^"]+)"/);
39
+ return match ? match[1] : "?";
40
+ }
41
+ catch {
42
+ return "?";
43
+ }
44
+ }
45
+ function killPid(pid, signal) {
46
+ try {
47
+ const forceFlag = signal === "KILL" ? "/F" : "";
48
+ (0, child_process_1.execSync)(`taskkill /PID ${pid} /T ${forceFlag}`, { stdio: "pipe" });
49
+ return true;
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ }
55
+ function isChromeRunning() {
56
+ return getChromePids().length > 0;
57
+ }
58
+ const processManager = {
59
+ getChromePids,
60
+ getProcessArgs,
61
+ getProcessName,
62
+ killPid,
63
+ isChromeRunning,
64
+ };
65
+ function findChrome() {
66
+ const candidates = [];
67
+ if (process.env.LOCALAPPDATA) {
68
+ candidates.push(`${process.env.LOCALAPPDATA}\\Google\\Chrome\\Application\\chrome.exe`);
69
+ }
70
+ if (process.env.PROGRAMFILES) {
71
+ candidates.push(`${process.env.PROGRAMFILES}\\Google\\Chrome\\Application\\chrome.exe`);
72
+ }
73
+ if (process.env["PROGRAMFILES(X86)"]) {
74
+ candidates.push(`${process.env["PROGRAMFILES(X86)"]}\\Google\\Chrome\\Application\\chrome.exe`);
75
+ }
76
+ for (const candidate of candidates) {
77
+ if ((0, fs_1.existsSync)(candidate)) {
78
+ return candidate;
79
+ }
80
+ }
81
+ return candidates[0] || "chrome.exe";
82
+ }
83
+ exports.win32Provider = {
84
+ name: "win32",
85
+ getChromeExecutablePath() {
86
+ return findChrome();
87
+ },
88
+ getDefaultChromeDataDir() {
89
+ if (process.env.LOCALAPPDATA) {
90
+ return `${process.env.LOCALAPPDATA}\\Google\\Chrome\\User Data`;
91
+ }
92
+ return `${process.env.USERPROFILE || ""}\\AppData\\Local\\Google\\Chrome\\User Data`;
93
+ },
94
+ getProcessManager() {
95
+ return processManager;
96
+ },
97
+ supportedShells() {
98
+ return ["powershell"];
99
+ },
100
+ generateCompletion(shell, profileDirs) {
101
+ switch (shell) {
102
+ case "powershell":
103
+ return (0, completion_helpers_1.generatePowerShellCompletion)(profileDirs);
104
+ default:
105
+ throw new Error(`Unsupported shell: ${shell}`);
106
+ }
107
+ },
108
+ };
@@ -8,12 +8,13 @@ exports.profileExists = profileExists;
8
8
  exports.validateProfileDir = validateProfileDir;
9
9
  const fs_1 = require("fs");
10
10
  const path_1 = require("path");
11
+ const platform_1 = require("../platform");
11
12
  function getChromeDataDir() {
12
13
  const dir = process.env.CHROME_DATA_DIR;
13
- if (!dir) {
14
- throw new Error("CHROME_DATA_DIR environment variable is not set");
14
+ if (dir) {
15
+ return dir;
15
16
  }
16
- return dir;
17
+ return (0, platform_1.getPlatform)().getDefaultChromeDataDir();
17
18
  }
18
19
  function getLocalStatePath() {
19
20
  return (0, path_1.join)(getChromeDataDir(), "Local State");
@@ -6,51 +6,23 @@ exports.getProcessName = getProcessName;
6
6
  exports.extractDebugPort = extractDebugPort;
7
7
  exports.killPid = killPid;
8
8
  exports.isChromeRunning = isChromeRunning;
9
- const child_process_1 = require("child_process");
9
+ const platform_1 = require("../platform");
10
10
  function getChromePids(exact = false) {
11
- try {
12
- const flag = exact ? "-x" : "-f";
13
- const output = (0, child_process_1.execSync)(`pgrep ${flag} "Google Chrome"`, { encoding: "utf-8" });
14
- return output
15
- .trim()
16
- .split("\n")
17
- .filter((line) => line.trim() !== "")
18
- .map((line) => parseInt(line.trim(), 10))
19
- .filter((pid) => !isNaN(pid));
20
- }
21
- catch {
22
- return [];
23
- }
11
+ return (0, platform_1.getPlatform)().getProcessManager().getChromePids(exact);
24
12
  }
25
13
  function getProcessArgs(pid) {
26
- try {
27
- return (0, child_process_1.execSync)(`ps -p "${pid}" -o args=`, { encoding: "utf-8" }).trim();
28
- }
29
- catch {
30
- return "?";
31
- }
14
+ return (0, platform_1.getPlatform)().getProcessManager().getProcessArgs(pid);
32
15
  }
33
16
  function getProcessName(pid) {
34
- try {
35
- return (0, child_process_1.execSync)(`ps -p "${pid}" -o comm=`, { encoding: "utf-8" }).trim();
36
- }
37
- catch {
38
- return "?";
39
- }
17
+ return (0, platform_1.getPlatform)().getProcessManager().getProcessName(pid);
40
18
  }
41
19
  function extractDebugPort(args) {
42
20
  const match = args.match(/--remote-debugging-port=(\d+)/);
43
21
  return match ? parseInt(match[1], 10) : null;
44
22
  }
45
23
  function killPid(pid, signal) {
46
- try {
47
- (0, child_process_1.execSync)(`/bin/kill -${signal} "${pid}"`, { stdio: "pipe" });
48
- return true;
49
- }
50
- catch {
51
- return false;
52
- }
24
+ return (0, platform_1.getPlatform)().getProcessManager().killPid(pid, signal);
53
25
  }
54
26
  function isChromeRunning() {
55
- return getChromePids(true).length > 0;
27
+ return (0, platform_1.getPlatform)().getProcessManager().isChromeRunning();
56
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chrome-proc",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Manage Chrome browser processes, profiles, and CDP endpoints",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -10,7 +10,11 @@
10
10
  "build": "tsc",
11
11
  "dev": "tsc --watch"
12
12
  },
13
- "keywords": ["chrome", "cdp", "devtools"],
13
+ "keywords": [
14
+ "chrome",
15
+ "cdp",
16
+ "devtools"
17
+ ],
14
18
  "license": "MIT",
15
19
  "dependencies": {
16
20
  "commander": "^12.0.0"
@@ -0,0 +1,21 @@
1
+ import { getPlatform } from "../platform";
2
+ import { readLocalState } from "../utils/localState";
3
+
4
+ export function completionCommand(shell: string): void {
5
+ const platform = getPlatform();
6
+ const shells = platform.supportedShells();
7
+ if (!shells.includes(shell)) {
8
+ console.error(`Error: unsupported shell '${shell}'. Supported: ${shells.join(", ")}`);
9
+ process.exit(1);
10
+ }
11
+ console.log(platform.generateCompletion(shell, getProfileDirs()));
12
+ }
13
+
14
+ function getProfileDirs(): string[] {
15
+ try {
16
+ const state = readLocalState();
17
+ return Object.keys(state.profile?.info_cache ?? {});
18
+ } catch {
19
+ return [];
20
+ }
21
+ }
@@ -1,6 +1,7 @@
1
1
  import { spawn } from "child_process";
2
2
  import { existsSync } from "fs";
3
- import { isChromeRunning } from "../utils/process";
3
+ import { getPlatform } from "../platform";
4
+ import { isChromeRunning, getChromePids } from "../utils/process";
4
5
 
5
6
  interface LaunchOptions {
6
7
  dir?: string;
@@ -10,7 +11,7 @@ interface LaunchOptions {
10
11
  }
11
12
 
12
13
  export function launchCommand(options: LaunchOptions): void {
13
- const chromeBin = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
14
+ const chromeBin = getPlatform().getChromeExecutablePath();
14
15
  const profile = options.profile ?? process.env.CHROME_PROFILE ?? "";
15
16
  const dataDir = options.dir ?? process.env.CHROME_DATA_DIR ?? "";
16
17
 
@@ -38,10 +39,9 @@ export function launchCommand(options: LaunchOptions): void {
38
39
  }
39
40
 
40
41
  if (isChromeRunning()) {
41
- const { execSync } = require("child_process");
42
- const existing = execSync('pgrep -x "Google Chrome" | tr "\\n" " " | sed "s/ $//"', { encoding: "utf-8" }).trim();
43
- if (existing) {
44
- console.error(`Warning: Chrome is already running (PIDs: ${existing})`);
42
+ const existing = getChromePids(true);
43
+ if (existing.length > 0) {
44
+ console.error(`Warning: Chrome is already running (PIDs: ${existing.join(" ")})`);
45
45
  }
46
46
  }
47
47
 
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ import { killCommand } from "./commands/kill";
5
5
  import { launchCommand } from "./commands/launch";
6
6
  import { profileList, profileName, profileDelete } from "./commands/profile";
7
7
  import { cdpCommand } from "./commands/cdp";
8
+ import { completionCommand } from "./commands/completion";
8
9
 
9
10
  const program = new Command();
10
11
 
@@ -75,4 +76,11 @@ program
75
76
  await cdpCommand(options);
76
77
  });
77
78
 
79
+ program
80
+ .command("completion <shell>")
81
+ .description("Generate shell completion script (bash or zsh)")
82
+ .action((shell: string) => {
83
+ completionCommand(shell);
84
+ });
85
+
78
86
  program.parse();
@@ -0,0 +1,253 @@
1
+ export function generateBashCompletion(profileDirs: string[]): string {
2
+ const profileDirsNewline = profileDirs.join("\n");
3
+
4
+ return `#!/usr/bin/env bash
5
+ _chrome_proc() {
6
+ local cur="\${COMP_WORDS[COMP_CWORD]}"
7
+ local prev="\${COMP_WORDS[COMP_CWORD-1]}"
8
+
9
+ local commands="list kill launch profile cdp completion"
10
+ local profile_subcommands="list name delete"
11
+
12
+ local list_opts="--verbose --json"
13
+ local kill_opts="--force --all"
14
+ local launch_opts="--dir --profile --debug --debugging-port"
15
+ local profile_list_opts="--json"
16
+ local cdp_opts="--json"
17
+ local completion_shells="bash zsh powershell"
18
+
19
+ local profile_dirs='
20
+ ${profileDirsNewline}
21
+ '
22
+
23
+ local cmd=""
24
+ local subcmd=""
25
+ local i=1
26
+
27
+ while [[ $i -lt $COMP_CWORD ]]; do
28
+ local word="\${COMP_WORDS[$i]}"
29
+ if [[ "$word" != -* ]]; then
30
+ if [[ -z "$cmd" ]]; then
31
+ cmd="$word"
32
+ elif [[ "$cmd" == "profile" && -z "$subcmd" ]]; then
33
+ subcmd="$word"
34
+ break
35
+ else
36
+ break
37
+ fi
38
+ fi
39
+ ((i++))
40
+ done
41
+
42
+ if [[ -z "$cmd" ]]; then
43
+ if [[ "$cur" == -* ]]; then
44
+ COMPREPLY=()
45
+ else
46
+ COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
47
+ fi
48
+ return
49
+ fi
50
+
51
+ case "$cmd" in
52
+ list)
53
+ COMPREPLY=( $(compgen -W "$list_opts" -- "$cur") )
54
+ ;;
55
+ kill)
56
+ COMPREPLY=( $(compgen -W "$kill_opts" -- "$cur") )
57
+ ;;
58
+ launch)
59
+ COMPREPLY=( $(compgen -W "$launch_opts" -- "$cur") )
60
+ ;;
61
+ cdp)
62
+ COMPREPLY=( $(compgen -W "$cdp_opts" -- "$cur") )
63
+ ;;
64
+ completion)
65
+ COMPREPLY=( $(compgen -W "$completion_shells" -- "$cur") )
66
+ ;;
67
+ profile)
68
+ if [[ -z "$subcmd" ]]; then
69
+ if [[ "$cur" == -* ]]; then
70
+ COMPREPLY=()
71
+ else
72
+ COMPREPLY=( $(compgen -W "$profile_subcommands" -- "$cur") )
73
+ fi
74
+ else
75
+ case "$subcmd" in
76
+ list)
77
+ COMPREPLY=( $(compgen -W "$profile_list_opts" -- "$cur") )
78
+ ;;
79
+ name|delete)
80
+ if [[ -n "$profile_dirs" && ( -z "$prev" || "$prev" == "name" || "$prev" == "delete" ) ]]; then
81
+ local OLD_IFS="$IFS"
82
+ IFS=$'\n'
83
+ COMPREPLY=( $(compgen -W "$profile_dirs" -- "$cur") )
84
+ IFS="$OLD_IFS"
85
+ else
86
+ COMPREPLY=()
87
+ fi
88
+ ;;
89
+ *)
90
+ COMPREPLY=()
91
+ ;;
92
+ esac
93
+ fi
94
+ ;;
95
+ *)
96
+ COMPREPLY=()
97
+ ;;
98
+ esac
99
+ }
100
+
101
+ complete -F _chrome_proc chrome-proc
102
+ `;
103
+ }
104
+
105
+ export function generateZshCompletion(profileDirs: string[]): string {
106
+ const profileDirsNewline = profileDirs.join("\n");
107
+
108
+ return `#!/usr/bin/env zsh
109
+ #compdef chrome-proc
110
+
111
+ _chrome_proc() {
112
+ local curcontext="$curcontext" state line
113
+ typeset -A opt_args
114
+
115
+ local profile_dirs='
116
+ ${profileDirsNewline}
117
+ '
118
+
119
+ _arguments -C \\
120
+ '1: :->command' \\
121
+ '2: :->subcommand' \\
122
+ '*: :->args'
123
+
124
+ case "$state" in
125
+ command)
126
+ local commands=(list kill launch profile cdp completion)
127
+ _describe -t commands 'chrome-proc command' commands
128
+ ;;
129
+ subcommand)
130
+ case "$line[1]" in
131
+ list)
132
+ local opts=('--verbose:Show full command line' '--json:Output as JSON lines')
133
+ _describe -t options 'list options' opts
134
+ ;;
135
+ kill)
136
+ local opts=('--force:Use SIGKILL instead of SIGTERM' '--all:Kill helper processes too')
137
+ _describe -t options 'kill options' opts
138
+ ;;
139
+ launch)
140
+ local opts=('--dir:Chrome user data directory' '--profile:Chrome profile name' '--debug:Enable remote debugging mode' '--debugging-port:Remote debugging port')
141
+ _describe -t options 'launch options' opts
142
+ ;;
143
+ cdp)
144
+ local opts=('--json:Output as JSON lines')
145
+ _describe -t options 'cdp options' opts
146
+ ;;
147
+ completion)
148
+ local shells=(bash zsh powershell)
149
+ _describe -t shells 'shell' shells
150
+ ;;
151
+ profile)
152
+ local subcmds=(list name delete)
153
+ _describe -t subcommands 'profile subcommand' subcmds
154
+ ;;
155
+ esac
156
+ ;;
157
+ args)
158
+ case "$line[1]" in
159
+ list)
160
+ local opts=('--verbose:Show full command line' '--json:Output as JSON lines')
161
+ _describe -t options 'list options' opts
162
+ ;;
163
+ kill)
164
+ local opts=('--force:Use SIGKILL instead of SIGTERM' '--all:Kill helper processes too')
165
+ _describe -t options 'kill options' opts
166
+ ;;
167
+ launch)
168
+ local opts=('--dir:Chrome user data directory' '--profile:Chrome profile name' '--debug:Enable remote debugging mode' '--debugging-port:Remote debugging port')
169
+ _describe -t options 'launch options' opts
170
+ ;;
171
+ cdp)
172
+ local opts=('--json:Output as JSON lines')
173
+ _describe -t options 'cdp options' opts
174
+ ;;
175
+ profile)
176
+ case "$line[2]" in
177
+ list)
178
+ local opts=('--json:Output as JSON lines')
179
+ _describe -t options 'profile list options' opts
180
+ ;;
181
+ name|delete)
182
+ if [[ -n "$profile_dirs" ]]; then
183
+ local dirs=(\${(f)profile_dirs})
184
+ _describe -t directories 'profile directory' dirs
185
+ fi
186
+ ;;
187
+ esac
188
+ ;;
189
+ esac
190
+ ;;
191
+ esac
192
+ }
193
+
194
+ _chrome_proc "$@"
195
+ `;
196
+ }
197
+
198
+ export function generatePowerShellCompletion(profileDirs: string[]): string {
199
+ const profileDirsQuoted = profileDirs.map((d) => `'${d.replace(/'/g, "''")}'`).join(", ");
200
+
201
+ return `Register-ArgumentCompleter -Native -CommandName chrome-proc -ScriptBlock {
202
+ param($wordToComplete, $commandAst, $cursorPosition)
203
+
204
+ $commands = @('list', 'kill', 'launch', 'profile', 'cdp', 'completion')
205
+ $profileSubcommands = @('list', 'name', 'delete')
206
+ $tokens = $commandAst.CommandElements | ForEach-Object { $_.Value }
207
+ $cmd = $tokens[1]
208
+ $subcmd = $tokens[2]
209
+
210
+ if (-not $cmd) {
211
+ $commands | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { $_ }
212
+ return
213
+ }
214
+
215
+ switch ($cmd) {
216
+ 'list' {
217
+ @('--verbose', '--json') | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { $_ }
218
+ }
219
+ 'kill' {
220
+ @('--force', '--all') | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { $_ }
221
+ }
222
+ 'launch' {
223
+ @('--dir', '--profile', '--debug', '--debugging-port') | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { $_ }
224
+ }
225
+ 'cdp' {
226
+ @('--json') | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { $_ }
227
+ }
228
+ 'completion' {
229
+ @('bash', 'zsh', 'powershell') | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { $_ }
230
+ }
231
+ 'profile' {
232
+ if (-not $subcmd) {
233
+ $profileSubcommands | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { $_ }
234
+ } else {
235
+ switch ($subcmd) {
236
+ 'list' {
237
+ @('--json') | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { $_ }
238
+ }
239
+ 'name' {
240
+ $profileDirs = @(${profileDirsQuoted})
241
+ $profileDirs | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { $_ }
242
+ }
243
+ 'delete' {
244
+ $profileDirs = @(${profileDirsQuoted})
245
+ $profileDirs | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { $_ }
246
+ }
247
+ }
248
+ }
249
+ }
250
+ }
251
+ }
252
+ `;
253
+ }