@nac3/forge-cli 1.23.7 → 1.24.1

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 (165) hide show
  1. package/dist/chat/claude.d.ts +8 -0
  2. package/dist/chat/claude.d.ts.map +1 -1
  3. package/dist/chat/claude.js.map +1 -1
  4. package/dist/chat/claude_cli.d.ts +23 -0
  5. package/dist/chat/claude_cli.d.ts.map +1 -1
  6. package/dist/chat/claude_cli.js +76 -2
  7. package/dist/chat/claude_cli.js.map +1 -1
  8. package/dist/chat/doctrine_digest.d.ts.map +1 -1
  9. package/dist/chat/doctrine_digest.js +2 -1
  10. package/dist/chat/doctrine_digest.js.map +1 -1
  11. package/dist/chat/server.d.ts.map +1 -1
  12. package/dist/chat/server.js +11 -0
  13. package/dist/chat/server.js.map +1 -1
  14. package/dist/chat/tools/pending.d.ts +11 -0
  15. package/dist/chat/tools/pending.d.ts.map +1 -1
  16. package/dist/chat/tools/pending.js +55 -8
  17. package/dist/chat/tools/pending.js.map +1 -1
  18. package/dist/chat/tools/shell.d.ts +39 -4
  19. package/dist/chat/tools/shell.d.ts.map +1 -1
  20. package/dist/chat/tools/shell.js +167 -7
  21. package/dist/chat/tools/shell.js.map +1 -1
  22. package/dist/chat/tools/urazuke.d.ts.map +1 -1
  23. package/dist/chat/tools/urazuke.js +8 -5
  24. package/dist/chat/tools/urazuke.js.map +1 -1
  25. package/dist/chat/urazuke_section.d.ts +26 -4
  26. package/dist/chat/urazuke_section.d.ts.map +1 -1
  27. package/dist/chat/urazuke_section.js +115 -9
  28. package/dist/chat/urazuke_section.js.map +1 -1
  29. package/dist/commands/pending.d.ts.map +1 -1
  30. package/dist/commands/pending.js +116 -12
  31. package/dist/commands/pending.js.map +1 -1
  32. package/dist/commands/urazuke.d.ts +3 -0
  33. package/dist/commands/urazuke.d.ts.map +1 -1
  34. package/dist/commands/urazuke.js +80 -3
  35. package/dist/commands/urazuke.js.map +1 -1
  36. package/dist/core/ascii_purity.d.ts +69 -0
  37. package/dist/core/ascii_purity.d.ts.map +1 -0
  38. package/dist/core/ascii_purity.js +141 -0
  39. package/dist/core/ascii_purity.js.map +1 -0
  40. package/dist/core/battery_stamp.d.ts +111 -0
  41. package/dist/core/battery_stamp.d.ts.map +1 -0
  42. package/dist/core/battery_stamp.js +287 -0
  43. package/dist/core/battery_stamp.js.map +1 -0
  44. package/dist/core/ci_gaps.d.ts +130 -0
  45. package/dist/core/ci_gaps.d.ts.map +1 -0
  46. package/dist/core/ci_gaps.js +353 -0
  47. package/dist/core/ci_gaps.js.map +1 -0
  48. package/dist/core/doc_citations.d.ts +133 -0
  49. package/dist/core/doc_citations.d.ts.map +1 -0
  50. package/dist/core/doc_citations.js +271 -0
  51. package/dist/core/doc_citations.js.map +1 -0
  52. package/dist/core/hook_budget.d.ts +60 -0
  53. package/dist/core/hook_budget.d.ts.map +1 -0
  54. package/dist/core/hook_budget.js +163 -0
  55. package/dist/core/hook_budget.js.map +1 -0
  56. package/dist/docs/doctrine/urazuke.md +173 -2
  57. package/dist/nac3/internal_manifest.d.ts.map +1 -1
  58. package/dist/nac3/internal_manifest.js +28 -2
  59. package/dist/nac3/internal_manifest.js.map +1 -1
  60. package/dist/pending/store.d.ts +29 -0
  61. package/dist/pending/store.d.ts.map +1 -1
  62. package/dist/pending/store.js +51 -1
  63. package/dist/pending/store.js.map +1 -1
  64. package/dist/pending/types.d.ts +23 -0
  65. package/dist/pending/types.d.ts.map +1 -1
  66. package/dist/pending/types.js.map +1 -1
  67. package/dist/telemetry/usage.d.ts +18 -0
  68. package/dist/telemetry/usage.d.ts.map +1 -1
  69. package/dist/telemetry/usage.js +16 -1
  70. package/dist/telemetry/usage.js.map +1 -1
  71. package/dist/urazuke/announce.d.ts +7 -0
  72. package/dist/urazuke/announce.d.ts.map +1 -1
  73. package/dist/urazuke/announce.js +20 -0
  74. package/dist/urazuke/announce.js.map +1 -1
  75. package/dist/urazuke/catalog.d.ts +1 -1
  76. package/dist/urazuke/catalog.d.ts.map +1 -1
  77. package/dist/urazuke/catalog.js.map +1 -1
  78. package/dist/urazuke/close_gate.d.ts +31 -4
  79. package/dist/urazuke/close_gate.d.ts.map +1 -1
  80. package/dist/urazuke/close_gate.js +70 -13
  81. package/dist/urazuke/close_gate.js.map +1 -1
  82. package/dist/urazuke/current.d.ts +28 -0
  83. package/dist/urazuke/current.d.ts.map +1 -1
  84. package/dist/urazuke/current.js +18 -5
  85. package/dist/urazuke/current.js.map +1 -1
  86. package/dist/urazuke/cycle.d.ts +3 -0
  87. package/dist/urazuke/cycle.d.ts.map +1 -1
  88. package/dist/urazuke/cycle.js +5 -3
  89. package/dist/urazuke/cycle.js.map +1 -1
  90. package/dist/urazuke/evidence.d.ts +14 -1
  91. package/dist/urazuke/evidence.d.ts.map +1 -1
  92. package/dist/urazuke/evidence.js +88 -2
  93. package/dist/urazuke/evidence.js.map +1 -1
  94. package/dist/urazuke/evidence_env.d.ts +78 -0
  95. package/dist/urazuke/evidence_env.d.ts.map +1 -0
  96. package/dist/urazuke/evidence_env.js +341 -0
  97. package/dist/urazuke/evidence_env.js.map +1 -0
  98. package/dist/urazuke/freeze.d.ts.map +1 -1
  99. package/dist/urazuke/freeze.js +16 -9
  100. package/dist/urazuke/freeze.js.map +1 -1
  101. package/dist/urazuke/gate.d.ts +48 -0
  102. package/dist/urazuke/gate.d.ts.map +1 -1
  103. package/dist/urazuke/gate.js +251 -25
  104. package/dist/urazuke/gate.js.map +1 -1
  105. package/dist/urazuke/gates_data.d.ts +30 -3
  106. package/dist/urazuke/gates_data.d.ts.map +1 -1
  107. package/dist/urazuke/gates_data.js +51 -5
  108. package/dist/urazuke/gates_data.js.map +1 -1
  109. package/dist/urazuke/gates_pull.d.ts +40 -0
  110. package/dist/urazuke/gates_pull.d.ts.map +1 -1
  111. package/dist/urazuke/gates_pull.js +118 -8
  112. package/dist/urazuke/gates_pull.js.map +1 -1
  113. package/dist/urazuke/manual_cases.d.ts +11 -1
  114. package/dist/urazuke/manual_cases.d.ts.map +1 -1
  115. package/dist/urazuke/manual_cases.js +1 -0
  116. package/dist/urazuke/manual_cases.js.map +1 -1
  117. package/dist/urazuke/overrides.d.ts +107 -0
  118. package/dist/urazuke/overrides.d.ts.map +1 -0
  119. package/dist/urazuke/overrides.js +128 -0
  120. package/dist/urazuke/overrides.js.map +1 -0
  121. package/dist/urazuke/probes.d.ts.map +1 -1
  122. package/dist/urazuke/probes.js +51 -0
  123. package/dist/urazuke/probes.js.map +1 -1
  124. package/dist/urazuke/profiles.d.ts +135 -0
  125. package/dist/urazuke/profiles.d.ts.map +1 -0
  126. package/dist/urazuke/profiles.js +470 -0
  127. package/dist/urazuke/profiles.js.map +1 -0
  128. package/dist/urazuke/receipt_audit.d.ts +67 -0
  129. package/dist/urazuke/receipt_audit.d.ts.map +1 -0
  130. package/dist/urazuke/receipt_audit.js +103 -0
  131. package/dist/urazuke/receipt_audit.js.map +1 -0
  132. package/dist/urazuke/receipts.d.ts +22 -0
  133. package/dist/urazuke/receipts.d.ts.map +1 -1
  134. package/dist/urazuke/receipts.js +44 -0
  135. package/dist/urazuke/receipts.js.map +1 -1
  136. package/dist/urazuke/report.d.ts +30 -0
  137. package/dist/urazuke/report.d.ts.map +1 -1
  138. package/dist/urazuke/report.js +39 -0
  139. package/dist/urazuke/report.js.map +1 -1
  140. package/dist/urazuke/reset.d.ts +35 -0
  141. package/dist/urazuke/reset.d.ts.map +1 -0
  142. package/dist/urazuke/reset.js +150 -0
  143. package/dist/urazuke/reset.js.map +1 -0
  144. package/dist/urazuke/retro.d.ts +5 -1
  145. package/dist/urazuke/retro.d.ts.map +1 -1
  146. package/dist/urazuke/retro.js +21 -8
  147. package/dist/urazuke/retro.js.map +1 -1
  148. package/dist/urazuke/section.d.ts.map +1 -1
  149. package/dist/urazuke/section.js +17 -2
  150. package/dist/urazuke/section.js.map +1 -1
  151. package/dist/urazuke/semantics.d.ts +173 -0
  152. package/dist/urazuke/semantics.d.ts.map +1 -0
  153. package/dist/urazuke/semantics.js +232 -0
  154. package/dist/urazuke/semantics.js.map +1 -0
  155. package/dist/urazuke/start.d.ts +8 -0
  156. package/dist/urazuke/start.d.ts.map +1 -1
  157. package/dist/urazuke/start.js +10 -2
  158. package/dist/urazuke/start.js.map +1 -1
  159. package/dist/version.d.ts +1 -1
  160. package/dist/version.js +1 -1
  161. package/dist/workflow/orchestrator.d.ts.map +1 -1
  162. package/dist/workflow/orchestrator.js +6 -7
  163. package/dist/workflow/orchestrator.js.map +1 -1
  164. package/docs/doctrine/urazuke.md +173 -2
  165. package/package.json +9 -2
@@ -0,0 +1,271 @@
1
+ /**
2
+ * LAS CITAS A LA NADA -- la compuerta que el dueno pidio (2026-11-01).
3
+ *
4
+ * EL DEFECTO, en sus palabras: "un documento que afirma una compuerta con
5
+ * confianza es mas convincente que uno que falta. La ausencia se nota; la
6
+ * afirmacion falsa no." Van tres citas a la nada medidas en dos lotes
7
+ * -- `docs/PROGRAMMING_NORMS.md` citado por `.github/workflows/ci.yml` cinco
8
+ * meses sin existir, cuatro jobs y dos crons descritos en
9
+ * `docs/CI_PIPELINE.md` que nunca existieron, y un comentario de
10
+ * `.github/workflows/ci.yml` al que remitia `CLAUDE.md` -- y las tres
11
+ * describian compuertas. Esta compuerta cierra la familia: todo archivo de
12
+ * este repositorio citado en un documento VIGENTE tiene que existir.
13
+ *
14
+ * POR QUE EL DETECTOR ES CONSERVADOR. Una compuerta ruidosa se desactiva, y
15
+ * un gancho desactivado es peor que ninguno porque figura como existente
16
+ * (el mismo argumento con el que el dueno acoto F-15). Asi que esto NO
17
+ * intenta encontrar toda cita: encuentra las que son inequivocamente una
18
+ * afirmacion sobre ESTE repositorio HOY. Las reglas, en orden:
19
+ *
20
+ * 1. Los bloques de codigo cercados no se miran. Un `ls docs/FOO.md` de
21
+ * ejemplo no es una afirmacion sobre el repositorio.
22
+ * 2. Solo cuentan los tramos entre acentos graves y los destinos de los
23
+ * enlaces markdown. Una ruta en prosa suelta no se toca.
24
+ * 3. Con `/`: el primer segmento tiene que ser un directorio que EXISTE en
25
+ * la raiz y no ser generado (`dist/`, `test-results/`, `.forge/`...).
26
+ * La cita afirma una UBICACION, asi que se verifica tal cual.
27
+ * Sin `/`: es un NOMBRE, no una ubicacion, y se verifica como tal --
28
+ * basta que un archivo con ese nombre exista en algun lugar del
29
+ * repositorio. Medido: tratar `claude.ts` como archivo de la raiz daba
30
+ * cientos de falsos positivos, y descartarlo del todo dejaba pasar
31
+ * nombres que ya no existen en ninguna parte (`relay_error.ts`).
32
+ * 4. Nada con comodin (`*`, `?`), hueco (`<x>`, `{x}`, `$x`), dos puntos
33
+ * (rutas de Windows, `repo:ruta`) ni esquema (`http://`). Son formas
34
+ * que no afirman un archivo concreto.
35
+ *
36
+ * Y LOS DOCUMENTOS HISTORICOS NO ENTRAN, por una razon que no es comodidad:
37
+ * un changelog, un traspaso o un informe fechado describen el estado del
38
+ * repositorio EN SU FECHA, y un archivo que existia entonces y se renombro
39
+ * despues es historia correcta, no una cita a la nada. Medido: de 2378 citas
40
+ * verificables, 762 estaban muertas y la enorme mayoria vivia justamente
41
+ * ahi. Meterlas obligaria a una lista de permisos de cientos de entradas sin
42
+ * motivo real, que es la misma afirmacion sin respaldo que esto persigue. La
43
+ * exclusion se DECLARA (`isHistoricalDoc`) y la corrida dice cuantos
44
+ * documentos salteo, nunca en silencio.
45
+ *
46
+ * ASCII-only.
47
+ */
48
+ /** Directorios de la raiz que existen pero NO son fuente: lo que hay dentro
49
+ * lo genera una corrida o lo escribe un producto en ejecucion, asi que un
50
+ * documento puede nombrarlos legitimamente sin que esten en disco. */
51
+ export const GENERATED_ROOTS = [
52
+ 'dist', 'node_modules', 'test-results', 'qa_reports', 'coverage', 'build',
53
+ ];
54
+ /** Extensiones que hacen que un token sin `/` cuente como cita de un nombre
55
+ * de archivo. Corta a proposito: un token cualquiera no es una cita. */
56
+ const NAME_EXT = [
57
+ '.md', '.json', '.yml', '.yaml', '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
58
+ '.toml', '.sql', '.sh', '.py', '.php',
59
+ ];
60
+ /** Sufijos de puntuacion que la prosa deja pegados a una ruta. */
61
+ function trimPunctuation(s) {
62
+ return s.replace(/^[('"`]+/, '').replace(/[)'"`,.;:!?]+$/, '');
63
+ }
64
+ /** La forma de la cita, o el motivo por el que no es una cita verificable. */
65
+ export function classifyToken(token, rootDirs) {
66
+ const t = token.trim();
67
+ if (!t)
68
+ return { reject: 'vacio' };
69
+ if (/\s/.test(t))
70
+ return { reject: 'tiene espacios' };
71
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(t))
72
+ return { reject: 'es una URL' };
73
+ if (t.startsWith('#') || t.startsWith('mailto:'))
74
+ return { reject: 'es un ancla o un correo' };
75
+ if (/[*?<>{}$|]/.test(t))
76
+ return { reject: 'tiene comodin o hueco' };
77
+ if (t.includes(':'))
78
+ return { reject: 'tiene dos puntos (ruta ajena o de Windows)' };
79
+ if (t.includes('\\'))
80
+ return { reject: 'usa separador de Windows' };
81
+ if (t.includes('..'))
82
+ return { reject: 'sube de directorio' };
83
+ if (t.startsWith('/'))
84
+ return { reject: 'es absoluta' };
85
+ if (t.startsWith('~'))
86
+ return { reject: 'es del home del usuario' };
87
+ const clean = t.replace(/^\.\//, '').replace(/\/+$/, '');
88
+ if (!clean)
89
+ return { reject: 'vacio' };
90
+ const dot = clean.lastIndexOf('.');
91
+ const ext = dot > 0 ? clean.slice(dot).toLowerCase() : '';
92
+ if (clean.includes('/')) {
93
+ const segs = clean.split('/');
94
+ const first = segs[0];
95
+ if (!rootDirs.includes(first))
96
+ return { reject: 'su primer segmento no es un directorio de este repositorio' };
97
+ if (first.startsWith('.') && first !== '.github')
98
+ return { reject: 'vive en un directorio de estado local' };
99
+ /* Generado en CUALQUIER tramo, no solo en el primero: la salida de un
100
+ * build de CI (`apps/x/android/app/build/outputs/...`) la produce la
101
+ * corrida, asi que nombrarla no afirma un archivo en disco. */
102
+ if (segs.some((s) => GENERATED_ROOTS.includes(s)))
103
+ return { reject: 'vive en un directorio generado' };
104
+ return 'path';
105
+ }
106
+ if (!ext)
107
+ return { reject: 'no parece un archivo' };
108
+ if (!NAME_EXT.includes(ext))
109
+ return { reject: 'extension no reconocida' };
110
+ return 'name';
111
+ }
112
+ /** Las citas verificables de un documento markdown. */
113
+ export function extractCitations(md, rootDirs) {
114
+ const out = [];
115
+ const lines = md.split(/\r?\n/);
116
+ let fence = null;
117
+ for (let i = 0; i < lines.length; i++) {
118
+ const line = lines[i];
119
+ const fenceMatch = /^\s*(```+|~~~+)/.exec(line);
120
+ if (fenceMatch) {
121
+ const mark = fenceMatch[1];
122
+ if (fence === null)
123
+ fence = mark[0];
124
+ else if (mark[0] === fence)
125
+ fence = null;
126
+ continue;
127
+ }
128
+ if (fence !== null)
129
+ continue;
130
+ /* Lineas sangradas cuatro espacios: bloque de codigo indentado. */
131
+ if (/^ {4,}\S/.test(line) && !/^ {0,3}[-*+]/.test(line))
132
+ continue;
133
+ const tokens = [];
134
+ for (const m of line.matchAll(/`([^`\n]+)`/g))
135
+ tokens.push(m[1]);
136
+ for (const m of line.matchAll(/\]\(([^)\s]+)\)/g))
137
+ tokens.push(m[1]);
138
+ for (const raw of tokens) {
139
+ /* El ancla (`docs/X.md#seccion`) no es parte del archivo. */
140
+ const target0 = trimPunctuation(raw).split('#')[0];
141
+ const target = target0.replace(/^\.\//, '').replace(/\/+$/, '');
142
+ const shape = classifyToken(target, rootDirs);
143
+ if (typeof shape !== 'string')
144
+ continue;
145
+ if (out.some((c) => c.line === i + 1 && c.target === target))
146
+ continue;
147
+ out.push({ line: i + 1, target, raw, shape });
148
+ }
149
+ }
150
+ return out;
151
+ }
152
+ /** Un documento que describe el estado del repositorio en su fecha, no hoy.
153
+ * La lista es de FORMAS de nombre, no de rutas: una lista de rutas se
154
+ * desactualiza con cada documento nuevo y acaba siendo una lista de
155
+ * permisos. */
156
+ export function isHistoricalDoc(rel) {
157
+ const p = rel.replace(/\\/g, '/');
158
+ const base = p.split('/').pop();
159
+ if (base === 'CHANGELOG.md')
160
+ return true;
161
+ /* Carpetas de contexto volcado de una sesion. */
162
+ if (/(^|\/)context-from-/.test(p))
163
+ return true;
164
+ if (/(^|\/)handoff\//i.test(p))
165
+ return true;
166
+ /* Nombre con fecha: un documento fechado afirma sobre su fecha. Los dos
167
+ * separadores se mezclan de verdad en este repositorio
168
+ * (`CATCHUP_PRELIMINAR_2026-06-11.md`), asi que la forma los acepta
169
+ * mezclados en vez de pedir uno solo. */
170
+ if (/[_-]\d{4}[_-]\d{2}[_-]\d{2}/.test(base))
171
+ return true;
172
+ /* Generos que son registro, no especificacion vigente. */
173
+ if (/^(HANDOFF|SESSION|SESION|AUTOPILOT|CODE_REVIEW|INFORME|PROMPT|RETRO|SNAPSHOT|PENDING_REGISTRY_SNAPSHOT)[_-]/i.test(base))
174
+ return true;
175
+ return false;
176
+ }
177
+ /** Las citas de un archivo de MAQUINARIA (workflow, lefthook, manifiesto):
178
+ * ahi una ruta no viene entre acentos graves, viene en un comentario o en
179
+ * un valor. Se buscan por forma y se pasan por el mismo clasificador.
180
+ *
181
+ * Esto NO se usa sobre fuentes TypeScript a proposito: un especificador de
182
+ * import (`./tools/x.js`) tiene forma de ruta, es relativo al archivo y
183
+ * apunta al transpilado, asi que daria cientos de falsos positivos.
184
+ * Medido antes de acotar: 307.
185
+ *
186
+ * Y aca la cita tiene que llevar EXTENSION. En un archivo de maquinaria no
187
+ * hay acentos graves que delimiten el token, asi que un tramo sin extension
188
+ * suele ser otra cosa con forma de ruta -- medido: `src/version\.ts` dentro
189
+ * de una expresion regular de `lefthook.yml` se lee como `src/version`. Las
190
+ * tres citas a la nada que este repositorio ya pago llevaban extension. */
191
+ export function extractMachineryCitations(text, rootDirs) {
192
+ const out = [];
193
+ const lines = text.split(/\r?\n/);
194
+ const re = /[A-Za-z0-9_.][A-Za-z0-9_./-]*\/[A-Za-z0-9_][A-Za-z0-9_./-]*/g;
195
+ for (let i = 0; i < lines.length; i++) {
196
+ for (const m of lines[i].matchAll(re)) {
197
+ const target = trimPunctuation(m[0]).replace(/^\.\//, '').replace(/\/+$/, '');
198
+ if (!/\.[a-z0-9]{1,6}$/i.test(target))
199
+ continue;
200
+ const shape = classifyToken(target, rootDirs);
201
+ if (shape !== 'path')
202
+ continue;
203
+ if (out.some((c) => c.line === i + 1 && c.target === target))
204
+ continue;
205
+ out.push({ line: i + 1, target, raw: m[0], shape });
206
+ }
207
+ }
208
+ return out;
209
+ }
210
+ /** EL ALCANCE QUE BLOQUEA, y por que es este y no "todos los documentos".
211
+ *
212
+ * Medido en este repositorio: de 1331 citas verificables en documentos
213
+ * vigentes, 206 apuntan a archivos que no existen -- y casi todas son
214
+ * correctas. El espacio `docs/` esta SOBRECARGADO: `docs/SQ.md` exige
215
+ * `docs/USER_MANUAL.md` al proyecto ADOPTANTE, `src/urazuke/catalog.ts`
216
+ * nombra `docs/GATES.md` como artefacto que produce el proyecto que corre
217
+ * el metodo, y `docs/worker/README.md` cita `src/relay.js` relativo a su
218
+ * propio componente. Prescribir rutas para otros proyectos es el negocio
219
+ * de este repositorio, asi que "toda ruta citada existe" es FALSO como
220
+ * regla general y una compuerta que lo exija pide una lista de permisos de
221
+ * cientos de entradas -- que es la misma afirmacion sin respaldo que esto
222
+ * persigue.
223
+ *
224
+ * Lo que si se puede exigir sin excepciones es este conjunto: los archivos
225
+ * que se leen como AUTORIDAD sobre la maquinaria de este repositorio. Es
226
+ * donde vivieron los tres defectos medidos y es chico y verificable. El
227
+ * resto se MIDE y se informa en la misma salida, nunca en silencio.
228
+ *
229
+ * Y dentro de ese conjunto bloquean solo las citas con forma de RUTA. Un
230
+ * nombre suelto (`nac-bridge.js`, `pilot.bundle.js` en el README) no afirma
231
+ * una ubicacion de este repositorio: nombra un artefacto de otro paquete.
232
+ * Una ruta si afirma: dice "esta aca". Esa es la afirmacion que las tres
233
+ * citas a la nada hicieron y la que esto verifica. */
234
+ export const AUTHORITY_SCOPE = [
235
+ 'CLAUDE.md',
236
+ 'README.md',
237
+ 'PROJECT.md',
238
+ 'docs/PROGRAMMING_NORMS.md',
239
+ 'docs/CI_PIPELINE.md',
240
+ 'lefthook.yml',
241
+ 'package.json',
242
+ /* mas .github/workflows/*.yml, que el script expande del disco. */
243
+ ];
244
+ export function renderCitationReport(r) {
245
+ const out = [];
246
+ out.push('doc-citations [compuerta]: ' + r.authority_files + ' archivos de autoridad, '
247
+ + r.authority_checked + ' citas verificadas'
248
+ + (r.allowed ? ', ' + r.allowed + ' permitidas por declaracion' : '')
249
+ + ', ' + r.violations.length + ' a la nada.');
250
+ out.push('doc-citations [relevamiento, NO bloquea]: ' + r.survey_docs
251
+ + ' documentos vigentes (' + r.survey_skipped_historical + ' historicos salteados), '
252
+ + r.survey_checked + ' citas, ' + r.survey_dead + ' sin archivo en disco.');
253
+ out.push(' El relevamiento no bloquea porque este repositorio PRESCRIBE rutas para otros');
254
+ out.push(' proyectos (docs/SQ.md exige docs/USER_MANUAL.md al adoptante), asi que una ruta');
255
+ out.push(' sin archivo no es por si misma un defecto. El numero esta a la vista para que');
256
+ out.push(' nadie lo descubra midiendo de nuevo.');
257
+ if (!r.violations.length)
258
+ return out.join('\n');
259
+ out.push('');
260
+ out.push('CITAS A LA NADA EN EL ALCANCE QUE BLOQUEA (' + r.violations.length + '):');
261
+ for (const v of r.violations) {
262
+ out.push(' ' + v.doc + ':' + v.line + ' -> ' + v.target
263
+ + (v.shape === 'name' ? ' (no existe con ese nombre en ninguna parte)' : ' (no existe)'));
264
+ }
265
+ out.push('');
266
+ out.push('Un documento que afirma un archivo que no existe es peor que uno que falta:');
267
+ out.push('la ausencia se nota, la afirmacion falsa no. Arregla la cita, crea el archivo,');
268
+ out.push('o declara la excepcion con su motivo en docs/.doc-citations-allow.');
269
+ return out.join('\n');
270
+ }
271
+ //# sourceMappingURL=doc_citations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doc_citations.js","sourceRoot":"","sources":["../../src/core/doc_citations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ export declare const HOOK_BUDGET_REL = ".forge/hook-budget.json";
2
+ /** Aviso. Medido: la serie ya toco 32,0 / 39,2 / 38,7, asi que esto habla. */
3
+ export declare const WARN_MS = 30000;
4
+ /** Techo declarado por el dueno. Cruzarlo es una decision. */
5
+ export declare const CEILING_MS = 35000;
6
+ /** Cuantas corridas se guardan. Alcanza para ver la tendencia sin que el
7
+ * archivo crezca: lo que decide el rojo son las dos ultimas. */
8
+ export declare const HISTORY_MAX = 10;
9
+ export interface HookRun {
10
+ ended_at: number;
11
+ duration_ms: number;
12
+ /** Para saber si la corrida fue el paquete entero o una parte. */
13
+ commands?: number;
14
+ }
15
+ export interface HookBudgetFile {
16
+ version: 1;
17
+ /** Marca de `--start`. Se borra al medir: una marca vieja no es una
18
+ * medicion, y dejarla permitiria leer como duracion el tiempo entre dos
19
+ * corridas distintas. */
20
+ started_at?: number;
21
+ history: HookRun[];
22
+ }
23
+ export type BudgetLevel = 'ok' | 'warn' | 'over';
24
+ export interface BudgetVerdict {
25
+ level: BudgetLevel;
26
+ duration_ms: number;
27
+ /** Rojo del gancho. Solo con DOS corridas seguidas arriba del techo. */
28
+ blocked: boolean;
29
+ warn_ms: number;
30
+ ceiling_ms: number;
31
+ /** La corrida anterior, cuando hay, para explicar el veredicto. */
32
+ previous_ms?: number;
33
+ }
34
+ export declare function emptyBudgetFile(): HookBudgetFile;
35
+ export declare function readBudgetFile(repo: string): HookBudgetFile;
36
+ export declare function writeBudgetFile(repo: string, data: HookBudgetFile): void;
37
+ /** `--start`: deja la marca y NO toca el historial. */
38
+ export declare function startRun(prev: HookBudgetFile, now: number): HookBudgetFile;
39
+ /**
40
+ * El veredicto, puro: duracion contra los dos umbrales, y el rojo solo
41
+ * cuando la corrida ANTERIOR tambien cruzo el techo.
42
+ */
43
+ export declare function judgeBudget(duration_ms: number, history: HookRun[], limits?: {
44
+ warn_ms?: number;
45
+ ceiling_ms?: number;
46
+ }): BudgetVerdict;
47
+ /** `--check`: mide, guarda la corrida y devuelve el veredicto. */
48
+ export declare function finishRun(prev: HookBudgetFile, now: number, limits?: {
49
+ warn_ms?: number;
50
+ ceiling_ms?: number;
51
+ commands?: number;
52
+ }): {
53
+ file: HookBudgetFile;
54
+ verdict: BudgetVerdict;
55
+ } | {
56
+ file: HookBudgetFile;
57
+ verdict: null;
58
+ };
59
+ export declare function renderBudget(verdict: BudgetVerdict): string[];
60
+ //# sourceMappingURL=hook_budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook_budget.d.ts","sourceRoot":"","sources":["../../src/core/hook_budget.ts"],"names":[],"mappings":"AA8CA,eAAO,MAAM,eAAe,4BAA4B,CAAC;AAEzD,8EAA8E;AAC9E,eAAO,MAAM,OAAO,QAAS,CAAC;AAC9B,8DAA8D;AAC9D,eAAO,MAAM,UAAU,QAAS,CAAC;AACjC;iEACiE;AACjE,eAAO,MAAM,WAAW,KAAK,CAAC;AAE9B,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,CAAC,CAAC;IACX;;8BAE0B;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,EAAE,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,WAAW,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,eAAe,IAAI,cAAc,CAEhD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAuB3D;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAIxE;AAED,uDAAuD;AACvD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,cAAc,CAE1E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,OAAO,EAAE,EAClB,MAAM,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACrD,aAAa,CAef;AAED,kEAAkE;AAClE,wBAAgB,SAAS,CACvB,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,MAAM,EACX,MAAM,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GACxE;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,CAY5F;AAID,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,EAAE,CAmC7D"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * EL PRESUPUESTO DEL GANCHO -- 35 s de techo, aviso al pasar de 30 (F-15,
3
+ * decision del dueno 2026-11-01, PROMPT_FIX_FORGE_CIERRE_4).
4
+ *
5
+ * POR QUE UN PRESUPUESTO Y NO UN NUMERO APROBADO. El precio del paquete
6
+ * pre-push se midio ocho veces en una sola jornada y la serie fue
7
+ * 20,8 / 25,1 / 25,8 / 29,6 / 32,0 / 39,2 / 38,7 / 30,5 s. Lo que la mueve
8
+ * es `build`, que crece con el codigo, asi que aprobar "32" seria aprobar
9
+ * un numero que ya se sabe que va a volver a subir. El dueno fijo el techo
10
+ * en su lugar: cruzar los 35 s tiene que ser una DECISION y no una deriva.
11
+ *
12
+ * Y la serie le dio la razon el mismo dia: las dos primeras lecturas del
13
+ * instrumento (39,2 y 38,7 s) cruzaron el techo. Las dos salieron minutos
14
+ * despues de una bateria de 6 min, con la maquina caliente; la tercera, ya
15
+ * libre, dio 30,5 s. Es el caso exacto para el que el rojo pide DOS
16
+ * corridas seguidas y no una.
17
+ *
18
+ * COMO SE MIDE. `scripts/hook_budget.mjs --start` es el PRIMER comando del
19
+ * pre-push y deja la marca de arranque; `--check` es el ULTIMO y mide lo
20
+ * que paso entre las dos. Es el precio del gancho COMPLETO -- la suma de
21
+ * las piezas ya se probo que miente por abajo (las piezas se midieron en
22
+ * 24,8 s y la corrida real dio 32,0, y despues 39,2). Y el sobrecosto de
23
+ * lefthook no es la explicacion: son 0,4 s sobre los diez comandos. Lo que
24
+ * separa la suma de la corrida es `build` bajo carga -- 21,3 s suelto y
25
+ * 26,3 s en la corrida completa, el mismo arbol, un minuto de diferencia.
26
+ *
27
+ * POR QUE EL ROJO PIDE DOS CORRIDAS SEGUIDAS Y NO UNA. `build` vario de
28
+ * 18,1 a 24,6 s en la misma maquina sin que cambiara una linea: lo mueve la
29
+ * carga. Un rojo por un pico aislado seria un falso rojo, y un gancho que
30
+ * tira falsos rojos se desactiva -- que es exactamente el dano que este
31
+ * paquete existe para no causar (un gancho desactivado figura como
32
+ * existente). Dos corridas consecutivas arriba del techo ya no son un pico:
33
+ * son el estado de la maquina, y ahi el cruce es la decision que el dueno
34
+ * pidio que se tome a mano.
35
+ *
36
+ * LO QUE ESTE ARCHIVO NO DECIDE. La salida de fondo -- que `hito4-lint` y
37
+ * `brain-matrix-gate` lean `src/` en vez de `dist/` para que `build` salga
38
+ * del gancho y el paquete baje a unos 8 s -- queda registrada como
39
+ * pendiente. Si eso se hace, el techo deja de ser un problema de raiz
40
+ * porque lo que crece es la compilacion, no las compuertas.
41
+ *
42
+ * ASCII-only.
43
+ */
44
+ import fs from 'node:fs';
45
+ import path from 'node:path';
46
+ export const HOOK_BUDGET_REL = '.forge/hook-budget.json';
47
+ /** Aviso. Medido: la serie ya toco 32,0 / 39,2 / 38,7, asi que esto habla. */
48
+ export const WARN_MS = 30_000;
49
+ /** Techo declarado por el dueno. Cruzarlo es una decision. */
50
+ export const CEILING_MS = 35_000;
51
+ /** Cuantas corridas se guardan. Alcanza para ver la tendencia sin que el
52
+ * archivo crezca: lo que decide el rojo son las dos ultimas. */
53
+ export const HISTORY_MAX = 10;
54
+ export function emptyBudgetFile() {
55
+ return { version: 1, history: [] };
56
+ }
57
+ export function readBudgetFile(repo) {
58
+ const file = path.join(repo, HOOK_BUDGET_REL);
59
+ let raw;
60
+ try {
61
+ raw = fs.readFileSync(file, 'utf8');
62
+ }
63
+ catch {
64
+ return emptyBudgetFile();
65
+ }
66
+ try {
67
+ const parsed = JSON.parse(raw);
68
+ const history = Array.isArray(parsed.history) ? parsed.history : [];
69
+ return {
70
+ version: 1,
71
+ started_at: typeof parsed.started_at === 'number' ? parsed.started_at : undefined,
72
+ history: history.filter((r) => !!r && typeof r.duration_ms === 'number' && typeof r.ended_at === 'number'),
73
+ };
74
+ }
75
+ catch {
76
+ /* Un archivo ilegible se reporta como ausente y no tira: el presupuesto
77
+ * no puede ser el motivo de que un push no se pueda hacer. */
78
+ return emptyBudgetFile();
79
+ }
80
+ }
81
+ export function writeBudgetFile(repo, data) {
82
+ const file = path.join(repo, HOOK_BUDGET_REL);
83
+ fs.mkdirSync(path.dirname(file), { recursive: true });
84
+ fs.writeFileSync(file, JSON.stringify(data, null, 2) + '\n', 'utf8');
85
+ }
86
+ /** `--start`: deja la marca y NO toca el historial. */
87
+ export function startRun(prev, now) {
88
+ return { version: 1, started_at: now, history: prev.history.slice(0, HISTORY_MAX) };
89
+ }
90
+ /**
91
+ * El veredicto, puro: duracion contra los dos umbrales, y el rojo solo
92
+ * cuando la corrida ANTERIOR tambien cruzo el techo.
93
+ */
94
+ export function judgeBudget(duration_ms, history, limits = {}) {
95
+ const warn_ms = limits.warn_ms ?? WARN_MS;
96
+ const ceiling_ms = limits.ceiling_ms ?? CEILING_MS;
97
+ const previous = history.length ? history[history.length - 1] : undefined;
98
+ const level = duration_ms > ceiling_ms ? 'over' : duration_ms > warn_ms ? 'warn' : 'ok';
99
+ const blocked = level === 'over' && !!previous && previous.duration_ms > ceiling_ms;
100
+ return {
101
+ level,
102
+ duration_ms,
103
+ blocked,
104
+ warn_ms,
105
+ ceiling_ms,
106
+ previous_ms: previous?.duration_ms,
107
+ };
108
+ }
109
+ /** `--check`: mide, guarda la corrida y devuelve el veredicto. */
110
+ export function finishRun(prev, now, limits = {}) {
111
+ if (typeof prev.started_at !== 'number') {
112
+ /* Sin marca de arranque no hay nada que medir. Se dice y no se inventa:
113
+ * una medicion imposible no se reporta como "entro en el presupuesto". */
114
+ return { file: prev, verdict: null };
115
+ }
116
+ const duration_ms = Math.max(0, now - prev.started_at);
117
+ const verdict = judgeBudget(duration_ms, prev.history, limits);
118
+ const run = { ended_at: now, duration_ms };
119
+ if (typeof limits.commands === 'number')
120
+ run.commands = limits.commands;
121
+ const history = [...prev.history, run].slice(-HISTORY_MAX);
122
+ return { file: { version: 1, history }, verdict };
123
+ }
124
+ const secs = (ms) => (ms / 1000).toFixed(1).replace('.', ',') + ' s';
125
+ export function renderBudget(verdict) {
126
+ const lines = [];
127
+ const head = 'hook-budget: el paquete pre-push tardo ' + secs(verdict.duration_ms)
128
+ + ' (aviso ' + secs(verdict.warn_ms) + ', techo ' + secs(verdict.ceiling_ms) + ').';
129
+ lines.push(head);
130
+ if (verdict.level === 'ok')
131
+ return lines;
132
+ if (verdict.level === 'warn') {
133
+ lines.push('AVISO: paso del aviso y no del techo. Lo que mueve el numero es'
134
+ + ' `build`, que crece con el codigo.');
135
+ lines.push('La salida de fondo esta registrada: si hito4-lint y'
136
+ + ' brain-matrix-gate leen src/ en vez de dist/, `build` sale del gancho.');
137
+ return lines;
138
+ }
139
+ lines.push('TECHO CRUZADO: ' + secs(verdict.duration_ms) + ' > '
140
+ + secs(verdict.ceiling_ms) + '. Cruzar el techo es una DECISION, no una deriva.');
141
+ if (verdict.previous_ms !== undefined) {
142
+ lines.push('Corrida anterior: ' + secs(verdict.previous_ms) + '.');
143
+ }
144
+ else {
145
+ lines.push('Corrida anterior: no hay registro.');
146
+ }
147
+ if (!verdict.blocked) {
148
+ lines.push('No bloquea TODAVIA: una sola corrida arriba del techo puede ser'
149
+ + ' carga de la maquina (build vario 18,1 a 24,6 s sin cambiar una linea).');
150
+ lines.push('Si la proxima tambien cruza, el gancho sale rojo y hay que'
151
+ + ' decidir: sacar `build` del paquete, o subir el techo en lefthook.yml'
152
+ + ' y escribir por que.');
153
+ return lines;
154
+ }
155
+ lines.push('DOS CORRIDAS SEGUIDAS arriba del techo: ya no es un pico, es el'
156
+ + ' estado. El gancho sale rojo a proposito.');
157
+ lines.push('Las dos salidas, las dos a mano: (1) sacar `build` del pre-push'
158
+ + ' haciendo que hito4-lint y brain-matrix-gate lean src/; (2) subir'
159
+ + ' CEILING_MS en src/core/hook_budget.ts y declarar el motivo en'
160
+ + ' lefthook.yml.');
161
+ return lines;
162
+ }
163
+ //# sourceMappingURL=hook_budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook_budget.js","sourceRoot":"","sources":["../../src/core/hook_budget.ts"],"names":[],"mappings":"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"}