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,256 @@
1
+ /**
2
+ * Floating Point Arithmetic Implementation
3
+ * Provides ZSH-compatible floating point math support
4
+ */
5
+ export class FloatingPointArithmetic {
6
+ mathFunctions = new Map();
7
+ precision = 6;
8
+ constructor() {
9
+ this.setupMathFunctions();
10
+ }
11
+ /**
12
+ * Evaluate arithmetic expression with floating point support
13
+ */
14
+ evaluate(expression) {
15
+ try {
16
+ // Clean and validate expression
17
+ const cleaned = this.cleanExpression(expression);
18
+ // Replace variables with their values
19
+ const withVariables = this.replaceVariables(cleaned);
20
+ // Replace function calls
21
+ const withFunctions = this.replaceFunctions(withVariables);
22
+ // Evaluate the expression
23
+ const result = this.evaluateExpression(withFunctions);
24
+ // Round to specified precision
25
+ return this.roundToPrecision(result);
26
+ }
27
+ catch (error) {
28
+ throw new Error(`Arithmetic error: ${error.message}`);
29
+ }
30
+ }
31
+ /**
32
+ * Set precision for floating point results
33
+ */
34
+ setPrecision(precision) {
35
+ this.precision = Math.max(0, Math.min(15, precision));
36
+ }
37
+ /**
38
+ * Get current precision
39
+ */
40
+ getPrecision() {
41
+ return this.precision;
42
+ }
43
+ /**
44
+ * Add a custom math function
45
+ */
46
+ addMathFunction(func) {
47
+ this.mathFunctions.set(func.name, func);
48
+ }
49
+ /**
50
+ * Get available math functions
51
+ */
52
+ getAvailableFunctions() {
53
+ return Array.from(this.mathFunctions.keys());
54
+ }
55
+ /**
56
+ * Setup built-in math functions
57
+ */
58
+ setupMathFunctions() {
59
+ // Basic trigonometric functions
60
+ this.addMathFunction({ name: 'sin', func: Math.sin, arity: 1 });
61
+ this.addMathFunction({ name: 'cos', func: Math.cos, arity: 1 });
62
+ this.addMathFunction({ name: 'tan', func: Math.tan, arity: 1 });
63
+ this.addMathFunction({ name: 'asin', func: Math.asin, arity: 1 });
64
+ this.addMathFunction({ name: 'acos', func: Math.acos, arity: 1 });
65
+ this.addMathFunction({ name: 'atan', func: Math.atan, arity: 1 });
66
+ this.addMathFunction({ name: 'atan2', func: (x, y) => Math.atan2(y ?? 0, x), arity: 2 });
67
+ // Hyperbolic functions
68
+ this.addMathFunction({ name: 'sinh', func: Math.sinh, arity: 1 });
69
+ this.addMathFunction({ name: 'cosh', func: Math.cosh, arity: 1 });
70
+ this.addMathFunction({ name: 'tanh', func: Math.tanh, arity: 1 });
71
+ this.addMathFunction({ name: 'asinh', func: Math.asinh, arity: 1 });
72
+ this.addMathFunction({ name: 'acosh', func: Math.acosh, arity: 1 });
73
+ this.addMathFunction({ name: 'atanh', func: Math.atanh, arity: 1 });
74
+ // Exponential and logarithmic functions
75
+ this.addMathFunction({ name: 'exp', func: Math.exp, arity: 1 });
76
+ this.addMathFunction({ name: 'log', func: Math.log, arity: 1 });
77
+ this.addMathFunction({ name: 'log10', func: Math.log10, arity: 1 });
78
+ this.addMathFunction({ name: 'log2', func: Math.log2, arity: 1 });
79
+ this.addMathFunction({ name: 'pow', func: (x, y) => Math.pow(x, y ?? 0), arity: 2 });
80
+ // Power and root functions
81
+ this.addMathFunction({ name: 'sqrt', func: Math.sqrt, arity: 1 });
82
+ this.addMathFunction({ name: 'cbrt', func: Math.cbrt, arity: 1 });
83
+ // Rounding functions
84
+ this.addMathFunction({ name: 'ceil', func: Math.ceil, arity: 1 });
85
+ this.addMathFunction({ name: 'floor', func: Math.floor, arity: 1 });
86
+ this.addMathFunction({ name: 'round', func: Math.round, arity: 1 });
87
+ this.addMathFunction({ name: 'trunc', func: Math.trunc, arity: 1 });
88
+ // Absolute value and sign
89
+ this.addMathFunction({ name: 'abs', func: Math.abs, arity: 1 });
90
+ this.addMathFunction({ name: 'sign', func: Math.sign, arity: 1 });
91
+ // Random functions
92
+ this.addMathFunction({ name: 'random', func: () => Math.random(), arity: 1 });
93
+ this.addMathFunction({ name: 'rand', func: () => Math.random(), arity: 1 });
94
+ // Constants
95
+ this.addMathFunction({ name: 'pi', func: () => Math.PI, arity: 1 });
96
+ this.addMathFunction({ name: 'e', func: () => Math.E, arity: 1 });
97
+ // Additional utility functions
98
+ this.addMathFunction({ name: 'min', func: (x, y) => Math.min(x, y ?? x), arity: 2 });
99
+ this.addMathFunction({ name: 'max', func: (x, y) => Math.max(x, y ?? x), arity: 2 });
100
+ this.addMathFunction({ name: 'clz32', func: Math.clz32, arity: 1 });
101
+ this.addMathFunction({ name: 'fround', func: Math.fround, arity: 1 });
102
+ this.addMathFunction({ name: 'imul', func: (x, y) => Math.imul(x, y ?? 0), arity: 2 });
103
+ }
104
+ /**
105
+ * Clean expression by removing whitespace and validating characters
106
+ */
107
+ cleanExpression(expression) {
108
+ // Remove whitespace
109
+ const cleaned = expression.replace(/\s/g, '');
110
+ // Validate characters (allow numbers, operators, parentheses, function names, and dots)
111
+ if (!/^[0-9+\-*/().,a-zA-Z_]+$/.test(cleaned)) {
112
+ throw new Error('Invalid characters in expression');
113
+ }
114
+ return cleaned;
115
+ }
116
+ /**
117
+ * Replace variables in expression (placeholder for future variable support)
118
+ */
119
+ replaceVariables(expression) {
120
+ // For now, just return the expression as-is
121
+ // In a full implementation, this would replace variables like $x with their values
122
+ return expression;
123
+ }
124
+ /**
125
+ * Replace function calls with their results
126
+ */
127
+ replaceFunctions(expression) {
128
+ let result = expression;
129
+ // Find function calls like sin(1.5) or pow(2,3)
130
+ const functionRegex = /([a-zA-Z_][a-zA-Z0-9_]*)\(([^)]*)\)/g;
131
+ let match;
132
+ while ((match = functionRegex.exec(expression)) !== null) {
133
+ const [fullMatch, funcName, argsStr] = match;
134
+ const func = this.mathFunctions.get(funcName);
135
+ if (!func) {
136
+ throw new Error(`Unknown function: ${funcName}`);
137
+ }
138
+ const args = this.parseFunctionArguments(argsStr);
139
+ if (args.length !== func.arity) {
140
+ throw new Error(`Function ${funcName} expects ${func.arity} arguments, got ${args.length}`);
141
+ }
142
+ const funcResult = func.func(args[0], args[1]);
143
+ result = result.replace(fullMatch, funcResult.toString());
144
+ }
145
+ return result;
146
+ }
147
+ /**
148
+ * Parse function arguments
149
+ */
150
+ parseFunctionArguments(argsStr) {
151
+ if (!argsStr.trim())
152
+ return [];
153
+ const args = [];
154
+ let current = '';
155
+ let parenCount = 0;
156
+ for (let i = 0; i < argsStr.length; i++) {
157
+ const char = argsStr[i];
158
+ if (char === '(') {
159
+ parenCount++;
160
+ current += char;
161
+ }
162
+ else if (char === ')') {
163
+ parenCount--;
164
+ current += char;
165
+ }
166
+ else if (char === ',' && parenCount === 0) {
167
+ args.push(parseFloat(current.trim()));
168
+ current = '';
169
+ }
170
+ else {
171
+ current += char;
172
+ }
173
+ }
174
+ if (current.trim()) {
175
+ args.push(parseFloat(current.trim()));
176
+ }
177
+ return args;
178
+ }
179
+ /**
180
+ * Evaluate the mathematical expression
181
+ */
182
+ evaluateExpression(expression) {
183
+ try {
184
+ // Use Function constructor for safe evaluation
185
+ // This is a simplified approach - a full implementation would use a proper parser
186
+ const func = new Function(`return ${expression}`);
187
+ const result = func();
188
+ if (typeof result !== 'number' || isNaN(result)) {
189
+ throw new Error('Invalid expression result');
190
+ }
191
+ return result;
192
+ }
193
+ catch (error) {
194
+ throw new Error(`Expression evaluation failed: ${error.message}`);
195
+ }
196
+ }
197
+ /**
198
+ * Round number to specified precision
199
+ */
200
+ roundToPrecision(num) {
201
+ const factor = Math.pow(10, this.precision);
202
+ return Math.round(num * factor) / factor;
203
+ }
204
+ /**
205
+ * Format number with specified precision
206
+ */
207
+ formatNumber(num, precision) {
208
+ const prec = precision !== undefined ? precision : this.precision;
209
+ return num.toFixed(prec);
210
+ }
211
+ /**
212
+ * Check if a string represents a valid floating point number
213
+ */
214
+ isValidFloat(str) {
215
+ const num = parseFloat(str);
216
+ return !isNaN(num) && isFinite(num);
217
+ }
218
+ /**
219
+ * Convert string to floating point number
220
+ */
221
+ parseFloat(str) {
222
+ const num = parseFloat(str);
223
+ if (isNaN(num)) {
224
+ throw new Error(`Invalid floating point number: ${str}`);
225
+ }
226
+ return num;
227
+ }
228
+ /**
229
+ * Get mathematical constants
230
+ */
231
+ getConstants() {
232
+ return {
233
+ pi: Math.PI,
234
+ e: Math.E,
235
+ ln2: Math.LN2,
236
+ ln10: Math.LN10,
237
+ log2e: Math.LOG2E,
238
+ log10e: Math.LOG10E,
239
+ sqrt1_2: Math.SQRT1_2,
240
+ sqrt2: Math.SQRT2,
241
+ };
242
+ }
243
+ /**
244
+ * Evaluate expression with error handling
245
+ */
246
+ safeEvaluate(expression) {
247
+ try {
248
+ const result = this.evaluate(expression);
249
+ return { success: true, result };
250
+ }
251
+ catch (error) {
252
+ return { success: false, error: error.message };
253
+ }
254
+ }
255
+ }
256
+ export default FloatingPointArithmetic;
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Command History System Implementation
3
+ * Provides ZSH-compatible history functionality
4
+ */
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+ import * as os from 'os';
8
+ export class HistorySystem {
9
+ entries = [];
10
+ currentIndex = -1;
11
+ config;
12
+ isEnabled = true;
13
+ constructor(config) {
14
+ this.config = {
15
+ maxSize: 10000,
16
+ filePath: path.join(os.homedir(), '.lsh_history'),
17
+ shareHistory: false,
18
+ ignoreDups: true,
19
+ ignoreSpace: false,
20
+ expireDuplicatesFirst: true,
21
+ ...config,
22
+ };
23
+ this.loadHistory();
24
+ }
25
+ /**
26
+ * Add a command to history
27
+ */
28
+ addCommand(command, exitCode) {
29
+ if (!this.isEnabled)
30
+ return;
31
+ // Skip empty commands
32
+ if (!command.trim())
33
+ return;
34
+ // Skip commands starting with space if ignoreSpace is enabled
35
+ if (this.config.ignoreSpace && command.startsWith(' '))
36
+ return;
37
+ // Remove duplicates if configured
38
+ if (this.config.ignoreDups) {
39
+ this.removeDuplicateCommand(command);
40
+ }
41
+ const entry = {
42
+ lineNumber: this.entries.length + 1,
43
+ command: command.trim(),
44
+ timestamp: Date.now(),
45
+ exitCode,
46
+ };
47
+ this.entries.push(entry);
48
+ // Trim history if it exceeds max size
49
+ if (this.entries.length > this.config.maxSize) {
50
+ this.entries = this.entries.slice(-this.config.maxSize);
51
+ this.renumberEntries();
52
+ }
53
+ this.currentIndex = this.entries.length - 1;
54
+ this.saveHistory();
55
+ }
56
+ /**
57
+ * Get history entry by line number
58
+ */
59
+ getEntry(lineNumber) {
60
+ return this.entries.find(entry => entry.lineNumber === lineNumber);
61
+ }
62
+ /**
63
+ * Get history entry by command prefix
64
+ */
65
+ getEntryByPrefix(prefix) {
66
+ return this.entries
67
+ .slice()
68
+ .reverse()
69
+ .find(entry => entry.command.startsWith(prefix));
70
+ }
71
+ /**
72
+ * Get all history entries
73
+ */
74
+ getAllEntries() {
75
+ return [...this.entries];
76
+ }
77
+ /**
78
+ * Search history for commands matching pattern
79
+ */
80
+ searchHistory(pattern) {
81
+ const regex = new RegExp(pattern, 'i');
82
+ return this.entries.filter(entry => regex.test(entry.command));
83
+ }
84
+ /**
85
+ * Get previous command in history
86
+ */
87
+ getPreviousCommand() {
88
+ if (this.currentIndex > 0) {
89
+ this.currentIndex--;
90
+ return this.entries[this.currentIndex].command;
91
+ }
92
+ return null;
93
+ }
94
+ /**
95
+ * Get next command in history
96
+ */
97
+ getNextCommand() {
98
+ if (this.currentIndex < this.entries.length - 1) {
99
+ this.currentIndex++;
100
+ return this.entries[this.currentIndex].command;
101
+ }
102
+ return null;
103
+ }
104
+ /**
105
+ * Reset history navigation index
106
+ */
107
+ resetIndex() {
108
+ this.currentIndex = this.entries.length - 1;
109
+ }
110
+ /**
111
+ * Expand history references like !! !n !string
112
+ */
113
+ expandHistory(command) {
114
+ let result = command;
115
+ // Handle !! (last command)
116
+ result = result.replace(/!!/g, () => {
117
+ const lastEntry = this.entries[this.entries.length - 1];
118
+ return lastEntry ? lastEntry.command : '!!';
119
+ });
120
+ // Handle !n (command number n)
121
+ result = result.replace(/!(\d+)/g, (match, numStr) => {
122
+ const num = parseInt(numStr, 10);
123
+ const entry = this.getEntry(num);
124
+ return entry ? entry.command : match;
125
+ });
126
+ // Handle !string (last command starting with string)
127
+ result = result.replace(/!([a-zA-Z0-9_]+)/g, (match, prefix) => {
128
+ const entry = this.getEntryByPrefix(prefix);
129
+ return entry ? entry.command : match;
130
+ });
131
+ // Handle ^old^new (quick substitution)
132
+ result = result.replace(/\^([^^]+)\^([^^]*)/g, (match, old, replacement) => {
133
+ const lastEntry = this.entries[this.entries.length - 1];
134
+ if (lastEntry) {
135
+ return lastEntry.command.replace(new RegExp(old, 'g'), replacement);
136
+ }
137
+ return match;
138
+ });
139
+ return result;
140
+ }
141
+ /**
142
+ * Clear history
143
+ */
144
+ clearHistory() {
145
+ this.entries = [];
146
+ this.currentIndex = -1;
147
+ this.saveHistory();
148
+ }
149
+ /**
150
+ * Get history statistics
151
+ */
152
+ getStats() {
153
+ const unique = new Set(this.entries.map(e => e.command)).size;
154
+ const oldest = this.entries.length > 0 ? new Date(this.entries[0].timestamp) : null;
155
+ const newest = this.entries.length > 0 ? new Date(this.entries[this.entries.length - 1].timestamp) : null;
156
+ return {
157
+ total: this.entries.length,
158
+ unique,
159
+ oldest,
160
+ newest,
161
+ };
162
+ }
163
+ /**
164
+ * Enable/disable history
165
+ */
166
+ setEnabled(enabled) {
167
+ this.isEnabled = enabled;
168
+ }
169
+ /**
170
+ * Update configuration
171
+ */
172
+ updateConfig(newConfig) {
173
+ this.config = { ...this.config, ...newConfig };
174
+ }
175
+ /**
176
+ * Load history from file
177
+ */
178
+ loadHistory() {
179
+ try {
180
+ if (fs.existsSync(this.config.filePath)) {
181
+ const content = fs.readFileSync(this.config.filePath, 'utf8');
182
+ const lines = content.split('\n').filter(line => line.trim());
183
+ this.entries = lines.map((line, index) => {
184
+ // Parse history line format: timestamp:command
185
+ const colonIndex = line.indexOf(':');
186
+ if (colonIndex > 0) {
187
+ const timestamp = parseInt(line.substring(0, colonIndex), 10);
188
+ const command = line.substring(colonIndex + 1);
189
+ return {
190
+ lineNumber: index + 1,
191
+ command,
192
+ timestamp: isNaN(timestamp) ? Date.now() : timestamp,
193
+ };
194
+ }
195
+ else {
196
+ return {
197
+ lineNumber: index + 1,
198
+ command: line,
199
+ timestamp: Date.now(),
200
+ };
201
+ }
202
+ });
203
+ }
204
+ }
205
+ catch (_error) {
206
+ // If loading fails, start with empty history
207
+ this.entries = [];
208
+ }
209
+ }
210
+ /**
211
+ * Save history to file
212
+ */
213
+ saveHistory() {
214
+ try {
215
+ const content = this.entries
216
+ .map(entry => `${entry.timestamp}:${entry.command}`)
217
+ .join('\n');
218
+ // Ensure directory exists
219
+ const dir = path.dirname(this.config.filePath);
220
+ if (!fs.existsSync(dir)) {
221
+ fs.mkdirSync(dir, { recursive: true });
222
+ }
223
+ fs.writeFileSync(this.config.filePath, content, 'utf8');
224
+ }
225
+ catch (_error) {
226
+ // Silently fail if we can't save history
227
+ }
228
+ }
229
+ /**
230
+ * Remove duplicate command from history
231
+ */
232
+ removeDuplicateCommand(command) {
233
+ const trimmedCommand = command.trim();
234
+ this.entries = this.entries.filter(entry => entry.command !== trimmedCommand);
235
+ }
236
+ /**
237
+ * Renumber entries after trimming
238
+ */
239
+ renumberEntries() {
240
+ this.entries.forEach((entry, index) => {
241
+ entry.lineNumber = index + 1;
242
+ });
243
+ }
244
+ }
245
+ export default HistorySystem;