lsh-framework 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +70 -4
  2. package/dist/cli.js +104 -486
  3. package/dist/commands/doctor.js +427 -0
  4. package/dist/commands/init.js +371 -0
  5. package/dist/constants/api.js +94 -0
  6. package/dist/constants/commands.js +64 -0
  7. package/dist/constants/config.js +56 -0
  8. package/dist/constants/database.js +21 -0
  9. package/dist/constants/errors.js +79 -0
  10. package/dist/constants/index.js +28 -0
  11. package/dist/constants/paths.js +28 -0
  12. package/dist/constants/ui.js +73 -0
  13. package/dist/constants/validation.js +124 -0
  14. package/dist/daemon/lshd.js +11 -32
  15. package/dist/lib/daemon-client-helper.js +7 -4
  16. package/dist/lib/daemon-client.js +9 -2
  17. package/dist/lib/format-utils.js +163 -0
  18. package/dist/lib/job-manager.js +2 -1
  19. package/dist/lib/platform-utils.js +211 -0
  20. package/dist/lib/secrets-manager.js +11 -1
  21. package/dist/lib/string-utils.js +128 -0
  22. package/dist/services/daemon/daemon-registrar.js +3 -2
  23. package/dist/services/secrets/secrets.js +154 -30
  24. package/package.json +10 -74
  25. package/dist/app.js +0 -33
  26. package/dist/cicd/analytics.js +0 -261
  27. package/dist/cicd/auth.js +0 -269
  28. package/dist/cicd/cache-manager.js +0 -172
  29. package/dist/cicd/data-retention.js +0 -305
  30. package/dist/cicd/performance-monitor.js +0 -224
  31. package/dist/cicd/webhook-receiver.js +0 -640
  32. package/dist/commands/api.js +0 -346
  33. package/dist/commands/theme.js +0 -261
  34. package/dist/commands/zsh-import.js +0 -240
  35. package/dist/components/App.js +0 -1
  36. package/dist/components/Divider.js +0 -29
  37. package/dist/components/REPL.js +0 -43
  38. package/dist/components/Terminal.js +0 -232
  39. package/dist/components/UserInput.js +0 -30
  40. package/dist/daemon/api-server.js +0 -316
  41. package/dist/daemon/monitoring-api.js +0 -220
  42. package/dist/lib/api-error-handler.js +0 -185
  43. package/dist/lib/associative-arrays.js +0 -285
  44. package/dist/lib/base-api-server.js +0 -290
  45. package/dist/lib/brace-expansion.js +0 -160
  46. package/dist/lib/builtin-commands.js +0 -439
  47. package/dist/lib/executors/builtin-executor.js +0 -52
  48. package/dist/lib/extended-globbing.js +0 -411
  49. package/dist/lib/extended-parameter-expansion.js +0 -227
  50. package/dist/lib/interactive-shell.js +0 -460
  51. package/dist/lib/job-builtins.js +0 -582
  52. package/dist/lib/pathname-expansion.js +0 -216
  53. package/dist/lib/script-runner.js +0 -226
  54. package/dist/lib/shell-executor.js +0 -2504
  55. package/dist/lib/shell-parser.js +0 -958
  56. package/dist/lib/shell-types.js +0 -6
  57. package/dist/lib/shell.lib.js +0 -40
  58. package/dist/lib/theme-manager.js +0 -476
  59. package/dist/lib/variable-expansion.js +0 -385
  60. package/dist/lib/zsh-compatibility.js +0 -659
  61. package/dist/lib/zsh-import-manager.js +0 -707
  62. package/dist/lib/zsh-options.js +0 -328
  63. package/dist/pipeline/job-tracker.js +0 -491
  64. package/dist/pipeline/mcli-bridge.js +0 -309
  65. package/dist/pipeline/pipeline-service.js +0 -1119
  66. package/dist/pipeline/workflow-engine.js +0 -870
  67. package/dist/services/api/api.js +0 -58
  68. package/dist/services/api/auth.js +0 -35
  69. package/dist/services/api/config.js +0 -7
  70. package/dist/services/api/file.js +0 -22
  71. package/dist/services/shell/shell.js +0 -28
  72. package/dist/services/zapier.js +0 -16
  73. package/dist/simple-api-server.js +0 -148
@@ -1,385 +0,0 @@
1
- /**
2
- * POSIX Parameter and Variable Expansion Implementation
3
- * Implements POSIX.1-2017 Section 2.6 Parameter Expansion
4
- */
5
- import { exec } from 'child_process';
6
- import { promisify } from 'util';
7
- const execAsync = promisify(exec);
8
- export class VariableExpander {
9
- context;
10
- constructor(context) {
11
- this.context = context;
12
- }
13
- updateContext(updates) {
14
- this.context = { ...this.context, ...updates };
15
- }
16
- async expandString(input) {
17
- let result = input;
18
- // Process in order: parameter expansion, command substitution, arithmetic expansion
19
- result = await this.processParameterExpansion(result);
20
- result = await this.processCommandSubstitution(result);
21
- result = await this.processArithmeticExpansion(result);
22
- return result;
23
- }
24
- async processParameterExpansion(input) {
25
- // Handle ${parameter} and $parameter forms
26
- // More comprehensive regex to handle all parameter expansion forms
27
- const paramRegex = /\$\{([^}]+)\}|\$([a-zA-Z_][a-zA-Z0-9_]*|\d+|[*@#?$!-])/g;
28
- let result = input;
29
- // Process all matches from right to left to avoid index shifting issues
30
- const matches = Array.from(input.matchAll(paramRegex));
31
- for (let i = matches.length - 1; i >= 0; i--) {
32
- const match = matches[i];
33
- const fullMatch = match[0];
34
- const paramExpr = match[1] || match[2];
35
- const startIndex = match.index;
36
- const endIndex = startIndex + fullMatch.length;
37
- const expandedValue = await this.expandParameter(paramExpr);
38
- // Replace the match with the expanded value
39
- result = result.slice(0, startIndex) + expandedValue + result.slice(endIndex);
40
- }
41
- return result;
42
- }
43
- async expandParameter(paramExpr) {
44
- // Handle different parameter expansion forms
45
- // String length: ${#VAR}
46
- if (paramExpr.startsWith('#')) {
47
- return this.handleStringLength(paramExpr.substring(1));
48
- }
49
- // Substring extraction: ${VAR:offset:length}
50
- if (paramExpr.match(/^[^:]+:-?\d+/)) {
51
- return this.handleSubstring(paramExpr);
52
- }
53
- // Case conversion: ${VAR^}, ${VAR,}, ${VAR^^}, ${VAR,,}
54
- if (paramExpr.match(/\^+$|,+$/)) {
55
- return this.handleCaseConversion(paramExpr);
56
- }
57
- // Check for parameter expansion operators
58
- if (paramExpr.includes(':-')) {
59
- return this.handleDefaultValue(paramExpr, ':-');
60
- }
61
- else if (paramExpr.includes(':=')) {
62
- return this.handleAssignDefault(paramExpr, ':=');
63
- }
64
- else if (paramExpr.includes(':?')) {
65
- return this.handleErrorIfNull(paramExpr, ':?');
66
- }
67
- else if (paramExpr.includes(':+')) {
68
- return this.handleAlternativeValue(paramExpr, ':+');
69
- }
70
- else if (paramExpr.includes('%')) {
71
- return this.handleSuffixRemoval(paramExpr);
72
- }
73
- else if (paramExpr.includes('#')) {
74
- return this.handlePrefixRemoval(paramExpr);
75
- }
76
- else {
77
- // Simple parameter expansion
78
- return this.getParameterValue(paramExpr);
79
- }
80
- }
81
- getParameterValue(param) {
82
- // Handle special parameters
83
- if (param in this.context.specialParams) {
84
- const value = this.context.specialParams[param];
85
- return Array.isArray(value) ? value.join(' ') : value;
86
- }
87
- // Handle positional parameters
88
- if (/^\d+$/.test(param)) {
89
- const index = parseInt(param, 10);
90
- if (index === 0)
91
- return this.context.specialParams['0'];
92
- const value = this.context.positionalParams[index - 1];
93
- // Implement set -u (nounset): error on unset parameters
94
- if (this.context.options?.nounset && value === undefined) {
95
- throw new Error(`${param}: parameter not set`);
96
- }
97
- return value || '';
98
- }
99
- // Handle regular variables
100
- const value = this.context.variables[param] || this.context.env[param];
101
- // Implement set -u (nounset): error on unset variables
102
- if (this.context.options?.nounset && value === undefined && !(param in this.context.variables) && !(param in this.context.env)) {
103
- throw new Error(`${param}: parameter not set`);
104
- }
105
- return value || '';
106
- }
107
- handleDefaultValue(paramExpr, operator) {
108
- const parts = paramExpr.split(operator);
109
- const param = parts[0].trim();
110
- const defaultValue = parts.slice(1).join(operator).trim();
111
- const value = this.getParameterValue(param);
112
- // Use default if parameter is unset or null (for :- operator)
113
- return (value === '' || value === undefined) ? (defaultValue || '') : value;
114
- }
115
- handleAssignDefault(paramExpr, operator) {
116
- const parts = paramExpr.split(operator);
117
- const param = parts[0].trim();
118
- const defaultValue = parts.slice(1).join(operator).trim();
119
- let value = this.getParameterValue(param);
120
- // Assign default if parameter is unset or null
121
- if (value === '' || value === undefined) {
122
- value = defaultValue || '';
123
- this.context.variables[param] = value;
124
- }
125
- return value;
126
- }
127
- handleErrorIfNull(paramExpr, operator) {
128
- const parts = paramExpr.split(operator);
129
- const param = parts[0].trim();
130
- const errorMessage = parts.slice(1).join(operator).trim();
131
- const value = this.getParameterValue(param);
132
- if (value === '' || value === undefined) {
133
- const message = errorMessage || `${param}: parameter null or not set`;
134
- throw new Error(message);
135
- }
136
- return value;
137
- }
138
- handleAlternativeValue(paramExpr, operator) {
139
- const parts = paramExpr.split(operator);
140
- const param = parts[0].trim();
141
- const altValue = parts.slice(1).join(operator).trim();
142
- const value = this.getParameterValue(param);
143
- // Use alternative value if parameter is set and not null
144
- return (value !== '' && value !== undefined) ? (altValue || '') : '';
145
- }
146
- handleSuffixRemoval(paramExpr) {
147
- const isLongest = paramExpr.includes('%%');
148
- const operator = isLongest ? '%%' : '%';
149
- const [param, pattern] = paramExpr.split(operator, 2);
150
- const value = this.getParameterValue(param);
151
- if (!value)
152
- return '';
153
- return this.removeSuffix(value, pattern, isLongest);
154
- }
155
- handlePrefixRemoval(paramExpr) {
156
- const isLongest = paramExpr.includes('##');
157
- const operator = isLongest ? '##' : '#';
158
- const [param, pattern] = paramExpr.split(operator, 2);
159
- const value = this.getParameterValue(param);
160
- if (!value)
161
- return '';
162
- return this.removePrefix(value, pattern, isLongest);
163
- }
164
- removeSuffix(value, pattern, longest) {
165
- const regex = this.patternToRegex(pattern);
166
- if (longest) {
167
- // Find longest matching suffix
168
- for (let i = 0; i < value.length; i++) {
169
- const suffix = value.slice(i);
170
- if (regex.test(suffix)) {
171
- return value.slice(0, i);
172
- }
173
- }
174
- }
175
- else {
176
- // Find shortest matching suffix
177
- for (let i = value.length; i > 0; i--) {
178
- const suffix = value.slice(i - 1);
179
- if (regex.test(suffix)) {
180
- return value.slice(0, i - 1);
181
- }
182
- }
183
- }
184
- return value;
185
- }
186
- removePrefix(value, pattern, longest) {
187
- const regex = this.patternToRegex(pattern);
188
- if (longest) {
189
- // Find longest matching prefix
190
- for (let i = value.length; i > 0; i--) {
191
- const prefix = value.slice(0, i);
192
- if (regex.test(prefix)) {
193
- return value.slice(i);
194
- }
195
- }
196
- }
197
- else {
198
- // Find shortest matching prefix
199
- for (let i = 1; i <= value.length; i++) {
200
- const prefix = value.slice(0, i);
201
- if (regex.test(prefix)) {
202
- return value.slice(i);
203
- }
204
- }
205
- }
206
- return value;
207
- }
208
- handleStringLength(param) {
209
- const value = this.getParameterValue(param);
210
- return value.length.toString();
211
- }
212
- handleSubstring(paramExpr) {
213
- // Parse ${VAR:offset:length} or ${VAR:offset}
214
- const match = paramExpr.match(/^([^:]+):(-?\d+)(?::(\d+))?$/);
215
- if (!match) {
216
- // Invalid format, return empty
217
- return '';
218
- }
219
- const [, param, offsetStr, lengthStr] = match;
220
- const value = this.getParameterValue(param);
221
- let offset = parseInt(offsetStr, 10);
222
- // Handle negative offset (from end of string)
223
- if (offset < 0) {
224
- offset = value.length + offset;
225
- if (offset < 0)
226
- offset = 0;
227
- }
228
- if (lengthStr) {
229
- const length = parseInt(lengthStr, 10);
230
- return value.substring(offset, offset + length);
231
- }
232
- else {
233
- return value.substring(offset);
234
- }
235
- }
236
- handleCaseConversion(paramExpr) {
237
- // Handle ${VAR^}, ${VAR,}, ${VAR^^}, ${VAR,,}
238
- let operator = '';
239
- let param = paramExpr;
240
- if (paramExpr.endsWith('^^')) {
241
- operator = '^^';
242
- param = paramExpr.slice(0, -2);
243
- }
244
- else if (paramExpr.endsWith('^')) {
245
- operator = '^';
246
- param = paramExpr.slice(0, -1);
247
- }
248
- else if (paramExpr.endsWith(',,')) {
249
- operator = ',,';
250
- param = paramExpr.slice(0, -2);
251
- }
252
- else if (paramExpr.endsWith(',')) {
253
- operator = ',';
254
- param = paramExpr.slice(0, -1);
255
- }
256
- const value = this.getParameterValue(param);
257
- switch (operator) {
258
- case '^':
259
- // Uppercase first character
260
- return value.charAt(0).toUpperCase() + value.slice(1);
261
- case '^^':
262
- // Uppercase all characters
263
- return value.toUpperCase();
264
- case ',':
265
- // Lowercase first character
266
- return value.charAt(0).toLowerCase() + value.slice(1);
267
- case ',,':
268
- // Lowercase all characters
269
- return value.toLowerCase();
270
- default:
271
- return value;
272
- }
273
- }
274
- patternToRegex(pattern) {
275
- // Convert shell pattern to regex
276
- const regex = pattern
277
- .replace(/\*/g, '.*') // * matches any string
278
- .replace(/\?/g, '.') // ? matches any single character
279
- .replace(/\[([^\]]+)\]/g, '[$1]'); // [abc] character class
280
- return new RegExp(`^${regex}$`);
281
- }
282
- async processCommandSubstitution(input) {
283
- // Handle both $(command) and `command` forms
284
- const dollarParenRegex = /\$\(([^)]+)\)/g;
285
- const backtickRegex = /`([^`]+)`/g;
286
- let result = input;
287
- // Process $(command) form
288
- result = await this.processSubstitutionWithRegex(result, dollarParenRegex);
289
- // Process `command` form
290
- result = await this.processSubstitutionWithRegex(result, backtickRegex);
291
- return result;
292
- }
293
- async processSubstitutionWithRegex(input, regex) {
294
- let result = '';
295
- let lastIndex = 0;
296
- let match;
297
- while ((match = regex.exec(input)) !== null) {
298
- result += input.slice(lastIndex, match.index);
299
- const command = match[1];
300
- try {
301
- const { stdout } = await execAsync(command, {
302
- env: { ...this.context.env, ...this.context.variables },
303
- });
304
- // Remove trailing newlines as per POSIX
305
- result += stdout.replace(/\n+$/, '');
306
- }
307
- catch (_error) {
308
- // Command substitution failed, leave empty
309
- result += '';
310
- }
311
- lastIndex = regex.lastIndex;
312
- }
313
- result += input.slice(lastIndex);
314
- return result;
315
- }
316
- async processArithmeticExpansion(input) {
317
- const arithmeticRegex = /\$\(\(([^)]+)\)\)/g;
318
- let result = input;
319
- const matches = Array.from(input.matchAll(arithmeticRegex));
320
- // Process all matches from right to left to avoid index shifting issues
321
- for (let i = matches.length - 1; i >= 0; i--) {
322
- const match = matches[i];
323
- const fullMatch = match[0];
324
- const expression = match[1];
325
- const startIndex = match.index;
326
- const endIndex = startIndex + fullMatch.length;
327
- const value = this.evaluateArithmetic(expression);
328
- // Replace the match with the evaluated value
329
- result = result.slice(0, startIndex) + value.toString() + result.slice(endIndex);
330
- }
331
- return result;
332
- }
333
- evaluateArithmetic(expression) {
334
- // Simple arithmetic evaluator
335
- // Replace variables with their numeric values
336
- const expr = expression.replace(/[a-zA-Z_][a-zA-Z0-9_]*/g, (match) => {
337
- const value = this.getParameterValue(match);
338
- const numValue = parseInt(value, 10);
339
- return isNaN(numValue) ? '0' : numValue.toString();
340
- });
341
- try {
342
- // Use Function constructor for safe evaluation
343
- // This is a simplified version - full implementation would need proper arithmetic parser
344
- return Function(`"use strict"; return (${expr})`)() || 0;
345
- }
346
- catch (_error) {
347
- return 0;
348
- }
349
- }
350
- // Public method to expand parameter expressions
351
- async expandParameterExpression(paramExpr) {
352
- return this.expandParameter(paramExpr);
353
- }
354
- // Public method to evaluate arithmetic expressions
355
- evaluateArithmeticExpression(expression) {
356
- return this.evaluateArithmetic(expression);
357
- }
358
- // Utility method for field splitting (will be used by shell executor)
359
- splitFields(input, ifs = ' \t\n') {
360
- if (!ifs)
361
- return [input]; // No field splitting if IFS is empty
362
- if (ifs === ' \t\n') {
363
- // Default IFS behavior - split on any whitespace and trim
364
- return input.trim().split(/\s+/).filter(field => field.length > 0);
365
- }
366
- // Custom IFS - more complex splitting rules
367
- const fields = [];
368
- let currentField = '';
369
- for (const char of input) {
370
- if (ifs.includes(char)) {
371
- if (currentField || fields.length === 0) {
372
- fields.push(currentField);
373
- currentField = '';
374
- }
375
- }
376
- else {
377
- currentField += char;
378
- }
379
- }
380
- if (currentField || fields.length === 0) {
381
- fields.push(currentField);
382
- }
383
- return fields;
384
- }
385
- }