@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orxataguy/tyr",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "tyr": "./bin/tyr.js"
@@ -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
+ }