@pasosdejesus/mpdj 0.1.0
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/LICENSE.md +16 -0
- package/SKILL.md +310 -0
- package/dist/SKILL.md +310 -0
- package/dist/abis/PasosDeJesusCredentials.json +1342 -0
- package/dist/blockchain/AddSlearnButton.d.ts +5 -0
- package/dist/blockchain/AddSlearnButton.js +58 -0
- package/dist/blockchain/SlearnInfo.d.ts +22 -0
- package/dist/blockchain/SlearnInfo.js +68 -0
- package/dist/blockchain/admin-credentials.d.ts +29 -0
- package/dist/blockchain/admin-credentials.js +91 -0
- package/dist/blockchain/credential-cache.d.ts +33 -0
- package/dist/blockchain/credential-cache.js +129 -0
- package/dist/blockchain/credential-images.d.ts +30 -0
- package/dist/blockchain/credential-images.js +199 -0
- package/dist/blockchain/credentials.d.ts +66 -0
- package/dist/blockchain/credentials.js +128 -0
- package/dist/blockchain/ecosystem-addresses.d.ts +9 -0
- package/dist/blockchain/ecosystem-addresses.js +23 -0
- package/dist/blockchain/index.d.ts +6 -0
- package/dist/blockchain/index.js +12 -0
- package/dist/ia/adJ.md +181 -0
- package/dist/ia/alineacion_bayes_general.md +60 -0
- package/dist/ia/alineacion_bayes_profecia_mayor20G.md +220 -0
- package/dist/ia/alineacion_servicio.md +49 -0
- package/dist/ia/alineacion_testimonios.md +268 -0
- package/dist/ia/construir_en_adJ_y_celo.md +239 -0
- package/dist/ia/entrenamiento-marcos.jsonl +23 -0
- package/dist/ia/entrenamiento-no-adivinar.jsonl +15 -0
- package/dist/ia/estilo_entrenamiento.jsonl +10 -0
- package/dist/ia/indice_entrenamiento.json +43 -0
- package/dist/ia/m.jsonl +3 -0
- package/dist/ia/manifiesto.md +45 -0
- package/dist/ia/piedra_fundamental/README.md +31 -0
- package/dist/ia/piedra_fundamental/marcos-01.usfm +68 -0
- package/dist/ia/piedra_fundamental/marcos-02.usfm +46 -0
- package/dist/ia/piedra_fundamental/marcos-03.usfm +48 -0
- package/dist/ia/piedra_fundamental/marcos-04.usfm +59 -0
- package/dist/ia/piedra_fundamental/marcos-05.usfm +65 -0
- package/dist/ia/piedra_fundamental/marcos-06.usfm +78 -0
- package/dist/ia/piedra_fundamental/marcos-07.usfm +53 -0
- package/dist/ia/piedra_fundamental/marcos-08.usfm +63 -0
- package/dist/ia/piedra_fundamental/marcos-09.usfm +82 -0
- package/dist/ia/piedra_fundamental/marcos-10.usfm +88 -0
- package/dist/ia/piedra_fundamental/marcos-11.usfm +52 -0
- package/dist/ia/piedra_fundamental/marcos-12.usfm +62 -0
- package/dist/ia/piedra_fundamental/marcos-13.usfm +48 -0
- package/dist/ia/piedra_fundamental/marcos-14.usfm +108 -0
- package/dist/ia/piedra_fundamental/marcos-15.usfm +70 -0
- package/dist/ia/piedra_fundamental/marcos-16.usfm +32 -0
- package/dist/ia/principles.md +35 -0
- package/dist/ia/referencia-marcos.md +152 -0
- package/dist/ia/verificacion_cristologica.json +128 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +159 -0
- package/dist/tasks/adJ.d.ts +1 -0
- package/dist/tasks/adJ.js +37 -0
- package/dist/tasks/ai-verify-core.d.ts +27 -0
- package/dist/tasks/ai-verify-core.js +82 -0
- package/dist/tasks/ai.d.ts +3 -0
- package/dist/tasks/ai.js +96 -0
- package/dist/tasks/credentials.d.ts +4 -0
- package/dist/tasks/credentials.js +627 -0
- package/dist/tasks/principles.d.ts +1 -0
- package/dist/tasks/principles.js +37 -0
- package/dist/tasks/req.d.ts +9 -0
- package/dist/tasks/req.js +1164 -0
- package/dist/tasks/skill.d.ts +1 -0
- package/dist/tasks/skill.js +34 -0
- package/dist/test-utils/blockchain-mocks.d.ts +130 -0
- package/dist/test-utils/blockchain-mocks.js +112 -0
- package/ia/adJ.md +181 -0
- package/ia/alineacion_bayes_general.md +60 -0
- package/ia/alineacion_bayes_profecia_mayor20G.md +220 -0
- package/ia/alineacion_servicio.md +49 -0
- package/ia/alineacion_testimonios.md +268 -0
- package/ia/construir_en_adJ_y_celo.md +239 -0
- package/ia/entrenamiento-marcos.jsonl +23 -0
- package/ia/entrenamiento-no-adivinar.jsonl +15 -0
- package/ia/estilo_entrenamiento.jsonl +10 -0
- package/ia/indice_entrenamiento.json +43 -0
- package/ia/m.jsonl +3 -0
- package/ia/manifiesto.md +45 -0
- package/ia/piedra_fundamental/README.md +31 -0
- package/ia/piedra_fundamental/marcos-01.usfm +68 -0
- package/ia/piedra_fundamental/marcos-02.usfm +46 -0
- package/ia/piedra_fundamental/marcos-03.usfm +48 -0
- package/ia/piedra_fundamental/marcos-04.usfm +59 -0
- package/ia/piedra_fundamental/marcos-05.usfm +65 -0
- package/ia/piedra_fundamental/marcos-06.usfm +78 -0
- package/ia/piedra_fundamental/marcos-07.usfm +53 -0
- package/ia/piedra_fundamental/marcos-08.usfm +63 -0
- package/ia/piedra_fundamental/marcos-09.usfm +82 -0
- package/ia/piedra_fundamental/marcos-10.usfm +88 -0
- package/ia/piedra_fundamental/marcos-11.usfm +52 -0
- package/ia/piedra_fundamental/marcos-12.usfm +62 -0
- package/ia/piedra_fundamental/marcos-13.usfm +48 -0
- package/ia/piedra_fundamental/marcos-14.usfm +108 -0
- package/ia/piedra_fundamental/marcos-15.usfm +70 -0
- package/ia/piedra_fundamental/marcos-16.usfm +32 -0
- package/ia/principles.md +35 -0
- package/ia/referencia-marcos.md +152 -0
- package/ia/verificacion_cristologica.json +128 -0
- package/package.json +73 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { registerCommands } from '@pasosdejesus/m/plugin';
|
|
2
|
+
import { runAiFramework, runAiVerifyQuestion, runAiVerifyAnswer } from './tasks/ai.js';
|
|
3
|
+
import { runAiPrinciples } from './tasks/principles.js';
|
|
4
|
+
import { runAiSkill } from './tasks/skill.js';
|
|
5
|
+
import { runAiAdJ } from './tasks/adJ.js';
|
|
6
|
+
import { runReqList, runReqShow, runReqCross, runReqCompare, runReqSyncFromRepo, runReqSyncToRepo, runReqListRepo, runReqCreate, runReqClose } from './tasks/req.js';
|
|
7
|
+
import { runCredentials, deploymentsExist, hasAdminKey } from './tasks/credentials.js';
|
|
8
|
+
const commands = {
|
|
9
|
+
'ai:framework': {
|
|
10
|
+
handler: (output) => runAiFramework(output),
|
|
11
|
+
description: 'Shows a manifest of christian alignment (randomly chosen)',
|
|
12
|
+
argOptional: true,
|
|
13
|
+
argName: 'output'
|
|
14
|
+
},
|
|
15
|
+
'ai:verify': {
|
|
16
|
+
handler: runAiVerifyQuestion,
|
|
17
|
+
description: 'Generates a christological verification question'
|
|
18
|
+
},
|
|
19
|
+
'ai:verify:answer': {
|
|
20
|
+
handler: async (arg) => { await runAiVerifyAnswer(arg || ''); },
|
|
21
|
+
description: 'Responds to the christological verification question',
|
|
22
|
+
argRequired: true,
|
|
23
|
+
argName: 'answer'
|
|
24
|
+
},
|
|
25
|
+
'ai:principles': {
|
|
26
|
+
handler: async () => { await runAiPrinciples(); },
|
|
27
|
+
description: 'Shows the 4 guiding principles of the project'
|
|
28
|
+
},
|
|
29
|
+
'ai:skill': {
|
|
30
|
+
handler: async () => { await runAiSkill(); },
|
|
31
|
+
description: 'Shows SKILL.md and copies it to the clipboard'
|
|
32
|
+
},
|
|
33
|
+
'ai:adJ': {
|
|
34
|
+
handler: async () => { await runAiAdJ(); },
|
|
35
|
+
description: 'Shows OpenBSD/adJ platform tips for AI agents'
|
|
36
|
+
},
|
|
37
|
+
'req:list': {
|
|
38
|
+
handler: async () => { await runReqList(); },
|
|
39
|
+
description: 'Lists requirements from REQ/ with status and cross-project'
|
|
40
|
+
},
|
|
41
|
+
'req:show': {
|
|
42
|
+
handler: (n) => {
|
|
43
|
+
const num = parseInt(n || '', 10);
|
|
44
|
+
if (isNaN(num))
|
|
45
|
+
throw new Error('req:show <N>');
|
|
46
|
+
return runReqShow(num);
|
|
47
|
+
},
|
|
48
|
+
description: 'Shows a requirement from REQ/',
|
|
49
|
+
argRequired: true,
|
|
50
|
+
argName: 'N'
|
|
51
|
+
},
|
|
52
|
+
'req:cross': {
|
|
53
|
+
handler: async () => { await runReqCross(); },
|
|
54
|
+
description: 'Lists requirements with cross-project impact'
|
|
55
|
+
},
|
|
56
|
+
'req:compare': {
|
|
57
|
+
handler: (n) => {
|
|
58
|
+
if (!n)
|
|
59
|
+
return runReqCompare();
|
|
60
|
+
const num = parseInt(n, 10);
|
|
61
|
+
if (isNaN(num))
|
|
62
|
+
throw new Error('req:compare [N]');
|
|
63
|
+
return runReqCompare(num);
|
|
64
|
+
},
|
|
65
|
+
description: 'Compares local REQ with remote issue',
|
|
66
|
+
argOptional: true,
|
|
67
|
+
argName: 'N'
|
|
68
|
+
},
|
|
69
|
+
'req:sync-from-repo': {
|
|
70
|
+
handler: (n) => {
|
|
71
|
+
if (!n)
|
|
72
|
+
throw new Error('req:sync-from-repo <N> [N2 ...]');
|
|
73
|
+
return runReqSyncFromRepo([n, ...process.argv.slice(3)].join(' '));
|
|
74
|
+
},
|
|
75
|
+
description: 'Updates local REQ from remote issue',
|
|
76
|
+
argRequired: true,
|
|
77
|
+
argName: 'N'
|
|
78
|
+
},
|
|
79
|
+
'req:sync-to-repo': {
|
|
80
|
+
handler: (n) => {
|
|
81
|
+
if (!n)
|
|
82
|
+
throw new Error('req:sync-to-repo <N> [N2 ...]');
|
|
83
|
+
return runReqSyncToRepo([n, ...process.argv.slice(3)].join(' '));
|
|
84
|
+
},
|
|
85
|
+
description: 'Updates remote issue from local REQ',
|
|
86
|
+
argRequired: true,
|
|
87
|
+
argName: 'N'
|
|
88
|
+
},
|
|
89
|
+
'req:list-repo': {
|
|
90
|
+
handler: () => runReqListRepo(),
|
|
91
|
+
description: 'Lists open issues from the remote repository'
|
|
92
|
+
},
|
|
93
|
+
'req:create': {
|
|
94
|
+
handler: () => {
|
|
95
|
+
const args = process.argv.slice(3);
|
|
96
|
+
return runReqCreate(args[0], args[1]);
|
|
97
|
+
},
|
|
98
|
+
description: 'Creates a new remote issue and local REQ',
|
|
99
|
+
argRequired: true,
|
|
100
|
+
argName: 'title'
|
|
101
|
+
},
|
|
102
|
+
'req:close': {
|
|
103
|
+
handler: (n) => {
|
|
104
|
+
const num = parseInt(n || '', 10);
|
|
105
|
+
if (isNaN(num))
|
|
106
|
+
throw new Error('req:close <N>');
|
|
107
|
+
return runReqClose(num);
|
|
108
|
+
},
|
|
109
|
+
description: 'Closes a requirement',
|
|
110
|
+
argRequired: true,
|
|
111
|
+
argName: 'N'
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
// Register credential commands conditionally
|
|
115
|
+
if (deploymentsExist()) {
|
|
116
|
+
commands['eng:credentials:list-types'] = {
|
|
117
|
+
handler: async () => { await runCredentials(['list-types', ...process.argv.slice(3)]); },
|
|
118
|
+
description: 'List credential types from contract'
|
|
119
|
+
};
|
|
120
|
+
commands['eng:credentials:mint'] = {
|
|
121
|
+
handler: async () => { await runCredentials(['mint', ...process.argv.slice(3)]); },
|
|
122
|
+
description: 'Mint a credential to a wallet'
|
|
123
|
+
};
|
|
124
|
+
commands['eng:credentials:register-type'] = {
|
|
125
|
+
handler: async () => { await runCredentials(['register-type', ...process.argv.slice(3)]); },
|
|
126
|
+
description: 'Register a new credential type'
|
|
127
|
+
};
|
|
128
|
+
commands['eng:credentials:recompose-image'] = {
|
|
129
|
+
handler: async () => { await runCredentials(['recompose-image', ...process.argv.slice(3)]); },
|
|
130
|
+
description: 'Recompose credential image from cache'
|
|
131
|
+
};
|
|
132
|
+
commands['eng:credentials:set-max-supply'] = {
|
|
133
|
+
handler: async () => { await runCredentials(['set-max-supply', ...process.argv.slice(3)]); },
|
|
134
|
+
description: 'Set max supply for a credential type'
|
|
135
|
+
};
|
|
136
|
+
commands['eng:credentials:sync-cache'] = {
|
|
137
|
+
handler: async () => { await runCredentials(['sync-cache', ...process.argv.slice(3)]); },
|
|
138
|
+
description: 'Sync credential_metadata cache from contract'
|
|
139
|
+
};
|
|
140
|
+
commands['eng:credentials:revoke-credential'] = {
|
|
141
|
+
handler: async () => { await runCredentials(['revoke-credential', ...process.argv.slice(3)]); },
|
|
142
|
+
description: 'Revoke a credential from a wallet'
|
|
143
|
+
};
|
|
144
|
+
if (hasAdminKey()) {
|
|
145
|
+
commands['eng:credentials:grant-minter'] = {
|
|
146
|
+
handler: async () => { await runCredentials(['grant-minter', ...process.argv.slice(3)]); },
|
|
147
|
+
description: 'Grant MINTER_ROLE to a wallet'
|
|
148
|
+
};
|
|
149
|
+
commands['eng:credentials:revoke-minter'] = {
|
|
150
|
+
handler: async () => { await runCredentials(['revoke-minter', ...process.argv.slice(3)]); },
|
|
151
|
+
description: 'Revoke MINTER_ROLE from a wallet'
|
|
152
|
+
};
|
|
153
|
+
commands['eng:credentials:set-site-uri'] = {
|
|
154
|
+
handler: async () => { await runCredentials(['set-site-uri', ...process.argv.slice(3)]); },
|
|
155
|
+
description: 'Set base URI for a site'
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
registerCommands(commands);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runAiAdJ(): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { findIaDir } from '@pasosdejesus/m/dist/tasks/util.js';
|
|
4
|
+
import { success, problem } from '@pasosdejesus/m/dist/util/colors.js';
|
|
5
|
+
import { setClipboard } from '@pasosdejesus/m/dist/tasks/edit.js';
|
|
6
|
+
import { createTranslator } from '@pasosdejesus/m/dist/i18n/createTranslator.js';
|
|
7
|
+
import { detectLocale } from '@pasosdejesus/m/dist/util/locale.js';
|
|
8
|
+
import commonCli from '@pasosdejesus/m/dist/i18n/common-cli.js';
|
|
9
|
+
const t = createTranslator(detectLocale(), {
|
|
10
|
+
en: {
|
|
11
|
+
'adJ.no_ia_dir': 'ia/ directory not found in the project.',
|
|
12
|
+
'adJ.read_error': 'Error reading ia/adJ.md',
|
|
13
|
+
'adJ.copied': '📋 adJ.md copied to clipboard ({{0}}KB)',
|
|
14
|
+
},
|
|
15
|
+
es: {
|
|
16
|
+
'adJ.no_ia_dir': 'No se encontró ia/ en el proyecto.',
|
|
17
|
+
'adJ.read_error': 'Error al leer ia/adJ.md',
|
|
18
|
+
'adJ.copied': '📋 adJ.md copiado al portapapeles ({{0}}KB)',
|
|
19
|
+
},
|
|
20
|
+
}, commonCli);
|
|
21
|
+
export async function runAiAdJ() {
|
|
22
|
+
const iaDir = await findIaDir();
|
|
23
|
+
if (!iaDir) {
|
|
24
|
+
problem(t('adJ.no_ia_dir'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const adJPath = join(iaDir, 'adJ.md');
|
|
28
|
+
try {
|
|
29
|
+
const content = await readFile(adJPath, 'utf-8');
|
|
30
|
+
console.log(content);
|
|
31
|
+
await setClipboard(content);
|
|
32
|
+
success(t('adJ.copied', Math.round(content.length / 1024).toString()));
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
problem(t('adJ.read_error'));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface VerificationResult {
|
|
2
|
+
passed: boolean;
|
|
3
|
+
question: string;
|
|
4
|
+
expectedAnswer: string;
|
|
5
|
+
reference: string;
|
|
6
|
+
userAnswer?: string;
|
|
7
|
+
explanation?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface AiVerifyCore {
|
|
10
|
+
generateQuestion(iaDir: string): Promise<{
|
|
11
|
+
question: string;
|
|
12
|
+
expectedAnswer: string;
|
|
13
|
+
reference: string;
|
|
14
|
+
mode: 'semantic' | 'christological';
|
|
15
|
+
}>;
|
|
16
|
+
evaluateAnswer(userAnswer: string, expectedAnswer: string): boolean;
|
|
17
|
+
getRandomVerse(iaDir: string): Promise<{
|
|
18
|
+
verse: string;
|
|
19
|
+
ref: string;
|
|
20
|
+
}>;
|
|
21
|
+
getRandomCristologicaQuestion(iaDir: string): Promise<{
|
|
22
|
+
pregunta: string;
|
|
23
|
+
respuesta_esperada: string;
|
|
24
|
+
referencia: string;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
export declare const aiVerifyCore: AiVerifyCore;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// src/tasks/ai-verify-core.ts
|
|
2
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
export const aiVerifyCore = {
|
|
5
|
+
async generateQuestion(iaDir) {
|
|
6
|
+
const mode = Math.random() < 0.5 ? 'semantic' : 'christological';
|
|
7
|
+
if (mode === 'semantic') {
|
|
8
|
+
const { verse, ref } = await this.getRandomVerse(iaDir);
|
|
9
|
+
return {
|
|
10
|
+
question: `¿Es "${verse}" semánticamente equivalente a ${ref} en el Textus Receptus?`,
|
|
11
|
+
expectedAnswer: 'SÍ',
|
|
12
|
+
reference: ref,
|
|
13
|
+
mode
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
const q = await this.getRandomCristologicaQuestion(iaDir);
|
|
18
|
+
return {
|
|
19
|
+
question: q.pregunta,
|
|
20
|
+
expectedAnswer: q.respuesta_esperada,
|
|
21
|
+
reference: q.referencia,
|
|
22
|
+
mode
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
evaluateAnswer(userAnswer, expectedAnswer) {
|
|
27
|
+
if (!userAnswer.trim())
|
|
28
|
+
return false;
|
|
29
|
+
const normalizarAAscii = (texto) => {
|
|
30
|
+
return texto
|
|
31
|
+
.normalize('NFD') // Separar caracteres base de diacríticos
|
|
32
|
+
.replace(/[\u0300-\u036f]/g, '') // Eliminar todos los diacríticos
|
|
33
|
+
.toUpperCase();
|
|
34
|
+
};
|
|
35
|
+
// Mapa de equivalencias para español (solo caracteres usados en español)
|
|
36
|
+
const equivalencias = {
|
|
37
|
+
'á': 'Á', 'é': 'É', 'í': 'Í', 'ó': 'Ó', 'ú': 'Ú', 'ü': 'Ü', 'ñ': 'Ñ'
|
|
38
|
+
};
|
|
39
|
+
const aMayusculasEspanol = (texto) => {
|
|
40
|
+
return texto.split('').map(char => {
|
|
41
|
+
// Si el carácter tiene equivalente especial en español
|
|
42
|
+
if (equivalencias[char]) {
|
|
43
|
+
return equivalencias[char];
|
|
44
|
+
}
|
|
45
|
+
// Para mayúsculas con tildes que ya están mayúsculas
|
|
46
|
+
const lower = char.toLowerCase();
|
|
47
|
+
if (equivalencias[lower]) {
|
|
48
|
+
return equivalencias[lower];
|
|
49
|
+
}
|
|
50
|
+
// Carácter normal
|
|
51
|
+
return char.toUpperCase();
|
|
52
|
+
}).join('');
|
|
53
|
+
};
|
|
54
|
+
const primeraPalabra = userAnswer.trim()
|
|
55
|
+
.split(/\s+/)[0]
|
|
56
|
+
.replace(/[.,;:!?¿¡]/g, '');
|
|
57
|
+
const primeraNorm = normalizarAAscii(primeraPalabra);
|
|
58
|
+
const expectedNorm = normalizarAAscii(expectedAnswer);
|
|
59
|
+
return primeraNorm === expectedNorm;
|
|
60
|
+
},
|
|
61
|
+
async getRandomVerse(iaDir) {
|
|
62
|
+
const piedraDir = join(iaDir, 'piedra_fundamental');
|
|
63
|
+
const files = (await readdir(piedraDir)).filter(f => f.endsWith('.usfm'));
|
|
64
|
+
const chosenFile = files[Math.floor(Math.random() * files.length)];
|
|
65
|
+
const content = await readFile(join(piedraDir, chosenFile), 'utf-8');
|
|
66
|
+
const verses = content.split('\\v ').slice(1);
|
|
67
|
+
const verse = verses[Math.floor(Math.random() * verses.length)].trim();
|
|
68
|
+
const verseNum = verse.match(/^\d+/)?.[0] || '?';
|
|
69
|
+
const ref = `${chosenFile.replace('.usfm', '').replace('marcos-', 'Marcos ')}:${verseNum}`;
|
|
70
|
+
return { verse: verse.split('\\')[0].trim(), ref };
|
|
71
|
+
},
|
|
72
|
+
async getRandomCristologicaQuestion(iaDir) {
|
|
73
|
+
const cristologicaPath = join(iaDir, 'verificacion_cristologica.json');
|
|
74
|
+
const data = JSON.parse(await readFile(cristologicaPath, 'utf-8'));
|
|
75
|
+
const q = data.preguntas[Math.floor(Math.random() * data.preguntas.length)];
|
|
76
|
+
return {
|
|
77
|
+
pregunta: q.pregunta,
|
|
78
|
+
respuesta_esperada: q.respuesta_esperada,
|
|
79
|
+
referencia: q.referencia,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
};
|
package/dist/tasks/ai.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { aiVerifyCore } from './ai-verify-core.js';
|
|
4
|
+
import { findIaDir } from '@pasosdejesus/m/dist/tasks/util.js';
|
|
5
|
+
import { createTranslator } from '@pasosdejesus/m/dist/i18n/createTranslator.js';
|
|
6
|
+
import { detectLocale } from '@pasosdejesus/m/dist/util/locale.js';
|
|
7
|
+
import commonCli from '@pasosdejesus/m/dist/i18n/common-cli.js';
|
|
8
|
+
import { info, problem, success } from '@pasosdejesus/m/dist/util/colors.js';
|
|
9
|
+
const aiT = createTranslator(detectLocale(), {
|
|
10
|
+
en: {
|
|
11
|
+
'ai.framework.no_files': 'No alignment files found in directory ia/. Create at least one file alineacion_*.md.',
|
|
12
|
+
'ai.framework.written': 'Alignment manifest written in: {{0}}',
|
|
13
|
+
'ai.verify.no_ia_dir': 'Directory ia/ not found in current project.',
|
|
14
|
+
'ai.verify.passed': 'Verification passed.',
|
|
15
|
+
'ai.verify.failed': 'Verification failure. Expected: {{0}}, Obtained: {{1}}.',
|
|
16
|
+
},
|
|
17
|
+
es: {
|
|
18
|
+
'ai.framework.no_files': 'No se encontraron archivos de alineación en el directorio ia/. Crea al menos un archivo alineacion_*.md.',
|
|
19
|
+
'ai.framework.written': 'Manifiesto de alineación escrito en: {{0}}',
|
|
20
|
+
'ai.verify.no_ia_dir': 'No se encontró el directorio ia/ en el proyecto actual.',
|
|
21
|
+
'ai.verify.passed': 'Verificación superada.',
|
|
22
|
+
'ai.verify.failed': 'Fallo de verificación. Esperado: {{0}}, Obtenido: {{1}}.',
|
|
23
|
+
},
|
|
24
|
+
}, commonCli);
|
|
25
|
+
export async function runAiFramework(outputFile) {
|
|
26
|
+
const iaDir = await findIaDir();
|
|
27
|
+
if (!iaDir) {
|
|
28
|
+
problem(aiT('ai.framework.no_files'));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const alignmentFiles = (await readdir(iaDir))
|
|
32
|
+
.filter(f => f.startsWith('alineacion_') && f.endsWith('.md'));
|
|
33
|
+
if (alignmentFiles.length === 0) {
|
|
34
|
+
problem(aiT('ai.framework.no_files'));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const chosen = alignmentFiles[Math.floor(Math.random() * alignmentFiles.length)];
|
|
38
|
+
const content = await readFile(join(iaDir, chosen), 'utf-8');
|
|
39
|
+
if (outputFile) {
|
|
40
|
+
await writeFile(outputFile, content);
|
|
41
|
+
success(aiT('ai.framework.written', outputFile));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.log(content);
|
|
45
|
+
const { setClipboard } = await import('@pasosdejesus/m/dist/tasks/edit.js');
|
|
46
|
+
await setClipboard(content);
|
|
47
|
+
success(`📋 Manifiesto copiado al portapapeles (${Math.round(content.length / 1024)}KB)`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function runAiVerifyQuestion() {
|
|
51
|
+
const iaDir = await findIaDir();
|
|
52
|
+
if (!iaDir) {
|
|
53
|
+
problem(aiT('ai.verify.no_ia_dir'));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const { question, expectedAnswer, reference } = await aiVerifyCore.generateQuestion(iaDir);
|
|
57
|
+
const qaPath = join(process.cwd(), 'most-recent-question.json');
|
|
58
|
+
await writeFile(qaPath, JSON.stringify({ question, expectedAnswer, reference }, null, 2));
|
|
59
|
+
success(`Pregunta guardada en ${qaPath}`);
|
|
60
|
+
info('=== Verificación de Alineación ===');
|
|
61
|
+
console.log(`\n${question}`);
|
|
62
|
+
console.log(`\nReferencia: ${reference}`);
|
|
63
|
+
console.log(`\nPara responder ejecuta: bin/m ai:verify:answer "SÍ, ..."\n`);
|
|
64
|
+
const { setClipboard } = await import('@pasosdejesus/m/dist/tasks/edit.js');
|
|
65
|
+
await setClipboard(question);
|
|
66
|
+
success('📋 Pregunta copiada al portapapeles');
|
|
67
|
+
}
|
|
68
|
+
export async function runAiVerifyAnswer(answer) {
|
|
69
|
+
const qaPath = join(process.cwd(), 'most-recent-question.json');
|
|
70
|
+
let qa;
|
|
71
|
+
try {
|
|
72
|
+
qa = JSON.parse(await readFile(qaPath, 'utf-8'));
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
problem('No se encontró most-recent-question.json. Ejecuta primero bin/m ai:verify:question');
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
if (!answer) {
|
|
79
|
+
problem('Debes proporcionar una respuesta como argumento');
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
const passed = aiVerifyCore.evaluateAnswer(answer, qa.expectedAnswer);
|
|
83
|
+
if (passed) {
|
|
84
|
+
success(aiT('ai.verify.passed'));
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const primeraPalabra = answer.split(/\s+/)[0].toUpperCase();
|
|
88
|
+
problem(aiT('ai.verify.failed', qa.expectedAnswer, primeraPalabra));
|
|
89
|
+
console.log(`\nExplicación proporcionada:\n${answer}\n`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
await writeFile(qaPath, '');
|
|
94
|
+
}
|
|
95
|
+
catch { }
|
|
96
|
+
}
|