@nac3/forge-cli 1.23.7 → 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.
- package/dist/bin/yf.js +0 -0
- package/dist/chat/claude.d.ts +8 -0
- package/dist/chat/claude.d.ts.map +1 -1
- package/dist/chat/claude.js.map +1 -1
- package/dist/chat/claude_cli.d.ts +23 -0
- package/dist/chat/claude_cli.d.ts.map +1 -1
- package/dist/chat/claude_cli.js +76 -2
- package/dist/chat/claude_cli.js.map +1 -1
- package/dist/chat/doctrine_digest.d.ts.map +1 -1
- package/dist/chat/doctrine_digest.js +2 -1
- package/dist/chat/doctrine_digest.js.map +1 -1
- package/dist/chat/server.d.ts.map +1 -1
- package/dist/chat/server.js +11 -0
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/tools/pending.d.ts +11 -0
- package/dist/chat/tools/pending.d.ts.map +1 -1
- package/dist/chat/tools/pending.js +55 -8
- package/dist/chat/tools/pending.js.map +1 -1
- package/dist/chat/tools/shell.d.ts +39 -4
- package/dist/chat/tools/shell.d.ts.map +1 -1
- package/dist/chat/tools/shell.js +167 -7
- package/dist/chat/tools/shell.js.map +1 -1
- package/dist/chat/tools/urazuke.d.ts.map +1 -1
- package/dist/chat/tools/urazuke.js +8 -5
- package/dist/chat/tools/urazuke.js.map +1 -1
- package/dist/chat/urazuke_section.d.ts +26 -4
- package/dist/chat/urazuke_section.d.ts.map +1 -1
- package/dist/chat/urazuke_section.js +115 -9
- package/dist/chat/urazuke_section.js.map +1 -1
- package/dist/commands/pending.d.ts.map +1 -1
- package/dist/commands/pending.js +116 -12
- package/dist/commands/pending.js.map +1 -1
- package/dist/commands/urazuke.d.ts +3 -0
- package/dist/commands/urazuke.d.ts.map +1 -1
- package/dist/commands/urazuke.js +80 -3
- package/dist/commands/urazuke.js.map +1 -1
- package/dist/core/ascii_purity.d.ts +69 -0
- package/dist/core/ascii_purity.d.ts.map +1 -0
- package/dist/core/ascii_purity.js +141 -0
- package/dist/core/ascii_purity.js.map +1 -0
- package/dist/core/battery_stamp.d.ts +85 -0
- package/dist/core/battery_stamp.d.ts.map +1 -0
- package/dist/core/battery_stamp.js +237 -0
- package/dist/core/battery_stamp.js.map +1 -0
- package/dist/core/ci_gaps.d.ts +129 -0
- package/dist/core/ci_gaps.d.ts.map +1 -0
- package/dist/core/ci_gaps.js +352 -0
- package/dist/core/ci_gaps.js.map +1 -0
- package/dist/core/doc_citations.d.ts +133 -0
- package/dist/core/doc_citations.d.ts.map +1 -0
- package/dist/core/doc_citations.js +271 -0
- package/dist/core/doc_citations.js.map +1 -0
- package/dist/docs/doctrine/urazuke.md +173 -2
- package/dist/nac3/internal_manifest.d.ts.map +1 -1
- package/dist/nac3/internal_manifest.js +28 -2
- package/dist/nac3/internal_manifest.js.map +1 -1
- package/dist/pending/store.d.ts +29 -0
- package/dist/pending/store.d.ts.map +1 -1
- package/dist/pending/store.js +51 -1
- package/dist/pending/store.js.map +1 -1
- package/dist/pending/types.d.ts +23 -0
- package/dist/pending/types.d.ts.map +1 -1
- package/dist/pending/types.js.map +1 -1
- package/dist/telemetry/usage.d.ts +18 -0
- package/dist/telemetry/usage.d.ts.map +1 -1
- package/dist/telemetry/usage.js +16 -1
- package/dist/telemetry/usage.js.map +1 -1
- package/dist/urazuke/announce.d.ts +7 -0
- package/dist/urazuke/announce.d.ts.map +1 -1
- package/dist/urazuke/announce.js +20 -0
- package/dist/urazuke/announce.js.map +1 -1
- package/dist/urazuke/catalog.d.ts +1 -1
- package/dist/urazuke/catalog.d.ts.map +1 -1
- package/dist/urazuke/catalog.js.map +1 -1
- package/dist/urazuke/close_gate.d.ts +31 -4
- package/dist/urazuke/close_gate.d.ts.map +1 -1
- package/dist/urazuke/close_gate.js +70 -13
- package/dist/urazuke/close_gate.js.map +1 -1
- package/dist/urazuke/current.d.ts +28 -0
- package/dist/urazuke/current.d.ts.map +1 -1
- package/dist/urazuke/current.js +18 -5
- package/dist/urazuke/current.js.map +1 -1
- package/dist/urazuke/cycle.d.ts +3 -0
- package/dist/urazuke/cycle.d.ts.map +1 -1
- package/dist/urazuke/cycle.js +5 -3
- package/dist/urazuke/cycle.js.map +1 -1
- package/dist/urazuke/evidence.d.ts +14 -1
- package/dist/urazuke/evidence.d.ts.map +1 -1
- package/dist/urazuke/evidence.js +88 -2
- package/dist/urazuke/evidence.js.map +1 -1
- package/dist/urazuke/evidence_env.d.ts +78 -0
- package/dist/urazuke/evidence_env.d.ts.map +1 -0
- package/dist/urazuke/evidence_env.js +341 -0
- package/dist/urazuke/evidence_env.js.map +1 -0
- package/dist/urazuke/freeze.d.ts.map +1 -1
- package/dist/urazuke/freeze.js +16 -9
- package/dist/urazuke/freeze.js.map +1 -1
- package/dist/urazuke/gate.d.ts +48 -0
- package/dist/urazuke/gate.d.ts.map +1 -1
- package/dist/urazuke/gate.js +251 -25
- package/dist/urazuke/gate.js.map +1 -1
- package/dist/urazuke/gates_data.d.ts +30 -3
- package/dist/urazuke/gates_data.d.ts.map +1 -1
- package/dist/urazuke/gates_data.js +51 -5
- package/dist/urazuke/gates_data.js.map +1 -1
- package/dist/urazuke/gates_pull.d.ts +40 -0
- package/dist/urazuke/gates_pull.d.ts.map +1 -1
- package/dist/urazuke/gates_pull.js +118 -8
- package/dist/urazuke/gates_pull.js.map +1 -1
- package/dist/urazuke/manual_cases.d.ts +11 -1
- package/dist/urazuke/manual_cases.d.ts.map +1 -1
- package/dist/urazuke/manual_cases.js +1 -0
- package/dist/urazuke/manual_cases.js.map +1 -1
- package/dist/urazuke/overrides.d.ts +107 -0
- package/dist/urazuke/overrides.d.ts.map +1 -0
- package/dist/urazuke/overrides.js +128 -0
- package/dist/urazuke/overrides.js.map +1 -0
- package/dist/urazuke/probes.d.ts.map +1 -1
- package/dist/urazuke/probes.js +51 -0
- package/dist/urazuke/probes.js.map +1 -1
- package/dist/urazuke/profiles.d.ts +135 -0
- package/dist/urazuke/profiles.d.ts.map +1 -0
- package/dist/urazuke/profiles.js +470 -0
- package/dist/urazuke/profiles.js.map +1 -0
- package/dist/urazuke/receipt_audit.d.ts +67 -0
- package/dist/urazuke/receipt_audit.d.ts.map +1 -0
- package/dist/urazuke/receipt_audit.js +103 -0
- package/dist/urazuke/receipt_audit.js.map +1 -0
- package/dist/urazuke/receipts.d.ts +22 -0
- package/dist/urazuke/receipts.d.ts.map +1 -1
- package/dist/urazuke/receipts.js +44 -0
- package/dist/urazuke/receipts.js.map +1 -1
- package/dist/urazuke/report.d.ts +30 -0
- package/dist/urazuke/report.d.ts.map +1 -1
- package/dist/urazuke/report.js +39 -0
- package/dist/urazuke/report.js.map +1 -1
- package/dist/urazuke/reset.d.ts +35 -0
- package/dist/urazuke/reset.d.ts.map +1 -0
- package/dist/urazuke/reset.js +150 -0
- package/dist/urazuke/reset.js.map +1 -0
- package/dist/urazuke/retro.d.ts +5 -1
- package/dist/urazuke/retro.d.ts.map +1 -1
- package/dist/urazuke/retro.js +21 -8
- package/dist/urazuke/retro.js.map +1 -1
- package/dist/urazuke/section.d.ts.map +1 -1
- package/dist/urazuke/section.js +17 -2
- package/dist/urazuke/section.js.map +1 -1
- package/dist/urazuke/semantics.d.ts +173 -0
- package/dist/urazuke/semantics.d.ts.map +1 -0
- package/dist/urazuke/semantics.js +232 -0
- package/dist/urazuke/semantics.js.map +1 -0
- package/dist/urazuke/start.d.ts +8 -0
- package/dist/urazuke/start.d.ts.map +1 -1
- package/dist/urazuke/start.js +10 -2
- package/dist/urazuke/start.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workflow/orchestrator.d.ts.map +1 -1
- package/dist/workflow/orchestrator.js +6 -7
- package/dist/workflow/orchestrator.js.map +1 -1
- package/docs/doctrine/urazuke.md +173 -2
- 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"}
|