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.
- package/README.md +70 -4
- package/dist/cli.js +104 -486
- package/dist/commands/doctor.js +427 -0
- package/dist/commands/init.js +371 -0
- package/dist/constants/api.js +94 -0
- package/dist/constants/commands.js +64 -0
- package/dist/constants/config.js +56 -0
- package/dist/constants/database.js +21 -0
- package/dist/constants/errors.js +79 -0
- package/dist/constants/index.js +28 -0
- package/dist/constants/paths.js +28 -0
- package/dist/constants/ui.js +73 -0
- package/dist/constants/validation.js +124 -0
- package/dist/daemon/lshd.js +11 -32
- package/dist/lib/daemon-client-helper.js +7 -4
- package/dist/lib/daemon-client.js +9 -2
- package/dist/lib/format-utils.js +163 -0
- package/dist/lib/job-manager.js +2 -1
- package/dist/lib/platform-utils.js +211 -0
- package/dist/lib/secrets-manager.js +11 -1
- package/dist/lib/string-utils.js +128 -0
- package/dist/services/daemon/daemon-registrar.js +3 -2
- package/dist/services/secrets/secrets.js +154 -30
- package/package.json +10 -74
- package/dist/app.js +0 -33
- package/dist/cicd/analytics.js +0 -261
- package/dist/cicd/auth.js +0 -269
- package/dist/cicd/cache-manager.js +0 -172
- package/dist/cicd/data-retention.js +0 -305
- package/dist/cicd/performance-monitor.js +0 -224
- package/dist/cicd/webhook-receiver.js +0 -640
- package/dist/commands/api.js +0 -346
- package/dist/commands/theme.js +0 -261
- package/dist/commands/zsh-import.js +0 -240
- package/dist/components/App.js +0 -1
- package/dist/components/Divider.js +0 -29
- package/dist/components/REPL.js +0 -43
- package/dist/components/Terminal.js +0 -232
- package/dist/components/UserInput.js +0 -30
- package/dist/daemon/api-server.js +0 -316
- package/dist/daemon/monitoring-api.js +0 -220
- package/dist/lib/api-error-handler.js +0 -185
- package/dist/lib/associative-arrays.js +0 -285
- package/dist/lib/base-api-server.js +0 -290
- package/dist/lib/brace-expansion.js +0 -160
- package/dist/lib/builtin-commands.js +0 -439
- package/dist/lib/executors/builtin-executor.js +0 -52
- package/dist/lib/extended-globbing.js +0 -411
- package/dist/lib/extended-parameter-expansion.js +0 -227
- package/dist/lib/interactive-shell.js +0 -460
- package/dist/lib/job-builtins.js +0 -582
- package/dist/lib/pathname-expansion.js +0 -216
- package/dist/lib/script-runner.js +0 -226
- package/dist/lib/shell-executor.js +0 -2504
- package/dist/lib/shell-parser.js +0 -958
- package/dist/lib/shell-types.js +0 -6
- package/dist/lib/shell.lib.js +0 -40
- package/dist/lib/theme-manager.js +0 -476
- package/dist/lib/variable-expansion.js +0 -385
- package/dist/lib/zsh-compatibility.js +0 -659
- package/dist/lib/zsh-import-manager.js +0 -707
- package/dist/lib/zsh-options.js +0 -328
- package/dist/pipeline/job-tracker.js +0 -491
- package/dist/pipeline/mcli-bridge.js +0 -309
- package/dist/pipeline/pipeline-service.js +0 -1119
- package/dist/pipeline/workflow-engine.js +0 -870
- package/dist/services/api/api.js +0 -58
- package/dist/services/api/auth.js +0 -35
- package/dist/services/api/config.js +0 -7
- package/dist/services/api/file.js +0 -22
- package/dist/services/shell/shell.js +0 -28
- package/dist/services/zapier.js +0 -16
- package/dist/simple-api-server.js +0 -148
|
@@ -1,707 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Enhanced ZSH Import Manager
|
|
3
|
-
* Handles importing ZSH configurations with conflict resolution, diagnostics, and selective import
|
|
4
|
-
*/
|
|
5
|
-
import * as fs from 'fs';
|
|
6
|
-
import * as path from 'path';
|
|
7
|
-
import * as os from 'os';
|
|
8
|
-
import { parseShellCommand } from './shell-parser.js';
|
|
9
|
-
export class ZshImportManager {
|
|
10
|
-
executor;
|
|
11
|
-
options;
|
|
12
|
-
diagnostics = [];
|
|
13
|
-
existingAliases = new Set();
|
|
14
|
-
existingExports = new Set();
|
|
15
|
-
existingFunctions = new Set();
|
|
16
|
-
constructor(executor, options = {}) {
|
|
17
|
-
this.executor = executor;
|
|
18
|
-
this.options = {
|
|
19
|
-
autoImport: false,
|
|
20
|
-
selective: false,
|
|
21
|
-
conflictResolution: 'skip',
|
|
22
|
-
diagnosticLog: path.join(os.homedir(), '.lsh', 'zsh-import.log'),
|
|
23
|
-
includeAliases: true,
|
|
24
|
-
includeExports: true,
|
|
25
|
-
includeFunctions: true,
|
|
26
|
-
includeOptions: true,
|
|
27
|
-
includePlugins: true,
|
|
28
|
-
excludePatterns: [],
|
|
29
|
-
includePatterns: [],
|
|
30
|
-
...options,
|
|
31
|
-
};
|
|
32
|
-
// Ensure diagnostic log directory exists
|
|
33
|
-
this.ensureLogDirectory();
|
|
34
|
-
}
|
|
35
|
-
ensureLogDirectory() {
|
|
36
|
-
const logDir = path.dirname(this.options.diagnosticLog);
|
|
37
|
-
if (!fs.existsSync(logDir)) {
|
|
38
|
-
fs.mkdirSync(logDir, { recursive: true });
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Import ZSH configuration from .zshrc
|
|
43
|
-
*/
|
|
44
|
-
async importZshConfig(zshrcPath) {
|
|
45
|
-
const configPath = zshrcPath || path.join(os.homedir(), '.zshrc');
|
|
46
|
-
this.diagnostics = [];
|
|
47
|
-
this.log({ type: 'alias', name: 'IMPORT_START', status: 'success', reason: `Starting import from ${configPath}` });
|
|
48
|
-
try {
|
|
49
|
-
// Check if .zshrc exists
|
|
50
|
-
if (!fs.existsSync(configPath)) {
|
|
51
|
-
const result = {
|
|
52
|
-
success: false,
|
|
53
|
-
message: `ZSH configuration not found: ${configPath}`,
|
|
54
|
-
diagnostics: this.diagnostics,
|
|
55
|
-
stats: { total: 0, succeeded: 0, failed: 0, skipped: 0, conflicts: 0 },
|
|
56
|
-
};
|
|
57
|
-
this.writeDiagnosticLog();
|
|
58
|
-
return result;
|
|
59
|
-
}
|
|
60
|
-
// Load existing items to detect conflicts
|
|
61
|
-
await this.loadExistingItems();
|
|
62
|
-
// Read and parse .zshrc
|
|
63
|
-
const zshrcContent = fs.readFileSync(configPath, 'utf8');
|
|
64
|
-
const parsed = this.parseZshrc(zshrcContent);
|
|
65
|
-
// Apply configurations based on options
|
|
66
|
-
const stats = {
|
|
67
|
-
total: 0,
|
|
68
|
-
succeeded: 0,
|
|
69
|
-
failed: 0,
|
|
70
|
-
skipped: 0,
|
|
71
|
-
conflicts: 0,
|
|
72
|
-
};
|
|
73
|
-
if (this.options.includeAliases) {
|
|
74
|
-
const result = await this.importAliases(parsed.aliases);
|
|
75
|
-
stats.total += result.total;
|
|
76
|
-
stats.succeeded += result.succeeded;
|
|
77
|
-
stats.failed += result.failed;
|
|
78
|
-
stats.skipped += result.skipped;
|
|
79
|
-
stats.conflicts += result.conflicts;
|
|
80
|
-
}
|
|
81
|
-
if (this.options.includeExports) {
|
|
82
|
-
const result = await this.importExports(parsed.exports);
|
|
83
|
-
stats.total += result.total;
|
|
84
|
-
stats.succeeded += result.succeeded;
|
|
85
|
-
stats.failed += result.failed;
|
|
86
|
-
stats.skipped += result.skipped;
|
|
87
|
-
stats.conflicts += result.conflicts;
|
|
88
|
-
}
|
|
89
|
-
if (this.options.includeFunctions) {
|
|
90
|
-
const result = await this.importFunctions(parsed.functions);
|
|
91
|
-
stats.total += result.total;
|
|
92
|
-
stats.succeeded += result.succeeded;
|
|
93
|
-
stats.failed += result.failed;
|
|
94
|
-
stats.skipped += result.skipped;
|
|
95
|
-
stats.conflicts += result.conflicts;
|
|
96
|
-
}
|
|
97
|
-
if (this.options.includeOptions) {
|
|
98
|
-
const result = await this.importSetopts(parsed.setopts);
|
|
99
|
-
stats.total += result.total;
|
|
100
|
-
stats.succeeded += result.succeeded;
|
|
101
|
-
stats.failed += result.failed;
|
|
102
|
-
stats.skipped += result.skipped;
|
|
103
|
-
}
|
|
104
|
-
if (this.options.includePlugins) {
|
|
105
|
-
const result = await this.importPlugins(parsed.plugins);
|
|
106
|
-
stats.total += result.total;
|
|
107
|
-
stats.succeeded += result.succeeded;
|
|
108
|
-
stats.failed += result.failed;
|
|
109
|
-
stats.skipped += result.skipped;
|
|
110
|
-
}
|
|
111
|
-
this.log({
|
|
112
|
-
type: 'alias',
|
|
113
|
-
name: 'IMPORT_COMPLETE',
|
|
114
|
-
status: 'success',
|
|
115
|
-
reason: `Imported ${stats.succeeded}/${stats.total} items`
|
|
116
|
-
});
|
|
117
|
-
const result = {
|
|
118
|
-
success: true,
|
|
119
|
-
message: this.formatImportMessage(stats),
|
|
120
|
-
diagnostics: this.diagnostics,
|
|
121
|
-
stats,
|
|
122
|
-
};
|
|
123
|
-
this.writeDiagnosticLog();
|
|
124
|
-
return result;
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
const err = error;
|
|
128
|
-
this.log({
|
|
129
|
-
type: 'error',
|
|
130
|
-
name: 'IMPORT_ERROR',
|
|
131
|
-
status: 'failed',
|
|
132
|
-
reason: err.message
|
|
133
|
-
});
|
|
134
|
-
const result = {
|
|
135
|
-
success: false,
|
|
136
|
-
message: `Import failed: ${err.message}`,
|
|
137
|
-
diagnostics: this.diagnostics,
|
|
138
|
-
stats: { total: 0, succeeded: 0, failed: 1, skipped: 0, conflicts: 0 },
|
|
139
|
-
};
|
|
140
|
-
this.writeDiagnosticLog();
|
|
141
|
-
return result;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Parse .zshrc with enhanced function parsing
|
|
146
|
-
*/
|
|
147
|
-
parseZshrc(content) {
|
|
148
|
-
const lines = content.split('\n');
|
|
149
|
-
const config = {
|
|
150
|
-
aliases: [],
|
|
151
|
-
functions: [],
|
|
152
|
-
exports: [],
|
|
153
|
-
setopts: [],
|
|
154
|
-
completions: [],
|
|
155
|
-
plugins: [],
|
|
156
|
-
};
|
|
157
|
-
let inFunction = false;
|
|
158
|
-
let functionName = '';
|
|
159
|
-
let functionBody = '';
|
|
160
|
-
let functionStartLine = 0;
|
|
161
|
-
let braceCount = 0;
|
|
162
|
-
for (let i = 0; i < lines.length; i++) {
|
|
163
|
-
const line = lines[i];
|
|
164
|
-
const trimmed = line.trim();
|
|
165
|
-
// Skip comments and empty lines
|
|
166
|
-
if (trimmed.startsWith('#') || trimmed === '') {
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
// Handle function definitions (multiple formats)
|
|
170
|
-
// Format 1: name() { ... }
|
|
171
|
-
// Format 2: function name { ... }
|
|
172
|
-
// Format 3: function name() { ... }
|
|
173
|
-
const funcMatch = trimmed.match(/^(?:function\s+)?([a-zA-Z_][a-zA-Z0-9_]*)\s*\(\s*\)\s*\{?/) ||
|
|
174
|
-
trimmed.match(/^function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\{?/);
|
|
175
|
-
if (funcMatch && !inFunction) {
|
|
176
|
-
inFunction = true;
|
|
177
|
-
functionName = funcMatch[1];
|
|
178
|
-
functionBody = line;
|
|
179
|
-
functionStartLine = i + 1;
|
|
180
|
-
braceCount = (line.match(/\{/g) || []).length - (line.match(/\}/g) || []).length;
|
|
181
|
-
if (braceCount === 0 && line.includes('{') && line.includes('}')) {
|
|
182
|
-
// Single-line function
|
|
183
|
-
inFunction = false;
|
|
184
|
-
config.functions.push({
|
|
185
|
-
name: functionName,
|
|
186
|
-
body: functionBody,
|
|
187
|
-
line: functionStartLine,
|
|
188
|
-
});
|
|
189
|
-
functionName = '';
|
|
190
|
-
functionBody = '';
|
|
191
|
-
}
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
if (inFunction) {
|
|
195
|
-
functionBody += '\n' + line;
|
|
196
|
-
braceCount += (line.match(/\{/g) || []).length;
|
|
197
|
-
braceCount -= (line.match(/\}/g) || []).length;
|
|
198
|
-
if (braceCount <= 0) {
|
|
199
|
-
inFunction = false;
|
|
200
|
-
config.functions.push({
|
|
201
|
-
name: functionName,
|
|
202
|
-
body: functionBody,
|
|
203
|
-
line: functionStartLine,
|
|
204
|
-
});
|
|
205
|
-
functionName = '';
|
|
206
|
-
functionBody = '';
|
|
207
|
-
}
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
210
|
-
// Parse aliases
|
|
211
|
-
const aliasMatch = trimmed.match(/^alias\s+([^=]+)=(.+)$/);
|
|
212
|
-
if (aliasMatch) {
|
|
213
|
-
config.aliases.push({
|
|
214
|
-
name: aliasMatch[1].trim(),
|
|
215
|
-
value: aliasMatch[2].replace(/^['"]|['"]$/g, ''),
|
|
216
|
-
line: i + 1,
|
|
217
|
-
});
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
// Parse exports (handle various formats)
|
|
221
|
-
const exportMatch = trimmed.match(/^export\s+([^=]+)(?:=(.+))?$/);
|
|
222
|
-
if (exportMatch) {
|
|
223
|
-
config.exports.push({
|
|
224
|
-
name: exportMatch[1].trim(),
|
|
225
|
-
value: exportMatch[2] ? exportMatch[2].replace(/^['"]|['"]$/g, '') : '',
|
|
226
|
-
line: i + 1,
|
|
227
|
-
});
|
|
228
|
-
continue;
|
|
229
|
-
}
|
|
230
|
-
// Parse setopt
|
|
231
|
-
const setoptMatch = trimmed.match(/^setopt\s+(.+)$/);
|
|
232
|
-
if (setoptMatch) {
|
|
233
|
-
const options = setoptMatch[1].split(/\s+/);
|
|
234
|
-
for (const option of options) {
|
|
235
|
-
config.setopts.push({
|
|
236
|
-
option: option.trim(),
|
|
237
|
-
enabled: true,
|
|
238
|
-
line: i + 1,
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
continue;
|
|
242
|
-
}
|
|
243
|
-
// Parse unsetopt
|
|
244
|
-
const unsetoptMatch = trimmed.match(/^unsetopt\s+(.+)$/);
|
|
245
|
-
if (unsetoptMatch) {
|
|
246
|
-
const options = unsetoptMatch[1].split(/\s+/);
|
|
247
|
-
for (const option of options) {
|
|
248
|
-
config.setopts.push({
|
|
249
|
-
option: option.trim(),
|
|
250
|
-
enabled: false,
|
|
251
|
-
line: i + 1,
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
// Parse completions
|
|
257
|
-
if (trimmed.includes('compinit') || trimmed.includes('autoload')) {
|
|
258
|
-
config.completions.push({
|
|
259
|
-
config: trimmed,
|
|
260
|
-
line: i + 1,
|
|
261
|
-
});
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
// Parse plugins
|
|
265
|
-
const pluginMatch = trimmed.match(/plugins?=\(([^)]+)\)/);
|
|
266
|
-
if (pluginMatch) {
|
|
267
|
-
const plugins = pluginMatch[1].split(/\s+/).filter(p => p.trim());
|
|
268
|
-
for (const plugin of plugins) {
|
|
269
|
-
config.plugins.push({
|
|
270
|
-
name: plugin.trim(),
|
|
271
|
-
line: i + 1,
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
continue;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return config;
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Load existing items to detect conflicts
|
|
281
|
-
*/
|
|
282
|
-
async loadExistingItems() {
|
|
283
|
-
// Get existing aliases from context
|
|
284
|
-
const context = this.executor.getContext();
|
|
285
|
-
if (context && context.variables) {
|
|
286
|
-
for (const key in context.variables) {
|
|
287
|
-
if (key.startsWith('alias_')) {
|
|
288
|
-
this.existingAliases.add(key.substring(6));
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
this.existingExports.add(key);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
// TODO: Load existing functions when function storage is implemented
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Import aliases with conflict resolution
|
|
299
|
-
*/
|
|
300
|
-
async importAliases(aliases) {
|
|
301
|
-
const stats = { total: aliases.length, succeeded: 0, failed: 0, skipped: 0, conflicts: 0 };
|
|
302
|
-
for (const alias of aliases) {
|
|
303
|
-
// Check include/exclude patterns
|
|
304
|
-
if (!this.shouldImport(alias.name)) {
|
|
305
|
-
this.log({
|
|
306
|
-
type: 'alias',
|
|
307
|
-
name: alias.name,
|
|
308
|
-
status: 'skipped',
|
|
309
|
-
reason: 'Excluded by pattern',
|
|
310
|
-
source: `line ${alias.line}`,
|
|
311
|
-
});
|
|
312
|
-
stats.skipped++;
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
|
-
// Check for conflicts
|
|
316
|
-
if (this.existingAliases.has(alias.name)) {
|
|
317
|
-
stats.conflicts++;
|
|
318
|
-
const action = await this.resolveConflict('alias', alias.name);
|
|
319
|
-
if (action === 'skip') {
|
|
320
|
-
this.log({
|
|
321
|
-
type: 'alias',
|
|
322
|
-
name: alias.name,
|
|
323
|
-
status: 'skipped',
|
|
324
|
-
reason: 'Conflict - alias already exists',
|
|
325
|
-
source: `line ${alias.line}`,
|
|
326
|
-
action: 'skipped',
|
|
327
|
-
});
|
|
328
|
-
stats.skipped++;
|
|
329
|
-
continue;
|
|
330
|
-
}
|
|
331
|
-
else if (action === 'rename') {
|
|
332
|
-
alias.name = `${alias.name}_zsh`;
|
|
333
|
-
this.log({
|
|
334
|
-
type: 'alias',
|
|
335
|
-
name: alias.name,
|
|
336
|
-
status: 'success',
|
|
337
|
-
reason: 'Conflict - renamed to avoid collision',
|
|
338
|
-
source: `line ${alias.line}`,
|
|
339
|
-
action: 'renamed',
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
// Import alias
|
|
344
|
-
try {
|
|
345
|
-
const ast = parseShellCommand(`alias ${alias.name}="${alias.value}"`);
|
|
346
|
-
await this.executor.execute(ast);
|
|
347
|
-
this.existingAliases.add(alias.name);
|
|
348
|
-
this.log({
|
|
349
|
-
type: 'alias',
|
|
350
|
-
name: alias.name,
|
|
351
|
-
status: 'success',
|
|
352
|
-
source: `line ${alias.line}`,
|
|
353
|
-
});
|
|
354
|
-
stats.succeeded++;
|
|
355
|
-
}
|
|
356
|
-
catch (error) {
|
|
357
|
-
const err = error;
|
|
358
|
-
this.log({
|
|
359
|
-
type: 'alias',
|
|
360
|
-
name: alias.name,
|
|
361
|
-
status: 'failed',
|
|
362
|
-
reason: err.message,
|
|
363
|
-
source: `line ${alias.line}`,
|
|
364
|
-
});
|
|
365
|
-
stats.failed++;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
return stats;
|
|
369
|
-
}
|
|
370
|
-
/**
|
|
371
|
-
* Import environment variables with conflict resolution
|
|
372
|
-
*/
|
|
373
|
-
async importExports(exports) {
|
|
374
|
-
const stats = { total: exports.length, succeeded: 0, failed: 0, skipped: 0, conflicts: 0 };
|
|
375
|
-
for (const export_ of exports) {
|
|
376
|
-
// Check include/exclude patterns
|
|
377
|
-
if (!this.shouldImport(export_.name)) {
|
|
378
|
-
this.log({
|
|
379
|
-
type: 'export',
|
|
380
|
-
name: export_.name,
|
|
381
|
-
status: 'skipped',
|
|
382
|
-
reason: 'Excluded by pattern',
|
|
383
|
-
source: `line ${export_.line}`,
|
|
384
|
-
});
|
|
385
|
-
stats.skipped++;
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
// Check for conflicts
|
|
389
|
-
if (this.existingExports.has(export_.name) || process.env[export_.name]) {
|
|
390
|
-
stats.conflicts++;
|
|
391
|
-
const action = await this.resolveConflict('export', export_.name);
|
|
392
|
-
if (action === 'skip') {
|
|
393
|
-
this.log({
|
|
394
|
-
type: 'export',
|
|
395
|
-
name: export_.name,
|
|
396
|
-
status: 'skipped',
|
|
397
|
-
reason: 'Conflict - variable already exists',
|
|
398
|
-
source: `line ${export_.line}`,
|
|
399
|
-
action: 'skipped',
|
|
400
|
-
});
|
|
401
|
-
stats.skipped++;
|
|
402
|
-
continue;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
// Import export
|
|
406
|
-
try {
|
|
407
|
-
const value = export_.value || '';
|
|
408
|
-
const ast = parseShellCommand(`export ${export_.name}="${value}"`);
|
|
409
|
-
await this.executor.execute(ast);
|
|
410
|
-
this.existingExports.add(export_.name);
|
|
411
|
-
this.log({
|
|
412
|
-
type: 'export',
|
|
413
|
-
name: export_.name,
|
|
414
|
-
status: 'success',
|
|
415
|
-
source: `line ${export_.line}`,
|
|
416
|
-
});
|
|
417
|
-
stats.succeeded++;
|
|
418
|
-
}
|
|
419
|
-
catch (error) {
|
|
420
|
-
const err = error;
|
|
421
|
-
this.log({
|
|
422
|
-
type: 'export',
|
|
423
|
-
name: export_.name,
|
|
424
|
-
status: 'failed',
|
|
425
|
-
reason: err.message,
|
|
426
|
-
source: `line ${export_.line}`,
|
|
427
|
-
});
|
|
428
|
-
stats.failed++;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
return stats;
|
|
432
|
-
}
|
|
433
|
-
/**
|
|
434
|
-
* Import functions with enhanced parsing
|
|
435
|
-
*/
|
|
436
|
-
async importFunctions(functions) {
|
|
437
|
-
const stats = { total: functions.length, succeeded: 0, failed: 0, skipped: 0, conflicts: 0 };
|
|
438
|
-
for (const func of functions) {
|
|
439
|
-
// Check include/exclude patterns
|
|
440
|
-
if (!this.shouldImport(func.name)) {
|
|
441
|
-
this.log({
|
|
442
|
-
type: 'function',
|
|
443
|
-
name: func.name,
|
|
444
|
-
status: 'skipped',
|
|
445
|
-
reason: 'Excluded by pattern',
|
|
446
|
-
source: `line ${func.line}`,
|
|
447
|
-
});
|
|
448
|
-
stats.skipped++;
|
|
449
|
-
continue;
|
|
450
|
-
}
|
|
451
|
-
// Check for conflicts
|
|
452
|
-
if (this.existingFunctions.has(func.name)) {
|
|
453
|
-
stats.conflicts++;
|
|
454
|
-
const action = await this.resolveConflict('function', func.name);
|
|
455
|
-
if (action === 'skip') {
|
|
456
|
-
this.log({
|
|
457
|
-
type: 'function',
|
|
458
|
-
name: func.name,
|
|
459
|
-
status: 'skipped',
|
|
460
|
-
reason: 'Conflict - function already exists',
|
|
461
|
-
source: `line ${func.line}`,
|
|
462
|
-
action: 'skipped',
|
|
463
|
-
});
|
|
464
|
-
stats.skipped++;
|
|
465
|
-
continue;
|
|
466
|
-
}
|
|
467
|
-
else if (action === 'rename') {
|
|
468
|
-
// Rename function in body
|
|
469
|
-
const oldName = func.name;
|
|
470
|
-
func.name = `${func.name}_zsh`;
|
|
471
|
-
func.body = func.body.replace(new RegExp(`^(function\\s+)?${oldName}`, 'm'), `$1${func.name}`);
|
|
472
|
-
this.log({
|
|
473
|
-
type: 'function',
|
|
474
|
-
name: func.name,
|
|
475
|
-
status: 'success',
|
|
476
|
-
reason: 'Conflict - renamed to avoid collision',
|
|
477
|
-
source: `line ${func.line}`,
|
|
478
|
-
action: 'renamed',
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
// Import function
|
|
483
|
-
try {
|
|
484
|
-
const ast = parseShellCommand(func.body);
|
|
485
|
-
await this.executor.execute(ast);
|
|
486
|
-
this.existingFunctions.add(func.name);
|
|
487
|
-
this.log({
|
|
488
|
-
type: 'function',
|
|
489
|
-
name: func.name,
|
|
490
|
-
status: 'success',
|
|
491
|
-
source: `line ${func.line}`,
|
|
492
|
-
});
|
|
493
|
-
stats.succeeded++;
|
|
494
|
-
}
|
|
495
|
-
catch (error) {
|
|
496
|
-
const err = error;
|
|
497
|
-
this.log({
|
|
498
|
-
type: 'function',
|
|
499
|
-
name: func.name,
|
|
500
|
-
status: 'disabled',
|
|
501
|
-
reason: `Parse error: ${err.message}`,
|
|
502
|
-
source: `line ${func.line}`,
|
|
503
|
-
});
|
|
504
|
-
stats.failed++;
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
return stats;
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Import ZSH options
|
|
511
|
-
*/
|
|
512
|
-
async importSetopts(setopts) {
|
|
513
|
-
const stats = { total: setopts.length, succeeded: 0, failed: 0, skipped: 0, conflicts: 0 };
|
|
514
|
-
for (const setopt of setopts) {
|
|
515
|
-
try {
|
|
516
|
-
const command = setopt.enabled ? 'setopt' : 'unsetopt';
|
|
517
|
-
const ast = parseShellCommand(`${command} ${setopt.option}`);
|
|
518
|
-
await this.executor.execute(ast);
|
|
519
|
-
this.log({
|
|
520
|
-
type: 'setopt',
|
|
521
|
-
name: setopt.option,
|
|
522
|
-
status: 'success',
|
|
523
|
-
source: `line ${setopt.line}`,
|
|
524
|
-
});
|
|
525
|
-
stats.succeeded++;
|
|
526
|
-
}
|
|
527
|
-
catch (error) {
|
|
528
|
-
const err = error;
|
|
529
|
-
this.log({
|
|
530
|
-
type: 'setopt',
|
|
531
|
-
name: setopt.option,
|
|
532
|
-
status: 'disabled',
|
|
533
|
-
reason: err.message,
|
|
534
|
-
source: `line ${setopt.line}`,
|
|
535
|
-
});
|
|
536
|
-
stats.failed++;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
return stats;
|
|
540
|
-
}
|
|
541
|
-
/**
|
|
542
|
-
* Import Oh-My-Zsh plugins
|
|
543
|
-
*/
|
|
544
|
-
async importPlugins(plugins) {
|
|
545
|
-
const stats = { total: plugins.length, succeeded: 0, failed: 0, skipped: 0, conflicts: 0 };
|
|
546
|
-
for (const plugin of plugins) {
|
|
547
|
-
this.log({
|
|
548
|
-
type: 'plugin',
|
|
549
|
-
name: plugin.name,
|
|
550
|
-
status: 'disabled',
|
|
551
|
-
reason: 'Oh-My-Zsh plugin support not yet implemented',
|
|
552
|
-
source: `line ${plugin.line}`,
|
|
553
|
-
});
|
|
554
|
-
stats.skipped++;
|
|
555
|
-
}
|
|
556
|
-
return stats;
|
|
557
|
-
}
|
|
558
|
-
/**
|
|
559
|
-
* Check if item should be imported based on include/exclude patterns
|
|
560
|
-
*/
|
|
561
|
-
shouldImport(name) {
|
|
562
|
-
// Check exclude patterns first
|
|
563
|
-
if (this.options.excludePatterns.length > 0) {
|
|
564
|
-
for (const pattern of this.options.excludePatterns) {
|
|
565
|
-
if (this.matchPattern(name, pattern)) {
|
|
566
|
-
return false;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
// Check include patterns
|
|
571
|
-
if (this.options.includePatterns.length > 0) {
|
|
572
|
-
for (const pattern of this.options.includePatterns) {
|
|
573
|
-
if (this.matchPattern(name, pattern)) {
|
|
574
|
-
return true;
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
return false; // If include patterns specified, only import matching items
|
|
578
|
-
}
|
|
579
|
-
return true; // No patterns specified, import everything
|
|
580
|
-
}
|
|
581
|
-
/**
|
|
582
|
-
* Match name against pattern (supports wildcards)
|
|
583
|
-
*/
|
|
584
|
-
matchPattern(name, pattern) {
|
|
585
|
-
const regexPattern = pattern
|
|
586
|
-
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape regex special chars
|
|
587
|
-
.replace(/\*/g, '.*') // Convert * to .*
|
|
588
|
-
.replace(/\?/g, '.'); // Convert ? to .
|
|
589
|
-
return new RegExp(`^${regexPattern}$`).test(name);
|
|
590
|
-
}
|
|
591
|
-
/**
|
|
592
|
-
* Resolve naming conflicts
|
|
593
|
-
*/
|
|
594
|
-
async resolveConflict(_type, _name) {
|
|
595
|
-
switch (this.options.conflictResolution) {
|
|
596
|
-
case 'skip':
|
|
597
|
-
return 'skip';
|
|
598
|
-
case 'overwrite':
|
|
599
|
-
return 'overwrite';
|
|
600
|
-
case 'rename':
|
|
601
|
-
return 'rename';
|
|
602
|
-
case 'prompt':
|
|
603
|
-
// TODO: Implement interactive prompt for CLI
|
|
604
|
-
return 'skip'; // Default to skip for now
|
|
605
|
-
default:
|
|
606
|
-
return 'skip';
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
/**
|
|
610
|
-
* Log diagnostic entry
|
|
611
|
-
*/
|
|
612
|
-
log(entry) {
|
|
613
|
-
this.diagnostics.push({
|
|
614
|
-
timestamp: new Date(),
|
|
615
|
-
...entry,
|
|
616
|
-
});
|
|
617
|
-
}
|
|
618
|
-
/**
|
|
619
|
-
* Write diagnostic log to file
|
|
620
|
-
*/
|
|
621
|
-
writeDiagnosticLog() {
|
|
622
|
-
try {
|
|
623
|
-
const logContent = this.diagnostics
|
|
624
|
-
.map(d => {
|
|
625
|
-
const parts = [
|
|
626
|
-
d.timestamp.toISOString(),
|
|
627
|
-
d.type.padEnd(10),
|
|
628
|
-
d.status.padEnd(10),
|
|
629
|
-
d.name.padEnd(30),
|
|
630
|
-
];
|
|
631
|
-
if (d.source)
|
|
632
|
-
parts.push(`[${d.source}]`);
|
|
633
|
-
if (d.reason)
|
|
634
|
-
parts.push(d.reason);
|
|
635
|
-
if (d.action)
|
|
636
|
-
parts.push(`(${d.action})`);
|
|
637
|
-
return parts.join(' ');
|
|
638
|
-
})
|
|
639
|
-
.join('\n');
|
|
640
|
-
fs.appendFileSync(this.options.diagnosticLog, logContent + '\n\n', 'utf8');
|
|
641
|
-
}
|
|
642
|
-
catch (error) {
|
|
643
|
-
const err = error;
|
|
644
|
-
console.error(`Failed to write diagnostic log: ${err.message}`);
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
/**
|
|
648
|
-
* Format import summary message
|
|
649
|
-
*/
|
|
650
|
-
formatImportMessage(stats) {
|
|
651
|
-
const lines = [
|
|
652
|
-
`ZSH Import Complete:`,
|
|
653
|
-
` ✅ Succeeded: ${stats.succeeded}`,
|
|
654
|
-
` ❌ Failed: ${stats.failed}`,
|
|
655
|
-
` ⏭️ Skipped: ${stats.skipped}`,
|
|
656
|
-
` ⚠️ Conflicts: ${stats.conflicts}`,
|
|
657
|
-
` 📊 Total: ${stats.total}`,
|
|
658
|
-
];
|
|
659
|
-
if (stats.failed > 0) {
|
|
660
|
-
lines.push(`\nSee diagnostic log: ${this.options.diagnosticLog}`);
|
|
661
|
-
}
|
|
662
|
-
return lines.join('\n');
|
|
663
|
-
}
|
|
664
|
-
/**
|
|
665
|
-
* Get import statistics from last run
|
|
666
|
-
*/
|
|
667
|
-
getLastImportStats() {
|
|
668
|
-
if (this.diagnostics.length === 0) {
|
|
669
|
-
return null;
|
|
670
|
-
}
|
|
671
|
-
const stats = {
|
|
672
|
-
total: 0,
|
|
673
|
-
succeeded: 0,
|
|
674
|
-
failed: 0,
|
|
675
|
-
skipped: 0,
|
|
676
|
-
conflicts: 0,
|
|
677
|
-
byType: {},
|
|
678
|
-
};
|
|
679
|
-
for (const diagnostic of this.diagnostics) {
|
|
680
|
-
if (diagnostic.name === 'IMPORT_START' || diagnostic.name === 'IMPORT_COMPLETE' || diagnostic.name === 'IMPORT_ERROR') {
|
|
681
|
-
continue;
|
|
682
|
-
}
|
|
683
|
-
stats.total++;
|
|
684
|
-
if (diagnostic.status === 'success')
|
|
685
|
-
stats.succeeded++;
|
|
686
|
-
if (diagnostic.status === 'failed')
|
|
687
|
-
stats.failed++;
|
|
688
|
-
if (diagnostic.status === 'skipped')
|
|
689
|
-
stats.skipped++;
|
|
690
|
-
if (diagnostic.status === 'conflict')
|
|
691
|
-
stats.conflicts++;
|
|
692
|
-
if (!stats.byType[diagnostic.type]) {
|
|
693
|
-
stats.byType[diagnostic.type] = { total: 0, succeeded: 0, failed: 0, skipped: 0, conflicts: 0 };
|
|
694
|
-
}
|
|
695
|
-
stats.byType[diagnostic.type].total++;
|
|
696
|
-
if (diagnostic.status === 'success')
|
|
697
|
-
stats.byType[diagnostic.type].succeeded++;
|
|
698
|
-
if (diagnostic.status === 'failed')
|
|
699
|
-
stats.byType[diagnostic.type].failed++;
|
|
700
|
-
if (diagnostic.status === 'skipped')
|
|
701
|
-
stats.byType[diagnostic.type].skipped++;
|
|
702
|
-
if (diagnostic.status === 'conflict')
|
|
703
|
-
stats.byType[diagnostic.type].conflicts++;
|
|
704
|
-
}
|
|
705
|
-
return stats;
|
|
706
|
-
}
|
|
707
|
-
}
|