@nac3/forge-cli 1.24.0 → 1.25.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/dist/bin/yf.js +0 -0
- package/dist/chat/agent_session.d.ts.map +1 -1
- package/dist/chat/agent_session.js +132 -12
- package/dist/chat/agent_session.js.map +1 -1
- package/dist/chat/panel.d.ts.map +1 -1
- package/dist/chat/panel.js +31 -4
- package/dist/chat/panel.js.map +1 -1
- package/dist/chat/server.d.ts.map +1 -1
- package/dist/chat/server.js +29 -3
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/tools/keys.d.ts.map +1 -1
- package/dist/chat/tools/keys.js +22 -2
- package/dist/chat/tools/keys.js.map +1 -1
- package/dist/chat/tools/pending.d.ts +3 -0
- package/dist/chat/tools/pending.d.ts.map +1 -1
- package/dist/chat/tools/pending.js +40 -3
- package/dist/chat/tools/pending.js.map +1 -1
- package/dist/chat/tools/session_verbs.d.ts +81 -0
- package/dist/chat/tools/session_verbs.d.ts.map +1 -1
- package/dist/chat/tools/session_verbs.js +188 -18
- package/dist/chat/tools/session_verbs.js.map +1 -1
- package/dist/chat/tools/shell.d.ts.map +1 -1
- package/dist/chat/tools/shell.js +22 -0
- package/dist/chat/tools/shell.js.map +1 -1
- package/dist/commands/limits.d.ts.map +1 -1
- package/dist/commands/limits.js +9 -1
- package/dist/commands/limits.js.map +1 -1
- package/dist/commands/pending.d.ts.map +1 -1
- package/dist/commands/pending.js +26 -1
- package/dist/commands/pending.js.map +1 -1
- package/dist/commands/urazuke.d.ts.map +1 -1
- package/dist/commands/urazuke.js +82 -0
- package/dist/commands/urazuke.js.map +1 -1
- package/dist/core/battery_stamp.d.ts +26 -0
- package/dist/core/battery_stamp.d.ts.map +1 -1
- package/dist/core/battery_stamp.js +51 -1
- package/dist/core/battery_stamp.js.map +1 -1
- package/dist/core/ci_gaps.d.ts +2 -1
- package/dist/core/ci_gaps.d.ts.map +1 -1
- package/dist/core/ci_gaps.js +2 -1
- package/dist/core/ci_gaps.js.map +1 -1
- package/dist/core/hook_budget.d.ts +60 -0
- package/dist/core/hook_budget.d.ts.map +1 -0
- package/dist/core/hook_budget.js +163 -0
- package/dist/core/hook_budget.js.map +1 -0
- package/dist/core/limits_config.d.ts +50 -0
- package/dist/core/limits_config.d.ts.map +1 -1
- package/dist/core/limits_config.js +59 -0
- package/dist/core/limits_config.js.map +1 -1
- package/dist/core/provider_keys.d.ts +33 -0
- package/dist/core/provider_keys.d.ts.map +1 -1
- package/dist/core/provider_keys.js +40 -3
- package/dist/core/provider_keys.js.map +1 -1
- package/dist/docs/doctrine/session-orchestration.md +91 -86
- package/dist/llm/sse_stream.d.ts +3 -0
- package/dist/llm/sse_stream.d.ts.map +1 -1
- package/dist/llm/sse_stream.js +16 -2
- package/dist/llm/sse_stream.js.map +1 -1
- package/dist/mcp/bridge_registry.d.ts +1 -1
- package/dist/pending/store.d.ts +12 -0
- package/dist/pending/store.d.ts.map +1 -1
- package/dist/pending/store.js +20 -0
- package/dist/pending/store.js.map +1 -1
- package/dist/pending/types.d.ts +11 -0
- package/dist/pending/types.d.ts.map +1 -1
- package/dist/pending/types.js.map +1 -1
- package/dist/tasks/supervisor.d.ts +31 -0
- package/dist/tasks/supervisor.d.ts.map +1 -1
- package/dist/tasks/supervisor.js +61 -5
- package/dist/tasks/supervisor.js.map +1 -1
- package/dist/urazuke/close_gate.d.ts +47 -3
- package/dist/urazuke/close_gate.d.ts.map +1 -1
- package/dist/urazuke/close_gate.js +57 -3
- package/dist/urazuke/close_gate.js.map +1 -1
- package/dist/urazuke/evidence.d.ts +5 -0
- package/dist/urazuke/evidence.d.ts.map +1 -1
- package/dist/urazuke/evidence.js +61 -3
- package/dist/urazuke/evidence.js.map +1 -1
- package/dist/urazuke/external_audit.d.ts +89 -0
- package/dist/urazuke/external_audit.d.ts.map +1 -0
- package/dist/urazuke/external_audit.js +309 -0
- package/dist/urazuke/external_audit.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/doctrine/session-orchestration.md +91 -86
- package/package.json +26 -23
- package/src/i18n/catalogs/ar.json +570 -568
- package/src/i18n/catalogs/de.json +570 -568
- package/src/i18n/catalogs/en.json +570 -568
- package/src/i18n/catalogs/es.json +570 -568
- package/src/i18n/catalogs/fr.json +570 -568
- package/src/i18n/catalogs/hi.json +570 -568
- package/src/i18n/catalogs/it.json +570 -568
- package/src/i18n/catalogs/ja.json +570 -568
- package/src/i18n/catalogs/pt.json +570 -568
- package/src/i18n/catalogs/zh.json +570 -568
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external_audit.d.ts","sourceRoot":"","sources":["../../src/urazuke/external_audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAoBH,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,UAAU,EAAE,MAAM,CAAC;CACpB;AA8BD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,0BAA0B,CAAC,CAgGrC;AAED;;;8CAG8C;AAC9C,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBnF;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,OAAO,CAAC;IACZ,4DAA4D;IAC5D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,KAAK,EAAE,MAAM,CAAC;CACf;AAyBD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,0BAA0B,CAAC,CAoFrC"}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EL CAMINO DEL AUDITOR EXTERNO (PND-258, opcion b).
|
|
3
|
+
*
|
|
4
|
+
* El peldano 13 pide que la auditoria la haga OTRA sesion, idealmente otro
|
|
5
|
+
* modelo. Forge ya sabia dos cosas: armar la consigna (`buildAuditTask`) y
|
|
6
|
+
* lanzar una sub-sesion headless (`yf urazuke audit --spawn`). Lo que faltaba
|
|
7
|
+
* es el caso que el experimento A/B encontro a la mala: quien tiene el PLAN de
|
|
8
|
+
* Claude Code y no una clave de API NO PUEDE correr el peldano 13 con un
|
|
9
|
+
* cerebro Anthropic, aunque lo tenga pagado y corriendo en la misma maquina.
|
|
10
|
+
*
|
|
11
|
+
* El hard-codeo que lo impide esta BIEN PENSADO y no se deshace: el hijo se
|
|
12
|
+
* fuerza al camino HTTP para que su alcance acotado de verbos sea real, y un
|
|
13
|
+
* subproceso del CLI trae sus propias herramientas y no pasa por nac3_invoke.
|
|
14
|
+
* Lo que estaba mal era la consecuencia: no habia NINGUN otro camino, asi que
|
|
15
|
+
* en el experimento esa auditoria hubo que armarla a mano.
|
|
16
|
+
*
|
|
17
|
+
* Entonces: el producto prepara la consigna Y EL ESPACIO DE SALIDA, el dueno
|
|
18
|
+
* lanza la sesion independiente con el cerebro que quiera -- Claude Code con
|
|
19
|
+
* su Plan, otra marca, una sesion web --, y el producto RECIBE el informe y lo
|
|
20
|
+
* evalua. Dos funciones, dos comandos, y la consigna en un archivo en vez de
|
|
21
|
+
* en la pantalla de una terminal.
|
|
22
|
+
*
|
|
23
|
+
* LA OPCION (a) QUEDA ESCRITA COMO LA EVOLUCION SIGUIENTE, con su fundamento:
|
|
24
|
+
* una sub-sesion de SOLO LECTURA podria usar el Plan, porque si el hijo no
|
|
25
|
+
* puede escribir, la razon para acotarlo por nac3_invoke se debilita mucho --
|
|
26
|
+
* el alcance ya no lo daria el dispatcher sino la ausencia de permisos de
|
|
27
|
+
* escritura. No se hace hoy porque cambia el modelo de alcance de las
|
|
28
|
+
* sub-sesiones, que es una decision de producto propia y merece su terna de
|
|
29
|
+
* recibos.
|
|
30
|
+
*
|
|
31
|
+
* ASCII-only.
|
|
32
|
+
*/
|
|
33
|
+
import { promises as fs } from 'node:fs';
|
|
34
|
+
import path from 'node:path';
|
|
35
|
+
import { URAZUKE_STEPS } from './catalog.js';
|
|
36
|
+
/** El peldano por defecto: 13, la auditoria periodica. */
|
|
37
|
+
const DEFAULT_STEP = 13;
|
|
38
|
+
/** El minimo del informe cuando el catalogo no lo declara. Un esbozo no es
|
|
39
|
+
* una auditoria, y 200 es el default del evaluador de artefactos: el numero
|
|
40
|
+
* tiene que ser EL MISMO en las dos puertas o el dueno recibe dos respuestas
|
|
41
|
+
* distintas sobre el mismo archivo. */
|
|
42
|
+
const MIN_REPORT_BYTES_DEFAULT = 200;
|
|
43
|
+
/** El respaldo de la regla de autoria, si el catalogo no la declarara. Es la
|
|
44
|
+
* MISMA expresion que el peldano 13 lleva en su artefacto; vive aca solo para
|
|
45
|
+
* que la funcion no se quede sin regla, nunca para reemplazarla. */
|
|
46
|
+
const AUTHOR_LINE_FALLBACK = '^\\s*\\**\\s*auditor\\s*\\**\\s*:';
|
|
47
|
+
function today() {
|
|
48
|
+
return new Date().toISOString().slice(0, 10);
|
|
49
|
+
}
|
|
50
|
+
function toPosix(p) {
|
|
51
|
+
return p.split(path.sep).join('/');
|
|
52
|
+
}
|
|
53
|
+
/** La regla que Forge VA A APLICAR sobre el informe, leida del catalogo y no
|
|
54
|
+
* copiada: si manana el peldano exige otra cosa, la consigna lo dice sola.
|
|
55
|
+
* Esto es lo que evita que la consigna y el evaluador se desincronicen -- el
|
|
56
|
+
* defecto que este lote vio cuatro veces en cuatro lugares distintos. */
|
|
57
|
+
function auditArtifactRule(step) {
|
|
58
|
+
const def = URAZUKE_STEPS.find((s) => s.num === step);
|
|
59
|
+
const art = def?.artifacts?.find((a) => /AUDIT/i.test(a.path)) ?? def?.artifacts?.[0];
|
|
60
|
+
return {
|
|
61
|
+
glob: art?.path ?? 'docs/AUDIT_*.md',
|
|
62
|
+
should: [...(art?.should_contain ?? [])],
|
|
63
|
+
must: [...(art?.must_contain ?? [])],
|
|
64
|
+
...(art?.fresh_days !== undefined ? { fresh_days: art.fresh_days } : {}),
|
|
65
|
+
min_bytes: art?.min_bytes ?? MIN_REPORT_BYTES_DEFAULT,
|
|
66
|
+
verify: [...(def?.verify ?? [])],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Prepara la consigna y el espacio de salida. No lanza nada: lanzar es del
|
|
71
|
+
* dueno, que es justamente el punto de este camino.
|
|
72
|
+
*/
|
|
73
|
+
export async function prepareExternalAudit(input) {
|
|
74
|
+
const step = input.step ?? DEFAULT_STEP;
|
|
75
|
+
const root = input.projectRoot;
|
|
76
|
+
const date = today();
|
|
77
|
+
const rule = auditArtifactRule(step);
|
|
78
|
+
const reportPath = path.join(root, 'docs', 'AUDIT_' + date + '.md');
|
|
79
|
+
const reportRel = toPosix(path.relative(root, reportPath));
|
|
80
|
+
/* El espacio de salida existe ANTES de que el auditor arranque: una consigna
|
|
81
|
+
* que manda escribir en un directorio que no esta hace que la sesion gaste
|
|
82
|
+
* su primer turno creandolo, o que falle al final con todo el trabajo hecho
|
|
83
|
+
* (paso en el experimento: un pase murio justo al ir a escribir y se
|
|
84
|
+
* perdieron 400 mil tokens ya verificados). */
|
|
85
|
+
await fs.mkdir(path.dirname(reportPath), { recursive: true });
|
|
86
|
+
/* La consigna NO se escribe en docs/: el peldano 13 busca docs/AUDIT_*.md y
|
|
87
|
+
* un brief ahi adentro se haria pasar por el informe. Un falso verde por el
|
|
88
|
+
* nombre de un archivo es exactamente la clase de cero que este lote vino a
|
|
89
|
+
* sacar. */
|
|
90
|
+
const briefDir = path.join(root, '.forge', 'urazuke');
|
|
91
|
+
await fs.mkdir(briefDir, { recursive: true });
|
|
92
|
+
const briefPath = path.join(briefDir, 'audit-brief-' + date + '.md');
|
|
93
|
+
/* La consigna sale de buildAuditTask, que es la que ya usa
|
|
94
|
+
* `yf urazuke audit`. Un segundo texto de auditoria seria una segunda
|
|
95
|
+
* fuente de verdad sobre lo mismo. */
|
|
96
|
+
const { buildAuditTask } = await import('./retro.js');
|
|
97
|
+
const task = await buildAuditTask(root);
|
|
98
|
+
const lines = [];
|
|
99
|
+
lines.push('# Consigna de auditoria externa -- peldano ' + step);
|
|
100
|
+
lines.push('');
|
|
101
|
+
lines.push('Proyecto: ' + input.slug);
|
|
102
|
+
lines.push('Raiz: ' + root);
|
|
103
|
+
lines.push('Preparada: ' + date);
|
|
104
|
+
lines.push('');
|
|
105
|
+
lines.push('## Como se usa');
|
|
106
|
+
lines.push('');
|
|
107
|
+
lines.push('Esta consigna es para una sesion INDEPENDIENTE, con el cerebro que vos');
|
|
108
|
+
lines.push('quieras: Claude Code con tu Plan, otra marca, una sesion web. No hace');
|
|
109
|
+
lines.push('falta una clave de API, y no hace falta que sea una sub-sesion de Forge.');
|
|
110
|
+
lines.push('El peldano pide una sesion distinta de la que construye; de que');
|
|
111
|
+
lines.push('proveedor sea es tu decision, no una consecuencia de como esta cableado');
|
|
112
|
+
lines.push('el producto.');
|
|
113
|
+
lines.push('');
|
|
114
|
+
lines.push('Pasos:');
|
|
115
|
+
lines.push('');
|
|
116
|
+
lines.push('1. Abri la sesion que elijas, en la raiz del proyecto.');
|
|
117
|
+
lines.push('2. Pegale el bloque "Consigna" de abajo, tal cual.');
|
|
118
|
+
lines.push('3. Cuando termine, volve aca y corre:');
|
|
119
|
+
lines.push('');
|
|
120
|
+
lines.push(' yf urazuke audit-receive --project ' + input.slug);
|
|
121
|
+
lines.push('');
|
|
122
|
+
lines.push(' Forge lee el informe, verifica lo que se puede verificar, y te dice');
|
|
123
|
+
lines.push(' que falta antes de que el peldano lo acepte.');
|
|
124
|
+
lines.push('');
|
|
125
|
+
lines.push('## Donde va el informe');
|
|
126
|
+
lines.push('');
|
|
127
|
+
lines.push(' ' + reportRel);
|
|
128
|
+
lines.push('');
|
|
129
|
+
lines.push('Esa ruta no es decorativa: el peldano ' + step + ' busca `' + rule.glob + '`'
|
|
130
|
+
+ (rule.fresh_days ? ' y exige que el mas nuevo tenga menos de ' + rule.fresh_days + ' dias' : '')
|
|
131
|
+
+ '.');
|
|
132
|
+
lines.push('');
|
|
133
|
+
lines.push('## Lo que Forge va a verificar del informe');
|
|
134
|
+
lines.push('');
|
|
135
|
+
lines.push('- Que exista en esa ruta y que no sea un esbozo (minimo '
|
|
136
|
+
+ rule.min_bytes + ' bytes).');
|
|
137
|
+
lines.push('- Que declare QUIEN lo escribio, en una linea propia:');
|
|
138
|
+
lines.push('');
|
|
139
|
+
lines.push(' Auditor: <la sesion y el modelo que hizo esta auditoria>');
|
|
140
|
+
lines.push('');
|
|
141
|
+
lines.push(' Sin esa linea Forge no puede distinguir una auditoria externa de un');
|
|
142
|
+
lines.push(' informe escrito por la misma sesion que construyo el codigo (D-040),');
|
|
143
|
+
lines.push(' y el peldano no lo acepta como evidencia.');
|
|
144
|
+
lines.push('- Cuantos hallazgos trae y con que prioridad, contando las lineas');
|
|
145
|
+
lines.push(' marcadas P0 / P1 / P2. Si el informe no usa esas marcas, Forge lo dice');
|
|
146
|
+
lines.push(' en vez de estimar.');
|
|
147
|
+
if (rule.verify.length) {
|
|
148
|
+
lines.push('');
|
|
149
|
+
lines.push('Y estas son las preguntas que el peldano hace sobre el resultado, que');
|
|
150
|
+
lines.push('las contesta el dueno y no la herramienta:');
|
|
151
|
+
lines.push('');
|
|
152
|
+
for (const q of rule.verify)
|
|
153
|
+
lines.push('- ' + q);
|
|
154
|
+
}
|
|
155
|
+
lines.push('');
|
|
156
|
+
lines.push('## Consigna');
|
|
157
|
+
lines.push('');
|
|
158
|
+
lines.push(task);
|
|
159
|
+
lines.push('');
|
|
160
|
+
const consigna = lines.join('\n');
|
|
161
|
+
await fs.writeFile(briefPath, consigna, 'utf8');
|
|
162
|
+
return { brief_path: briefPath, report_path: reportPath, consigna, report_rel: reportRel };
|
|
163
|
+
}
|
|
164
|
+
/** El informe de auditoria MAS NUEVO del proyecto, o null si no hay ninguno.
|
|
165
|
+
* El peldano busca por glob y se queda con el mas reciente; esta funcion
|
|
166
|
+
* resuelve lo mismo para que `audit-receive` sin argumentos lea el archivo
|
|
167
|
+
* que el evaluador va a mirar, y no otro. */
|
|
168
|
+
export async function newestAuditReport(projectRoot) {
|
|
169
|
+
const dir = path.join(projectRoot, 'docs');
|
|
170
|
+
let names = [];
|
|
171
|
+
try {
|
|
172
|
+
names = (await fs.readdir(dir)).filter((n) => /^AUDIT_.*\.md$/i.test(n));
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
if (!names.length)
|
|
178
|
+
return null;
|
|
179
|
+
const stamped = [];
|
|
180
|
+
for (const n of names) {
|
|
181
|
+
const full = path.join(dir, n);
|
|
182
|
+
try {
|
|
183
|
+
const st = await fs.stat(full);
|
|
184
|
+
stamped.push({ p: full, at: st.mtimeMs });
|
|
185
|
+
}
|
|
186
|
+
catch { /* desaparecio entre el readdir y el stat */ }
|
|
187
|
+
}
|
|
188
|
+
if (!stamped.length)
|
|
189
|
+
return null;
|
|
190
|
+
stamped.sort((a, b) => b.at - a.at);
|
|
191
|
+
return stamped[0].p;
|
|
192
|
+
}
|
|
193
|
+
/** Cuantos hallazgos trae y con que prioridad. Cuenta por LINEA con una marca
|
|
194
|
+
* de prioridad, que es la forma que la consigna pide; no intenta entender
|
|
195
|
+
* prosa. Lo que no se puede contar con certeza se informa como cero Y SE
|
|
196
|
+
* DICE, en vez de estimarse: un numero inventado sobre una auditoria es peor
|
|
197
|
+
* que no tener el numero. */
|
|
198
|
+
function countFindings(body) {
|
|
199
|
+
const by = { p0: 0, p1: 0, p2: 0 };
|
|
200
|
+
let findings = 0;
|
|
201
|
+
for (const raw of body.split(/\r?\n/)) {
|
|
202
|
+
const line = raw.trim();
|
|
203
|
+
if (!line)
|
|
204
|
+
continue;
|
|
205
|
+
/* Un titulo de seccion ("## Hallazgos P0") no es un hallazgo. */
|
|
206
|
+
if (/^#{1,6}\s/.test(line))
|
|
207
|
+
continue;
|
|
208
|
+
const m = /\bP([012])\b/.exec(line);
|
|
209
|
+
if (!m)
|
|
210
|
+
continue;
|
|
211
|
+
findings += 1;
|
|
212
|
+
if (m[1] === '0')
|
|
213
|
+
by.p0 += 1;
|
|
214
|
+
else if (m[1] === '1')
|
|
215
|
+
by.p1 += 1;
|
|
216
|
+
else
|
|
217
|
+
by.p2 += 1;
|
|
218
|
+
}
|
|
219
|
+
return { findings, by };
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Recibe el informe del auditor externo y lo evalua con lo que se puede
|
|
223
|
+
* verificar mecanicamente. Lo que no se puede verificar queda como aviso CON
|
|
224
|
+
* SU NOMBRE: un informe admisible no significa que la auditoria sea buena,
|
|
225
|
+
* significa que sirve como evidencia del peldano. Decir mas que eso seria
|
|
226
|
+
* exactamente el cero que este lote vino a sacar.
|
|
227
|
+
*/
|
|
228
|
+
export async function receiveExternalAudit(input) {
|
|
229
|
+
const missing = [];
|
|
230
|
+
const warnings = [];
|
|
231
|
+
const rel = toPosix(path.relative(input.projectRoot, input.report_path)) || input.report_path;
|
|
232
|
+
let body = '';
|
|
233
|
+
try {
|
|
234
|
+
body = await fs.readFile(input.report_path, 'utf8');
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
return {
|
|
238
|
+
ok: false, auditor: null,
|
|
239
|
+
missing: ['el informe no esta en ' + rel + ': la sesion de auditoria no lo escribio,'
|
|
240
|
+
+ ' o lo dejo en otra ruta'],
|
|
241
|
+
warnings: [], findings: 0, by_priority: { p0: 0, p1: 0, p2: 0 }, bytes: 0,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const bytes = Buffer.byteLength(body, 'utf8');
|
|
245
|
+
const rule = auditArtifactRule(DEFAULT_STEP);
|
|
246
|
+
/* LA LINEA DE AUTORIA, con la MISMA expresion que el evaluador del peldano.
|
|
247
|
+
* Si aca se aceptara algo que el evaluador despues rechaza, el dueno tendria
|
|
248
|
+
* dos respuestas distintas sobre el mismo archivo -- que es el defecto de
|
|
249
|
+
* familia de este lote entero. */
|
|
250
|
+
/* POR LINEA, y no sobre el cuerpo entero. La expresion del catalogo lleva
|
|
251
|
+
* `\\s*` despues del `^`, y `\\s` incluye el salto de linea: aplicada al cuerpo
|
|
252
|
+
* con 'm' engancha en la linea VACIA anterior y se come el salto, asi que
|
|
253
|
+
* extraer 'la linea del match' devolvia la vacia. Escanear linea por linea
|
|
254
|
+
* es ademas lo que 'una linea propia' quiere decir. */
|
|
255
|
+
let auditor = null;
|
|
256
|
+
const sources = (rule.should.length ? rule.should : [AUTHOR_LINE_FALLBACK])
|
|
257
|
+
.map((src) => new RegExp(src, 'i'));
|
|
258
|
+
for (const raw of body.split(/\r?\n/)) {
|
|
259
|
+
const line = raw.trim();
|
|
260
|
+
if (!line)
|
|
261
|
+
continue;
|
|
262
|
+
if (!sources.some((re) => re.test(line)))
|
|
263
|
+
continue;
|
|
264
|
+
auditor = line;
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
if (!auditor) {
|
|
268
|
+
missing.push('el informe no dice QUIEN lo escribio. Falta una linea propia'
|
|
269
|
+
+ ' "Auditor: <la sesion y el modelo>" -- sin eso no se puede distinguir una auditoria'
|
|
270
|
+
+ ' externa de un informe de la misma sesion que construyo el codigo (D-040), y el'
|
|
271
|
+
+ ' peldano no lo puede aceptar como evidencia');
|
|
272
|
+
}
|
|
273
|
+
if (bytes < rule.min_bytes) {
|
|
274
|
+
missing.push('el informe tiene ' + bytes + ' bytes y el minimo es ' + rule.min_bytes
|
|
275
|
+
+ ': lo que hay es un esbozo, no una auditoria');
|
|
276
|
+
}
|
|
277
|
+
for (const src of rule.must) {
|
|
278
|
+
if (!new RegExp(src, 'i').test(body)) {
|
|
279
|
+
missing.push('el informe no contiene lo que el peldano exige (expresion /' + src + '/i)');
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const { findings, by } = countFindings(body);
|
|
283
|
+
if (findings === 0) {
|
|
284
|
+
warnings.push('no encontre ninguna linea con prioridad P0 / P1 / P2. O la auditoria no hallo'
|
|
285
|
+
+ ' nada -- que es un resultado, pero conviene que lo diga con esas palabras -- o no uso el'
|
|
286
|
+
+ ' formato que la consigna pide, y entonces no puedo contar sus hallazgos');
|
|
287
|
+
}
|
|
288
|
+
if (by.p0 + by.p1 > 0) {
|
|
289
|
+
warnings.push('hay ' + (by.p0 + by.p1) + ' hallazgo(s) P0/P1: el peldano pide UN pendiente por'
|
|
290
|
+
+ ' cada uno, citando el hallazgo. Eso no lo verifico yo -- lo contesta el dueno');
|
|
291
|
+
}
|
|
292
|
+
/* La tercera pregunta del peldano: que la auditoria vuelva a correr una
|
|
293
|
+
* muestra de los recibos de rojo. No se puede verificar leyendo el informe,
|
|
294
|
+
* pero SI se puede ver si lo menciona, y decirlo es mas util que callarlo. */
|
|
295
|
+
if (!/recibo|receipt|red_proof|rojo/i.test(body)) {
|
|
296
|
+
warnings.push('el informe no menciona los recibos. El peldano pregunta si la auditoria volvio'
|
|
297
|
+
+ ' a correr una muestra de los rojos; si no lo hizo, eso tambien es parte del resultado');
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
ok: missing.length === 0,
|
|
301
|
+
auditor,
|
|
302
|
+
missing,
|
|
303
|
+
warnings,
|
|
304
|
+
findings,
|
|
305
|
+
by_priority: by,
|
|
306
|
+
bytes,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
//# sourceMappingURL=external_audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external_audit.js","sourceRoot":"","sources":["../../src/urazuke/external_audit.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Yujin Forge CLI version. Kept in sync with package.json by the npm
|
|
3
3
|
* "version" lifecycle (scripts/sync_version.mjs) so the two never drift.
|
|
4
4
|
*/
|
|
5
|
-
export declare const VERSION = "1.
|
|
5
|
+
export declare const VERSION = "1.25.0";
|
|
6
6
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
|
@@ -1,86 +1,91 @@
|
|
|
1
|
-
# Doctrine: session orchestration (yujin.session.*)
|
|
2
|
-
|
|
3
|
-
When it is optimal, you may launch other `yf chat` instances as
|
|
4
|
-
HEADLESS AGENT sub-sessions to do orthogonal, well-scoped work in
|
|
5
|
-
parallel with this conversation, and collect their results over the
|
|
6
|
-
coordination bridge. This is the `yujin.session.*` verb family.
|
|
7
|
-
|
|
8
|
-
This doctrine is about WHEN to spawn and how to keep it safe and
|
|
9
|
-
cheap. It is distinct from `agent-orchestrator` (product-side agents
|
|
10
|
-
the generated software dispatches on the user's machine).
|
|
11
|
-
|
|
12
|
-
## Off by default
|
|
13
|
-
|
|
14
|
-
The whole capability is gated by `multiagent.enabled` in the limits
|
|
15
|
-
config (Ajustes > Limites), DEFAULT OFF. While off, the
|
|
16
|
-
`yujin.session.*` verbs are hidden from the manifest, this doctrine is
|
|
17
|
-
not injected, the system prompt tells you it is OFF, and the handlers
|
|
18
|
-
refuse. So you only see + use these verbs when the user has explicitly
|
|
19
|
-
turned multi-agent on. If the user asks for parallel sub-sessions while
|
|
20
|
-
it is off, tell them to enable it in Ajustes > Limites.
|
|
21
|
-
|
|
22
|
-
## The verbs
|
|
23
|
-
|
|
24
|
-
- `yujin.session.spawn { task, project_root?, budget_tokens?, label? }`
|
|
25
|
-
-- launch a sub-session for one self-contained task. Returns a
|
|
26
|
-
handle immediately (NON-blocking). The user approves each spawn
|
|
27
|
-
(it spends BYOK tokens autonomously).
|
|
28
|
-
- `yujin.session.collect { handle?, wait_ms? }` -- read the results
|
|
29
|
-
sub-sessions have published. `wait_ms` blocks up to that long for
|
|
30
|
-
at least one result; default 0 = return whatever has arrived.
|
|
31
|
-
- `yujin.session.list` -- what you have spawned
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
1
|
+
# Doctrine: session orchestration (yujin.session.*)
|
|
2
|
+
|
|
3
|
+
When it is optimal, you may launch other `yf chat` instances as
|
|
4
|
+
HEADLESS AGENT sub-sessions to do orthogonal, well-scoped work in
|
|
5
|
+
parallel with this conversation, and collect their results over the
|
|
6
|
+
coordination bridge. This is the `yujin.session.*` verb family.
|
|
7
|
+
|
|
8
|
+
This doctrine is about WHEN to spawn and how to keep it safe and
|
|
9
|
+
cheap. It is distinct from `agent-orchestrator` (product-side agents
|
|
10
|
+
the generated software dispatches on the user's machine).
|
|
11
|
+
|
|
12
|
+
## Off by default
|
|
13
|
+
|
|
14
|
+
The whole capability is gated by `multiagent.enabled` in the limits
|
|
15
|
+
config (Ajustes > Limites), DEFAULT OFF. While off, the
|
|
16
|
+
`yujin.session.*` verbs are hidden from the manifest, this doctrine is
|
|
17
|
+
not injected, the system prompt tells you it is OFF, and the handlers
|
|
18
|
+
refuse. So you only see + use these verbs when the user has explicitly
|
|
19
|
+
turned multi-agent on. If the user asks for parallel sub-sessions while
|
|
20
|
+
it is off, tell them to enable it in Ajustes > Limites.
|
|
21
|
+
|
|
22
|
+
## The verbs
|
|
23
|
+
|
|
24
|
+
- `yujin.session.spawn { task, project_root?, budget_tokens?, label? }`
|
|
25
|
+
-- launch a sub-session for one self-contained task. Returns a
|
|
26
|
+
handle immediately (NON-blocking). The user approves each spawn
|
|
27
|
+
(it spends BYOK tokens autonomously).
|
|
28
|
+
- `yujin.session.collect { handle?, wait_ms? }` -- read the results
|
|
29
|
+
sub-sessions have published. `wait_ms` blocks up to that long for
|
|
30
|
+
at least one result; default 0 = return whatever has arrived.
|
|
31
|
+
- `yujin.session.list` -- what you have spawned, with TWO facts that are
|
|
32
|
+
not the same one (PND-256): `alive` is whether the process exists
|
|
33
|
+
(asked of the OS), and `registered` is whether the child already
|
|
34
|
+
published itself on the coordination bridge. A child can be alive and
|
|
35
|
+
not yet registered (booting), and a dead child can linger in the
|
|
36
|
+
roster. Reading one as the other costs either a needless relaunch or
|
|
37
|
+
an endless wait.
|
|
38
|
+
- `yujin.session.stop { handle }` -- terminate one.
|
|
39
|
+
|
|
40
|
+
## Spawn ONLY when it pays off
|
|
41
|
+
|
|
42
|
+
A sub-session boots a whole headless server and spends tokens, so the
|
|
43
|
+
overhead must be justified. Spawn when ALL of these hold:
|
|
44
|
+
|
|
45
|
+
1. **Orthogonal** -- the subtask is independent of the work you are
|
|
46
|
+
doing right now; it does not need the live conversation context.
|
|
47
|
+
(The child gets ONLY the `task` string you write -- be specific.)
|
|
48
|
+
2. **Parallelizable** -- it can run while you keep working, and you
|
|
49
|
+
genuinely benefit from not blocking on it (e.g. a wide read /
|
|
50
|
+
research / analysis sweep over a different subsystem).
|
|
51
|
+
3. **No write collision** -- it will not edit the same files you are
|
|
52
|
+
editing. If both might write, scope them to different paths or do
|
|
53
|
+
it yourself.
|
|
54
|
+
4. **Fits a budget** -- set `budget_tokens` to bound the spend.
|
|
55
|
+
|
|
56
|
+
Do NOT spawn for:
|
|
57
|
+
|
|
58
|
+
- Trivial tasks (a single read, a one-line answer) -- the overhead
|
|
59
|
+
costs more than doing it inline.
|
|
60
|
+
- Anything that needs the user's live judgement or the chat history.
|
|
61
|
+
- Work you could do with one of your own verbs in this turn.
|
|
62
|
+
|
|
63
|
+
Typical good uses: "map how subsystem X wires together and report the
|
|
64
|
+
key files + entry points", "search the whole repo for every place
|
|
65
|
+
pattern Y appears and summarise", "read these 8 docs and extract the
|
|
66
|
+
constraints". Launch one per independent angle, then `collect`.
|
|
67
|
+
|
|
68
|
+
## The child's scope (enforced, not advisory)
|
|
69
|
+
|
|
70
|
+
A sub-session runs with a RESTRICTED verb scope (enforced in
|
|
71
|
+
`nac3_invoke` via `YF_AGENT_MODE`):
|
|
72
|
+
|
|
73
|
+
- CAN: read / search / write files in its project root, run SAFE
|
|
74
|
+
shell, query the graph / pendings / reader.
|
|
75
|
+
- CANNOT: `git push` / `git commit`, destructive actions, `fs.move`,
|
|
76
|
+
re-anchor the project, mutate the workflow / pending / keys, run
|
|
77
|
+
lifecycle servers, or spawn its OWN sub-sessions (no grandchildren).
|
|
78
|
+
|
|
79
|
+
So the child is a safe builder/analyst. Anything outward or
|
|
80
|
+
irreversible stays with YOU, the parent, where the user can approve
|
|
81
|
+
it. Have the child RETURN its deliverable; you surface it (pizarron,
|
|
82
|
+
etc.) and you do the push/commit.
|
|
83
|
+
|
|
84
|
+
## Lifecycle
|
|
85
|
+
|
|
86
|
+
Sub-sessions are one-shot: a child runs its task to completion (a
|
|
87
|
+
`[SESSION_DONE]` marker), publishes its result, and exits. The full
|
|
88
|
+
result is written to disk; the bridge signal carries a summary + the
|
|
89
|
+
path. Always `collect` what you spawn -- do not leave results
|
|
90
|
+
unread. If a child is no longer useful or is burning budget, `stop`
|
|
91
|
+
it.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nac3/forge-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
4
|
"description": "Yujin Forge -- voice-first NAC-3 React development framework. CLI + chat panel + spec ingest + 10-format document reader + voice loop.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "Pablo Kuschnirof <pablo@rpaforce.com>",
|
|
@@ -15,6 +15,29 @@
|
|
|
15
15
|
"exports": {
|
|
16
16
|
".": "./dist/index.js"
|
|
17
17
|
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"version": "node scripts/sync_version.mjs && git add src/version.ts",
|
|
20
|
+
"build": "node scripts/clean_dist.mjs && tsc && node scripts/copy_qa_assets.mjs",
|
|
21
|
+
"dev": "tsx watch src/bin/yf.ts",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"typecheck:all": "pnpm typecheck && pnpm --filter @yujin/hito4-server typecheck && pnpm --filter @yujin/forge-mobile typecheck",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"lint": "tsc --noEmit",
|
|
27
|
+
"yf": "tsx src/bin/yf.ts",
|
|
28
|
+
"catalog:lint": "node scripts/catalog_lint.mjs",
|
|
29
|
+
"pairing:check": "node scripts/check_pairing_sync.mjs",
|
|
30
|
+
"brain-matrix:gate": "node scripts/brain_matrix_gate.mjs",
|
|
31
|
+
"hito4:lint": "node scripts/hito4_lint_bundle.mjs",
|
|
32
|
+
"docs:lint": "node scripts/doc_citations_lint.mjs",
|
|
33
|
+
"ascii:check": "node scripts/ascii_purity.mjs --push --survey",
|
|
34
|
+
"version:check": "node scripts/version_sync_check.mjs",
|
|
35
|
+
"battery:freshness": "node scripts/battery_freshness.mjs",
|
|
36
|
+
"hooks:install": "node scripts/install_hooks.mjs",
|
|
37
|
+
"publish-alpha-emergency": "node scripts/publish_alpha_emergency.mjs",
|
|
38
|
+
"prepublishOnly": "pnpm run build && pnpm run typecheck && pnpm run catalog:lint && pnpm run test && pnpm run brain-matrix:gate && pnpm run hito4:lint && node scripts/battery_freshness.mjs",
|
|
39
|
+
"prepare": "node scripts/install_hooks.mjs"
|
|
40
|
+
},
|
|
18
41
|
"dependencies": {
|
|
19
42
|
"@anthropic-ai/sdk": "^0.32.1",
|
|
20
43
|
"@aws-sdk/client-ecs": "^3.1053.0",
|
|
@@ -52,6 +75,7 @@
|
|
|
52
75
|
"node": ">=18.17",
|
|
53
76
|
"pnpm": ">=9"
|
|
54
77
|
},
|
|
78
|
+
"packageManager": "pnpm@11.3.0",
|
|
55
79
|
"files": [
|
|
56
80
|
"dist",
|
|
57
81
|
"templates",
|
|
@@ -96,26 +120,5 @@
|
|
|
96
120
|
"publishConfig": {
|
|
97
121
|
"access": "public",
|
|
98
122
|
"tag": "latest"
|
|
99
|
-
},
|
|
100
|
-
"scripts": {
|
|
101
|
-
"version": "node scripts/sync_version.mjs && git add src/version.ts",
|
|
102
|
-
"build": "node scripts/clean_dist.mjs && tsc && node scripts/copy_qa_assets.mjs",
|
|
103
|
-
"dev": "tsx watch src/bin/yf.ts",
|
|
104
|
-
"typecheck": "tsc --noEmit",
|
|
105
|
-
"typecheck:all": "pnpm typecheck && pnpm --filter @yujin/hito4-server typecheck && pnpm --filter @yujin/forge-mobile typecheck",
|
|
106
|
-
"test": "vitest run",
|
|
107
|
-
"test:watch": "vitest",
|
|
108
|
-
"lint": "tsc --noEmit",
|
|
109
|
-
"yf": "tsx src/bin/yf.ts",
|
|
110
|
-
"catalog:lint": "node scripts/catalog_lint.mjs",
|
|
111
|
-
"pairing:check": "node scripts/check_pairing_sync.mjs",
|
|
112
|
-
"brain-matrix:gate": "node scripts/brain_matrix_gate.mjs",
|
|
113
|
-
"hito4:lint": "node scripts/hito4_lint_bundle.mjs",
|
|
114
|
-
"docs:lint": "node scripts/doc_citations_lint.mjs",
|
|
115
|
-
"ascii:check": "node scripts/ascii_purity.mjs --push --survey",
|
|
116
|
-
"version:check": "node scripts/version_sync_check.mjs",
|
|
117
|
-
"battery:freshness": "node scripts/battery_freshness.mjs",
|
|
118
|
-
"hooks:install": "node scripts/install_hooks.mjs",
|
|
119
|
-
"publish-alpha-emergency": "node scripts/publish_alpha_emergency.mjs"
|
|
120
123
|
}
|
|
121
|
-
}
|
|
124
|
+
}
|