@nac3/forge-cli 1.23.6 → 1.24.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 (166) hide show
  1. package/dist/bin/yf.js +0 -0
  2. package/dist/chat/claude.d.ts +8 -0
  3. package/dist/chat/claude.d.ts.map +1 -1
  4. package/dist/chat/claude.js.map +1 -1
  5. package/dist/chat/claude_cli.d.ts +23 -0
  6. package/dist/chat/claude_cli.d.ts.map +1 -1
  7. package/dist/chat/claude_cli.js +76 -2
  8. package/dist/chat/claude_cli.js.map +1 -1
  9. package/dist/chat/doctrine_digest.d.ts.map +1 -1
  10. package/dist/chat/doctrine_digest.js +2 -1
  11. package/dist/chat/doctrine_digest.js.map +1 -1
  12. package/dist/chat/server.d.ts.map +1 -1
  13. package/dist/chat/server.js +11 -0
  14. package/dist/chat/server.js.map +1 -1
  15. package/dist/chat/tools/pending.d.ts +11 -0
  16. package/dist/chat/tools/pending.d.ts.map +1 -1
  17. package/dist/chat/tools/pending.js +55 -8
  18. package/dist/chat/tools/pending.js.map +1 -1
  19. package/dist/chat/tools/shell.d.ts +39 -4
  20. package/dist/chat/tools/shell.d.ts.map +1 -1
  21. package/dist/chat/tools/shell.js +167 -7
  22. package/dist/chat/tools/shell.js.map +1 -1
  23. package/dist/chat/tools/urazuke.d.ts.map +1 -1
  24. package/dist/chat/tools/urazuke.js +8 -5
  25. package/dist/chat/tools/urazuke.js.map +1 -1
  26. package/dist/chat/urazuke_section.d.ts +26 -4
  27. package/dist/chat/urazuke_section.d.ts.map +1 -1
  28. package/dist/chat/urazuke_section.js +115 -9
  29. package/dist/chat/urazuke_section.js.map +1 -1
  30. package/dist/commands/pending.d.ts.map +1 -1
  31. package/dist/commands/pending.js +116 -12
  32. package/dist/commands/pending.js.map +1 -1
  33. package/dist/commands/urazuke.d.ts +3 -0
  34. package/dist/commands/urazuke.d.ts.map +1 -1
  35. package/dist/commands/urazuke.js +80 -3
  36. package/dist/commands/urazuke.js.map +1 -1
  37. package/dist/core/ascii_purity.d.ts +69 -0
  38. package/dist/core/ascii_purity.d.ts.map +1 -0
  39. package/dist/core/ascii_purity.js +141 -0
  40. package/dist/core/ascii_purity.js.map +1 -0
  41. package/dist/core/battery_stamp.d.ts +85 -0
  42. package/dist/core/battery_stamp.d.ts.map +1 -0
  43. package/dist/core/battery_stamp.js +237 -0
  44. package/dist/core/battery_stamp.js.map +1 -0
  45. package/dist/core/ci_gaps.d.ts +129 -0
  46. package/dist/core/ci_gaps.d.ts.map +1 -0
  47. package/dist/core/ci_gaps.js +352 -0
  48. package/dist/core/ci_gaps.js.map +1 -0
  49. package/dist/core/doc_citations.d.ts +133 -0
  50. package/dist/core/doc_citations.d.ts.map +1 -0
  51. package/dist/core/doc_citations.js +271 -0
  52. package/dist/core/doc_citations.js.map +1 -0
  53. package/dist/core/turn_classifier.d.ts +4 -3
  54. package/dist/core/turn_classifier.d.ts.map +1 -1
  55. package/dist/core/turn_classifier.js +65 -20
  56. package/dist/core/turn_classifier.js.map +1 -1
  57. package/dist/docs/doctrine/urazuke.md +173 -2
  58. package/dist/nac3/internal_manifest.d.ts.map +1 -1
  59. package/dist/nac3/internal_manifest.js +28 -2
  60. package/dist/nac3/internal_manifest.js.map +1 -1
  61. package/dist/pending/store.d.ts +29 -0
  62. package/dist/pending/store.d.ts.map +1 -1
  63. package/dist/pending/store.js +51 -1
  64. package/dist/pending/store.js.map +1 -1
  65. package/dist/pending/types.d.ts +23 -0
  66. package/dist/pending/types.d.ts.map +1 -1
  67. package/dist/pending/types.js.map +1 -1
  68. package/dist/telemetry/usage.d.ts +18 -0
  69. package/dist/telemetry/usage.d.ts.map +1 -1
  70. package/dist/telemetry/usage.js +16 -1
  71. package/dist/telemetry/usage.js.map +1 -1
  72. package/dist/urazuke/announce.d.ts +7 -0
  73. package/dist/urazuke/announce.d.ts.map +1 -1
  74. package/dist/urazuke/announce.js +20 -0
  75. package/dist/urazuke/announce.js.map +1 -1
  76. package/dist/urazuke/catalog.d.ts +1 -1
  77. package/dist/urazuke/catalog.d.ts.map +1 -1
  78. package/dist/urazuke/catalog.js.map +1 -1
  79. package/dist/urazuke/close_gate.d.ts +31 -4
  80. package/dist/urazuke/close_gate.d.ts.map +1 -1
  81. package/dist/urazuke/close_gate.js +70 -13
  82. package/dist/urazuke/close_gate.js.map +1 -1
  83. package/dist/urazuke/current.d.ts +28 -0
  84. package/dist/urazuke/current.d.ts.map +1 -1
  85. package/dist/urazuke/current.js +18 -5
  86. package/dist/urazuke/current.js.map +1 -1
  87. package/dist/urazuke/cycle.d.ts +3 -0
  88. package/dist/urazuke/cycle.d.ts.map +1 -1
  89. package/dist/urazuke/cycle.js +5 -3
  90. package/dist/urazuke/cycle.js.map +1 -1
  91. package/dist/urazuke/evidence.d.ts +58 -1
  92. package/dist/urazuke/evidence.d.ts.map +1 -1
  93. package/dist/urazuke/evidence.js +203 -27
  94. package/dist/urazuke/evidence.js.map +1 -1
  95. package/dist/urazuke/evidence_env.d.ts +78 -0
  96. package/dist/urazuke/evidence_env.d.ts.map +1 -0
  97. package/dist/urazuke/evidence_env.js +341 -0
  98. package/dist/urazuke/evidence_env.js.map +1 -0
  99. package/dist/urazuke/freeze.d.ts.map +1 -1
  100. package/dist/urazuke/freeze.js +16 -9
  101. package/dist/urazuke/freeze.js.map +1 -1
  102. package/dist/urazuke/gate.d.ts +48 -0
  103. package/dist/urazuke/gate.d.ts.map +1 -1
  104. package/dist/urazuke/gate.js +251 -25
  105. package/dist/urazuke/gate.js.map +1 -1
  106. package/dist/urazuke/gates_data.d.ts +30 -3
  107. package/dist/urazuke/gates_data.d.ts.map +1 -1
  108. package/dist/urazuke/gates_data.js +51 -5
  109. package/dist/urazuke/gates_data.js.map +1 -1
  110. package/dist/urazuke/gates_pull.d.ts +40 -0
  111. package/dist/urazuke/gates_pull.d.ts.map +1 -1
  112. package/dist/urazuke/gates_pull.js +118 -8
  113. package/dist/urazuke/gates_pull.js.map +1 -1
  114. package/dist/urazuke/manual_cases.d.ts +11 -1
  115. package/dist/urazuke/manual_cases.d.ts.map +1 -1
  116. package/dist/urazuke/manual_cases.js +1 -0
  117. package/dist/urazuke/manual_cases.js.map +1 -1
  118. package/dist/urazuke/overrides.d.ts +107 -0
  119. package/dist/urazuke/overrides.d.ts.map +1 -0
  120. package/dist/urazuke/overrides.js +128 -0
  121. package/dist/urazuke/overrides.js.map +1 -0
  122. package/dist/urazuke/probes.d.ts.map +1 -1
  123. package/dist/urazuke/probes.js +51 -0
  124. package/dist/urazuke/probes.js.map +1 -1
  125. package/dist/urazuke/profiles.d.ts +135 -0
  126. package/dist/urazuke/profiles.d.ts.map +1 -0
  127. package/dist/urazuke/profiles.js +470 -0
  128. package/dist/urazuke/profiles.js.map +1 -0
  129. package/dist/urazuke/receipt_audit.d.ts +67 -0
  130. package/dist/urazuke/receipt_audit.d.ts.map +1 -0
  131. package/dist/urazuke/receipt_audit.js +103 -0
  132. package/dist/urazuke/receipt_audit.js.map +1 -0
  133. package/dist/urazuke/receipts.d.ts +22 -0
  134. package/dist/urazuke/receipts.d.ts.map +1 -1
  135. package/dist/urazuke/receipts.js +44 -0
  136. package/dist/urazuke/receipts.js.map +1 -1
  137. package/dist/urazuke/report.d.ts +30 -0
  138. package/dist/urazuke/report.d.ts.map +1 -1
  139. package/dist/urazuke/report.js +39 -0
  140. package/dist/urazuke/report.js.map +1 -1
  141. package/dist/urazuke/reset.d.ts +35 -0
  142. package/dist/urazuke/reset.d.ts.map +1 -0
  143. package/dist/urazuke/reset.js +150 -0
  144. package/dist/urazuke/reset.js.map +1 -0
  145. package/dist/urazuke/retro.d.ts +5 -1
  146. package/dist/urazuke/retro.d.ts.map +1 -1
  147. package/dist/urazuke/retro.js +21 -8
  148. package/dist/urazuke/retro.js.map +1 -1
  149. package/dist/urazuke/section.d.ts.map +1 -1
  150. package/dist/urazuke/section.js +17 -2
  151. package/dist/urazuke/section.js.map +1 -1
  152. package/dist/urazuke/semantics.d.ts +173 -0
  153. package/dist/urazuke/semantics.d.ts.map +1 -0
  154. package/dist/urazuke/semantics.js +232 -0
  155. package/dist/urazuke/semantics.js.map +1 -0
  156. package/dist/urazuke/start.d.ts +8 -0
  157. package/dist/urazuke/start.d.ts.map +1 -1
  158. package/dist/urazuke/start.js +10 -2
  159. package/dist/urazuke/start.js.map +1 -1
  160. package/dist/version.d.ts +1 -1
  161. package/dist/version.js +1 -1
  162. package/dist/workflow/orchestrator.d.ts.map +1 -1
  163. package/dist/workflow/orchestrator.js +6 -7
  164. package/dist/workflow/orchestrator.js.map +1 -1
  165. package/docs/doctrine/urazuke.md +173 -2
  166. package/package.json +24 -20
@@ -0,0 +1,85 @@
1
+ export declare const BATTERY_STAMP_REL = ".forge/battery-stamp.json";
2
+ export declare const FINGERPRINT_SPEC: string;
3
+ export interface GitState {
4
+ commit: string;
5
+ dirty: boolean;
6
+ fingerprint: string;
7
+ /** Lo que la huella cubre, en el propio sello: un dato sin su definicion
8
+ * al lado es una afirmacion que el lector no puede verificar. */
9
+ fingerprint_spec: string;
10
+ }
11
+ export interface BatteryCounts {
12
+ files: number;
13
+ passed: number;
14
+ failed: number;
15
+ skipped: number;
16
+ }
17
+ export interface BatteryStamp extends GitState {
18
+ version: 1;
19
+ ran_at: number;
20
+ duration_ms: number;
21
+ counts: BatteryCounts;
22
+ /** Verde = la bateria termino sin fallas. Un sello rojo NO se descarta:
23
+ * "la bateria corrio y fallo" es informacion, y borrarla dejaria el
24
+ * mismo silencio que no tener sello. */
25
+ green: boolean;
26
+ /** Para que el dueno pueda repetir la corrida exacta. */
27
+ invocation: string;
28
+ /** La corrida llevaba un filtro de archivos (`vitest run tests/x.test.ts`),
29
+ * asi que NO es la bateria: es una parte. Se registra porque la mitad de
30
+ * las corridas de un dia de trabajo son parciales, y un sello parcial
31
+ * que se lea como "la bateria paso" seria exactamente la clase de verde
32
+ * que afirma mas de lo que midio. */
33
+ filtered: boolean;
34
+ }
35
+ /** Si la invocacion llevaba un filtro de archivos. Mecanico: cualquier
36
+ * argumento posicional que no sea una bandera ni el subcomando `run` es un
37
+ * patron de archivos para vitest.
38
+ *
39
+ * El sesgo es a proposito: `--reporter default` (con espacio) se lee como
40
+ * filtro y el sello sale marcado parcial sin serlo. Equivocarse hacia
41
+ * "parcial" avisa de mas; equivocarse hacia "completa" es el verde que
42
+ * afirma lo que no midio. */
43
+ export declare function isFilteredInvocation(args: string[]): boolean;
44
+ /** La huella y el estado de git, calculados en UN solo lugar. Si el sello y
45
+ * la verificacion los calcularan por su cuenta, un dia divergirian y la
46
+ * comparacion diria "no coincide" sin que nada hubiera cambiado -- o peor,
47
+ * al reves (simetria productor/consumidor, SQ 14). */
48
+ export declare function readGitState(cwd: string): GitState;
49
+ /** Los numeros de una corrida de vitest, del arbol de tareas que el
50
+ * reporter recibe. Pura a proposito: el arbol se puede sintetizar en un
51
+ * caso y asi el contador se prueba sin correr la bateria dentro de la
52
+ * bateria. */
53
+ export declare function countFromFiles(files: unknown[]): BatteryCounts;
54
+ export declare function writeBatteryStamp(repoRoot: string, stamp: BatteryStamp): void;
55
+ export declare function readBatteryStamp(repoRoot: string): BatteryStamp | null;
56
+ export type FreshnessVerdict = 'same_content' | 'same_commit' | 'other_commit' | 'partial' | 'red' | 'never';
57
+ export interface FreshnessReport {
58
+ verdict: FreshnessVerdict;
59
+ /** Lo que importa para el aviso: el contenido que se va a empaquetar NO
60
+ * es el que la bateria vio. */
61
+ stale: boolean;
62
+ stamp: BatteryStamp | null;
63
+ current: GitState;
64
+ }
65
+ export declare function judgeFreshness(stamp: BatteryStamp | null, current: GitState): FreshnessReport;
66
+ /** El aviso, con el formato que el dueno pidio: en que commit corrio la
67
+ * bateria por ultima vez, en que commit estas, y si no coinciden lo dice. */
68
+ export declare function renderFreshness(r: FreshnessReport): string;
69
+ /** El reporter de vitest que deja el sello. Pato-tipado (no importa tipos
70
+ * de vitest) para que este modulo siga siendo parte del producto y no de
71
+ * la bateria. */
72
+ export declare class BatteryStampReporter {
73
+ private started;
74
+ private root;
75
+ private invocation;
76
+ private filtered;
77
+ constructor(opts?: {
78
+ root?: string;
79
+ invocation?: string;
80
+ filtered?: boolean;
81
+ });
82
+ onInit(): void;
83
+ onFinished(files?: unknown[], errors?: unknown[]): void;
84
+ }
85
+ //# sourceMappingURL=battery_stamp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"battery_stamp.d.ts","sourceRoot":"","sources":["../../src/core/battery_stamp.ts"],"names":[],"mappings":"AA4CA,eAAO,MAAM,iBAAiB,8BAA8B,CAAC;AAE7D,eAAO,MAAM,gBAAgB,QAGsB,CAAC;AAEpD,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB;sEACkE;IAClE,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;IACtB;;6CAEyC;IACzC,KAAK,EAAE,OAAO,CAAC;IACf,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB;;;;0CAIsC;IACtC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;8BAO8B;AAC9B,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAE5D;AAED;;;uDAGuD;AACvD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAsBlD;AAED;;;eAGe;AACf,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,aAAa,CAY9D;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAI7E;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAQtE;AAED,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,aAAa,GACb,cAAc,GACd,SAAS,GACT,KAAK,GACL,OAAO,CAAC;AAEZ,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,gBAAgB,CAAC;IAC1B;oCACgC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,QAAQ,CAAC;CACnB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,EAAE,OAAO,EAAE,QAAQ,GAAG,eAAe,CAW7F;AASD;8EAC8E;AAC9E,wBAAgB,eAAe,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CA4C1D;AAED;;kBAEkB;AAClB,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAU;gBAEd,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE;IAO7E,MAAM,IAAI,IAAI;IAEd,UAAU,CAAC,KAAK,GAAE,OAAO,EAAO,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,IAAI;CAoBhE"}
@@ -0,0 +1,237 @@
1
+ /**
2
+ * EL SELLO DE LA BATERIA -- el instrumento del riesgo aceptado (F-15).
3
+ *
4
+ * EL RIESGO. El gancho pre-push corre el paquete de 24,8 s y NO corre la
5
+ * bateria (418 s): la decision es del dueno y esta escrita en
6
+ * docs/PROGRAMMING_NORMS.md. Pero un peor caso aceptado y no instrumentado
7
+ * es dano silencioso, asi que el riesgo tiene que AVISAR cuando ocurre, y
8
+ * "ocurre" aca significa: se esta publicando codigo que la bateria nunca
9
+ * vio.
10
+ *
11
+ * EL INSTRUMENTO. Cada corrida de vitest deja un sello
12
+ * (`.forge/battery-stamp.json`) con el commit, el estado del arbol y el
13
+ * resultado. Antes de empaquetar, `scripts/battery_freshness.mjs` compara
14
+ * ese sello con el estado de AHORA y lo dice. No bloquea -- eso es decision
15
+ * de costo del dueno -- pero deja de ser una frase en un documento.
16
+ *
17
+ * POR QUE NO ALCANZA EL COMMIT. 1.20.1 salio publicada con el bug adentro
18
+ * porque el tarball llevaba el `dist/` del build inicial y las fuentes se
19
+ * editaron DURANTE la compuerta: el commit era el mismo y el contenido no.
20
+ * Asi que el sello lleva una huella del contenido, no solo el commit.
21
+ *
22
+ * LA HUELLA, AUTODESCRIPTA (la misma regla que el congelado: una huella que
23
+ * no se puede reproducir desde afuera no es evidencia):
24
+ * algoritmo: SHA-256
25
+ * codificacion: UTF-8
26
+ * forma canonica: las tres partes unidas por \n, en este orden --
27
+ * (1) el commit de HEAD (40 hex)
28
+ * (2) la salida de `git status --porcelain -uall`
29
+ * (3) la salida de `git diff HEAD`
30
+ * cubre: el contenido de todo archivo rastreado (via la parte 3)
31
+ * y la LISTA de archivos sin rastrear (via la parte 2)
32
+ * excluye: el CONTENIDO de los archivos sin rastrear, y todo lo que
33
+ * .gitignore descarta (node_modules, dist). Un cambio solo
34
+ * ahi no mueve la huella, y eso esta dicho a proposito:
35
+ * decir que cubre mas de lo que cubre es el defecto que
36
+ * este archivo existe para no repetir.
37
+ *
38
+ * ASCII-only.
39
+ */
40
+ import { createHash } from 'node:crypto';
41
+ import { execFileSync } from 'node:child_process';
42
+ import fs from 'node:fs';
43
+ import path from 'node:path';
44
+ export const BATTERY_STAMP_REL = '.forge/battery-stamp.json';
45
+ export const FINGERPRINT_SPEC = 'sha256(utf8(HEAD + "\\n" + `git status --porcelain -uall`'
46
+ + ' sin la linea del propio sello + "\\n" + `git diff HEAD`)); cubre el contenido'
47
+ + ' rastreado y la lista de archivos sin rastrear; excluye el contenido sin'
48
+ + ' rastrear, lo ignorado y el archivo del sello';
49
+ /** Si la invocacion llevaba un filtro de archivos. Mecanico: cualquier
50
+ * argumento posicional que no sea una bandera ni el subcomando `run` es un
51
+ * patron de archivos para vitest.
52
+ *
53
+ * El sesgo es a proposito: `--reporter default` (con espacio) se lee como
54
+ * filtro y el sello sale marcado parcial sin serlo. Equivocarse hacia
55
+ * "parcial" avisa de mas; equivocarse hacia "completa" es el verde que
56
+ * afirma lo que no midio. */
57
+ export function isFilteredInvocation(args) {
58
+ return args.some((a) => a !== 'run' && a !== 'watch' && !a.startsWith('-'));
59
+ }
60
+ /** La huella y el estado de git, calculados en UN solo lugar. Si el sello y
61
+ * la verificacion los calcularan por su cuenta, un dia divergirian y la
62
+ * comparacion diria "no coincide" sin que nada hubiera cambiado -- o peor,
63
+ * al reves (simetria productor/consumidor, SQ 14). */
64
+ export function readGitState(cwd) {
65
+ const git = (args) => execFileSync('git', args, {
66
+ cwd, encoding: 'utf8', windowsHide: true, maxBuffer: 64 * 1024 * 1024,
67
+ stdio: ['ignore', 'pipe', 'ignore'],
68
+ });
69
+ const commit = git(['rev-parse', 'HEAD']).trim();
70
+ /* El sello se EXCLUYE de su propia huella. En este repositorio esta
71
+ * ignorado por git y no aparece, pero en uno que no lo ignore si: y
72
+ * entonces escribir el sello cambiaria la huella que el sello acaba de
73
+ * guardar, y el instrumento diria "no coincide" SIEMPRE. Un instrumento
74
+ * que avisa siempre deja de avisar -- se desactiva. */
75
+ const status = git(['status', '--porcelain', '-uall'])
76
+ .split(/\r?\n/)
77
+ .filter((l) => !l.includes(BATTERY_STAMP_REL) && !l.includes(BATTERY_STAMP_REL.replace(/\//g, '\\')))
78
+ .join('\n');
79
+ const diff = git(['diff', 'HEAD']);
80
+ return {
81
+ commit,
82
+ dirty: status.trim().length > 0,
83
+ fingerprint: createHash('sha256').update(commit + '\n' + status + '\n' + diff, 'utf8').digest('hex'),
84
+ fingerprint_spec: FINGERPRINT_SPEC,
85
+ };
86
+ }
87
+ /** Los numeros de una corrida de vitest, del arbol de tareas que el
88
+ * reporter recibe. Pura a proposito: el arbol se puede sintetizar en un
89
+ * caso y asi el contador se prueba sin correr la bateria dentro de la
90
+ * bateria. */
91
+ export function countFromFiles(files) {
92
+ const counts = { files: files.length, passed: 0, failed: 0, skipped: 0 };
93
+ const walk = (task) => {
94
+ const kids = Array.isArray(task.tasks) ? task.tasks : undefined;
95
+ if (kids) {
96
+ for (const k of kids)
97
+ walk(k);
98
+ return;
99
+ }
100
+ const state = task.result?.state;
101
+ if (state === 'pass')
102
+ counts.passed++;
103
+ else if (state === 'fail')
104
+ counts.failed++;
105
+ else
106
+ counts.skipped++;
107
+ };
108
+ for (const f of files)
109
+ walk(f);
110
+ return counts;
111
+ }
112
+ export function writeBatteryStamp(repoRoot, stamp) {
113
+ const file = path.join(repoRoot, BATTERY_STAMP_REL);
114
+ fs.mkdirSync(path.dirname(file), { recursive: true });
115
+ fs.writeFileSync(file, JSON.stringify(stamp, null, 2) + '\n', 'utf8');
116
+ }
117
+ export function readBatteryStamp(repoRoot) {
118
+ try {
119
+ const raw = fs.readFileSync(path.join(repoRoot, BATTERY_STAMP_REL), 'utf8');
120
+ const parsed = JSON.parse(raw);
121
+ return parsed && parsed.version === 1 ? parsed : null;
122
+ }
123
+ catch {
124
+ return null;
125
+ }
126
+ }
127
+ export function judgeFreshness(stamp, current) {
128
+ if (!stamp)
129
+ return { verdict: 'never', stale: true, stamp, current };
130
+ if (!stamp.green)
131
+ return { verdict: 'red', stale: true, stamp, current };
132
+ if (stamp.filtered)
133
+ return { verdict: 'partial', stale: true, stamp, current };
134
+ if (stamp.fingerprint === current.fingerprint) {
135
+ return { verdict: 'same_content', stale: false, stamp, current };
136
+ }
137
+ return {
138
+ verdict: stamp.commit === current.commit ? 'same_commit' : 'other_commit',
139
+ stale: true, stamp, current,
140
+ };
141
+ }
142
+ function when(ms) {
143
+ const d = new Date(ms);
144
+ const pad = (n) => String(n).padStart(2, '0');
145
+ return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate())
146
+ + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes());
147
+ }
148
+ /** El aviso, con el formato que el dueno pidio: en que commit corrio la
149
+ * bateria por ultima vez, en que commit estas, y si no coinciden lo dice. */
150
+ export function renderFreshness(r) {
151
+ const out = [];
152
+ const cur = r.current.commit.slice(0, 7) + (r.current.dirty ? ' (arbol sucio)' : '');
153
+ if (r.verdict === 'never') {
154
+ out.push('bateria: NO HAY SELLO -- en este arbol no hay registro de ninguna corrida.');
155
+ out.push('Estas en: ' + cur + '.');
156
+ out.push('Eso NO quiere decir que la bateria no corrio: quiere decir que nadie lo');
157
+ out.push('registro, que para decidir si publicar es lo mismo.');
158
+ }
159
+ else {
160
+ const s = r.stamp;
161
+ const tail = s.counts.passed + ' pasados, ' + s.counts.failed + ' fallados, '
162
+ + s.counts.skipped + ' salteados, ' + s.counts.files + ' archivos';
163
+ out.push('bateria: ultima corrida en ' + s.commit.slice(0, 7) + (s.dirty ? ' (arbol sucio)' : '')
164
+ + ' el ' + when(s.ran_at) + ' -- ' + (s.green ? 'VERDE' : 'ROJA')
165
+ + (s.filtered ? ', PARCIAL' : '') + ' (' + tail + ').');
166
+ out.push('Estas en: ' + cur + '.');
167
+ if (r.verdict === 'same_content') {
168
+ out.push('Coinciden: la bateria vio EXACTAMENTE este contenido (huella '
169
+ + s.fingerprint.slice(0, 12) + ').');
170
+ }
171
+ else if (r.verdict === 'partial') {
172
+ out.push('AVISO: LA ULTIMA CORRIDA FUE PARCIAL (' + s.invocation + '), asi que el');
173
+ out.push('sello dice que paso una PARTE. La bateria completa no tiene registro aca.');
174
+ }
175
+ else if (r.verdict === 'red') {
176
+ out.push('AVISO: el ultimo sello es ROJO. Lo que se esta por empaquetar no tiene');
177
+ out.push('una corrida verde que lo respalde.');
178
+ }
179
+ else if (r.verdict === 'same_commit') {
180
+ out.push('AVISO: MISMO COMMIT, CONTENIDO DISTINTO. Las fuentes se movieron despues');
181
+ out.push('de la corrida (huella ' + s.fingerprint.slice(0, 12) + ' contra '
182
+ + r.current.fingerprint.slice(0, 12) + ').');
183
+ out.push('Esta es la forma exacta de 1.20.1: el tarball se armo con fuentes que la');
184
+ out.push('compuerta no habia visto. No edites fuentes durante el publish.');
185
+ }
186
+ else {
187
+ out.push('AVISO: LA BATERIA CORRIO EN OTRO COMMIT. Lo que se va a empaquetar no es');
188
+ out.push('lo que la bateria verifico.');
189
+ }
190
+ }
191
+ out.push('Huella: ' + r.current.fingerprint_spec + '.');
192
+ if (r.stale) {
193
+ out.push('La bateria (418 s) queda FUERA del gancho pre-push a proposito -- la');
194
+ out.push('decision y su motivo estan en docs/PROGRAMMING_NORMS.md. Este aviso es el');
195
+ out.push('instrumento de ese riesgo aceptado: correla con `pnpm test` antes de');
196
+ out.push('publicar, o publica sabiendo lo que falta.');
197
+ }
198
+ return out.join('\n');
199
+ }
200
+ /** El reporter de vitest que deja el sello. Pato-tipado (no importa tipos
201
+ * de vitest) para que este modulo siga siendo parte del producto y no de
202
+ * la bateria. */
203
+ export class BatteryStampReporter {
204
+ started = Date.now();
205
+ root;
206
+ invocation;
207
+ filtered;
208
+ constructor(opts) {
209
+ this.root = opts?.root ?? process.cwd();
210
+ const args = process.argv.slice(2);
211
+ this.invocation = opts?.invocation ?? ('vitest ' + args.join(' ')).trim();
212
+ this.filtered = opts?.filtered ?? isFilteredInvocation(args);
213
+ }
214
+ onInit() { this.started = Date.now(); }
215
+ onFinished(files = [], errors = []) {
216
+ try {
217
+ const counts = countFromFiles(files);
218
+ const stamp = {
219
+ version: 1,
220
+ ran_at: Date.now(),
221
+ duration_ms: Date.now() - this.started,
222
+ counts,
223
+ green: counts.failed === 0 && (!errors || errors.length === 0) && counts.files > 0,
224
+ invocation: this.invocation,
225
+ filtered: this.filtered,
226
+ ...readGitState(this.root),
227
+ };
228
+ writeBatteryStamp(this.root, stamp);
229
+ }
230
+ catch {
231
+ /* Un sello que no se pudo escribir no puede voltear una corrida: el
232
+ * instrumento no es la bateria. El silencio lo cubre el otro lado --
233
+ * `battery_freshness` distingue "no hay sello" de "esta fresco". */
234
+ }
235
+ }
236
+ }
237
+ //# sourceMappingURL=battery_stamp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"battery_stamp.js","sourceRoot":"","sources":["../../src/core/battery_stamp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * LO QUE LA CADENA NO CORRIO -- F-14 / F-15 (pedido del dueno, 2026-11-01).
3
+ *
4
+ * EL DEFECTO. Medido en el repositorio: `.github/workflows/ci.yml` instala y
5
+ * corre `typecheck`, nada mas; `prepublishOnly` corre SEIS compuertas (build,
6
+ * typecheck, catalog:lint, test, brain-matrix:gate, hito4:lint). Asi que un
7
+ * VERDE en el badge de CI no significa "la bateria paso" -- significa "los
8
+ * tipos compilan" -- y nada en la salida de la corrida lo dice. Esta forma ya
9
+ * costo una vez: 1.20.1 salio publicada con un bug adentro.
10
+ *
11
+ * El dueno NO pidio mover las compuertas pesadas a la cadena (es una decision
12
+ * suya, con su motivo: la matriz multi-OS consumia la cuota en una rafaga).
13
+ * Pidio que la corrida DECLARE lo que no corrio. Es la misma regla que el
14
+ * metodo aplica a un recibo: una corrida que no mide algo tiene que decir que
15
+ * no lo midio, porque el que lee un verde no tiene otra forma de saberlo.
16
+ *
17
+ * Y LA PAREJA QUE EL DUENO SOSPECHO Y RESULTO PEOR (F-15). `lefthook.yml`
18
+ * declaraba un `pre-push` con `pnpm test` + `brain-matrix:gate`: dos
19
+ * compuertas, no las seis del publish. Pero antes de eso: el gancho no
20
+ * estaba instalado y no podia estarlo -- `.git/hooks` vacio,
21
+ * `core.hooksPath` sin poner, `lefthook` no era dependencia. Asi que la
22
+ * "preflight local" a la que el comentario de ci.yml remite no la corria
23
+ * ningun mecanismo: era un habito. Y el circulo se cerraba solo: ci.yml
24
+ * decia que lo pesado corre local, y lefthook.yml decia "CI is the real
25
+ * gate". Cada uno senalaba al otro y ninguno lo hacia.
26
+ *
27
+ * ARREGLADO EL 2026-11-01, con la decision del dueno: `lefthook` es
28
+ * devDependency, el ciclo `prepare` lo instala, y el pre-push corre el
29
+ * paquete de 24,8 s (todo `prepublishOnly` menos la bateria). La cadena NO
30
+ * se ensancha -- se mantiene liviana por cuota -- asi que para el trabajo en
31
+ * rama el gancho es la UNICA puerta. De ahi los dos agregados de este
32
+ * modulo: `triggers`, porque una cadena que solo dispara en main no es una
33
+ * segunda puerta para una rama; y la cobertura POR EQUIVALENCIA, porque el
34
+ * gancho invoca los scripts directo (arranca mas rapido) y `build` corre el
35
+ * mismo `tsc` que `typecheck` -- decir "no corre typecheck" ahi seria una
36
+ * falsa alarma, y una falsa alarma termina con el instrumento apagado.
37
+ *
38
+ * POR QUE ESTO SE DERIVA Y NO SE ESCRIBE A MANO. Una lista fija de "lo que
39
+ * no corre" es una segunda fuente de verdad, y se desincroniza el dia que
40
+ * alguien agrega una compuerta al publish -- el mismo defecto que este
41
+ * modulo esta reportando. Asi que las tres listas salen de los archivos que
42
+ * YA son la verdad (package.json, el workflow, lefthook.yml) y la diferencia
43
+ * se calcula. Si una de las tres no se puede leer, esto FALLA: una medicion
44
+ * que no se pudo hacer no se reporta como "no falta nada".
45
+ *
46
+ * ASCII-only.
47
+ */
48
+ export interface CiGapReport {
49
+ /** Los scripts npm que la corrida de CI ejecuta de verdad. */
50
+ ran: string[];
51
+ /** Los que la compuerta de publicacion exige y la cadena NO corre. */
52
+ not_run: string[];
53
+ /** Los que el gancho local declara (este o no instalado). Son los
54
+ * nombres de compuerta del publish que el gancho CUBRE: directamente
55
+ * (corre el script) o por equivalencia (corre otro script que invoca el
56
+ * mismo programa -- `build` corre el mismo `tsc` que `typecheck`). */
57
+ hook_declares: string[];
58
+ /** De los anteriores, los que el gancho cubre por EQUIVALENCIA y no por
59
+ * nombre. Se separan porque son la parte que hay que poder explicar: un
60
+ * "lo cubre otro" sin decir cual es una afirmacion sin respaldo. */
61
+ hook_covers_by_equivalence: Array<{
62
+ gate: string;
63
+ via: string;
64
+ }>;
65
+ /** Los del publish que el gancho local tampoco corre. */
66
+ hook_not_run: string[];
67
+ /** La cobertura de plataforma de la corrida, leida del workflow. */
68
+ os: string[];
69
+ node: string[];
70
+ /** Lo que ninguna de las tres puertas corre. */
71
+ nobody_runs: string[];
72
+ /** CUANDO dispara la cadena, leido del `on:` del workflow. El cuarto
73
+ * hueco de F-15: con `push: [main]` y `pull_request: [main]`, una rama
74
+ * sin PR no tiene NINGUNA corrida, asi que para el trabajo en rama la
75
+ * cadena no es una segunda puerta -- no es ninguna. */
76
+ triggers: {
77
+ push: string[];
78
+ pull_request: string[];
79
+ other: string[];
80
+ };
81
+ }
82
+ /** Los nombres de script que una linea de comandos invoca. Cubre las formas
83
+ * que este repositorio usa de verdad (`pnpm run x`, `pnpm x`, `npm run x`)
84
+ * y nada mas: inventar formas que nadie escribe es ruido. */
85
+ export declare function scriptsInvoked(command: string): string[];
86
+ /** Los PROGRAMAS que una linea de comandos invoca de verdad, expandiendo
87
+ * los scripts del paquete. Es lo que permite decir "el gancho cubre
88
+ * `typecheck` porque corre `build`, que corre el mismo tsc" sin escribirlo
89
+ * a mano en ninguna lista.
90
+ *
91
+ * La forma de cada invocacion: el programa, y para `node` tambien el
92
+ * archivo (`node:scripts/catalog_lint.mjs`) -- dos scripts de node
93
+ * distintos no son la misma compuerta. */
94
+ export declare function invocationsOf(command: string, scripts?: Record<string, string>, seen?: Set<string>): string[];
95
+ /** El `on:` del workflow: en que ramas dispara cada evento. Atajo sobre el
96
+ * YAML, igual que `runLines`, y por el mismo motivo: un parser completo
97
+ * seria una dependencia nueva para leer cuatro lineas, y el caso corre
98
+ * sobre el archivo real, asi que una forma que esto no entienda sale roja
99
+ * en vez de salir en silencio. */
100
+ export declare function readTriggers(yaml: string): {
101
+ push: string[];
102
+ pull_request: string[];
103
+ other: string[];
104
+ };
105
+ export interface CiGapInputs {
106
+ /** El contenido de package.json, ya parseado. */
107
+ pkg: {
108
+ scripts?: Record<string, string>;
109
+ };
110
+ /** El YAML del workflow de CI. */
111
+ workflow: string;
112
+ /** El YAML de lefthook. Opcional: un repositorio sin gancho declarado es
113
+ * un estado legitimo, y entonces las dos listas del gancho son vacias. */
114
+ lefthook?: string;
115
+ }
116
+ /** Derivar las tres listas y su diferencia. Tira cuando no puede medir: una
117
+ * medicion imposible no se reporta como "no falta nada". */
118
+ export declare function deriveCiGaps(input: CiGapInputs): CiGapReport;
119
+ /** Solo la seccion `pre-push` de lefthook.yml. El `pre-commit` corre en otro
120
+ * momento y meterlo aca diria que el push verifica mas de lo que verifica,
121
+ * que es el defecto, al revez. */
122
+ export declare function preprocessLefthookPrePush(yaml: string): string;
123
+ /** LA DECLARACION, con el formato que el dueno pidio textualmente.
124
+ *
125
+ * Primero lo que SI se verifico y despues lo que NO, en ese orden y en la
126
+ * misma salida: una lista de ausencias al final de un log de 300 lineas no
127
+ * la lee nadie. */
128
+ export declare function renderCiGaps(r: CiGapReport): string;
129
+ //# sourceMappingURL=ci_gaps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci_gaps.d.ts","sourceRoot":"","sources":["../../src/core/ci_gaps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,MAAM,WAAW,WAAW;IAC1B,8DAA8D;IAC9D,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,sEAAsE;IACtE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;2EAGuE;IACvE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB;;yEAEqE;IACrE,0BAA0B,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,yDAAyD;IACzD,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,oEAAoE;IACpE,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gDAAgD;IAChD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB;;;4DAGwD;IACxD,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,YAAY,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACvE;AAED;;8DAE8D;AAC9D,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAWxD;AAED;;;;;;;2CAO2C;AAC3C,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACpC,IAAI,GAAE,GAAG,CAAC,MAAM,CAAa,GAC5B,MAAM,EAAE,CA4CV;AAmDD;;;;mCAImC;AACnC,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CA+BtG;AAED,MAAM,WAAW,WAAW;IAC1B,iDAAiD;IACjD,GAAG,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IAC1C,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB;+EAC2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;6DAC6D;AAC7D,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CAwD5D;AAED;;mCAEmC;AACnC,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW9D;AAED;;;;oBAIoB;AACpB,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CA8CnD"}