fscr 6.2.6 → 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 (72) hide show
  1. package/README.md +48 -30
  2. package/dist/index.js +502 -186
  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 -17
  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 +50 -45
  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 +97 -90
  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 +13 -9
  61. package/dist/lib/test-files/inputSample.js +17 -14
  62. package/dist/lib/test-files/testConsole.js +1 -1
  63. package/dist/lib/test-files/testInput.js +1 -1
  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 +11 -29
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env fish
2
+ # FSCR Fish completion script
3
+
4
+ # Function to get available tasks
5
+ function __fscr_get_tasks
6
+ # Try to get tasks from fscripts.md using node
7
+ if command -v node >/dev/null 2>&1
8
+ set tasks_output (node -e "
9
+ import('$FSCR_COMPLETION_HELPER').then(async (m) => {
10
+ const tasks = await m.generateTaskNames();
11
+ console.log(tasks.join('\\n'));
12
+ }).catch(() => {});
13
+ " 2>/dev/null)
14
+
15
+ if test -n "$tasks_output"
16
+ echo $tasks_output
17
+ return
18
+ end
19
+ end
20
+
21
+ # Fallback: parse fscripts.md directly
22
+ if test -f "fscripts.md"
23
+ grep -E "^## " fscripts.md | sed 's/^## //'
24
+ end
25
+ end
26
+
27
+ # Function to check if a command has been given
28
+ function __fscr_using_command
29
+ set -l cmd (commandline -opc)
30
+ if test (count $cmd) -gt 1
31
+ if test $argv[1] = $cmd[2]
32
+ return 0
33
+ end
34
+ end
35
+ return 1
36
+ end
37
+
38
+ # Disable file completion by default
39
+ complete -c fsr -f
40
+ complete -c fsr -f
41
+
42
+ # Main commands
43
+ complete -c fsr -n "not __fscr_using_command start" -a "start" -d "Choose category then task to run"
44
+ complete -c fsr -n "not __fscr_using_command run" -a "run" -d "Run a specific task"
45
+ complete -c fsr -n "not __fscr_using_command list" -a "list" -d "Select any task with text autocompletion"
46
+ complete -c fsr -n "not __fscr_using_command scripts" -a "scripts" -d "Choose a script from package.json"
47
+ complete -c fsr -n "not __fscr_using_command run-s" -a "run-s" -d "Run tasks in sequence"
48
+ complete -c fsr -n "not __fscr_using_command run-p" -a "run-p" -d "Run tasks in parallel"
49
+ complete -c fsr -n "not __fscr_using_command bump" -a "bump" -d "Bump package.json version"
50
+ complete -c fsr -n "not __fscr_using_command upgrade" -a "upgrade" -d "Upgrade packages"
51
+ complete -c fsr -n "not __fscr_using_command branch" -a "branch" -d "Create new branch"
52
+ complete -c fsr -n "not __fscr_using_command remote" -a "remote" -d "Get remote configuration"
53
+ complete -c fsr -n "not __fscr_using_command encryption" -a "encryption" -d "Encrypt/Decrypt files"
54
+ complete -c fsr -n "not __fscr_using_command clear" -a "clear" -d "Clear recent task history"
55
+ complete -c fsr -n "not __fscr_using_command generate" -a "generate" -d "Generate sample fscripts.md"
56
+ complete -c fsr -n "not __fscr_using_command toc" -a "toc" -d "Generate table of contents"
57
+ complete -c fsr -n "not __fscr_using_command completion" -a "completion" -d "Manage shell completions"
58
+
59
+ # Task completion for 'run' command
60
+ complete -c fsr -n "__fscr_using_command run" -a "(__fscr_get_tasks)" -d "Run task"
61
+
62
+ # Task completion for 'run-s' command
63
+ complete -c fsr -n "__fscr_using_command run-s" -a "(__fscr_get_tasks)" -d "Run task"
64
+
65
+ # Task completion for 'run-p' command
66
+ complete -c fsr -n "__fscr_using_command run-p" -a "(__fscr_get_tasks)" -d "Run task"
67
+
68
+ # Completion subcommands
69
+ complete -c fsr -n "__fscr_using_command completion" -a "install" -d "Install completions"
70
+ complete -c fsr -n "__fscr_using_command completion" -a "uninstall" -d "Uninstall completions"
71
+ complete -c fsr -n "__fscr_using_command completion" -a "status" -d "Show completion status"
72
+ complete -c fsr -n "__fscr_using_command completion" -a "generate" -d "Generate completion script"
73
+
74
+ # Shell options for completion commands
75
+ complete -c fsr -l shell -d "Target shell" -a "bash zsh fish powershell"
76
+ complete -c fsr -l force -d "Force reinstall"
77
+ complete -c fsr -l help -d "Show help"
78
+
79
+ # Copy all completions to fsr alias
80
+ complete -c fsr -f
81
+ complete -c fsr -n "not __fscr_using_command start" -a "start" -d "Choose category then task to run"
82
+ complete -c fsr -n "not __fscr_using_command run" -a "run" -d "Run a specific task"
83
+ complete -c fsr -n "not __fscr_using_command list" -a "list" -d "Select any task with text autocompletion"
84
+ complete -c fsr -n "not __fscr_using_command scripts" -a "scripts" -d "Choose a script from package.json"
85
+ complete -c fsr -n "not __fscr_using_command run-s" -a "run-s" -d "Run tasks in sequence"
86
+ complete -c fsr -n "not __fscr_using_command run-p" -a "run-p" -d "Run tasks in parallel"
87
+ complete -c fsr -n "not __fscr_using_command bump" -a "bump" -d "Bump package.json version"
88
+ complete -c fsr -n "not __fscr_using_command upgrade" -a "upgrade" -d "Upgrade packages"
89
+ complete -c fsr -n "not __fscr_using_command branch" -a "branch" -d "Create new branch"
90
+ complete -c fsr -n "not __fscr_using_command remote" -a "remote" -d "Get remote configuration"
91
+ complete -c fsr -n "not __fscr_using_command encryption" -a "encryption" -d "Encrypt/Decrypt files"
92
+ complete -c fsr -n "not __fscr_using_command clear" -a "clear" -d "Clear recent task history"
93
+ complete -c fsr -n "not __fscr_using_command generate" -a "generate" -d "Generate sample fscripts.md"
94
+ complete -c fsr -n "not __fscr_using_command toc" -a "toc" -d "Generate table of contents"
95
+ complete -c fsr -n "not __fscr_using_command completion" -a "completion" -d "Manage shell completions"
96
+ complete -c fsr -n "__fscr_using_command run" -a "(__fscr_get_tasks)" -d "Run task"
97
+ complete -c fsr -n "__fscr_using_command run-s" -a "(__fscr_get_tasks)" -d "Run task"
98
+ complete -c fsr -n "__fscr_using_command run-p" -a "(__fscr_get_tasks)" -d "Run task"
99
+ complete -c fsr -n "__fscr_using_command completion" -a "install" -d "Install completions"
100
+ complete -c fsr -n "__fscr_using_command completion" -a "uninstall" -d "Uninstall completions"
101
+ complete -c fsr -n "__fscr_using_command completion" -a "status" -d "Show completion status"
102
+ complete -c fsr -n "__fscr_using_command completion" -a "generate" -d "Generate completion script"
103
+ complete -c fsr -l shell -d "Target shell" -a "bash zsh fish powershell"
104
+ complete -c fsr -l force -d "Force reinstall"
105
+ complete -c fsr -l help -d "Show help"
@@ -0,0 +1,168 @@
1
+ # FSCR PowerShell completion script
2
+
3
+ # Function to get available tasks
4
+ function Get-FscrTasks {
5
+ try {
6
+ # Try to get tasks from fscripts.md using node
7
+ if (Get-Command node -ErrorAction SilentlyContinue) {
8
+ $tasksOutput = node -e @"
9
+ import('$env:FSCR_COMPLETION_HELPER').then(async (m) => {
10
+ const tasks = await m.generateTaskNames();
11
+ console.log(tasks.join('\n'));
12
+ }).catch(() => {});
13
+ "@ 2>$null
14
+
15
+ if ($tasksOutput) {
16
+ return $tasksOutput -split '\n' | Where-Object { $_ }
17
+ }
18
+ }
19
+
20
+ # Fallback: parse fscripts.md directly
21
+ if (Test-Path "fscripts.md") {
22
+ Get-Content "fscripts.md" | Where-Object { $_ -match '^## ' } | ForEach-Object {
23
+ $_ -replace '^## ', ''
24
+ }
25
+ }
26
+ }
27
+ catch {
28
+ return @()
29
+ }
30
+ }
31
+
32
+ # Main completion function
33
+ $scriptBlock = {
34
+ param($wordToComplete, $commandAst, $cursorPosition)
35
+
36
+ $commands = @(
37
+ [PSCustomObject]@{Name='start'; Description='Choose category then task to run'}
38
+ [PSCustomObject]@{Name='run'; Description='Run a specific task'}
39
+ [PSCustomObject]@{Name='list'; Description='Select any task with text autocompletion'}
40
+ [PSCustomObject]@{Name='scripts'; Description='Choose a script from package.json'}
41
+ [PSCustomObject]@{Name='run-s'; Description='Run tasks in sequence'}
42
+ [PSCustomObject]@{Name='run-p'; Description='Run tasks in parallel'}
43
+ [PSCustomObject]@{Name='bump'; Description='Bump package.json version'}
44
+ [PSCustomObject]@{Name='upgrade'; Description='Upgrade packages'}
45
+ [PSCustomObject]@{Name='branch'; Description='Create new branch'}
46
+ [PSCustomObject]@{Name='remote'; Description='Get remote configuration'}
47
+ [PSCustomObject]@{Name='encryption'; Description='Encrypt/Decrypt files'}
48
+ [PSCustomObject]@{Name='clear'; Description='Clear recent task history'}
49
+ [PSCustomObject]@{Name='generate'; Description='Generate sample fscripts.md'}
50
+ [PSCustomObject]@{Name='toc'; Description='Generate table of contents'}
51
+ [PSCustomObject]@{Name='completion'; Description='Manage shell completions'}
52
+ )
53
+
54
+ $completionSubcommands = @(
55
+ [PSCustomObject]@{Name='install'; Description='Install completions'}
56
+ [PSCustomObject]@{Name='uninstall'; Description='Uninstall completions'}
57
+ [PSCustomObject]@{Name='status'; Description='Show completion status'}
58
+ [PSCustomObject]@{Name='generate'; Description='Generate completion script'}
59
+ )
60
+
61
+ $shells = @(
62
+ [PSCustomObject]@{Name='bash'; Description='Bash shell'}
63
+ [PSCustomObject]@{Name='zsh'; Description='Zsh shell'}
64
+ [PSCustomObject]@{Name='fish'; Description='Fish shell'}
65
+ [PSCustomObject]@{Name='powershell'; Description='PowerShell'}
66
+ )
67
+
68
+ # Parse the command line
69
+ $tokens = $commandAst.ToString() -split '\s+'
70
+ $commandCount = $tokens.Count
71
+
72
+ # If we're completing the first argument (command)
73
+ if ($commandCount -eq 1 -or ($commandCount -eq 2 -and $wordToComplete)) {
74
+ $commands | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object {
75
+ [System.Management.Automation.CompletionResult]::new(
76
+ $_.Name,
77
+ $_.Name,
78
+ 'ParameterValue',
79
+ $_.Description
80
+ )
81
+ }
82
+ return
83
+ }
84
+
85
+ # Get the main command
86
+ $mainCommand = $tokens[1]
87
+
88
+ # Handle completion based on the command
89
+ switch ($mainCommand) {
90
+ 'run' {
91
+ # Complete task names
92
+ $tasks = Get-FscrTasks
93
+ $tasks | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
94
+ [System.Management.Automation.CompletionResult]::new(
95
+ $_,
96
+ $_,
97
+ 'ParameterValue',
98
+ "Run task: $_"
99
+ )
100
+ }
101
+ }
102
+ 'run-s' {
103
+ # Complete task names
104
+ $tasks = Get-FscrTasks
105
+ $tasks | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
106
+ [System.Management.Automation.CompletionResult]::new(
107
+ $_,
108
+ $_,
109
+ 'ParameterValue',
110
+ "Run task: $_"
111
+ )
112
+ }
113
+ }
114
+ 'run-p' {
115
+ # Complete task names
116
+ $tasks = Get-FscrTasks
117
+ $tasks | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
118
+ [System.Management.Automation.CompletionResult]::new(
119
+ $_,
120
+ $_,
121
+ 'ParameterValue',
122
+ "Run task: $_"
123
+ )
124
+ }
125
+ }
126
+ 'completion' {
127
+ # If we're completing after 'completion'
128
+ if ($commandCount -eq 2 -or ($commandCount -eq 3 -and $wordToComplete)) {
129
+ $completionSubcommands | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object {
130
+ [System.Management.Automation.CompletionResult]::new(
131
+ $_.Name,
132
+ $_.Name,
133
+ 'ParameterValue',
134
+ $_.Description
135
+ )
136
+ }
137
+ }
138
+ # If we're completing after 'completion install/uninstall'
139
+ elseif ($tokens.Count -ge 3 -and ($tokens[2] -eq 'install' -or $tokens[2] -eq 'uninstall')) {
140
+ $shells | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object {
141
+ [System.Management.Automation.CompletionResult]::new(
142
+ $_.Name,
143
+ $_.Name,
144
+ 'ParameterValue',
145
+ $_.Description
146
+ )
147
+ }
148
+ }
149
+ }
150
+ default {
151
+ # Complete flags
152
+ if ($wordToComplete -like '-*') {
153
+ @('--help', '--version', '--shell', '--force') | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
154
+ [System.Management.Automation.CompletionResult]::new(
155
+ $_,
156
+ $_,
157
+ 'ParameterName',
158
+ "Option: $_"
159
+ )
160
+ }
161
+ }
162
+ }
163
+ }
164
+ }
165
+
166
+ # Register completion for fsr and fsr
167
+ Register-ArgumentCompleter -CommandName fsr -ScriptBlock $scriptBlock
168
+ Register-ArgumentCompleter -CommandName fsr -ScriptBlock $scriptBlock
@@ -0,0 +1,124 @@
1
+ #!/bin/zsh
2
+ # FSCR Zsh completion script
3
+
4
+ _fscr_get_tasks() {
5
+ # Try to get tasks from fscripts.md using node
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('\\n'));
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/^## //'
24
+ fi
25
+ }
26
+
27
+ _fscr() {
28
+ local curcontext="$curcontext" state line
29
+ typeset -A opt_args
30
+
31
+ local -a commands
32
+ commands=(
33
+ 'start:Choose category then task to run'
34
+ 'run:Run a specific task'
35
+ 'list:Select any task with text autocompletion'
36
+ 'scripts:Choose a script from package.json'
37
+ 'run-s:Run tasks in sequence'
38
+ 'run-p:Run tasks in parallel'
39
+ 'bump:Bump package.json version'
40
+ 'upgrade:Upgrade packages'
41
+ 'branch:Create new branch'
42
+ 'remote:Get remote configuration'
43
+ 'encryption:Encrypt/Decrypt files'
44
+ 'clear:Clear recent task history'
45
+ 'generate:Generate sample fscripts.md'
46
+ 'toc:Generate table of contents'
47
+ 'completion:Manage shell completions'
48
+ )
49
+
50
+ local -a completion_cmds
51
+ completion_cmds=(
52
+ 'install:Install completions'
53
+ 'uninstall:Uninstall completions'
54
+ 'status:Show completion status'
55
+ 'generate:Generate completion script'
56
+ )
57
+
58
+ local -a shells
59
+ shells=(
60
+ 'bash:Bash shell'
61
+ 'zsh:Zsh shell'
62
+ 'fish:Fish shell'
63
+ 'powershell:PowerShell'
64
+ )
65
+
66
+ _arguments -C \
67
+ '1: :->command' \
68
+ '*:: :->args' \
69
+ && return 0
70
+
71
+ case $state in
72
+ command)
73
+ _describe -t commands 'fsr commands' commands
74
+ ;;
75
+ args)
76
+ case $words[1] in
77
+ run)
78
+ local -a tasks
79
+ local task_list
80
+ task_list=($(_fscr_get_tasks))
81
+
82
+ # Format tasks with descriptions
83
+ for task in $task_list; do
84
+ tasks+=("$task:Run task $task")
85
+ done
86
+
87
+ _describe -t tasks 'available tasks' tasks
88
+ ;;
89
+ run-s|run-p)
90
+ local -a tasks
91
+ local task_list
92
+ task_list=($(_fscr_get_tasks))
93
+
94
+ for task in $task_list; do
95
+ tasks+=("$task:Run task $task")
96
+ done
97
+
98
+ _describe -t tasks 'available tasks' tasks
99
+ ;;
100
+ completion)
101
+ case $words[2] in
102
+ install|uninstall)
103
+ _describe -t shells 'available shells' shells
104
+ ;;
105
+ *)
106
+ _describe -t completion_cmds 'completion commands' completion_cmds
107
+ ;;
108
+ esac
109
+ ;;
110
+ *)
111
+ _arguments \
112
+ '--help[Show help]' \
113
+ '--version[Show version]'
114
+ ;;
115
+ esac
116
+ ;;
117
+ esac
118
+
119
+ return 0
120
+ }
121
+
122
+ # Register completion for both fsr and fsr
123
+ compdef _fscr fsr
124
+ compdef _fscr fsr
@@ -0,0 +1,121 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import chalk from 'chalk';
5
+
6
+ /**
7
+ * Get cache directory path
8
+ * @returns {string} Cache directory path
9
+ */
10
+ function getCacheDir() {
11
+ const homeDir = os.homedir();
12
+ return path.join(homeDir, '.fsr', 'cache');
13
+ }
14
+
15
+ /**
16
+ * Check cache system
17
+ * @param {Object} options - Check options
18
+ * @returns {Object} Check result
19
+ */
20
+ export async function checkCache(options = {}) {
21
+ const result = {
22
+ name: 'Cache system',
23
+ passed: false,
24
+ warning: false,
25
+ message: '',
26
+ details: {},
27
+ canFix: true,
28
+ fix: null
29
+ };
30
+
31
+ try {
32
+ const cacheDir = getCacheDir();
33
+
34
+ // Check if cache directory exists
35
+ if (await fs.pathExists(cacheDir)) {
36
+ // Check if we can write to it
37
+ const testFile = path.join(cacheDir, '.test');
38
+ try {
39
+ await fs.writeFile(testFile, 'test', 'utf8');
40
+ await fs.remove(testFile);
41
+
42
+ // Calculate cache size
43
+ const size = await getCacheSize(cacheDir);
44
+
45
+ result.passed = true;
46
+ result.message = `Operational (${formatBytes(size)})`;
47
+ result.details = {
48
+ path: cacheDir,
49
+ size: size,
50
+ sizeFormatted: formatBytes(size),
51
+ writable: true
52
+ };
53
+ } catch (writeError) {
54
+ result.passed = false;
55
+ result.message = 'Cache directory not writable';
56
+ result.canFix = true;
57
+ result.fix = async () => {
58
+ await fs.chmod(cacheDir, 0o755);
59
+ return 'Fixed cache directory permissions';
60
+ };
61
+ }
62
+ } else {
63
+ result.passed = false;
64
+ result.message = 'Cache directory does not exist';
65
+ result.canFix = true;
66
+ result.fix = async () => {
67
+ await fs.ensureDir(cacheDir);
68
+ return `Created cache directory at ${cacheDir}`;
69
+ };
70
+ }
71
+ } catch (error) {
72
+ result.passed = false;
73
+ result.message = `Cache check failed: ${error.message}`;
74
+ }
75
+
76
+ return result;
77
+ }
78
+
79
+ /**
80
+ * Calculate total size of cache directory
81
+ * @param {string} dir - Directory path
82
+ * @returns {Promise<number>} Total size in bytes
83
+ */
84
+ async function getCacheSize(dir) {
85
+ let totalSize = 0;
86
+
87
+ try {
88
+ const files = await fs.readdir(dir);
89
+
90
+ for (const file of files) {
91
+ const filePath = path.join(dir, file);
92
+ const stats = await fs.stat(filePath);
93
+
94
+ if (stats.isDirectory()) {
95
+ totalSize += await getCacheSize(filePath);
96
+ } else {
97
+ totalSize += stats.size;
98
+ }
99
+ }
100
+ } catch (error) {
101
+ // Directory doesn't exist or can't be read
102
+ return 0;
103
+ }
104
+
105
+ return totalSize;
106
+ }
107
+
108
+ /**
109
+ * Format bytes to human-readable format
110
+ * @param {number} bytes - Number of bytes
111
+ * @returns {string} Formatted string
112
+ */
113
+ function formatBytes(bytes) {
114
+ if (bytes === 0) return '0 Bytes';
115
+ const k = 1024;
116
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
117
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
118
+ return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
119
+ }
120
+
121
+ export default checkCache;