fscr 6.2.3 → 7.3.0

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.
Files changed (98) hide show
  1. package/README.md +48 -30
  2. package/dist/index.js +502 -185
  3. package/dist/lib/auth/auth-conf.js +49 -45
  4. package/dist/lib/cache/README.md +341 -0
  5. package/dist/lib/cache/cli.js +152 -0
  6. package/dist/lib/cache/file-watcher.js +193 -0
  7. package/dist/lib/cache/index.js +422 -0
  8. package/dist/lib/cache/monitor.js +224 -0
  9. package/dist/lib/commands/doctor.js +225 -0
  10. package/dist/lib/completions/completion.js +342 -0
  11. package/dist/lib/completions/generator.js +152 -0
  12. package/dist/lib/completions/scripts/bash.sh +108 -0
  13. package/dist/lib/completions/scripts/fish.sh +105 -0
  14. package/dist/lib/completions/scripts/powershell.ps1 +168 -0
  15. package/dist/lib/completions/scripts/zsh.sh +124 -0
  16. package/dist/lib/diagnostics/cache.js +121 -0
  17. package/dist/lib/diagnostics/fileSystem.js +236 -0
  18. package/dist/lib/diagnostics/gitCheck.js +41 -0
  19. package/dist/lib/diagnostics/nodeVersion.js +68 -0
  20. package/dist/lib/diagnostics/packageManager.js +64 -0
  21. package/dist/lib/diagnostics/performance.js +141 -0
  22. package/dist/lib/encryption/decryptConfig.js +3 -2
  23. package/dist/lib/encryption/encryption.js +153 -113
  24. package/dist/lib/generators/generateFScripts.js +16 -13
  25. package/dist/lib/generators/generateToc.js +23 -14
  26. package/dist/lib/generators/index.js +1 -1
  27. package/dist/lib/git/pub.js +27 -31
  28. package/dist/lib/git/taskRunner.js +79 -69
  29. package/dist/lib/git/validateNotDev.js +65 -54
  30. package/dist/lib/optionList.js +69 -57
  31. package/dist/lib/parsers/parseScriptsMd.cached.js +208 -0
  32. package/dist/lib/parsers/parseScriptsMd.js +88 -79
  33. package/dist/lib/parsers/parseScriptsPackage.js +4 -3
  34. package/dist/lib/performance/cache.js +199 -0
  35. package/dist/lib/performance/lazy-loader.js +189 -0
  36. package/dist/lib/performance/monitor.js +303 -0
  37. package/dist/lib/plugins/deployment/index.js +113 -0
  38. package/dist/lib/plugins/hooks.js +17 -0
  39. package/dist/lib/plugins/loader.js +91 -0
  40. package/dist/lib/plugins/task-notifier/index.js +72 -0
  41. package/dist/lib/release/bump.js +51 -43
  42. package/dist/lib/release/commitWithMessage.js +80 -52
  43. package/dist/lib/release/publish.js +19 -14
  44. package/dist/lib/release/pushToGit.js +40 -31
  45. package/dist/lib/release/releasenotes.js +116 -97
  46. package/dist/lib/release/seeChangedFiles.js +68 -60
  47. package/dist/lib/release/sort.js +200 -116
  48. package/dist/lib/release/tree.js +161 -147
  49. package/dist/lib/release/validateNotDev.js +52 -44
  50. package/dist/lib/running/index.js +1 -1
  51. package/dist/lib/running/runCLICommand.js +41 -31
  52. package/dist/lib/running/runParallel.js +61 -59
  53. package/dist/lib/running/runSequence.js +55 -53
  54. package/dist/lib/startScripts.js +129 -114
  55. package/dist/lib/taskList.js +99 -84
  56. package/dist/lib/test-files/.fscripts.md +113 -0
  57. package/dist/lib/test-files/.fscripts.test.md +103 -0
  58. package/dist/lib/test-files/.fscriptsb.md +107 -0
  59. package/dist/lib/test-files/.mdtest.md +40 -0
  60. package/dist/lib/test-files/consoleSample.js +17 -0
  61. package/dist/lib/test-files/inputSample.js +20 -0
  62. package/dist/lib/test-files/testConsole.js +1 -0
  63. package/dist/lib/test-files/testInput.js +2 -0
  64. package/dist/lib/upgradePackages.js +56 -46
  65. package/dist/lib/utils/clear.js +16 -13
  66. package/dist/lib/utils/console.js +27 -21
  67. package/dist/lib/utils/encryption.js +55 -13
  68. package/dist/lib/utils/hash.js +128 -0
  69. package/dist/lib/utils/helpers.js +153 -142
  70. package/dist/lib/utils/index.js +1 -1
  71. package/dist/lib/utils/prompt.js +24 -29
  72. package/package.json +20 -32
  73. package/dist/lib/codemod/arrow.js +0 -13
  74. package/dist/lib/codemod/arrow2.js +0 -67
  75. package/dist/lib/codemod/funcs.js +0 -25
  76. package/dist/lib/codemod/removeConsole.js +0 -12
  77. package/dist/lib/codemod/test.js +0 -8
  78. package/dist/lib/components/App.js +0 -64
  79. package/dist/lib/components/Selector.js +0 -133
  80. package/dist/lib/components/TabChanger.js +0 -113
  81. package/dist/lib/components/Table.js +0 -177
  82. package/dist/lib/components/Tabs.js +0 -221
  83. package/dist/lib/generateFScripts.js +0 -25
  84. package/dist/lib/generateToc.js +0 -30
  85. package/dist/lib/helpers.js +0 -191
  86. package/dist/lib/parseScriptsMd.js +0 -85
  87. package/dist/lib/parseScriptsPackage.js +0 -9
  88. package/dist/lib/release/index.js +0 -4
  89. package/dist/lib/run/lib.js +0 -454
  90. package/dist/lib/run/main-p.js +0 -59
  91. package/dist/lib/run/main-s.js +0 -56
  92. package/dist/lib/run/parse-cli-args.js +0 -222
  93. package/dist/lib/run/run-p.js +0 -30
  94. package/dist/lib/run/run-s.js +0 -57
  95. package/dist/lib/runCLICommand.js +0 -30
  96. package/dist/lib/runParallel.js +0 -20
  97. package/dist/lib/runSequence.js +0 -38
  98. package/dist/lib/taskListAutoComplete.js +0 -15
@@ -0,0 +1,342 @@
1
+ import chalk from "chalk";
2
+ import fs from "fs-extra";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+ import os from "os";
6
+ import { execSync } from "child_process";
7
+ import inquirer from "inquirer";
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+
12
+ /**
13
+ * Detect the user's current shell
14
+ */
15
+ export function detectShell() {
16
+ // Check SHELL environment variable
17
+ const shellEnv = process.env.SHELL;
18
+ if (shellEnv) {
19
+ const shellName = path.basename(shellEnv);
20
+ if (["bash", "zsh", "fish"].includes(shellName)) {
21
+ return shellName;
22
+ }
23
+ }
24
+
25
+ // Check for PowerShell on Windows
26
+ if (process.platform === "win32") {
27
+ return "powershell";
28
+ }
29
+
30
+ // Default to bash if unable to detect
31
+ return "bash";
32
+ }
33
+
34
+ /**
35
+ * Get shell configuration file path
36
+ */
37
+ export function getShellConfigPath(shell) {
38
+ const homeDir = os.homedir();
39
+
40
+ const configPaths = {
41
+ bash: path.join(homeDir, ".bashrc"),
42
+ zsh: path.join(homeDir, ".zshrc"),
43
+ fish: path.join(homeDir, ".config", "fish", "config.fish"),
44
+ powershell: path.join(
45
+ homeDir,
46
+ "Documents",
47
+ "WindowsPowerShell",
48
+ "Microsoft.PowerShell_profile.ps1"
49
+ )
50
+ };
51
+
52
+ return configPaths[shell] || configPaths.bash;
53
+ }
54
+
55
+ /**
56
+ * Get the completion script path for a shell
57
+ */
58
+ export function getCompletionScriptPath(shell) {
59
+ const scriptsDir = path.join(__dirname, "scripts");
60
+ const scriptFiles = {
61
+ bash: path.join(scriptsDir, "bash.sh"),
62
+ zsh: path.join(scriptsDir, "zsh.sh"),
63
+ fish: path.join(scriptsDir, "fish.sh"),
64
+ powershell: path.join(scriptsDir, "powershell.ps1")
65
+ };
66
+
67
+ return scriptFiles[shell];
68
+ }
69
+
70
+ /**
71
+ * Install completion script for a specific shell
72
+ */
73
+ export async function installCompletion(shell, options = {}) {
74
+ const { force = false, silent = false } = options;
75
+
76
+ try {
77
+ const configPath = getShellConfigPath(shell);
78
+ const scriptPath = getCompletionScriptPath(shell);
79
+
80
+ // Check if script exists
81
+ if (!fs.existsSync(scriptPath)) {
82
+ throw new Error(`Completion script not found for ${shell}`);
83
+ }
84
+
85
+ // Read the completion script
86
+ const completionScript = fs.readFileSync(scriptPath, "utf8");
87
+
88
+ // For fish, create completions directory
89
+ if (shell === "fish") {
90
+ const fishCompDir = path.join(os.homedir(), ".config", "fish", "completions");
91
+ await fs.ensureDir(fishCompDir);
92
+
93
+ const fishCompPath = path.join(fishCompDir, "fsr.fish");
94
+ await fs.writeFile(fishCompPath, completionScript);
95
+
96
+ if (!silent) {
97
+ console.log(chalk.green("✅ Installed Fish completions to"), fishCompPath);
98
+ }
99
+ return fishCompPath;
100
+ }
101
+
102
+ // For other shells, append to config file
103
+ await fs.ensureFile(configPath);
104
+ const currentConfig = await fs.readFile(configPath, "utf8");
105
+
106
+ // Check if already installed
107
+ const marker = "# FSCR completion";
108
+ if (currentConfig.includes(marker) && !force) {
109
+ if (!silent) {
110
+ console.log(chalk.yellow("⚠️ Completions already installed"));
111
+ console.log(chalk.dim(` Use --force to reinstall`));
112
+ }
113
+ return configPath;
114
+ }
115
+
116
+ // Prepare completion block
117
+ const completionBlock = `
118
+ ${marker}
119
+ ${completionScript}
120
+ # End FSCR completion
121
+ `;
122
+
123
+ // Append or replace completion block
124
+ let newConfig;
125
+ if (currentConfig.includes(marker)) {
126
+ // Replace existing block
127
+ newConfig = currentConfig.replace(
128
+ /# FSCR completion[\s\S]*?# End FSCR completion\n?/,
129
+ completionBlock
130
+ );
131
+ } else {
132
+ // Append new block
133
+ newConfig = currentConfig + "\n" + completionBlock;
134
+ }
135
+
136
+ await fs.writeFile(configPath, newConfig);
137
+
138
+ if (!silent) {
139
+ console.log(chalk.green("✅ Installed completions to"), configPath);
140
+ }
141
+
142
+ return configPath;
143
+ } catch (error) {
144
+ throw new Error(`Failed to install ${shell} completions: ${error.message}`);
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Uninstall completion script
150
+ */
151
+ export async function uninstallCompletion(shell, options = {}) {
152
+ const { silent = false } = options;
153
+
154
+ try {
155
+ const configPath = getShellConfigPath(shell);
156
+
157
+ if (shell === "fish") {
158
+ const fishCompPath = path.join(
159
+ os.homedir(),
160
+ ".config",
161
+ "fish",
162
+ "completions",
163
+ "fsr.fish"
164
+ );
165
+
166
+ if (fs.existsSync(fishCompPath)) {
167
+ await fs.remove(fishCompPath);
168
+ if (!silent) {
169
+ console.log(chalk.green("✅ Removed Fish completions"));
170
+ }
171
+ } else {
172
+ if (!silent) {
173
+ console.log(chalk.yellow("⚠️ No Fish completions found"));
174
+ }
175
+ }
176
+ return;
177
+ }
178
+
179
+ // For other shells, remove from config file
180
+ if (!fs.existsSync(configPath)) {
181
+ if (!silent) {
182
+ console.log(chalk.yellow(`⚠️ Config file not found: ${configPath}`));
183
+ }
184
+ return;
185
+ }
186
+
187
+ const currentConfig = await fs.readFile(configPath, "utf8");
188
+ const marker = "# FSCR completion";
189
+
190
+ if (!currentConfig.includes(marker)) {
191
+ if (!silent) {
192
+ console.log(chalk.yellow("⚠️ No completions found to uninstall"));
193
+ }
194
+ return;
195
+ }
196
+
197
+ // Remove completion block
198
+ const newConfig = currentConfig.replace(
199
+ /# FSCR completion[\s\S]*?# End FSCR completion\n?/,
200
+ ""
201
+ );
202
+
203
+ await fs.writeFile(configPath, newConfig);
204
+
205
+ if (!silent) {
206
+ console.log(chalk.green("✅ Removed completions from"), configPath);
207
+ }
208
+ } catch (error) {
209
+ throw new Error(`Failed to uninstall ${shell} completions: ${error.message}`);
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Show completion status for all shells
215
+ */
216
+ export async function completionStatus() {
217
+ const shells = ["bash", "zsh", "fish", "powershell"];
218
+ const currentShell = detectShell();
219
+
220
+ console.log(chalk.bold("\n📋 Completion Status\n"));
221
+
222
+ for (const shell of shells) {
223
+ const isCurrent = shell === currentShell;
224
+ const marker = isCurrent ? chalk.green("●") : chalk.dim("○");
225
+
226
+ try {
227
+ const configPath = getShellConfigPath(shell);
228
+ let installed = false;
229
+
230
+ if (shell === "fish") {
231
+ const fishCompPath = path.join(
232
+ os.homedir(),
233
+ ".config",
234
+ "fish",
235
+ "completions",
236
+ "fsr.fish"
237
+ );
238
+ installed = fs.existsSync(fishCompPath);
239
+ } else {
240
+ if (fs.existsSync(configPath)) {
241
+ const config = await fs.readFile(configPath, "utf8");
242
+ installed = config.includes("# FSCR completion");
243
+ }
244
+ }
245
+
246
+ const status = installed ? chalk.green("✅ Installed") : chalk.dim("Not installed");
247
+ const current = isCurrent ? chalk.yellow(" (current)") : "";
248
+
249
+ console.log(`${marker} ${chalk.bold(shell.padEnd(12))} ${status}${current}`);
250
+ } catch (error) {
251
+ console.log(`${marker} ${chalk.bold(shell.padEnd(12))} ${chalk.red("Error")}`);
252
+ }
253
+ }
254
+
255
+ console.log();
256
+ }
257
+
258
+ /**
259
+ * Main completion command handler
260
+ */
261
+ export default async function completion(argv) {
262
+ // Get the action from positional argument or from argv._[1]
263
+ const command = argv.action || argv._[1];
264
+ const shell = argv.shell || detectShell();
265
+
266
+ try {
267
+ switch (command) {
268
+ case "install":
269
+ await installCompletion(shell, { force: argv.force });
270
+ console.log();
271
+ console.log(chalk.cyan("🎉 Completions installed successfully!"));
272
+ console.log();
273
+ console.log(chalk.dim("To activate completions, restart your shell or run:"));
274
+ console.log(
275
+ chalk.yellow(
276
+ shell === "fish"
277
+ ? " exec fish"
278
+ : shell === "powershell"
279
+ ? " . $PROFILE"
280
+ : ` source ${getShellConfigPath(shell)}`
281
+ )
282
+ );
283
+ console.log();
284
+ break;
285
+
286
+ case "uninstall":
287
+ await uninstallCompletion(shell);
288
+ console.log();
289
+ console.log(chalk.cyan("✅ Completions uninstalled successfully!"));
290
+ console.log();
291
+ break;
292
+
293
+ case "status":
294
+ await completionStatus();
295
+ break;
296
+
297
+ case "generate":
298
+ // Generate completion script without installing
299
+ const scriptPath = getCompletionScriptPath(shell);
300
+ if (!fs.existsSync(scriptPath)) {
301
+ throw new Error(`Completion script not found for ${shell}`);
302
+ }
303
+ const script = fs.readFileSync(scriptPath, "utf8");
304
+ console.log(script);
305
+ break;
306
+
307
+ default:
308
+ // Interactive installation
309
+ const { confirmInstall } = await inquirer.prompt([
310
+ {
311
+ type: "confirm",
312
+ name: "confirmInstall",
313
+ message: `Install completions for ${chalk.cyan(shell)}?`,
314
+ default: true
315
+ }
316
+ ]);
317
+
318
+ if (confirmInstall) {
319
+ await installCompletion(shell, { force: argv.force });
320
+ console.log();
321
+ console.log(chalk.cyan("🎉 Completions installed successfully!"));
322
+ console.log();
323
+ console.log(chalk.dim("To activate completions, restart your shell or run:"));
324
+ console.log(
325
+ chalk.yellow(
326
+ shell === "fish"
327
+ ? " exec fish"
328
+ : shell === "powershell"
329
+ ? " . $PROFILE"
330
+ : ` source ${getShellConfigPath(shell)}`
331
+ )
332
+ );
333
+ console.log();
334
+ } else {
335
+ console.log(chalk.yellow("Installation cancelled"));
336
+ }
337
+ }
338
+ } catch (error) {
339
+ console.error(chalk.red("Error:"), error.message);
340
+ process.exit(1);
341
+ }
342
+ }
@@ -0,0 +1,152 @@
1
+ import fs from "fs-extra";
2
+ import path from "path";
3
+ import parseScriptFile from "../parsers/parseScriptsMd.js";
4
+
5
+ /**
6
+ * Cache for parsed tasks to avoid re-parsing on every completion
7
+ */
8
+ let taskCache = null;
9
+ let cacheTime = 0;
10
+ const CACHE_TTL = 5000; // 5 seconds
11
+
12
+ /**
13
+ * Get all available tasks from fscripts.md with caching
14
+ */
15
+ export async function getAvailableTasks(forceRefresh = false) {
16
+ const now = Date.now();
17
+
18
+ // Return cached tasks if still valid
19
+ if (!forceRefresh && taskCache && now - cacheTime < CACHE_TTL) {
20
+ return taskCache;
21
+ }
22
+
23
+ try {
24
+ const { allTasks } = await parseScriptFile();
25
+ taskCache = allTasks.map((task) => ({
26
+ name: task.name,
27
+ description: task.description || "",
28
+ lang: task.lang || "bash"
29
+ }));
30
+ cacheTime = now;
31
+ return taskCache;
32
+ } catch (error) {
33
+ // If parsing fails, return empty array
34
+ return [];
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Get all available commands
40
+ */
41
+ export function getAvailableCommands() {
42
+ return [
43
+ { name: "start", description: "Choose category then task to run" },
44
+ { name: "run", description: "Run a specific task" },
45
+ { name: "list", description: "Select any task with text autocompletion" },
46
+ { name: "scripts", description: "Choose a script from package.json" },
47
+ { name: "run-s", description: "Run tasks in sequence" },
48
+ { name: "run-p", description: "Run tasks in parallel" },
49
+ { name: "bump", description: "Bump package.json version" },
50
+ { name: "upgrade", description: "Upgrade packages" },
51
+ { name: "branch", description: "Create new branch" },
52
+ { name: "remote", description: "Get remote configuration" },
53
+ { name: "encryption", description: "Encrypt/Decrypt files" },
54
+ { name: "clear", description: "Clear recent task history" },
55
+ { name: "generate", description: "Generate sample fscripts.md" },
56
+ { name: "toc", description: "Generate table of contents" },
57
+ { name: "completion", description: "Manage shell completions" }
58
+ ];
59
+ }
60
+
61
+ /**
62
+ * Get completion subcommands
63
+ */
64
+ export function getCompletionSubcommands() {
65
+ return [
66
+ { name: "install", description: "Install completions" },
67
+ { name: "uninstall", description: "Uninstall completions" },
68
+ { name: "status", description: "Show completion status" },
69
+ { name: "generate", description: "Generate completion script" }
70
+ ];
71
+ }
72
+
73
+ /**
74
+ * Generate task names for shell completion
75
+ */
76
+ export async function generateTaskNames() {
77
+ const tasks = await getAvailableTasks();
78
+ return tasks.map((t) => t.name);
79
+ }
80
+
81
+ /**
82
+ * Generate bash completion data
83
+ */
84
+ export async function generateBashCompletionData() {
85
+ const tasks = await getAvailableTasks();
86
+ const commands = getAvailableCommands();
87
+ const completionCmds = getCompletionSubcommands();
88
+
89
+ return {
90
+ commands: commands.map((c) => c.name),
91
+ tasks: tasks.map((t) => t.name),
92
+ completionSubcommands: completionCmds.map((c) => c.name)
93
+ };
94
+ }
95
+
96
+ /**
97
+ * Generate zsh completion data
98
+ */
99
+ export async function generateZshCompletionData() {
100
+ const tasks = await getAvailableTasks();
101
+ const commands = getAvailableCommands();
102
+ const completionCmds = getCompletionSubcommands();
103
+
104
+ return {
105
+ commands: commands.map((c) => `${c.name}:${c.description}`),
106
+ tasks: tasks.map((t) => {
107
+ const desc = t.description.replace(/[:\n]/g, " ").trim();
108
+ return `${t.name}:${desc || "Run task"}`;
109
+ }),
110
+ completionSubcommands: completionCmds.map((c) => `${c.name}:${c.description}`)
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Generate fish completion data
116
+ */
117
+ export async function generateFishCompletionData() {
118
+ const tasks = await getAvailableTasks();
119
+ const commands = getAvailableCommands();
120
+ const completionCmds = getCompletionSubcommands();
121
+
122
+ return {
123
+ commands: commands.map((c) => ({
124
+ name: c.name,
125
+ description: c.description
126
+ })),
127
+ tasks: tasks.map((t) => ({
128
+ name: t.name,
129
+ description: t.description || "Run task"
130
+ })),
131
+ completionSubcommands: completionCmds.map((c) => ({
132
+ name: c.name,
133
+ description: c.description
134
+ }))
135
+ };
136
+ }
137
+
138
+ /**
139
+ * Export tasks for completion (used by shell scripts)
140
+ */
141
+ export async function exportTasksForCompletion() {
142
+ const tasks = await getAvailableTasks();
143
+ return tasks.map((t) => t.name).join("\n");
144
+ }
145
+
146
+ /**
147
+ * Clear the task cache (useful when fscripts.md is updated)
148
+ */
149
+ export function clearTaskCache() {
150
+ taskCache = null;
151
+ cacheTime = 0;
152
+ }
@@ -0,0 +1,108 @@
1
+ #!/bin/bash
2
+ # FSCR Bash completion script
3
+
4
+ _fscr_get_tasks() {
5
+ # Try to get tasks from fscripts.md
6
+ if command -v node >/dev/null 2>&1; then
7
+ local tasks_output
8
+ tasks_output=$(node -e "
9
+ import('$FSCR_COMPLETION_HELPER').then(async (m) => {
10
+ const tasks = await m.generateTaskNames();
11
+ console.log(tasks.join(' '));
12
+ }).catch(() => {});
13
+ " 2>/dev/null)
14
+
15
+ if [ -n "$tasks_output" ]; then
16
+ echo "$tasks_output"
17
+ return
18
+ fi
19
+ fi
20
+
21
+ # Fallback: parse fscripts.md directly
22
+ if [ -f "fscripts.md" ]; then
23
+ grep -E "^## " fscripts.md | sed 's/^## //' | tr '\n' ' '
24
+ fi
25
+ }
26
+
27
+ _fscr_completion() {
28
+ local cur prev words cword
29
+ _init_completion || return
30
+
31
+ # Main commands
32
+ local commands="start run list scripts run-s run-p bump upgrade branch remote encryption clear generate toc completion"
33
+
34
+ # Completion subcommands
35
+ local completion_cmds="install uninstall status generate"
36
+
37
+ # Get current word and previous word
38
+ local cur="${COMP_WORDS[COMP_CWORD]}"
39
+ local prev="${COMP_WORDS[COMP_CWORD-1]}"
40
+
41
+ # Get the main command (first argument after fsr)
42
+ local cmd=""
43
+ if [ ${COMP_CWORD} -gt 0 ]; then
44
+ cmd="${COMP_WORDS[1]}"
45
+ fi
46
+
47
+ case "${prev}" in
48
+ fsr|fsr)
49
+ # Complete main commands
50
+ COMPREPLY=($(compgen -W "${commands}" -- "${cur}"))
51
+ return 0
52
+ ;;
53
+ run|run-s|run-p)
54
+ # Complete task names
55
+ local tasks=$(_fscr_get_tasks)
56
+ COMPREPLY=($(compgen -W "${tasks}" -- "${cur}"))
57
+ return 0
58
+ ;;
59
+ completion)
60
+ # Complete completion subcommands
61
+ COMPREPLY=($(compgen -W "${completion_cmds}" -- "${cur}"))
62
+ return 0
63
+ ;;
64
+ install|uninstall)
65
+ # Complete shell names
66
+ if [ "${cmd}" = "completion" ]; then
67
+ COMPREPLY=($(compgen -W "bash zsh fish powershell" -- "${cur}"))
68
+ return 0
69
+ fi
70
+ ;;
71
+ --shell)
72
+ # Complete shell names for --shell flag
73
+ COMPREPLY=($(compgen -W "bash zsh fish powershell" -- "${cur}"))
74
+ return 0
75
+ ;;
76
+ esac
77
+
78
+ # Handle flags
79
+ case "${cur}" in
80
+ -*)
81
+ case "${cmd}" in
82
+ completion)
83
+ COMPREPLY=($(compgen -W "--shell --force --help" -- "${cur}"))
84
+ ;;
85
+ run)
86
+ COMPREPLY=($(compgen -W "--help" -- "${cur}"))
87
+ ;;
88
+ *)
89
+ COMPREPLY=($(compgen -W "--help" -- "${cur}"))
90
+ ;;
91
+ esac
92
+ return 0
93
+ ;;
94
+ esac
95
+
96
+ # Continue completing task names for run-s and run-p
97
+ if [ "${cmd}" = "run-s" ] || [ "${cmd}" = "run-p" ]; then
98
+ local tasks=$(_fscr_get_tasks)
99
+ COMPREPLY=($(compgen -W "${tasks}" -- "${cur}"))
100
+ return 0
101
+ fi
102
+
103
+ return 0
104
+ }
105
+
106
+ # Register completion for both fsr and fsr
107
+ complete -F _fscr_completion fsr
108
+ complete -F _fscr_completion fsr