@orxataguy/tyr 1.0.7 → 1.0.8
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/package.json +1 -1
- package/src/core/Kernel.ts +15 -0
- package/src/core/sys/help.ts +149 -0
package/package.json
CHANGED
package/src/core/Kernel.ts
CHANGED
|
@@ -11,6 +11,7 @@ import rem from './sys/rem';
|
|
|
11
11
|
import doc from './sys/doc';
|
|
12
12
|
import ai from './sys/ai';
|
|
13
13
|
import config from './sys/config';
|
|
14
|
+
import help from './sys/help';
|
|
14
15
|
|
|
15
16
|
import { TyrError } from './TyrError';
|
|
16
17
|
|
|
@@ -126,6 +127,20 @@ export class Kernel {
|
|
|
126
127
|
return;
|
|
127
128
|
}
|
|
128
129
|
|
|
130
|
+
// --help / -h: lista todos los comandos disponibles con su documentación
|
|
131
|
+
if (commandName === '--help' || commandName === '-h') {
|
|
132
|
+
const helpContext = {
|
|
133
|
+
...this.container.get(),
|
|
134
|
+
frameworkRoot: this.frameworkRoot,
|
|
135
|
+
userRoot: this.userRoot,
|
|
136
|
+
run: async () => {},
|
|
137
|
+
task: async <T>(_: string, action: () => Promise<T> | T) => action(),
|
|
138
|
+
fail: (msg: string) => { throw new Error(msg); },
|
|
139
|
+
} as any;
|
|
140
|
+
await help(helpContext)(args.slice(1));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
129
144
|
const runInternal = async (cmd: string, cmdArgs: string[] = []) => {
|
|
130
145
|
await this.handle([cmd, ...cmdArgs]);
|
|
131
146
|
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { TyrContext } from '../Kernel';
|
|
4
|
+
|
|
5
|
+
interface CommandDoc {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
usage: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Extrae el primer bloque JSDoc de un archivo .tyr.ts y lo parsea
|
|
13
|
+
* en descripción y ejemplos de uso.
|
|
14
|
+
*/
|
|
15
|
+
function parseCommandDoc(filePath: string): CommandDoc {
|
|
16
|
+
const fileName = path.basename(filePath, '.tyr.ts');
|
|
17
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
18
|
+
|
|
19
|
+
const match = content.match(/\/\*\*([\s\S]*?)\*\//);
|
|
20
|
+
if (!match) {
|
|
21
|
+
return { name: fileName, description: '', usage: '' };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Limpiar cada línea: eliminar el * inicial y espacios
|
|
25
|
+
const lines = match[1]
|
|
26
|
+
.split('\n')
|
|
27
|
+
.map(line => line.replace(/^\s*\*\s?/, '').trimEnd());
|
|
28
|
+
|
|
29
|
+
// Separar en descripción y bloque "Uso:"
|
|
30
|
+
const usoIndex = lines.findIndex(l => /^uso:/i.test(l.trim()));
|
|
31
|
+
|
|
32
|
+
let description = '';
|
|
33
|
+
let usage = '';
|
|
34
|
+
|
|
35
|
+
if (usoIndex !== -1) {
|
|
36
|
+
description = lines
|
|
37
|
+
.slice(0, usoIndex)
|
|
38
|
+
.filter(l => l.trim() !== '')
|
|
39
|
+
.join('\n')
|
|
40
|
+
.trim();
|
|
41
|
+
|
|
42
|
+
usage = lines
|
|
43
|
+
.slice(usoIndex + 1)
|
|
44
|
+
.filter(l => l.trim() !== '')
|
|
45
|
+
.map(l => l.trim())
|
|
46
|
+
.join('\n')
|
|
47
|
+
.trim();
|
|
48
|
+
} else {
|
|
49
|
+
description = lines.filter(l => l.trim() !== '').join('\n').trim();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { name: fileName, description, usage };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default function help({ userRoot }: TyrContext) {
|
|
56
|
+
return async (_args: string[]) => {
|
|
57
|
+
const commandsDir = path.join(userRoot, 'commands');
|
|
58
|
+
|
|
59
|
+
// ── ANSI ──────────────────────────────────────────────────────────
|
|
60
|
+
const reset = '\x1b[0m';
|
|
61
|
+
const bold = '\x1b[1m';
|
|
62
|
+
const dim = '\x1b[2m';
|
|
63
|
+
const cyan = '\x1b[36m';
|
|
64
|
+
const green = '\x1b[32m';
|
|
65
|
+
const yellow = '\x1b[33m';
|
|
66
|
+
const gray = '\x1b[90m';
|
|
67
|
+
const white = '\x1b[37m';
|
|
68
|
+
// ──────────────────────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
const separator = `${gray} ${'─'.repeat(50)}${reset}`;
|
|
71
|
+
|
|
72
|
+
console.log('');
|
|
73
|
+
console.log(` ${bold}${cyan}tyr${reset} ${white}Comandos disponibles${reset}`);
|
|
74
|
+
console.log(separator);
|
|
75
|
+
console.log('');
|
|
76
|
+
|
|
77
|
+
// Flags y comandos built-in del framework
|
|
78
|
+
const builtins = [
|
|
79
|
+
{ name: '--help', description: 'Muestra este listado de comandos.', usage: 'tyr --help' },
|
|
80
|
+
{ name: '--version', description: 'Muestra la versión instalada de tyr.', usage: 'tyr --version' },
|
|
81
|
+
{ name: '--config', description: 'Configura tyr por primera vez.', usage: 'tyr --config' },
|
|
82
|
+
{ name: '--update', description: 'Actualiza ~/.tyr desde el repositorio git.', usage: 'tyr --update' },
|
|
83
|
+
{ name: '--upgrade', description: 'Actualiza el paquete npm de tyr.', usage: 'tyr --upgrade' },
|
|
84
|
+
{ name: 'gen', description: 'Genera un nuevo comando a partir de una descripción con IA.', usage: 'tyr gen <nombre> "<descripción>"' },
|
|
85
|
+
{ name: 'doc', description: 'Levanta la documentación del framework en el navegador.', usage: 'tyr doc' },
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
console.log(` ${bold}${yellow}Framework${reset}`);
|
|
89
|
+
console.log('');
|
|
90
|
+
|
|
91
|
+
for (const cmd of builtins) {
|
|
92
|
+
console.log(` ${bold}${green}${cmd.name.padEnd(14)}${reset}${dim}${cmd.description}${reset}`);
|
|
93
|
+
console.log(` ${' '.repeat(14)}${gray}${cmd.usage}${reset}`);
|
|
94
|
+
console.log('');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Comandos de usuario en ~/.tyr/commands/
|
|
98
|
+
if (!fs.existsSync(commandsDir)) {
|
|
99
|
+
console.log(separator);
|
|
100
|
+
console.log(` ${yellow}No se encontró la carpeta de comandos: ${commandsDir}${reset}`);
|
|
101
|
+
console.log('');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const files = fs.readdirSync(commandsDir)
|
|
106
|
+
.filter(f => f.endsWith('.tyr.ts'))
|
|
107
|
+
.sort();
|
|
108
|
+
|
|
109
|
+
if (files.length === 0) {
|
|
110
|
+
console.log(separator);
|
|
111
|
+
console.log(` ${dim}No hay comandos en ${commandsDir}${reset}`);
|
|
112
|
+
console.log('');
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log(separator);
|
|
117
|
+
console.log('');
|
|
118
|
+
console.log(` ${bold}${yellow}Comandos de usuario${reset} ${gray}(~/.tyr/commands/)${reset}`);
|
|
119
|
+
console.log('');
|
|
120
|
+
|
|
121
|
+
for (const file of files) {
|
|
122
|
+
const doc = parseCommandDoc(path.join(commandsDir, file));
|
|
123
|
+
|
|
124
|
+
console.log(` ${bold}${green}${doc.name}${reset}`);
|
|
125
|
+
|
|
126
|
+
if (doc.description) {
|
|
127
|
+
for (const line of doc.description.split('\n')) {
|
|
128
|
+
console.log(` ${dim}${line}${reset}`);
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
console.log(` ${gray}Sin descripción${reset}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (doc.usage) {
|
|
135
|
+
console.log('');
|
|
136
|
+
console.log(` ${gray} Uso:${reset}`);
|
|
137
|
+
for (const line of doc.usage.split('\n')) {
|
|
138
|
+
console.log(` ${cyan} ${line}${reset}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
console.log('');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.log(separator);
|
|
146
|
+
console.log(` ${dim}Genera un comando nuevo con ${cyan}tyr gen <nombre> "<qué debe hacer>"${reset}`);
|
|
147
|
+
console.log('');
|
|
148
|
+
};
|
|
149
|
+
}
|