lsh-framework 0.5.4

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 (90) hide show
  1. package/.env.example +51 -0
  2. package/README.md +399 -0
  3. package/dist/app.js +33 -0
  4. package/dist/cicd/analytics.js +261 -0
  5. package/dist/cicd/auth.js +269 -0
  6. package/dist/cicd/cache-manager.js +172 -0
  7. package/dist/cicd/data-retention.js +305 -0
  8. package/dist/cicd/performance-monitor.js +224 -0
  9. package/dist/cicd/webhook-receiver.js +634 -0
  10. package/dist/cli.js +500 -0
  11. package/dist/commands/api.js +343 -0
  12. package/dist/commands/self.js +318 -0
  13. package/dist/commands/theme.js +257 -0
  14. package/dist/commands/zsh-import.js +240 -0
  15. package/dist/components/App.js +1 -0
  16. package/dist/components/Divider.js +29 -0
  17. package/dist/components/REPL.js +43 -0
  18. package/dist/components/Terminal.js +232 -0
  19. package/dist/components/UserInput.js +30 -0
  20. package/dist/daemon/api-server.js +315 -0
  21. package/dist/daemon/job-registry.js +554 -0
  22. package/dist/daemon/lshd.js +822 -0
  23. package/dist/daemon/monitoring-api.js +220 -0
  24. package/dist/examples/supabase-integration.js +106 -0
  25. package/dist/lib/api-error-handler.js +183 -0
  26. package/dist/lib/associative-arrays.js +285 -0
  27. package/dist/lib/base-api-server.js +290 -0
  28. package/dist/lib/base-command-registrar.js +286 -0
  29. package/dist/lib/base-job-manager.js +293 -0
  30. package/dist/lib/brace-expansion.js +160 -0
  31. package/dist/lib/builtin-commands.js +439 -0
  32. package/dist/lib/cloud-config-manager.js +347 -0
  33. package/dist/lib/command-validator.js +190 -0
  34. package/dist/lib/completion-system.js +344 -0
  35. package/dist/lib/cron-job-manager.js +364 -0
  36. package/dist/lib/daemon-client-helper.js +141 -0
  37. package/dist/lib/daemon-client.js +501 -0
  38. package/dist/lib/database-persistence.js +638 -0
  39. package/dist/lib/database-schema.js +259 -0
  40. package/dist/lib/enhanced-history-system.js +246 -0
  41. package/dist/lib/env-validator.js +265 -0
  42. package/dist/lib/executors/builtin-executor.js +52 -0
  43. package/dist/lib/extended-globbing.js +411 -0
  44. package/dist/lib/extended-parameter-expansion.js +227 -0
  45. package/dist/lib/floating-point-arithmetic.js +256 -0
  46. package/dist/lib/history-system.js +245 -0
  47. package/dist/lib/interactive-shell.js +460 -0
  48. package/dist/lib/job-builtins.js +580 -0
  49. package/dist/lib/job-manager.js +386 -0
  50. package/dist/lib/job-storage-database.js +156 -0
  51. package/dist/lib/job-storage-memory.js +73 -0
  52. package/dist/lib/logger.js +274 -0
  53. package/dist/lib/lshrc-init.js +177 -0
  54. package/dist/lib/pathname-expansion.js +216 -0
  55. package/dist/lib/prompt-system.js +328 -0
  56. package/dist/lib/script-runner.js +226 -0
  57. package/dist/lib/secrets-manager.js +193 -0
  58. package/dist/lib/shell-executor.js +2504 -0
  59. package/dist/lib/shell-parser.js +958 -0
  60. package/dist/lib/shell-types.js +6 -0
  61. package/dist/lib/shell.lib.js +40 -0
  62. package/dist/lib/supabase-client.js +58 -0
  63. package/dist/lib/theme-manager.js +476 -0
  64. package/dist/lib/variable-expansion.js +385 -0
  65. package/dist/lib/zsh-compatibility.js +658 -0
  66. package/dist/lib/zsh-import-manager.js +699 -0
  67. package/dist/lib/zsh-options.js +328 -0
  68. package/dist/pipeline/job-tracker.js +491 -0
  69. package/dist/pipeline/mcli-bridge.js +302 -0
  70. package/dist/pipeline/pipeline-service.js +1116 -0
  71. package/dist/pipeline/workflow-engine.js +867 -0
  72. package/dist/services/api/api.js +58 -0
  73. package/dist/services/api/auth.js +35 -0
  74. package/dist/services/api/config.js +7 -0
  75. package/dist/services/api/file.js +22 -0
  76. package/dist/services/cron/cron-registrar.js +235 -0
  77. package/dist/services/cron/cron.js +9 -0
  78. package/dist/services/daemon/daemon-registrar.js +565 -0
  79. package/dist/services/daemon/daemon.js +9 -0
  80. package/dist/services/lib/lib.js +86 -0
  81. package/dist/services/log-file-extractor.js +170 -0
  82. package/dist/services/secrets/secrets.js +94 -0
  83. package/dist/services/shell/shell.js +28 -0
  84. package/dist/services/supabase/supabase-registrar.js +367 -0
  85. package/dist/services/supabase/supabase.js +9 -0
  86. package/dist/services/zapier.js +16 -0
  87. package/dist/simple-api-server.js +148 -0
  88. package/dist/store/store.js +31 -0
  89. package/dist/util/lib.util.js +11 -0
  90. package/package.json +144 -0
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Theme Commands
3
+ * Import, preview, and apply ZSH themes
4
+ */
5
+ import { ThemeManager } from '../lib/theme-manager.js';
6
+ import chalk from 'chalk';
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import * as os from 'os';
10
+ export function registerThemeCommands(program) {
11
+ const themeCommand = program
12
+ .command('theme')
13
+ .description('Manage shell themes (import Oh-My-Zsh themes, apply built-in themes)');
14
+ themeCommand
15
+ .command('list')
16
+ .description('List available themes')
17
+ .option('--ohmyzsh', 'Show only Oh-My-Zsh themes')
18
+ .option('--builtin', 'Show only built-in themes')
19
+ .option('--custom', 'Show only custom themes')
20
+ .action(async (options) => {
21
+ const manager = new ThemeManager();
22
+ const themes = manager.listThemes();
23
+ console.log(chalk.bold('\n🎨 Available Themes\n'));
24
+ if (!options.ohmyzsh && !options.custom || options.builtin) {
25
+ console.log(chalk.cyan('Built-in Themes:'));
26
+ themes.builtin.forEach(name => {
27
+ console.log(` ${chalk.green('✓')} ${name}`);
28
+ });
29
+ console.log('');
30
+ }
31
+ if (!options.builtin && !options.custom || options.ohmyzsh) {
32
+ if (themes.ohmyzsh.length > 0) {
33
+ console.log(chalk.cyan('Oh-My-Zsh Themes:'));
34
+ themes.ohmyzsh.slice(0, 20).forEach(name => {
35
+ console.log(` ${chalk.yellow('◆')} ${name}`);
36
+ });
37
+ if (themes.ohmyzsh.length > 20) {
38
+ console.log(chalk.dim(` ... and ${themes.ohmyzsh.length - 20} more`));
39
+ }
40
+ console.log('');
41
+ }
42
+ else {
43
+ console.log(chalk.dim('No Oh-My-Zsh themes found. Install Oh-My-Zsh first.'));
44
+ console.log('');
45
+ }
46
+ }
47
+ if (!options.builtin && !options.ohmyzsh || options.custom) {
48
+ if (themes.custom.length > 0) {
49
+ console.log(chalk.cyan('Custom Themes:'));
50
+ themes.custom.forEach(name => {
51
+ console.log(` ${chalk.magenta('●')} ${name}`);
52
+ });
53
+ }
54
+ else {
55
+ console.log(chalk.dim('No custom themes found.'));
56
+ }
57
+ console.log('');
58
+ }
59
+ console.log(chalk.dim('Usage:'));
60
+ console.log(chalk.dim(' lsh theme preview <name>'));
61
+ console.log(chalk.dim(' lsh theme import <name> # For Oh-My-Zsh themes'));
62
+ console.log(chalk.dim(' lsh theme apply <name>'));
63
+ console.log('');
64
+ process.exit(0);
65
+ });
66
+ themeCommand
67
+ .command('import <name>')
68
+ .description('Import Oh-My-Zsh theme')
69
+ .option('--preview', 'Preview before importing')
70
+ .action(async (name, options) => {
71
+ try {
72
+ const manager = new ThemeManager();
73
+ console.log(chalk.dim(`Importing theme: ${name}...`));
74
+ const theme = await manager.importOhMyZshTheme(name);
75
+ console.log(chalk.green(`✓ Successfully imported theme: ${name}`));
76
+ if (options.preview) {
77
+ manager.previewTheme(theme);
78
+ }
79
+ console.log(chalk.dim('\nTo apply this theme:'));
80
+ console.log(chalk.cyan(` lsh theme apply ${name}`));
81
+ console.log('');
82
+ process.exit(0);
83
+ }
84
+ catch (error) {
85
+ console.error(chalk.red(`✗ Failed to import theme: ${error.message}`));
86
+ process.exit(1);
87
+ }
88
+ });
89
+ themeCommand
90
+ .command('preview <name>')
91
+ .description('Preview theme without applying')
92
+ .action(async (name) => {
93
+ try {
94
+ const manager = new ThemeManager();
95
+ // Try to load theme
96
+ let theme;
97
+ try {
98
+ theme = await manager.importOhMyZshTheme(name);
99
+ }
100
+ catch {
101
+ // Try built-in
102
+ theme = manager.getBuiltinTheme(name);
103
+ }
104
+ manager.previewTheme(theme);
105
+ console.log(chalk.dim('To apply this theme:'));
106
+ console.log(chalk.cyan(` lsh theme apply ${name}`));
107
+ console.log('');
108
+ process.exit(0);
109
+ }
110
+ catch (_error) {
111
+ console.error(chalk.red(`✗ Theme not found: ${name}`));
112
+ console.log(chalk.dim('\nAvailable themes:'));
113
+ console.log(chalk.dim(' lsh theme list'));
114
+ process.exit(1);
115
+ }
116
+ });
117
+ themeCommand
118
+ .command('apply <name>')
119
+ .description('Apply theme to current shell')
120
+ .option('--save', 'Save to ~/.lshrc for persistent use')
121
+ .action(async (name, options) => {
122
+ try {
123
+ const manager = new ThemeManager();
124
+ // Try to import/load theme
125
+ let theme;
126
+ try {
127
+ // Try as Oh-My-Zsh theme first
128
+ theme = await manager.importOhMyZshTheme(name);
129
+ }
130
+ catch {
131
+ // Try as built-in theme
132
+ theme = manager.getBuiltinTheme(name);
133
+ }
134
+ const commands = manager.applyTheme(theme);
135
+ console.log(chalk.green(`✓ Applied theme: ${name}`));
136
+ console.log('');
137
+ console.log(chalk.dim('Theme settings:'));
138
+ console.log(commands);
139
+ console.log('');
140
+ if (options.save) {
141
+ const lshrcPath = path.join(os.homedir(), '.lshrc');
142
+ let lshrcContent = '';
143
+ if (fs.existsSync(lshrcPath)) {
144
+ lshrcContent = fs.readFileSync(lshrcPath, 'utf8');
145
+ // Remove old theme settings
146
+ lshrcContent = lshrcContent.replace(/# LSH Theme[\s\S]*?# End LSH Theme\n*/g, '');
147
+ }
148
+ const themeBlock = `
149
+ # LSH Theme: ${name}
150
+ ${commands}
151
+ # End LSH Theme
152
+ `;
153
+ lshrcContent += themeBlock;
154
+ fs.writeFileSync(lshrcPath, lshrcContent, 'utf8');
155
+ console.log(chalk.green('✓ Theme saved to ~/.lshrc'));
156
+ console.log(chalk.dim(' Theme will be applied automatically on next shell start'));
157
+ }
158
+ else {
159
+ console.log(chalk.dim('To save permanently:'));
160
+ console.log(chalk.cyan(` lsh theme apply ${name} --save`));
161
+ }
162
+ console.log('');
163
+ process.exit(0);
164
+ }
165
+ catch (error) {
166
+ console.error(chalk.red(`✗ Failed to apply theme: ${error.message}`));
167
+ process.exit(1);
168
+ }
169
+ });
170
+ themeCommand
171
+ .command('current')
172
+ .description('Show current theme')
173
+ .action(() => {
174
+ const lshrcPath = path.join(os.homedir(), '.lshrc');
175
+ if (!fs.existsSync(lshrcPath)) {
176
+ console.log(chalk.dim('No theme configured (using default)'));
177
+ process.exit(0);
178
+ return;
179
+ }
180
+ const content = fs.readFileSync(lshrcPath, 'utf8');
181
+ const themeMatch = content.match(/# LSH Theme: (.+)/);
182
+ if (themeMatch) {
183
+ console.log(chalk.bold(`Current theme: ${chalk.cyan(themeMatch[1])}`));
184
+ }
185
+ else {
186
+ console.log(chalk.dim('No theme configured (using default)'));
187
+ }
188
+ process.exit(0);
189
+ });
190
+ themeCommand
191
+ .command('reset')
192
+ .description('Reset to default theme')
193
+ .action(() => {
194
+ const lshrcPath = path.join(os.homedir(), '.lshrc');
195
+ if (fs.existsSync(lshrcPath)) {
196
+ let content = fs.readFileSync(lshrcPath, 'utf8');
197
+ content = content.replace(/# LSH Theme[\s\S]*?# End LSH Theme\n*/g, '');
198
+ fs.writeFileSync(lshrcPath, content, 'utf8');
199
+ }
200
+ console.log(chalk.green('✓ Reset to default theme'));
201
+ console.log(chalk.dim('Restart shell to see changes'));
202
+ process.exit(0);
203
+ });
204
+ themeCommand
205
+ .command('from-zshrc')
206
+ .description('Import current ZSH theme from ~/.zshrc')
207
+ .option('--apply', 'Apply after importing')
208
+ .action(async (options) => {
209
+ try {
210
+ const zshrcPath = path.join(os.homedir(), '.zshrc');
211
+ if (!fs.existsSync(zshrcPath)) {
212
+ console.error(chalk.red('✗ ~/.zshrc not found'));
213
+ process.exit(1);
214
+ return;
215
+ }
216
+ const zshrcContent = fs.readFileSync(zshrcPath, 'utf8');
217
+ const themeMatch = zshrcContent.match(/ZSH_THEME="([^"]+)"/);
218
+ if (!themeMatch) {
219
+ console.error(chalk.red('✗ No theme found in ~/.zshrc'));
220
+ process.exit(1);
221
+ return;
222
+ }
223
+ const themeName = themeMatch[1];
224
+ console.log(chalk.dim(`Found ZSH theme: ${themeName}`));
225
+ const manager = new ThemeManager();
226
+ const theme = await manager.importOhMyZshTheme(themeName);
227
+ console.log(chalk.green(`✓ Imported theme: ${themeName}`));
228
+ if (options.apply) {
229
+ const commands = manager.applyTheme(theme);
230
+ const lshrcPath = path.join(os.homedir(), '.lshrc');
231
+ let lshrcContent = '';
232
+ if (fs.existsSync(lshrcPath)) {
233
+ lshrcContent = fs.readFileSync(lshrcPath, 'utf8');
234
+ lshrcContent = lshrcContent.replace(/# LSH Theme[\s\S]*?# End LSH Theme\n*/g, '');
235
+ }
236
+ const themeBlock = `
237
+ # LSH Theme: ${themeName}
238
+ ${commands}
239
+ # End LSH Theme
240
+ `;
241
+ lshrcContent += themeBlock;
242
+ fs.writeFileSync(lshrcPath, lshrcContent, 'utf8');
243
+ console.log(chalk.green('✓ Theme applied and saved to ~/.lshrc'));
244
+ }
245
+ else {
246
+ console.log(chalk.dim('\nTo apply:'));
247
+ console.log(chalk.cyan(` lsh theme apply ${themeName} --save`));
248
+ }
249
+ console.log('');
250
+ process.exit(0);
251
+ }
252
+ catch (error) {
253
+ console.error(chalk.red(`✗ Failed to import theme: ${error.message}`));
254
+ process.exit(1);
255
+ }
256
+ });
257
+ }
@@ -0,0 +1,240 @@
1
+ /**
2
+ * ZSH Import Commands
3
+ * CLI commands for importing ZSH configurations
4
+ */
5
+ import { ShellExecutor } from '../lib/shell-executor.js';
6
+ import { ZshImportManager } from '../lib/zsh-import-manager.js';
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import * as os from 'os';
10
+ export function registerZshImportCommands(program) {
11
+ const zshCommand = program
12
+ .command('zsh-import')
13
+ .description('Import ZSH configurations (aliases, functions, exports)');
14
+ zshCommand
15
+ .command('all')
16
+ .description('Import all ZSH configurations from .zshrc')
17
+ .option('--skip-conflicts', 'Skip items that conflict with existing ones', false)
18
+ .option('--rename-conflicts', 'Rename conflicting items with _zsh suffix', false)
19
+ .option('--overwrite-conflicts', 'Overwrite existing items', false)
20
+ .option('--exclude <patterns...>', 'Exclude items matching patterns (supports wildcards)')
21
+ .option('--include <patterns...>', 'Only include items matching patterns')
22
+ .option('--no-aliases', 'Skip importing aliases')
23
+ .option('--no-exports', 'Skip importing environment variables')
24
+ .option('--no-functions', 'Skip importing functions')
25
+ .option('--no-options', 'Skip importing ZSH options (setopt/unsetopt)')
26
+ .option('--diagnostic-log <path>', 'Path to diagnostic log file')
27
+ .action(async (options) => {
28
+ const executor = new ShellExecutor();
29
+ // Determine conflict resolution strategy
30
+ let conflictResolution = 'skip';
31
+ if (options.renameConflicts)
32
+ conflictResolution = 'rename';
33
+ if (options.overwriteConflicts)
34
+ conflictResolution = 'overwrite';
35
+ const importOptions = {
36
+ conflictResolution,
37
+ includeAliases: options.aliases !== false,
38
+ includeExports: options.exports !== false,
39
+ includeFunctions: options.functions !== false,
40
+ includeOptions: options.options !== false,
41
+ includePlugins: true,
42
+ excludePatterns: options.exclude || [],
43
+ includePatterns: options.include || [],
44
+ diagnosticLog: options.diagnosticLog,
45
+ };
46
+ const manager = new ZshImportManager(executor, importOptions);
47
+ const result = await manager.importZshConfig();
48
+ console.log(result.message);
49
+ if (result.diagnostics.filter(d => d.status === 'failed').length > 0) {
50
+ console.log(`\n⚠️ Some imports failed. Check diagnostic log: ${importOptions.diagnosticLog || '~/.lsh/zsh-import.log'}`);
51
+ }
52
+ process.exit(result.success ? 0 : 1);
53
+ });
54
+ zshCommand
55
+ .command('aliases')
56
+ .description('Import only aliases from .zshrc')
57
+ .option('--exclude <patterns...>', 'Exclude aliases matching patterns')
58
+ .option('--include <patterns...>', 'Only include aliases matching patterns')
59
+ .option('--rename-conflicts', 'Rename conflicting aliases')
60
+ .action(async (options) => {
61
+ const executor = new ShellExecutor();
62
+ const importOptions = {
63
+ includeAliases: true,
64
+ includeExports: false,
65
+ includeFunctions: false,
66
+ includeOptions: false,
67
+ includePlugins: false,
68
+ conflictResolution: options.renameConflicts ? 'rename' : 'skip',
69
+ excludePatterns: options.exclude || [],
70
+ includePatterns: options.include || [],
71
+ };
72
+ const manager = new ZshImportManager(executor, importOptions);
73
+ const result = await manager.importZshConfig();
74
+ console.log(result.message);
75
+ process.exit(result.success ? 0 : 1);
76
+ });
77
+ zshCommand
78
+ .command('exports')
79
+ .description('Import only environment variables from .zshrc')
80
+ .option('--exclude <patterns...>', 'Exclude exports matching patterns')
81
+ .option('--include <patterns...>', 'Only include exports matching patterns')
82
+ .action(async (options) => {
83
+ const executor = new ShellExecutor();
84
+ const importOptions = {
85
+ includeAliases: false,
86
+ includeExports: true,
87
+ includeFunctions: false,
88
+ includeOptions: false,
89
+ includePlugins: false,
90
+ excludePatterns: options.exclude || [],
91
+ includePatterns: options.include || [],
92
+ };
93
+ const manager = new ZshImportManager(executor, importOptions);
94
+ const result = await manager.importZshConfig();
95
+ console.log(result.message);
96
+ process.exit(result.success ? 0 : 1);
97
+ });
98
+ zshCommand
99
+ .command('functions')
100
+ .description('Import only functions from .zshrc')
101
+ .option('--exclude <patterns...>', 'Exclude functions matching patterns')
102
+ .option('--include <patterns...>', 'Only include functions matching patterns')
103
+ .option('--rename-conflicts', 'Rename conflicting functions')
104
+ .action(async (options) => {
105
+ const executor = new ShellExecutor();
106
+ const importOptions = {
107
+ includeAliases: false,
108
+ includeExports: false,
109
+ includeFunctions: true,
110
+ includeOptions: false,
111
+ includePlugins: false,
112
+ conflictResolution: options.renameConflicts ? 'rename' : 'skip',
113
+ excludePatterns: options.exclude || [],
114
+ includePatterns: options.include || [],
115
+ };
116
+ const manager = new ZshImportManager(executor, importOptions);
117
+ const result = await manager.importZshConfig();
118
+ console.log(result.message);
119
+ process.exit(result.success ? 0 : 1);
120
+ });
121
+ zshCommand
122
+ .command('setup-auto-import')
123
+ .description('Configure auto-import of ZSH config on LSH startup')
124
+ .option('--disable', 'Disable auto-import')
125
+ .option('--aliases-only', 'Only auto-import aliases')
126
+ .option('--exports-only', 'Only auto-import exports')
127
+ .option('--rename-conflicts', 'Auto-rename conflicts')
128
+ .action(async (options) => {
129
+ const lshrcPath = path.join(os.homedir(), '.lshrc');
130
+ if (options.disable) {
131
+ // Remove auto-import from .lshrc
132
+ if (fs.existsSync(lshrcPath)) {
133
+ let content = fs.readFileSync(lshrcPath, 'utf8');
134
+ content = content.replace(/# ZSH Auto-Import[\s\S]*?# End ZSH Auto-Import\n*/g, '');
135
+ fs.writeFileSync(lshrcPath, content, 'utf8');
136
+ console.log('✅ Auto-import disabled');
137
+ }
138
+ process.exit(0);
139
+ return;
140
+ }
141
+ // Generate auto-import configuration
142
+ const importCommand = 'zsh-source';
143
+ const options_list = [];
144
+ if (options.aliasesOnly) {
145
+ options_list.push('--no-exports', '--no-functions', '--no-options');
146
+ }
147
+ else if (options.exportsOnly) {
148
+ options_list.push('--no-aliases', '--no-functions', '--no-options');
149
+ }
150
+ if (options.renameConflicts) {
151
+ options_list.push('--rename-conflicts');
152
+ }
153
+ const autoImportConfig = `
154
+ # ZSH Auto-Import
155
+ # Automatically import ZSH configurations on startup
156
+ ${importCommand}${options_list.length > 0 ? ' ' + options_list.join(' ') : ''}
157
+ # End ZSH Auto-Import
158
+ `;
159
+ // Read or create .lshrc
160
+ let lshrcContent = '';
161
+ if (fs.existsSync(lshrcPath)) {
162
+ lshrcContent = fs.readFileSync(lshrcPath, 'utf8');
163
+ // Remove existing auto-import config
164
+ lshrcContent = lshrcContent.replace(/# ZSH Auto-Import[\s\S]*?# End ZSH Auto-Import\n*/g, '');
165
+ }
166
+ // Append new auto-import config
167
+ lshrcContent += autoImportConfig;
168
+ fs.writeFileSync(lshrcPath, lshrcContent, 'utf8');
169
+ console.log('✅ Auto-import configured in ~/.lshrc');
170
+ console.log(` ZSH config will be imported automatically on LSH startup`);
171
+ console.log(`\nConfiguration added:`);
172
+ console.log(autoImportConfig.trim());
173
+ process.exit(0);
174
+ });
175
+ zshCommand
176
+ .command('status')
177
+ .description('Show ZSH import status and diagnostics')
178
+ .action(async () => {
179
+ const executor = new ShellExecutor();
180
+ const manager = new ZshImportManager(executor);
181
+ const stats = manager.getLastImportStats();
182
+ if (!stats) {
183
+ console.log('No ZSH import has been performed yet.');
184
+ console.log('\nRun one of these commands to import:');
185
+ console.log(' lsh zsh-import all # Import everything');
186
+ console.log(' lsh zsh-import aliases # Import only aliases');
187
+ console.log(' lsh zsh-import exports # Import only exports');
188
+ console.log(' lsh zsh-import functions # Import only functions');
189
+ process.exit(0);
190
+ return;
191
+ }
192
+ console.log('📊 Last ZSH Import Status:\n');
193
+ console.log(` Total Items: ${stats.total}`);
194
+ console.log(` ✅ Succeeded: ${stats.succeeded}`);
195
+ console.log(` ❌ Failed: ${stats.failed}`);
196
+ console.log(` ⏭️ Skipped: ${stats.skipped}`);
197
+ console.log(` ⚠️ Conflicts: ${stats.conflicts}\n`);
198
+ if (stats.byType) {
199
+ console.log('By Type:');
200
+ for (const [type, typeStats] of Object.entries(stats.byType)) {
201
+ const ts = typeStats;
202
+ console.log(` ${type.padEnd(12)}: ${ts.succeeded}/${ts.total} succeeded, ${ts.failed} failed, ${ts.skipped} skipped`);
203
+ }
204
+ }
205
+ const diagnosticLog = path.join(os.homedir(), '.lsh', 'zsh-import.log');
206
+ if (fs.existsSync(diagnosticLog)) {
207
+ console.log(`\nDiagnostic log: ${diagnosticLog}`);
208
+ console.log('Run: cat ' + diagnosticLog + ' | tail -50');
209
+ }
210
+ process.exit(0);
211
+ });
212
+ zshCommand
213
+ .command('diagnose')
214
+ .description('Show failed imports from diagnostic log')
215
+ .option('-n <number>', 'Number of recent entries to show', '20')
216
+ .action((options) => {
217
+ const diagnosticLog = path.join(os.homedir(), '.lsh', 'zsh-import.log');
218
+ if (!fs.existsSync(diagnosticLog)) {
219
+ console.log('No diagnostic log found.');
220
+ console.log('Import ZSH config first: lsh zsh-import all');
221
+ process.exit(1);
222
+ return;
223
+ }
224
+ const content = fs.readFileSync(diagnosticLog, 'utf8');
225
+ const lines = content.trim().split('\n');
226
+ const numLines = parseInt(options.n, 10) || 20;
227
+ const recentLines = lines.slice(-numLines);
228
+ console.log(`📋 Recent ZSH Import Diagnostics (last ${numLines} entries):\n`);
229
+ const failedLines = recentLines.filter(line => line.includes('failed') || line.includes('disabled'));
230
+ if (failedLines.length === 0) {
231
+ console.log('✅ No failed imports found!');
232
+ }
233
+ else {
234
+ failedLines.forEach(line => {
235
+ console.log(' ' + line);
236
+ });
237
+ }
238
+ process.exit(0);
239
+ });
240
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,29 @@
1
+ // Divider
2
+ import { Text } from 'ink';
3
+ import React from 'react';
4
+ import stringWidth from 'string-width';
5
+ export const Divider = ({ title, width, padding, titlePadding, titleColor, dividerChar }) => {
6
+ const getSideDividerWidth = (width, titleWidth) => (width - titleWidth) / 2;
7
+ const getNumberOfCharsPerWidth = (char, width) => width / stringWidth(char);
8
+ const PAD = ' ';
9
+ const titleString = title ? `${PAD.repeat(titlePadding) + title + PAD.repeat(titlePadding)}` : '';
10
+ const titleWidth = stringWidth(titleString);
11
+ const dividerWidth = getSideDividerWidth(width, titleWidth);
12
+ const numberOfCharsPerSide = getNumberOfCharsPerWidth(dividerChar, dividerWidth);
13
+ const dividerSideString = dividerChar.repeat(numberOfCharsPerSide);
14
+ const paddingString = PAD.repeat(padding);
15
+ return (React.createElement(React.Fragment, null,
16
+ paddingString,
17
+ React.createElement(Text, { color: "grey" }, dividerSideString),
18
+ React.createElement(Text, { color: titleColor }, titleString),
19
+ React.createElement(Text, { color: "grey" }, dividerSideString),
20
+ paddingString));
21
+ };
22
+ Divider.defaultProps = {
23
+ title: "LSH REPL",
24
+ width: 60,
25
+ padding: 0,
26
+ titlePadding: 1,
27
+ titleColor: 'white',
28
+ dividerChar: '~'
29
+ };
@@ -0,0 +1,43 @@
1
+ import chalk from 'chalk';
2
+ import hljs from 'highlightjs';
3
+ import { Box, Text, useApp, useInput } from 'ink';
4
+ import TextInput from 'ink-text-input';
5
+ import React, { useState } from 'react';
6
+ import vm from 'vm';
7
+ // REPL Component
8
+ export const REPL = () => {
9
+ const { exit } = useApp();
10
+ const [input, setInput] = useState('');
11
+ const [history, setHistory] = useState([]);
12
+ useInput((input, key) => {
13
+ if (key.escape) {
14
+ exit();
15
+ }
16
+ });
17
+ const handleInput = (value) => {
18
+ setInput(value);
19
+ };
20
+ const executeCommand = () => {
21
+ try {
22
+ const script = new vm.Script(input);
23
+ const context = vm.createContext(global);
24
+ const result = script.runInContext(context);
25
+ const output = result === undefined || result === null ? 'undefined' : result.toString();
26
+ const highlightedOutput = chalk.green(highlight(output));
27
+ setHistory([...history, `> ${chalk.yellow(highlight(input))}`, `= ${highlightedOutput}`]);
28
+ }
29
+ catch (err) {
30
+ setHistory([...history, `> ${chalk.yellow(highlight(input))}`, `! Error: ${chalk.red(err.message)}`]);
31
+ }
32
+ finally {
33
+ setInput('');
34
+ }
35
+ };
36
+ return (React.createElement(Box, { flexDirection: "column", flexGrow: 1 },
37
+ React.createElement(Box, { flexGrow: 1, flexDirection: "column", borderColor: "cyan", borderStyle: "round" },
38
+ React.createElement(Box, { marginBottom: 1, flexDirection: "column" }, history.map((entry, index) => (React.createElement(Text, { key: index }, entry)))),
39
+ React.createElement(TextInput, { value: input, onChange: handleInput, onSubmit: executeCommand, placeholder: "Type JavaScript code and press Enter..." }))));
40
+ };
41
+ const highlight = (code) => {
42
+ return hljs.highlight(code, { language: 'javascript' }).value;
43
+ };