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.
- package/.env.example +51 -0
- package/README.md +399 -0
- package/dist/app.js +33 -0
- package/dist/cicd/analytics.js +261 -0
- package/dist/cicd/auth.js +269 -0
- package/dist/cicd/cache-manager.js +172 -0
- package/dist/cicd/data-retention.js +305 -0
- package/dist/cicd/performance-monitor.js +224 -0
- package/dist/cicd/webhook-receiver.js +634 -0
- package/dist/cli.js +500 -0
- package/dist/commands/api.js +343 -0
- package/dist/commands/self.js +318 -0
- package/dist/commands/theme.js +257 -0
- package/dist/commands/zsh-import.js +240 -0
- package/dist/components/App.js +1 -0
- package/dist/components/Divider.js +29 -0
- package/dist/components/REPL.js +43 -0
- package/dist/components/Terminal.js +232 -0
- package/dist/components/UserInput.js +30 -0
- package/dist/daemon/api-server.js +315 -0
- package/dist/daemon/job-registry.js +554 -0
- package/dist/daemon/lshd.js +822 -0
- package/dist/daemon/monitoring-api.js +220 -0
- package/dist/examples/supabase-integration.js +106 -0
- package/dist/lib/api-error-handler.js +183 -0
- package/dist/lib/associative-arrays.js +285 -0
- package/dist/lib/base-api-server.js +290 -0
- package/dist/lib/base-command-registrar.js +286 -0
- package/dist/lib/base-job-manager.js +293 -0
- package/dist/lib/brace-expansion.js +160 -0
- package/dist/lib/builtin-commands.js +439 -0
- package/dist/lib/cloud-config-manager.js +347 -0
- package/dist/lib/command-validator.js +190 -0
- package/dist/lib/completion-system.js +344 -0
- package/dist/lib/cron-job-manager.js +364 -0
- package/dist/lib/daemon-client-helper.js +141 -0
- package/dist/lib/daemon-client.js +501 -0
- package/dist/lib/database-persistence.js +638 -0
- package/dist/lib/database-schema.js +259 -0
- package/dist/lib/enhanced-history-system.js +246 -0
- package/dist/lib/env-validator.js +265 -0
- package/dist/lib/executors/builtin-executor.js +52 -0
- package/dist/lib/extended-globbing.js +411 -0
- package/dist/lib/extended-parameter-expansion.js +227 -0
- package/dist/lib/floating-point-arithmetic.js +256 -0
- package/dist/lib/history-system.js +245 -0
- package/dist/lib/interactive-shell.js +460 -0
- package/dist/lib/job-builtins.js +580 -0
- package/dist/lib/job-manager.js +386 -0
- package/dist/lib/job-storage-database.js +156 -0
- package/dist/lib/job-storage-memory.js +73 -0
- package/dist/lib/logger.js +274 -0
- package/dist/lib/lshrc-init.js +177 -0
- package/dist/lib/pathname-expansion.js +216 -0
- package/dist/lib/prompt-system.js +328 -0
- package/dist/lib/script-runner.js +226 -0
- package/dist/lib/secrets-manager.js +193 -0
- package/dist/lib/shell-executor.js +2504 -0
- package/dist/lib/shell-parser.js +958 -0
- package/dist/lib/shell-types.js +6 -0
- package/dist/lib/shell.lib.js +40 -0
- package/dist/lib/supabase-client.js +58 -0
- package/dist/lib/theme-manager.js +476 -0
- package/dist/lib/variable-expansion.js +385 -0
- package/dist/lib/zsh-compatibility.js +658 -0
- package/dist/lib/zsh-import-manager.js +699 -0
- package/dist/lib/zsh-options.js +328 -0
- package/dist/pipeline/job-tracker.js +491 -0
- package/dist/pipeline/mcli-bridge.js +302 -0
- package/dist/pipeline/pipeline-service.js +1116 -0
- package/dist/pipeline/workflow-engine.js +867 -0
- package/dist/services/api/api.js +58 -0
- package/dist/services/api/auth.js +35 -0
- package/dist/services/api/config.js +7 -0
- package/dist/services/api/file.js +22 -0
- package/dist/services/cron/cron-registrar.js +235 -0
- package/dist/services/cron/cron.js +9 -0
- package/dist/services/daemon/daemon-registrar.js +565 -0
- package/dist/services/daemon/daemon.js +9 -0
- package/dist/services/lib/lib.js +86 -0
- package/dist/services/log-file-extractor.js +170 -0
- package/dist/services/secrets/secrets.js +94 -0
- package/dist/services/shell/shell.js +28 -0
- package/dist/services/supabase/supabase-registrar.js +367 -0
- package/dist/services/supabase/supabase.js +9 -0
- package/dist/services/zapier.js +16 -0
- package/dist/simple-api-server.js +148 -0
- package/dist/store/store.js +31 -0
- package/dist/util/lib.util.js +11 -0
- package/package.json +144 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Variable Validation
|
|
3
|
+
* Validates required environment variables at startup
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Standard environment variable requirements for LSH
|
|
7
|
+
*/
|
|
8
|
+
export const LSH_ENV_REQUIREMENTS = [
|
|
9
|
+
// Core configuration
|
|
10
|
+
{
|
|
11
|
+
name: 'NODE_ENV',
|
|
12
|
+
required: false,
|
|
13
|
+
requireInProduction: false,
|
|
14
|
+
description: 'Environment mode (development, production, test)',
|
|
15
|
+
validate: (val) => ['development', 'production', 'test'].includes(val)
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: 'USER',
|
|
19
|
+
required: false,
|
|
20
|
+
requireInProduction: false,
|
|
21
|
+
description: 'Current system user'
|
|
22
|
+
},
|
|
23
|
+
// API Configuration
|
|
24
|
+
{
|
|
25
|
+
name: 'LSH_API_ENABLED',
|
|
26
|
+
required: false,
|
|
27
|
+
requireInProduction: false,
|
|
28
|
+
description: 'Enable API server',
|
|
29
|
+
validate: (val) => ['true', 'false'].includes(val)
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'LSH_API_PORT',
|
|
33
|
+
required: false,
|
|
34
|
+
requireInProduction: false,
|
|
35
|
+
description: 'API server port',
|
|
36
|
+
defaultValue: '3030',
|
|
37
|
+
validate: (val) => !isNaN(parseInt(val)) && parseInt(val) > 0 && parseInt(val) < 65536
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'LSH_API_KEY',
|
|
41
|
+
required: false,
|
|
42
|
+
requireInProduction: true, // Required if API is enabled in production
|
|
43
|
+
description: 'API authentication key',
|
|
44
|
+
sensitiveValue: true,
|
|
45
|
+
validate: (val) => val.length >= 32
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'LSH_JWT_SECRET',
|
|
49
|
+
required: false,
|
|
50
|
+
requireInProduction: true, // Required if API is enabled in production
|
|
51
|
+
description: 'JWT signing secret',
|
|
52
|
+
sensitiveValue: true,
|
|
53
|
+
validate: (val) => val.length >= 32
|
|
54
|
+
},
|
|
55
|
+
// Security Configuration
|
|
56
|
+
{
|
|
57
|
+
name: 'LSH_ALLOW_DANGEROUS_COMMANDS',
|
|
58
|
+
required: false,
|
|
59
|
+
requireInProduction: false,
|
|
60
|
+
description: 'Allow potentially dangerous commands (use with caution)',
|
|
61
|
+
validate: (val) => ['true', 'false'].includes(val)
|
|
62
|
+
},
|
|
63
|
+
// Webhook Configuration
|
|
64
|
+
{
|
|
65
|
+
name: 'LSH_ENABLE_WEBHOOKS',
|
|
66
|
+
required: false,
|
|
67
|
+
requireInProduction: false,
|
|
68
|
+
description: 'Enable webhook receiver',
|
|
69
|
+
validate: (val) => ['true', 'false'].includes(val)
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'WEBHOOK_PORT',
|
|
73
|
+
required: false,
|
|
74
|
+
requireInProduction: false,
|
|
75
|
+
description: 'Webhook receiver port',
|
|
76
|
+
defaultValue: '3033',
|
|
77
|
+
validate: (val) => !isNaN(parseInt(val)) && parseInt(val) > 0 && parseInt(val) < 65536
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'GITHUB_WEBHOOK_SECRET',
|
|
81
|
+
required: false,
|
|
82
|
+
requireInProduction: true, // Required if webhooks enabled in production
|
|
83
|
+
description: 'GitHub webhook secret',
|
|
84
|
+
sensitiveValue: true,
|
|
85
|
+
validate: (val) => val.length >= 16
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'GITLAB_WEBHOOK_SECRET',
|
|
89
|
+
required: false,
|
|
90
|
+
requireInProduction: false,
|
|
91
|
+
description: 'GitLab webhook secret',
|
|
92
|
+
sensitiveValue: true
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'JENKINS_WEBHOOK_SECRET',
|
|
96
|
+
required: false,
|
|
97
|
+
requireInProduction: false,
|
|
98
|
+
description: 'Jenkins webhook secret',
|
|
99
|
+
sensitiveValue: true
|
|
100
|
+
},
|
|
101
|
+
// Database Configuration
|
|
102
|
+
{
|
|
103
|
+
name: 'DATABASE_URL',
|
|
104
|
+
required: false,
|
|
105
|
+
requireInProduction: false,
|
|
106
|
+
description: 'PostgreSQL connection string',
|
|
107
|
+
sensitiveValue: true,
|
|
108
|
+
validate: (val) => val.startsWith('postgresql://') || val.startsWith('postgres://')
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'SUPABASE_URL',
|
|
112
|
+
required: false,
|
|
113
|
+
requireInProduction: false,
|
|
114
|
+
description: 'Supabase project URL',
|
|
115
|
+
validate: (val) => val.startsWith('http://') || val.startsWith('https://')
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'SUPABASE_ANON_KEY',
|
|
119
|
+
required: false,
|
|
120
|
+
requireInProduction: false,
|
|
121
|
+
description: 'Supabase anonymous key',
|
|
122
|
+
sensitiveValue: true
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'REDIS_URL',
|
|
126
|
+
required: false,
|
|
127
|
+
requireInProduction: false,
|
|
128
|
+
description: 'Redis connection string',
|
|
129
|
+
defaultValue: 'redis://localhost:6379',
|
|
130
|
+
validate: (val) => val.startsWith('redis://') || val.startsWith('rediss://')
|
|
131
|
+
},
|
|
132
|
+
// Monitoring
|
|
133
|
+
{
|
|
134
|
+
name: 'MONITORING_API_PORT',
|
|
135
|
+
required: false,
|
|
136
|
+
requireInProduction: false,
|
|
137
|
+
description: 'Monitoring API port',
|
|
138
|
+
defaultValue: '3031',
|
|
139
|
+
validate: (val) => !isNaN(parseInt(val)) && parseInt(val) > 0 && parseInt(val) < 65536
|
|
140
|
+
}
|
|
141
|
+
];
|
|
142
|
+
/**
|
|
143
|
+
* Validate environment variables based on requirements
|
|
144
|
+
*/
|
|
145
|
+
export function validateEnvironment(requirements = LSH_ENV_REQUIREMENTS, env = process.env) {
|
|
146
|
+
const result = {
|
|
147
|
+
isValid: true,
|
|
148
|
+
errors: [],
|
|
149
|
+
warnings: [],
|
|
150
|
+
missing: [],
|
|
151
|
+
recommendations: []
|
|
152
|
+
};
|
|
153
|
+
const isProduction = env.NODE_ENV === 'production';
|
|
154
|
+
const apiEnabled = env.LSH_API_ENABLED === 'true';
|
|
155
|
+
const webhooksEnabled = env.LSH_ENABLE_WEBHOOKS === 'true';
|
|
156
|
+
for (const req of requirements) {
|
|
157
|
+
const value = env[req.name];
|
|
158
|
+
const isEmpty = !value || value.trim().length === 0;
|
|
159
|
+
// Check if variable is required
|
|
160
|
+
if (req.required && isEmpty) {
|
|
161
|
+
result.errors.push(`Missing required environment variable: ${req.name}`);
|
|
162
|
+
result.missing.push(req.name);
|
|
163
|
+
result.isValid = false;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
// Check production requirements
|
|
167
|
+
if (req.requireInProduction && isProduction && isEmpty) {
|
|
168
|
+
// Special cases for conditional requirements
|
|
169
|
+
if (req.name === 'LSH_API_KEY' || req.name === 'LSH_JWT_SECRET') {
|
|
170
|
+
if (apiEnabled) {
|
|
171
|
+
result.errors.push(`${req.name} is required in production when LSH_API_ENABLED=true`);
|
|
172
|
+
result.missing.push(req.name);
|
|
173
|
+
result.isValid = false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else if (req.name === 'GITHUB_WEBHOOK_SECRET') {
|
|
177
|
+
if (webhooksEnabled) {
|
|
178
|
+
result.errors.push(`${req.name} is required in production when LSH_ENABLE_WEBHOOKS=true`);
|
|
179
|
+
result.missing.push(req.name);
|
|
180
|
+
result.isValid = false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
result.warnings.push(`${req.name} should be set in production (${req.description || 'no description'})`);
|
|
185
|
+
}
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
// If value exists, validate it
|
|
189
|
+
if (!isEmpty && req.validate) {
|
|
190
|
+
try {
|
|
191
|
+
if (!req.validate(value)) {
|
|
192
|
+
result.errors.push(`Invalid value for ${req.name}: ${req.description || 'validation failed'}`);
|
|
193
|
+
result.isValid = false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
result.errors.push(`Failed to validate ${req.name}: ${error instanceof Error ? error.message : 'unknown error'}`);
|
|
198
|
+
result.isValid = false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Provide recommendations for missing optional vars
|
|
202
|
+
if (isEmpty && req.defaultValue) {
|
|
203
|
+
result.recommendations.push(`${req.name} not set, using default: ${req.defaultValue}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Additional security checks
|
|
207
|
+
if (isProduction) {
|
|
208
|
+
if (env.LSH_ALLOW_DANGEROUS_COMMANDS === 'true') {
|
|
209
|
+
result.warnings.push('LSH_ALLOW_DANGEROUS_COMMANDS is enabled in production - this is a security risk');
|
|
210
|
+
}
|
|
211
|
+
if (apiEnabled && (!env.LSH_API_KEY || env.LSH_API_KEY.length < 32)) {
|
|
212
|
+
result.errors.push('LSH_API_KEY must be at least 32 characters in production');
|
|
213
|
+
result.isValid = false;
|
|
214
|
+
}
|
|
215
|
+
if (apiEnabled && (!env.LSH_JWT_SECRET || env.LSH_JWT_SECRET.length < 32)) {
|
|
216
|
+
result.errors.push('LSH_JWT_SECRET must be at least 32 characters in production');
|
|
217
|
+
result.isValid = false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Print validation results to console
|
|
224
|
+
*/
|
|
225
|
+
export function printValidationResults(result, exitOnError = false) {
|
|
226
|
+
if (result.errors.length > 0) {
|
|
227
|
+
console.error('\n❌ Environment Variable Errors:');
|
|
228
|
+
result.errors.forEach(err => console.error(` - ${err}`));
|
|
229
|
+
}
|
|
230
|
+
if (result.warnings.length > 0) {
|
|
231
|
+
console.warn('\n⚠️ Environment Variable Warnings:');
|
|
232
|
+
result.warnings.forEach(warn => console.warn(` - ${warn}`));
|
|
233
|
+
}
|
|
234
|
+
if (result.recommendations.length > 0) {
|
|
235
|
+
// eslint-disable-next-line no-console
|
|
236
|
+
console.log('\nℹ️ Environment Variable Recommendations:');
|
|
237
|
+
// eslint-disable-next-line no-console
|
|
238
|
+
result.recommendations.forEach(rec => console.log(` - ${rec}`));
|
|
239
|
+
}
|
|
240
|
+
if (result.isValid) {
|
|
241
|
+
// eslint-disable-next-line no-console
|
|
242
|
+
console.log('\n✅ Environment validation passed');
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
console.error('\n❌ Environment validation failed');
|
|
246
|
+
if (exitOnError) {
|
|
247
|
+
console.error('\nPlease check your .env file or environment variables');
|
|
248
|
+
console.error('See .env.example for required configuration\n');
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Validate and exit if invalid (for use at startup)
|
|
255
|
+
*/
|
|
256
|
+
export function validateOrExit(requirements = LSH_ENV_REQUIREMENTS) {
|
|
257
|
+
const result = validateEnvironment(requirements);
|
|
258
|
+
printValidationResults(result, true);
|
|
259
|
+
}
|
|
260
|
+
export default {
|
|
261
|
+
validateEnvironment,
|
|
262
|
+
printValidationResults,
|
|
263
|
+
validateOrExit,
|
|
264
|
+
LSH_ENV_REQUIREMENTS
|
|
265
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builtin Command Executor
|
|
3
|
+
* Handles execution of all POSIX and extended builtin commands
|
|
4
|
+
*/
|
|
5
|
+
export class BuiltinExecutor {
|
|
6
|
+
context;
|
|
7
|
+
expander;
|
|
8
|
+
pathExpander;
|
|
9
|
+
jobManager;
|
|
10
|
+
jobBuiltins;
|
|
11
|
+
constructor(context, expander, pathExpander, jobManager, jobBuiltins) {
|
|
12
|
+
this.context = context;
|
|
13
|
+
this.expander = expander;
|
|
14
|
+
this.pathExpander = pathExpander;
|
|
15
|
+
this.jobManager = jobManager;
|
|
16
|
+
this.jobBuiltins = jobBuiltins;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Execute a builtin command
|
|
20
|
+
* Returns null if the command is not a builtin
|
|
21
|
+
*/
|
|
22
|
+
async execute(name, args) {
|
|
23
|
+
const builtinMethod = this.getBuiltinMethod(name);
|
|
24
|
+
if (!builtinMethod) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return builtinMethod.call(this, args);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get the builtin method for a command name
|
|
31
|
+
*/
|
|
32
|
+
getBuiltinMethod(name) {
|
|
33
|
+
const builtins = {
|
|
34
|
+
'cd': this.builtin_cd.bind(this),
|
|
35
|
+
'pwd': this.builtin_pwd.bind(this),
|
|
36
|
+
'echo': this.builtin_echo.bind(this),
|
|
37
|
+
// Will add all 38 builtins here
|
|
38
|
+
};
|
|
39
|
+
return builtins[name] || null;
|
|
40
|
+
}
|
|
41
|
+
// ========== BUILTIN IMPLEMENTATIONS ==========
|
|
42
|
+
async builtin_cd(_args) {
|
|
43
|
+
// TODO: Move full implementation from shell-executor.ts
|
|
44
|
+
return { stdout: '', stderr: 'cd: stub', exitCode: 1, success: false };
|
|
45
|
+
}
|
|
46
|
+
async builtin_pwd(_args) {
|
|
47
|
+
return { stdout: this.context.cwd + '\n', stderr: '', exitCode: 0, success: true };
|
|
48
|
+
}
|
|
49
|
+
async builtin_echo(args) {
|
|
50
|
+
return { stdout: args.join(' ') + '\n', stderr: '', exitCode: 0, success: true };
|
|
51
|
+
}
|
|
52
|
+
}
|