@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.
Files changed (96) hide show
  1. package/dist/bin/yf.js +0 -0
  2. package/dist/chat/agent_session.d.ts.map +1 -1
  3. package/dist/chat/agent_session.js +132 -12
  4. package/dist/chat/agent_session.js.map +1 -1
  5. package/dist/chat/panel.d.ts.map +1 -1
  6. package/dist/chat/panel.js +31 -4
  7. package/dist/chat/panel.js.map +1 -1
  8. package/dist/chat/server.d.ts.map +1 -1
  9. package/dist/chat/server.js +29 -3
  10. package/dist/chat/server.js.map +1 -1
  11. package/dist/chat/tools/keys.d.ts.map +1 -1
  12. package/dist/chat/tools/keys.js +22 -2
  13. package/dist/chat/tools/keys.js.map +1 -1
  14. package/dist/chat/tools/pending.d.ts +3 -0
  15. package/dist/chat/tools/pending.d.ts.map +1 -1
  16. package/dist/chat/tools/pending.js +40 -3
  17. package/dist/chat/tools/pending.js.map +1 -1
  18. package/dist/chat/tools/session_verbs.d.ts +81 -0
  19. package/dist/chat/tools/session_verbs.d.ts.map +1 -1
  20. package/dist/chat/tools/session_verbs.js +188 -18
  21. package/dist/chat/tools/session_verbs.js.map +1 -1
  22. package/dist/chat/tools/shell.d.ts.map +1 -1
  23. package/dist/chat/tools/shell.js +22 -0
  24. package/dist/chat/tools/shell.js.map +1 -1
  25. package/dist/commands/limits.d.ts.map +1 -1
  26. package/dist/commands/limits.js +9 -1
  27. package/dist/commands/limits.js.map +1 -1
  28. package/dist/commands/pending.d.ts.map +1 -1
  29. package/dist/commands/pending.js +26 -1
  30. package/dist/commands/pending.js.map +1 -1
  31. package/dist/commands/urazuke.d.ts.map +1 -1
  32. package/dist/commands/urazuke.js +82 -0
  33. package/dist/commands/urazuke.js.map +1 -1
  34. package/dist/core/battery_stamp.d.ts +26 -0
  35. package/dist/core/battery_stamp.d.ts.map +1 -1
  36. package/dist/core/battery_stamp.js +51 -1
  37. package/dist/core/battery_stamp.js.map +1 -1
  38. package/dist/core/ci_gaps.d.ts +2 -1
  39. package/dist/core/ci_gaps.d.ts.map +1 -1
  40. package/dist/core/ci_gaps.js +2 -1
  41. package/dist/core/ci_gaps.js.map +1 -1
  42. package/dist/core/hook_budget.d.ts +60 -0
  43. package/dist/core/hook_budget.d.ts.map +1 -0
  44. package/dist/core/hook_budget.js +163 -0
  45. package/dist/core/hook_budget.js.map +1 -0
  46. package/dist/core/limits_config.d.ts +50 -0
  47. package/dist/core/limits_config.d.ts.map +1 -1
  48. package/dist/core/limits_config.js +59 -0
  49. package/dist/core/limits_config.js.map +1 -1
  50. package/dist/core/provider_keys.d.ts +33 -0
  51. package/dist/core/provider_keys.d.ts.map +1 -1
  52. package/dist/core/provider_keys.js +40 -3
  53. package/dist/core/provider_keys.js.map +1 -1
  54. package/dist/docs/doctrine/session-orchestration.md +91 -86
  55. package/dist/llm/sse_stream.d.ts +3 -0
  56. package/dist/llm/sse_stream.d.ts.map +1 -1
  57. package/dist/llm/sse_stream.js +16 -2
  58. package/dist/llm/sse_stream.js.map +1 -1
  59. package/dist/mcp/bridge_registry.d.ts +1 -1
  60. package/dist/pending/store.d.ts +12 -0
  61. package/dist/pending/store.d.ts.map +1 -1
  62. package/dist/pending/store.js +20 -0
  63. package/dist/pending/store.js.map +1 -1
  64. package/dist/pending/types.d.ts +11 -0
  65. package/dist/pending/types.d.ts.map +1 -1
  66. package/dist/pending/types.js.map +1 -1
  67. package/dist/tasks/supervisor.d.ts +31 -0
  68. package/dist/tasks/supervisor.d.ts.map +1 -1
  69. package/dist/tasks/supervisor.js +61 -5
  70. package/dist/tasks/supervisor.js.map +1 -1
  71. package/dist/urazuke/close_gate.d.ts +47 -3
  72. package/dist/urazuke/close_gate.d.ts.map +1 -1
  73. package/dist/urazuke/close_gate.js +57 -3
  74. package/dist/urazuke/close_gate.js.map +1 -1
  75. package/dist/urazuke/evidence.d.ts +5 -0
  76. package/dist/urazuke/evidence.d.ts.map +1 -1
  77. package/dist/urazuke/evidence.js +61 -3
  78. package/dist/urazuke/evidence.js.map +1 -1
  79. package/dist/urazuke/external_audit.d.ts +89 -0
  80. package/dist/urazuke/external_audit.d.ts.map +1 -0
  81. package/dist/urazuke/external_audit.js +309 -0
  82. package/dist/urazuke/external_audit.js.map +1 -0
  83. package/dist/version.d.ts +1 -1
  84. package/dist/version.js +1 -1
  85. package/docs/doctrine/session-orchestration.md +91 -86
  86. package/package.json +26 -23
  87. package/src/i18n/catalogs/ar.json +570 -568
  88. package/src/i18n/catalogs/de.json +570 -568
  89. package/src/i18n/catalogs/en.json +570 -568
  90. package/src/i18n/catalogs/es.json +570 -568
  91. package/src/i18n/catalogs/fr.json +570 -568
  92. package/src/i18n/catalogs/hi.json +570 -568
  93. package/src/i18n/catalogs/it.json +570 -568
  94. package/src/i18n/catalogs/ja.json +570 -568
  95. package/src/i18n/catalogs/pt.json +570 -568
  96. 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.24.0";
5
+ export declare const VERSION = "1.25.0";
6
6
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js 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 const VERSION = '1.24.0';
5
+ export const VERSION = '1.25.0';
6
6
  //# sourceMappingURL=version.js.map
@@ -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 + whether each is
32
- still alive.
33
- - `yujin.session.stop { handle }` -- terminate one.
34
-
35
- ## Spawn ONLY when it pays off
36
-
37
- A sub-session boots a whole headless server and spends tokens, so the
38
- overhead must be justified. Spawn when ALL of these hold:
39
-
40
- 1. **Orthogonal** -- the subtask is independent of the work you are
41
- doing right now; it does not need the live conversation context.
42
- (The child gets ONLY the `task` string you write -- be specific.)
43
- 2. **Parallelizable** -- it can run while you keep working, and you
44
- genuinely benefit from not blocking on it (e.g. a wide read /
45
- research / analysis sweep over a different subsystem).
46
- 3. **No write collision** -- it will not edit the same files you are
47
- editing. If both might write, scope them to different paths or do
48
- it yourself.
49
- 4. **Fits a budget** -- set `budget_tokens` to bound the spend.
50
-
51
- Do NOT spawn for:
52
-
53
- - Trivial tasks (a single read, a one-line answer) -- the overhead
54
- costs more than doing it inline.
55
- - Anything that needs the user's live judgement or the chat history.
56
- - Work you could do with one of your own verbs in this turn.
57
-
58
- Typical good uses: "map how subsystem X wires together and report the
59
- key files + entry points", "search the whole repo for every place
60
- pattern Y appears and summarise", "read these 8 docs and extract the
61
- constraints". Launch one per independent angle, then `collect`.
62
-
63
- ## The child's scope (enforced, not advisory)
64
-
65
- A sub-session runs with a RESTRICTED verb scope (enforced in
66
- `nac3_invoke` via `YF_AGENT_MODE`):
67
-
68
- - CAN: read / search / write files in its project root, run SAFE
69
- shell, query the graph / pendings / reader.
70
- - CANNOT: `git push` / `git commit`, destructive actions, `fs.move`,
71
- re-anchor the project, mutate the workflow / pending / keys, run
72
- lifecycle servers, or spawn its OWN sub-sessions (no grandchildren).
73
-
74
- So the child is a safe builder/analyst. Anything outward or
75
- irreversible stays with YOU, the parent, where the user can approve
76
- it. Have the child RETURN its deliverable; you surface it (pizarron,
77
- etc.) and you do the push/commit.
78
-
79
- ## Lifecycle
80
-
81
- Sub-sessions are one-shot: a child runs its task to completion (a
82
- `[SESSION_DONE]` marker), publishes its result, and exits. The full
83
- result is written to disk; the bridge signal carries a summary + the
84
- path. Always `collect` what you spawn -- do not leave results
85
- unread. If a child is no longer useful or is burning budget, `stop`
86
- it.
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.24.0",
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
+ }