lsh-framework 1.2.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 +40 -3
- 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 +54 -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
package/dist/lib/shell-types.js
DELETED
package/dist/lib/shell.lib.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { exec, spawn } from 'child_process';
|
|
2
|
-
import { promisify } from 'util';
|
|
3
|
-
const execAsync = promisify(exec);
|
|
4
|
-
// Execute shell command and return result
|
|
5
|
-
export async function shell_exec(command) {
|
|
6
|
-
try {
|
|
7
|
-
const { stdout, stderr } = await execAsync(command);
|
|
8
|
-
return { stdout: stdout.trim(), stderr: stderr.trim() };
|
|
9
|
-
}
|
|
10
|
-
catch (error) {
|
|
11
|
-
return {
|
|
12
|
-
stdout: '',
|
|
13
|
-
stderr: '',
|
|
14
|
-
error: error.message
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
// Execute shell command with streaming output
|
|
19
|
-
export function shell_spawn(command, args = []) {
|
|
20
|
-
return new Promise((resolve) => {
|
|
21
|
-
const [cmd, ...defaultArgs] = command.split(' ');
|
|
22
|
-
const finalArgs = args.length > 0 ? args : defaultArgs;
|
|
23
|
-
const child = spawn(cmd, finalArgs);
|
|
24
|
-
let stdout = '';
|
|
25
|
-
let stderr = '';
|
|
26
|
-
child.stdout.on('data', (data) => {
|
|
27
|
-
stdout += data.toString();
|
|
28
|
-
});
|
|
29
|
-
child.stderr.on('data', (data) => {
|
|
30
|
-
stderr += data.toString();
|
|
31
|
-
});
|
|
32
|
-
child.on('close', (code) => {
|
|
33
|
-
resolve({
|
|
34
|
-
stdout: stdout.trim(),
|
|
35
|
-
stderr: stderr.trim(),
|
|
36
|
-
code: code || 0
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
}
|
|
@@ -1,476 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Theme Manager
|
|
3
|
-
* Import and apply ZSH themes (Oh-My-Zsh, Powerlevel10k, custom)
|
|
4
|
-
*/
|
|
5
|
-
import * as fs from 'fs';
|
|
6
|
-
import * as path from 'path';
|
|
7
|
-
import * as os from 'os';
|
|
8
|
-
import chalk from 'chalk';
|
|
9
|
-
export class ThemeManager {
|
|
10
|
-
themesPath;
|
|
11
|
-
customThemesPath;
|
|
12
|
-
currentTheme = null;
|
|
13
|
-
constructor() {
|
|
14
|
-
this.themesPath = path.join(os.homedir(), '.oh-my-zsh', 'themes');
|
|
15
|
-
this.customThemesPath = path.join(os.homedir(), '.lsh', 'themes');
|
|
16
|
-
// Ensure custom themes directory exists
|
|
17
|
-
if (!fs.existsSync(this.customThemesPath)) {
|
|
18
|
-
fs.mkdirSync(this.customThemesPath, { recursive: true });
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* List available themes
|
|
23
|
-
*/
|
|
24
|
-
listThemes() {
|
|
25
|
-
const ohmyzsh = [];
|
|
26
|
-
const custom = [];
|
|
27
|
-
// Oh-My-Zsh themes
|
|
28
|
-
if (fs.existsSync(this.themesPath)) {
|
|
29
|
-
ohmyzsh.push(...fs.readdirSync(this.themesPath)
|
|
30
|
-
.filter(f => f.endsWith('.zsh-theme'))
|
|
31
|
-
.map(f => f.replace('.zsh-theme', '')));
|
|
32
|
-
}
|
|
33
|
-
// Custom themes
|
|
34
|
-
if (fs.existsSync(this.customThemesPath)) {
|
|
35
|
-
custom.push(...fs.readdirSync(this.customThemesPath)
|
|
36
|
-
.filter(f => f.endsWith('.lsh-theme'))
|
|
37
|
-
.map(f => f.replace('.lsh-theme', '')));
|
|
38
|
-
}
|
|
39
|
-
// Built-in LSH themes
|
|
40
|
-
const builtin = [
|
|
41
|
-
'default',
|
|
42
|
-
'minimal',
|
|
43
|
-
'powerline',
|
|
44
|
-
'simple',
|
|
45
|
-
'git',
|
|
46
|
-
'robbyrussell', // Popular Oh-My-Zsh theme
|
|
47
|
-
'agnoster',
|
|
48
|
-
];
|
|
49
|
-
return { ohmyzsh, custom, builtin };
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Import Oh-My-Zsh theme
|
|
53
|
-
*/
|
|
54
|
-
async importOhMyZshTheme(themeName) {
|
|
55
|
-
const themePath = path.join(this.themesPath, `${themeName}.zsh-theme`);
|
|
56
|
-
if (!fs.existsSync(themePath)) {
|
|
57
|
-
throw new Error(`Theme not found: ${themeName}`);
|
|
58
|
-
}
|
|
59
|
-
const themeContent = fs.readFileSync(themePath, 'utf8');
|
|
60
|
-
const parsed = this.parseZshTheme(themeName, themeContent);
|
|
61
|
-
// Convert to LSH format and save
|
|
62
|
-
this.saveAsLshTheme(parsed);
|
|
63
|
-
return parsed;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Parse ZSH theme file
|
|
67
|
-
*/
|
|
68
|
-
parseZshTheme(name, content) {
|
|
69
|
-
const theme = {
|
|
70
|
-
name,
|
|
71
|
-
colors: new Map(),
|
|
72
|
-
prompts: { left: '' },
|
|
73
|
-
variables: new Map(),
|
|
74
|
-
hooks: [],
|
|
75
|
-
dependencies: [],
|
|
76
|
-
};
|
|
77
|
-
const lines = content.split('\n');
|
|
78
|
-
for (const line of lines) {
|
|
79
|
-
let trimmed = line.trim();
|
|
80
|
-
// Skip comments and empty lines
|
|
81
|
-
if (trimmed.startsWith('#') || trimmed === '') {
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
// Strip inline comments (but preserve # inside quotes)
|
|
85
|
-
const inlineCommentMatch = trimmed.match(/^([^#]*?["'][^"']*["'])\s*#/);
|
|
86
|
-
if (inlineCommentMatch) {
|
|
87
|
-
trimmed = inlineCommentMatch[1].trim();
|
|
88
|
-
}
|
|
89
|
-
else if (trimmed.includes('#')) {
|
|
90
|
-
// Simple inline comment without quotes
|
|
91
|
-
const parts = trimmed.split('#');
|
|
92
|
-
if (parts[0].includes('=')) {
|
|
93
|
-
trimmed = parts[0].trim();
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
// Parse color definitions
|
|
97
|
-
const colorMatch = trimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)=["']?%\{.*?%F\{(\d+|[a-z]+)\}.*?\}["']?/);
|
|
98
|
-
if (colorMatch) {
|
|
99
|
-
theme.colors.set(colorMatch[1], colorMatch[2]);
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
// Parse PROMPT
|
|
103
|
-
const promptMatch = trimmed.match(/^PROMPT=["'](.+)["']$/);
|
|
104
|
-
if (promptMatch) {
|
|
105
|
-
theme.prompts.left = promptMatch[1];
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
// Parse RPROMPT
|
|
109
|
-
const rpromptMatch = trimmed.match(/^RPROMPT=["'](.+)["']$/);
|
|
110
|
-
if (rpromptMatch) {
|
|
111
|
-
theme.prompts.right = rpromptMatch[1];
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
// Parse PS2 (continuation)
|
|
115
|
-
const ps2Match = trimmed.match(/^PS2=["'](.+)["']$/);
|
|
116
|
-
if (ps2Match) {
|
|
117
|
-
theme.prompts.continuation = ps2Match[1];
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
// Parse PS3 (select)
|
|
121
|
-
const ps3Match = trimmed.match(/^PS3=["'](.+)["']$/);
|
|
122
|
-
if (ps3Match) {
|
|
123
|
-
theme.prompts.select = ps3Match[1];
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
// Parse git formats (custom formats)
|
|
127
|
-
if (trimmed.includes('FMT_BRANCH')) {
|
|
128
|
-
const fmtMatch = trimmed.match(/FMT_BRANCH=["'](.+)["']$/);
|
|
129
|
-
if (fmtMatch) {
|
|
130
|
-
if (!theme.gitFormats)
|
|
131
|
-
theme.gitFormats = {};
|
|
132
|
-
theme.gitFormats.branch = fmtMatch[1];
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
if (trimmed.includes('FMT_UNSTAGED')) {
|
|
136
|
-
const fmtMatch = trimmed.match(/FMT_UNSTAGED=["'](.+)["']$/);
|
|
137
|
-
if (fmtMatch) {
|
|
138
|
-
if (!theme.gitFormats)
|
|
139
|
-
theme.gitFormats = {};
|
|
140
|
-
theme.gitFormats.unstaged = fmtMatch[1];
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
if (trimmed.includes('FMT_STAGED')) {
|
|
144
|
-
const fmtMatch = trimmed.match(/FMT_STAGED=["'](.+)["']$/);
|
|
145
|
-
if (fmtMatch) {
|
|
146
|
-
if (!theme.gitFormats)
|
|
147
|
-
theme.gitFormats = {};
|
|
148
|
-
theme.gitFormats.staged = fmtMatch[1];
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
// Parse Oh-My-Zsh git prompt variables
|
|
152
|
-
const gitPromptVars = {
|
|
153
|
-
'ZSH_THEME_GIT_PROMPT_PREFIX': 'prefix',
|
|
154
|
-
'ZSH_THEME_GIT_PROMPT_SUFFIX': 'suffix',
|
|
155
|
-
'ZSH_THEME_GIT_PROMPT_DIRTY': 'dirty',
|
|
156
|
-
'ZSH_THEME_GIT_PROMPT_CLEAN': 'clean',
|
|
157
|
-
'ZSH_THEME_GIT_PROMPT_UNTRACKED': 'untracked',
|
|
158
|
-
};
|
|
159
|
-
for (const [varName, formatKey] of Object.entries(gitPromptVars)) {
|
|
160
|
-
if (trimmed.startsWith(varName)) {
|
|
161
|
-
const match = trimmed.match(new RegExp(`${varName}=["'](.+?)["']$`));
|
|
162
|
-
if (match) {
|
|
163
|
-
if (!theme.gitFormats)
|
|
164
|
-
theme.gitFormats = {};
|
|
165
|
-
// Construct branch format from prefix/suffix if we have them
|
|
166
|
-
if (formatKey === 'prefix' || formatKey === 'suffix') {
|
|
167
|
-
const prefix = formatKey === 'prefix' ? match[1] : theme.gitFormats.prefix || '';
|
|
168
|
-
const suffix = formatKey === 'suffix' ? match[1] : theme.gitFormats.suffix || '';
|
|
169
|
-
if (prefix || suffix) {
|
|
170
|
-
theme.gitFormats.branch = `${prefix}%b${suffix}`;
|
|
171
|
-
}
|
|
172
|
-
// Store the raw values too
|
|
173
|
-
theme.gitFormats[formatKey] = match[1];
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
theme.gitFormats[formatKey] = match[1];
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
// Parse variables (skip prompts, formats, and git theme variables)
|
|
182
|
-
const varMatch = trimmed.match(/^([A-Z_][A-Z0-9_]*)=["']?(.+?)["']?$/);
|
|
183
|
-
if (varMatch &&
|
|
184
|
-
!trimmed.includes('PROMPT') &&
|
|
185
|
-
!trimmed.includes('FMT_') &&
|
|
186
|
-
!trimmed.startsWith('ZSH_THEME_GIT_PROMPT_') &&
|
|
187
|
-
!trimmed.startsWith('PS2') &&
|
|
188
|
-
!trimmed.startsWith('PS3')) {
|
|
189
|
-
theme.variables.set(varMatch[1], varMatch[2]);
|
|
190
|
-
}
|
|
191
|
-
// Parse hooks
|
|
192
|
-
if (trimmed.includes('add-zsh-hook')) {
|
|
193
|
-
const hookMatch = trimmed.match(/add-zsh-hook\s+(\w+)\s+(\w+)/);
|
|
194
|
-
if (hookMatch) {
|
|
195
|
-
theme.hooks.push(`${hookMatch[1]}:${hookMatch[2]}`);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
// Detect dependencies
|
|
199
|
-
if (trimmed.includes('vcs_info')) {
|
|
200
|
-
if (!theme.dependencies.includes('vcs_info')) {
|
|
201
|
-
theme.dependencies.push('vcs_info');
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
if (trimmed.includes('git_branch') || trimmed.includes('git_prompt_info') || trimmed.includes('$(git ')) {
|
|
205
|
-
if (!theme.dependencies.includes('git')) {
|
|
206
|
-
theme.dependencies.push('git');
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
if (trimmed.includes('virtualenv_prompt_info')) {
|
|
210
|
-
if (!theme.dependencies.includes('virtualenv')) {
|
|
211
|
-
theme.dependencies.push('virtualenv');
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
if (trimmed.includes('ruby_prompt_info')) {
|
|
215
|
-
if (!theme.dependencies.includes('ruby')) {
|
|
216
|
-
theme.dependencies.push('ruby');
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
// Post-processing: Check prompts for dependencies
|
|
221
|
-
const allPrompts = [
|
|
222
|
-
theme.prompts.left,
|
|
223
|
-
theme.prompts.right,
|
|
224
|
-
theme.prompts.continuation,
|
|
225
|
-
theme.prompts.select
|
|
226
|
-
].filter(Boolean).join(' ');
|
|
227
|
-
if (allPrompts.includes('git_branch') || allPrompts.includes('git_prompt_info') || allPrompts.includes('$(git ')) {
|
|
228
|
-
if (!theme.dependencies.includes('git')) {
|
|
229
|
-
theme.dependencies.push('git');
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
if (allPrompts.includes('virtualenv_prompt_info')) {
|
|
233
|
-
if (!theme.dependencies.includes('virtualenv')) {
|
|
234
|
-
theme.dependencies.push('virtualenv');
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
if (allPrompts.includes('vcs_info')) {
|
|
238
|
-
if (!theme.dependencies.includes('vcs_info')) {
|
|
239
|
-
theme.dependencies.push('vcs_info');
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return theme;
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Convert ZSH prompt format to LSH format
|
|
246
|
-
*/
|
|
247
|
-
convertPromptToLsh(zshPrompt, colors) {
|
|
248
|
-
let lshPrompt = zshPrompt;
|
|
249
|
-
// Convert color variables
|
|
250
|
-
for (const [name, color] of colors.entries()) {
|
|
251
|
-
// Map ZSH color codes to chalk colors
|
|
252
|
-
const chalkColor = this.mapColorToChalk(color);
|
|
253
|
-
lshPrompt = lshPrompt.replace(new RegExp(`\\$\\{${name}\\}`, 'g'), chalkColor);
|
|
254
|
-
}
|
|
255
|
-
// Convert ZSH prompt escapes to LSH equivalents
|
|
256
|
-
const conversions = [
|
|
257
|
-
[/%n/g, process.env.USER || 'user'], // username
|
|
258
|
-
[/%m/g, os.hostname().split('.')[0]], // hostname (short)
|
|
259
|
-
[/%M/g, os.hostname()], // hostname (full)
|
|
260
|
-
[/%~|%d/g, '$(pwd | sed "s|^$HOME|~|")'], // current directory
|
|
261
|
-
[/%\//g, '$(pwd)'], // current directory (full)
|
|
262
|
-
[/%c/g, '$(basename "$(pwd)")'], // current directory (basename)
|
|
263
|
-
[/%D/g, '$(date +"%m/%d/%y")'], // date
|
|
264
|
-
[/%T/g, '$(date +"%H:%M")'], // time (24h)
|
|
265
|
-
[/%t/g, '$(date +"%I:%M %p")'], // time (12h)
|
|
266
|
-
[/%#/g, '\\$'], // # for root, $ for user
|
|
267
|
-
[/%\{.*?reset_color.*?\}/g, chalk.reset('')], // reset color
|
|
268
|
-
[/%\{.*?\}/g, ''], // remove other ZSH escapes
|
|
269
|
-
];
|
|
270
|
-
for (const [pattern, replacement] of conversions) {
|
|
271
|
-
lshPrompt = lshPrompt.replace(pattern, replacement);
|
|
272
|
-
}
|
|
273
|
-
// Handle git info
|
|
274
|
-
if (lshPrompt.includes('$vcs_info_msg_0_')) {
|
|
275
|
-
lshPrompt = lshPrompt.replace(/\$vcs_info_msg_0_/g, '$(git_prompt_info)');
|
|
276
|
-
}
|
|
277
|
-
// Handle virtualenv
|
|
278
|
-
if (lshPrompt.includes('$(virtualenv_prompt_info)')) {
|
|
279
|
-
lshPrompt = lshPrompt.replace(/\$\(virtualenv_prompt_info\)/g, '$([ -n "$VIRTUAL_ENV" ] && echo " ($(basename $VIRTUAL_ENV))")');
|
|
280
|
-
}
|
|
281
|
-
return lshPrompt;
|
|
282
|
-
}
|
|
283
|
-
/**
|
|
284
|
-
* Map ZSH color code to chalk color
|
|
285
|
-
*/
|
|
286
|
-
mapColorToChalk(zshColor) {
|
|
287
|
-
// 256 color codes
|
|
288
|
-
const colorMap = {
|
|
289
|
-
'81': 'cyan',
|
|
290
|
-
'166': 'yellow',
|
|
291
|
-
'135': 'magenta',
|
|
292
|
-
'161': 'red',
|
|
293
|
-
'118': 'green',
|
|
294
|
-
'208': 'yellow',
|
|
295
|
-
'39': 'blue',
|
|
296
|
-
'214': 'yellow',
|
|
297
|
-
// Standard colors
|
|
298
|
-
'black': 'black',
|
|
299
|
-
'red': 'red',
|
|
300
|
-
'green': 'green',
|
|
301
|
-
'yellow': 'yellow',
|
|
302
|
-
'blue': 'blue',
|
|
303
|
-
'magenta': 'magenta',
|
|
304
|
-
'cyan': 'cyan',
|
|
305
|
-
'white': 'white',
|
|
306
|
-
};
|
|
307
|
-
const mapped = colorMap[zshColor] || 'white';
|
|
308
|
-
return `\\[\\033[${this.getAnsiCode(mapped)}m\\]`;
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Get ANSI code for color name
|
|
312
|
-
*/
|
|
313
|
-
getAnsiCode(color) {
|
|
314
|
-
const codes = {
|
|
315
|
-
'black': '30',
|
|
316
|
-
'red': '31',
|
|
317
|
-
'green': '32',
|
|
318
|
-
'yellow': '33',
|
|
319
|
-
'blue': '34',
|
|
320
|
-
'magenta': '35',
|
|
321
|
-
'cyan': '36',
|
|
322
|
-
'white': '37',
|
|
323
|
-
'reset': '0',
|
|
324
|
-
'bold': '1',
|
|
325
|
-
'dim': '2',
|
|
326
|
-
'italic': '3',
|
|
327
|
-
'underline': '4',
|
|
328
|
-
};
|
|
329
|
-
return codes[color] || '37';
|
|
330
|
-
}
|
|
331
|
-
/**
|
|
332
|
-
* Save theme in LSH format
|
|
333
|
-
*/
|
|
334
|
-
saveAsLshTheme(theme) {
|
|
335
|
-
try {
|
|
336
|
-
const lshThemePath = path.join(this.customThemesPath, `${theme.name}.lsh-theme`);
|
|
337
|
-
const lshThemeContent = {
|
|
338
|
-
name: theme.name,
|
|
339
|
-
prompts: {
|
|
340
|
-
left: theme.prompts.left,
|
|
341
|
-
right: theme.prompts.right,
|
|
342
|
-
continuation: theme.prompts.continuation,
|
|
343
|
-
select: theme.prompts.select,
|
|
344
|
-
},
|
|
345
|
-
colors: Object.fromEntries(theme.colors),
|
|
346
|
-
gitFormats: theme.gitFormats,
|
|
347
|
-
variables: Object.fromEntries(theme.variables),
|
|
348
|
-
hooks: theme.hooks,
|
|
349
|
-
dependencies: theme.dependencies,
|
|
350
|
-
};
|
|
351
|
-
fs.writeFileSync(lshThemePath, JSON.stringify(lshThemeContent, null, 2), 'utf8');
|
|
352
|
-
}
|
|
353
|
-
catch (error) {
|
|
354
|
-
// Gracefully handle save errors (e.g., permission issues, invalid paths)
|
|
355
|
-
console.error(`Failed to save theme ${theme.name}:`, error);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* Apply theme
|
|
360
|
-
*/
|
|
361
|
-
applyTheme(theme) {
|
|
362
|
-
this.currentTheme = theme;
|
|
363
|
-
// Generate prompt setting commands
|
|
364
|
-
const commands = [];
|
|
365
|
-
// Set main prompt
|
|
366
|
-
if (theme.prompts.left) {
|
|
367
|
-
const lshPrompt = this.convertPromptToLsh(theme.prompts.left, theme.colors);
|
|
368
|
-
commands.push(`export LSH_PROMPT='${lshPrompt}'`);
|
|
369
|
-
}
|
|
370
|
-
// Set right prompt
|
|
371
|
-
if (theme.prompts.right) {
|
|
372
|
-
const lshRPrompt = this.convertPromptToLsh(theme.prompts.right, theme.colors);
|
|
373
|
-
commands.push(`export LSH_RPROMPT='${lshRPrompt}'`);
|
|
374
|
-
}
|
|
375
|
-
return commands.join('\n');
|
|
376
|
-
}
|
|
377
|
-
/**
|
|
378
|
-
* Get built-in theme
|
|
379
|
-
*/
|
|
380
|
-
getBuiltinTheme(name) {
|
|
381
|
-
const themes = {
|
|
382
|
-
'default': {
|
|
383
|
-
name: 'default',
|
|
384
|
-
colors: new Map([['blue', '34'], ['green', '32'], ['reset', '0']]),
|
|
385
|
-
prompts: {
|
|
386
|
-
left: chalk.blue('%n@%m') + ':' + chalk.green('%~') + '$ ',
|
|
387
|
-
},
|
|
388
|
-
variables: new Map(),
|
|
389
|
-
hooks: [],
|
|
390
|
-
dependencies: [],
|
|
391
|
-
},
|
|
392
|
-
'minimal': {
|
|
393
|
-
name: 'minimal',
|
|
394
|
-
colors: new Map([['cyan', '36'], ['reset', '0']]),
|
|
395
|
-
prompts: {
|
|
396
|
-
left: chalk.cyan('%~') + ' ❯ ',
|
|
397
|
-
},
|
|
398
|
-
variables: new Map(),
|
|
399
|
-
hooks: [],
|
|
400
|
-
dependencies: [],
|
|
401
|
-
},
|
|
402
|
-
'powerline': {
|
|
403
|
-
name: 'powerline',
|
|
404
|
-
colors: new Map([
|
|
405
|
-
['blue', '34'],
|
|
406
|
-
['white', '37'],
|
|
407
|
-
['green', '32'],
|
|
408
|
-
['yellow', '33'],
|
|
409
|
-
]),
|
|
410
|
-
prompts: {
|
|
411
|
-
left: chalk.bgBlue.white(' %n ') + '' + chalk.bgGreen.black(' %~ ') + '' + ' ',
|
|
412
|
-
},
|
|
413
|
-
variables: new Map(),
|
|
414
|
-
hooks: [],
|
|
415
|
-
dependencies: ['git'],
|
|
416
|
-
},
|
|
417
|
-
'robbyrussell': {
|
|
418
|
-
name: 'robbyrussell',
|
|
419
|
-
colors: new Map([['cyan', '36'], ['red', '31'], ['green', '32']]),
|
|
420
|
-
prompts: {
|
|
421
|
-
left: chalk.cyan('➜ ') + chalk.cyan('%~') + ' $(git_prompt_info)',
|
|
422
|
-
},
|
|
423
|
-
gitFormats: {
|
|
424
|
-
branch: chalk.red(' git:') + chalk.green('(%b)'),
|
|
425
|
-
},
|
|
426
|
-
variables: new Map(),
|
|
427
|
-
hooks: [],
|
|
428
|
-
dependencies: ['git'],
|
|
429
|
-
},
|
|
430
|
-
'simple': {
|
|
431
|
-
name: 'simple',
|
|
432
|
-
colors: new Map([['reset', '0']]),
|
|
433
|
-
prompts: {
|
|
434
|
-
left: '%~ $ ',
|
|
435
|
-
},
|
|
436
|
-
variables: new Map(),
|
|
437
|
-
hooks: [],
|
|
438
|
-
dependencies: [],
|
|
439
|
-
},
|
|
440
|
-
};
|
|
441
|
-
if (!themes[name]) {
|
|
442
|
-
throw new Error(`Theme not found: ${name}`);
|
|
443
|
-
}
|
|
444
|
-
return themes[name];
|
|
445
|
-
}
|
|
446
|
-
/**
|
|
447
|
-
* Preview theme without applying
|
|
448
|
-
*/
|
|
449
|
-
previewTheme(theme) {
|
|
450
|
-
console.log(chalk.bold(`\n📦 Theme: ${theme.name}\n`));
|
|
451
|
-
// Show prompt
|
|
452
|
-
console.log(chalk.dim('Prompt:'));
|
|
453
|
-
const examplePrompt = this.convertPromptToLsh(theme.prompts.left, theme.colors)
|
|
454
|
-
.replace('$(pwd | sed "s|^$HOME|~|")', '~/projects/my-app')
|
|
455
|
-
.replace('$(git_prompt_info)', ' git:(main)');
|
|
456
|
-
console.log(' ' + examplePrompt);
|
|
457
|
-
if (theme.prompts.right) {
|
|
458
|
-
console.log(chalk.dim('\nRight Prompt:'));
|
|
459
|
-
console.log(' ' + this.convertPromptToLsh(theme.prompts.right, theme.colors));
|
|
460
|
-
}
|
|
461
|
-
// Show colors
|
|
462
|
-
if (theme.colors.size > 0) {
|
|
463
|
-
console.log(chalk.dim('\nColors:'));
|
|
464
|
-
for (const [name, code] of theme.colors.entries()) {
|
|
465
|
-
const color = this.mapColorToChalk(code);
|
|
466
|
-
console.log(` ${name}: ${color}${name}${chalk.reset('')}`);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
// Show dependencies
|
|
470
|
-
if (theme.dependencies.length > 0) {
|
|
471
|
-
console.log(chalk.dim('\nDependencies:'));
|
|
472
|
-
theme.dependencies.forEach(dep => console.log(` - ${dep}`));
|
|
473
|
-
}
|
|
474
|
-
console.log('');
|
|
475
|
-
}
|
|
476
|
-
}
|