@imolko/ultra-agent 0.2.0-beta → 1.0.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-node/materializer.d.ts.map +1 -1
- package/dist-node/materializer.js +2 -1
- package/dist-node/materializer.js.map +1 -1
- package/dist-node/payload.d.ts +18 -4
- package/dist-node/payload.d.ts.map +1 -1
- package/dist-node/payload.js +27 -6
- package/dist-node/payload.js.map +1 -1
- package/docs/adr/ADR-0000-proceso-y-formato-de-adrs.md +2 -2
- package/docs/adr/foundational/A-052-distribucion-metodologia-paquete-versionado.md +1 -1
- package/package.json +8 -2
- package/scripts/adr-gate/links.mjs +59 -0
- package/scripts/adr-gate/registry.mjs +155 -0
- package/scripts/adr-gate/report.mjs +21 -0
- package/scripts/adr-gate/rules/enlaces.mjs +33 -0
- package/scripts/adr-gate/rules/frontmatter.mjs +126 -0
- package/scripts/adr-gate/rules/hardcoded.mjs +63 -0
- package/scripts/adr-gate/rules/indices.mjs +100 -0
- package/scripts/adr-gate/rules/jerarquia.mjs +102 -0
- package/scripts/adr-gate/text.mjs +263 -0
- package/scripts/ensure-bin-exec.mjs +8 -3
- package/scripts/verify-adr-consistency.mjs +71 -0
- package/skills/writing-for-agents/references/adrs.md +2 -2
- package/scripts/verify-adr-consistency.py +0 -250
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"materializer.d.ts","sourceRoot":"","sources":["../src/materializer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,EAKL,sBAAsB,EAEvB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,yBAAyB,EAG1B,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,CAAC;AAE7D,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,uBAAuB,CAAC;AAIzD,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,SAAS,GAAG,MAAM,CAAC;IAC/B,WAAW,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CAC9C;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,qBAAa,UAAW,SAAQ,KAAK;aACP,KAAK,EAAE,MAAM,EAAE;gBAAf,KAAK,EAAE,MAAM,EAAE;CAO5C;AA+BD,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"materializer.d.ts","sourceRoot":"","sources":["../src/materializer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,EAKL,sBAAsB,EAEvB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,yBAAyB,EAG1B,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,CAAC;AAE7D,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,uBAAuB,CAAC;AAIzD,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,SAAS,GAAG,MAAM,CAAC;IAC/B,WAAW,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CAC9C;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,qBAAa,UAAW,SAAQ,KAAK;aACP,KAAK,EAAE,MAAM,EAAE;gBAAf,KAAK,EAAE,MAAM,EAAE;CAO5C;AA+BD,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAe5E;AA0DD,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,aAAa,CAYrE;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,YAAY,CA2CtG;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY,CAoBnE"}
|
|
@@ -61,7 +61,8 @@ function walk(dir) {
|
|
|
61
61
|
/** Recorre el árbol del paquete y devuelve los archivos a espejar. */
|
|
62
62
|
function collectPayload(packageRoot, version) {
|
|
63
63
|
const adrFiles = walk((0, node_path_1.join)(packageRoot, "docs", "adr")).map((f) => `docs/adr/${f}`);
|
|
64
|
-
const
|
|
64
|
+
const gateModules = walk((0, node_path_1.join)(packageRoot, payload_1.GATE_MODULES_RELATIVE_DIR)).map((f) => `${payload_1.GATE_MODULES_RELATIVE_DIR}/${f}`);
|
|
65
|
+
const candidates = [...adrFiles, payload_1.GATE_RELATIVE_PATH, ...gateModules];
|
|
65
66
|
const files = [];
|
|
66
67
|
for (const relativePath of (0, payload_1.selectPayloadFiles)(candidates)) {
|
|
67
68
|
const abs = (0, node_path_1.join)(packageRoot, relativePath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"materializer.js","sourceRoot":"","sources":["../src/materializer.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AA2GH,
|
|
1
|
+
{"version":3,"file":"materializer.js","sourceRoot":"","sources":["../src/materializer.ts"],"names":[],"mappings":"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"}
|
package/dist-node/payload.d.ts
CHANGED
|
@@ -6,8 +6,16 @@
|
|
|
6
6
|
* Funciones puras: reciben una lista de rutas relativas al paquete y devuelven la
|
|
7
7
|
* lista de archivos a espejar, sin E/S.
|
|
8
8
|
*/
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Ruta relativa del gate de consistencia dentro del paquete (y del consumidor).
|
|
11
|
+
* Se ejecuta con Node, el runtime que el paquete garantiza.
|
|
12
|
+
*/
|
|
13
|
+
export declare const GATE_RELATIVE_PATH = "scripts/verify-adr-consistency.mjs";
|
|
14
|
+
/**
|
|
15
|
+
* Directorio de los módulos internos del gate. El gate los importa con rutas
|
|
16
|
+
* relativas, así que el payload los espeja junto al ejecutable.
|
|
17
|
+
*/
|
|
18
|
+
export declare const GATE_MODULES_RELATIVE_DIR = "scripts/adr-gate";
|
|
11
19
|
/**
|
|
12
20
|
* ¿Es un archivo del registro ADR canónico (tier A/T/P o ADR-0000 o índice raíz)?
|
|
13
21
|
* Cualquier otro `.md` en la raíz de `docs/adr/` es tier de proyecto y queda
|
|
@@ -16,8 +24,14 @@ export declare const GATE_RELATIVE_PATH = "scripts/verify-adr-consistency.py";
|
|
|
16
24
|
*/
|
|
17
25
|
export declare function isCanonicalAdr(relativePath: string): boolean;
|
|
18
26
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
27
|
+
* ¿Es el ejecutable del gate o uno de sus módulos internos?
|
|
28
|
+
* @param {string} relativePath Ruta relativa ya normalizada.
|
|
29
|
+
* @returns {boolean}
|
|
30
|
+
*/
|
|
31
|
+
export declare function isGateFile(relativePath: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Devuelve la lista de archivos a espejar (ADRs canónicos + gate + módulos),
|
|
34
|
+
* ordenada. Excluye el tier de proyecto y cualquier archivo que no sea payload.
|
|
21
35
|
*/
|
|
22
36
|
export declare function selectPayloadFiles(files: string[]): string[];
|
|
23
37
|
//# sourceMappingURL=payload.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../src/payload.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH
|
|
1
|
+
{"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../src/payload.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;GAGG;AACH,eAAO,MAAM,kBAAkB,uCAAuC,CAAC;AAEvE;;;GAGG;AACH,eAAO,MAAM,yBAAyB,qBAAqB,CAAC;AAQ5D;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAY5D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAQxD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAM5D"}
|
package/dist-node/payload.js
CHANGED
|
@@ -8,11 +8,20 @@
|
|
|
8
8
|
* lista de archivos a espejar, sin E/S.
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.GATE_RELATIVE_PATH = void 0;
|
|
11
|
+
exports.GATE_MODULES_RELATIVE_DIR = exports.GATE_RELATIVE_PATH = void 0;
|
|
12
12
|
exports.isCanonicalAdr = isCanonicalAdr;
|
|
13
|
+
exports.isGateFile = isGateFile;
|
|
13
14
|
exports.selectPayloadFiles = selectPayloadFiles;
|
|
14
|
-
/**
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Ruta relativa del gate de consistencia dentro del paquete (y del consumidor).
|
|
17
|
+
* Se ejecuta con Node, el runtime que el paquete garantiza.
|
|
18
|
+
*/
|
|
19
|
+
exports.GATE_RELATIVE_PATH = "scripts/verify-adr-consistency.mjs";
|
|
20
|
+
/**
|
|
21
|
+
* Directorio de los módulos internos del gate. El gate los importa con rutas
|
|
22
|
+
* relativas, así que el payload los espeja junto al ejecutable.
|
|
23
|
+
*/
|
|
24
|
+
exports.GATE_MODULES_RELATIVE_DIR = "scripts/adr-gate";
|
|
16
25
|
const TIER_DIRS = ["foundational", "typescript", "python"];
|
|
17
26
|
function normalize(path) {
|
|
18
27
|
return path.replace(/\\/g, "/");
|
|
@@ -37,13 +46,25 @@ function isCanonicalAdr(relativePath) {
|
|
|
37
46
|
return false;
|
|
38
47
|
}
|
|
39
48
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
49
|
+
* ¿Es el ejecutable del gate o uno de sus módulos internos?
|
|
50
|
+
* @param {string} relativePath Ruta relativa ya normalizada.
|
|
51
|
+
* @returns {boolean}
|
|
52
|
+
*/
|
|
53
|
+
function isGateFile(relativePath) {
|
|
54
|
+
return (relativePath === exports.GATE_RELATIVE_PATH ||
|
|
55
|
+
(relativePath.startsWith(`${exports.GATE_MODULES_RELATIVE_DIR}/`) &&
|
|
56
|
+
relativePath.endsWith(".mjs") &&
|
|
57
|
+
!relativePath.endsWith(".test.mjs") &&
|
|
58
|
+
!relativePath.endsWith(".spec.mjs")));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Devuelve la lista de archivos a espejar (ADRs canónicos + gate + módulos),
|
|
62
|
+
* ordenada. Excluye el tier de proyecto y cualquier archivo que no sea payload.
|
|
42
63
|
*/
|
|
43
64
|
function selectPayloadFiles(files) {
|
|
44
65
|
const selected = files.filter((file) => {
|
|
45
66
|
const path = normalize(file);
|
|
46
|
-
return isCanonicalAdr(path) || path
|
|
67
|
+
return isCanonicalAdr(path) || isGateFile(path);
|
|
47
68
|
});
|
|
48
69
|
return selected.sort();
|
|
49
70
|
}
|
package/dist-node/payload.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payload.js","sourceRoot":"","sources":["../src/payload.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;
|
|
1
|
+
{"version":3,"file":"payload.js","sourceRoot":"","sources":["../src/payload.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AA0BH,wCAYC;AAOD,gCAQC;AAMD,gDAMC;AA/DD;;;GAGG;AACU,QAAA,kBAAkB,GAAG,oCAAoC,CAAC;AAEvE;;;GAGG;AACU,QAAA,yBAAyB,GAAG,kBAAkB,CAAC;AAE5D,MAAM,SAAS,GAAG,CAAC,cAAc,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;AAE3D,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAClC,CAAC;AAED;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,YAAoB;IACjD,MAAM,IAAI,GAAG,SAAS,CAAC,YAAY,CAAC,CAAC;IAErC,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAChE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,IAAI,gCAAgC,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7D,IAAI,IAAI,KAAK,mBAAmB;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,SAAgB,UAAU,CAAC,YAAoB;IAC7C,OAAO,CACL,YAAY,KAAK,0BAAkB;QACnC,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,iCAAyB,GAAG,CAAC;YACvD,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC7B,CAAC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC;YACnC,CAAC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CACvC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,kBAAkB,CAAC,KAAe;IAChD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC"}
|
|
@@ -78,10 +78,10 @@ Los ADRs fundacionales (A-XXX) se agrupan en fases narrativas; el orden y el agr
|
|
|
78
78
|
|
|
79
79
|
### Gate de consistencia
|
|
80
80
|
|
|
81
|
-
La consistencia del registro se verifica con [`scripts/verify-adr-consistency.
|
|
81
|
+
La consistencia del registro se verifica con [`scripts/verify-adr-consistency.mjs`](../../scripts/verify-adr-consistency.mjs), un script de solo lectura que se ejecuta con Node —el runtime que el paquete garantiza ([A-052](./foundational/A-052-distribucion-metodologia-paquete-versionado.md) §2)— desde la raíz del repositorio:
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
|
-
|
|
84
|
+
node scripts/verify-adr-consistency.mjs
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
El gate valida **cinco reglas** y debe salir con código `0` y cero violaciones:
|
|
@@ -19,7 +19,7 @@ El formato de los skills ya es el estándar Agent Skills, agnóstico al harness,
|
|
|
19
19
|
Distribuir la metodología como un **paquete npm versionado por suscripción**: `@imolko/ultra-agent`. El consumidor instala una versión, la actualiza subiendo de versión y nunca edita el contenido canónico.
|
|
20
20
|
|
|
21
21
|
1. **Modelo de suscripción.** El conjunto canónico es de solo lectura en el repositorio consumidor. El consumidor añade sus propios artefactos —skills de proyecto y ADRs de su tier de proyecto— en ubicaciones que el instalador nunca toca. La regla es **«extender, no editar»**: si el consumidor disiente de una decisión canónica, escribe su propio skill o ADR en su espacio, no modifica el canónico.
|
|
22
|
-
2. **Límite de contenido.** Se distribuye solo la metodología: los tiers A, T y P, el meta-ADR `ADR-0000`, el gate de consistencia, los skills canónicos, las extensiones de pi y el **preset de lint** que materializa las reglas ejecutables del tier A — los guardrails aplicables ([A-045](./A-045-guardrails-aplicables-no-directrices.md)) y las reglas estructurales de costura y errores ([A-053](./A-053-errores-compartidos-entre-features-dos-hogares-por-capa.md), [A-054](./A-054-contrato-costura-driver-port-raw-data-canal-error.md)) —. Los ADRs del tier de proyecto de cada consumidor (prefijo `PJ-`) no forman parte del paquete.
|
|
22
|
+
2. **Límite de contenido.** Se distribuye solo la metodología: los tiers A, T y P, el meta-ADR `ADR-0000`, el gate de consistencia, los skills canónicos, las extensiones de pi y el **preset de lint** que materializa las reglas ejecutables del tier A — los guardrails aplicables ([A-045](./A-045-guardrails-aplicables-no-directrices.md)) y las reglas estructurales de costura y errores ([A-053](./A-053-errores-compartidos-entre-features-dos-hogares-por-capa.md), [A-054](./A-054-contrato-costura-driver-port-raw-data-canal-error.md)) —. Los ADRs del tier de proyecto de cada consumidor (prefijo `PJ-`) no forman parte del paquete. El **gate de consistencia** corre sobre **Node**, el runtime que la distribución garantiza: el paquete llega por `npx` a un repositorio TypeScript y ninguna decisión metodológica aporta Python; el gate corre, por tanto, sobre el runtime del paquete.
|
|
23
23
|
3. **Espejo de ADRs.** El instalador copia los tiers A, T y P en el `adr_dir` del consumidor como archivos de solo lectura. La actualización reconcilia el espejo y nunca toca el tier de proyecto ni los READMEs de dominio del consumidor.
|
|
24
24
|
4. **Mecanismo.** Un CLI —`npx @imolko/ultra-agent install | update | status`— materializa el conjunto en las ubicaciones de descubrimiento de cada harness y registra un manifiesto de versión para poder reconciliar después.
|
|
25
25
|
5. **Deriva.** Si el consumidor edita un archivo espejado, `update` falla en voz alta ([A-007](./A-007-data-contract-fail-fast.md)) y solo se resuelve con `--reset`, que respalda antes de sobrescribir. No existe `--keep`: conservar una edición del espejo viola el modelo de solo lectura.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imolko/ultra-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Metodología ultra como paquete versionado: skills canónicos, registro ADR A/T/P, extensiones de pi y CLI (install/update/status/ship).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -53,7 +53,10 @@
|
|
|
53
53
|
"clean": "rm -rf dist-node",
|
|
54
54
|
"build": "npm run clean && tsc -p tsconfig.json && bash scripts/copy-assets.sh",
|
|
55
55
|
"prepack": "node scripts/ensure-bin-exec.mjs",
|
|
56
|
-
"gate": "
|
|
56
|
+
"gate": "node scripts/verify-adr-consistency.mjs",
|
|
57
|
+
"gate:verify": "bash scripts/__fixtures__/gate/capture-oracle.sh",
|
|
58
|
+
"gate:update": "bash scripts/__fixtures__/gate/capture-oracle.sh --update",
|
|
59
|
+
"gate:oracle": "bash scripts/__fixtures__/gate/capture-oracle.sh --oracle"
|
|
57
60
|
},
|
|
58
61
|
"files": [
|
|
59
62
|
"bin",
|
|
@@ -64,10 +67,13 @@
|
|
|
64
67
|
"docs/adr",
|
|
65
68
|
"pi/extensions",
|
|
66
69
|
"scripts",
|
|
70
|
+
"!scripts/__fixtures__/**",
|
|
67
71
|
"README.md",
|
|
68
72
|
"!**/*.test.ts",
|
|
69
73
|
"!**/*.integration.test.ts",
|
|
70
74
|
"!**/*.spec.ts",
|
|
75
|
+
"!**/*.test.mjs",
|
|
76
|
+
"!**/*.spec.mjs",
|
|
71
77
|
"!**/package-lock.json",
|
|
72
78
|
"!**/vitest.config.ts",
|
|
73
79
|
"!**/node_modules/**",
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enlaces markdown del registro ADR.
|
|
3
|
+
*
|
|
4
|
+
* `resolveLink()` reproduce `resolve_link()` del gate histórico: descarta URLs
|
|
5
|
+
* externas, autolinks y anclas puras, ignora fragmentos y resuelve contra el
|
|
6
|
+
* directorio del ADR con la semántica de `Path.resolve()`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
LINK_DEST_RE,
|
|
13
|
+
joinUnnormalized,
|
|
14
|
+
pyStrip,
|
|
15
|
+
resolvePath,
|
|
16
|
+
} from "./text.mjs";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Devuelve los destinos de los enlaces markdown inline `](dest)`.
|
|
20
|
+
* @param {string} text
|
|
21
|
+
* @returns {string[]}
|
|
22
|
+
*/
|
|
23
|
+
export function linkTargets(text) {
|
|
24
|
+
return Array.from(text.matchAll(LINK_DEST_RE), (match) => match[1]);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Resuelve un target de enlace relativo contra el directorio del ADR.
|
|
29
|
+
* @param {string} adrFile
|
|
30
|
+
* @param {string} target
|
|
31
|
+
* @returns {string | null} ruta resuelta, o null si la regla no la considera
|
|
32
|
+
*/
|
|
33
|
+
export function resolveLink(adrFile, target) {
|
|
34
|
+
let value = pyStrip(target);
|
|
35
|
+
if (isOutsideGate(value)) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
value = value.split("#", 1)[0];
|
|
40
|
+
if (!value || !value.endsWith(".md")) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return resolvePath(joinUnnormalized(path.dirname(adrFile), value));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* ¿El destino queda fuera del gate (URL, autolink o ancla pura)?
|
|
49
|
+
* @param {string} value
|
|
50
|
+
* @returns {boolean}
|
|
51
|
+
*/
|
|
52
|
+
function isOutsideGate(value) {
|
|
53
|
+
return (
|
|
54
|
+
value.startsWith("<") ||
|
|
55
|
+
value.startsWith(">") ||
|
|
56
|
+
value.includes("://") ||
|
|
57
|
+
value.startsWith("#")
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registro ADR y orden de recorrido.
|
|
3
|
+
*
|
|
4
|
+
* El gate resuelve su raíz desde su propia ubicación (no desde `process.cwd()`),
|
|
5
|
+
* así que `createRegistry()` recibe esa raíz y deriva las rutas del registro.
|
|
6
|
+
* Los tiers se recorren siempre en el orden A, T, P.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { readdirSync } from "node:fs";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
|
|
12
|
+
import { comparePathComponents } from "./text.mjs";
|
|
13
|
+
|
|
14
|
+
const TIER_DEFINITIONS = Object.freeze([
|
|
15
|
+
{ prefix: "A", segment: "foundational", allowed: new Set(["A", "meta"]) },
|
|
16
|
+
{ prefix: "T", segment: "typescript", allowed: new Set(["A", "T", "meta"]) },
|
|
17
|
+
{ prefix: "P", segment: "python", allowed: new Set(["A", "P", "meta"]) },
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Construye las rutas del registro a partir de la raíz del repositorio.
|
|
22
|
+
* @param {string} root
|
|
23
|
+
* @returns {{
|
|
24
|
+
* root: string,
|
|
25
|
+
* adrDir: string,
|
|
26
|
+
* tiers: Array<{ prefix: string, segment: string, allowed: Set<string>, directory: string }>,
|
|
27
|
+
* }}
|
|
28
|
+
*/
|
|
29
|
+
export function createRegistry(root) {
|
|
30
|
+
const adrDir = path.join(root, "docs", "adr");
|
|
31
|
+
const tiers = TIER_DEFINITIONS.map((tier) => ({
|
|
32
|
+
...tier,
|
|
33
|
+
directory: path.join(adrDir, tier.segment),
|
|
34
|
+
}));
|
|
35
|
+
return { root, adrDir, tiers };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* ¿El prefijo corresponde a un tier con directorio propio?
|
|
40
|
+
* @param {{ tiers: Array<{ prefix: string }> }} registry
|
|
41
|
+
* @param {string} prefix
|
|
42
|
+
* @returns {boolean}
|
|
43
|
+
*/
|
|
44
|
+
export function hasTier(registry, prefix) {
|
|
45
|
+
return registry.tiers.some((tier) => tier.prefix === prefix);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Lista los ADRs de un tier (`<tier>-*.md`) ordenados por componentes de ruta,
|
|
50
|
+
* como `sorted(Path.glob(...))` de Python.
|
|
51
|
+
* @param {{ prefix: string, directory: string }} tier
|
|
52
|
+
* @returns {string[]}
|
|
53
|
+
*/
|
|
54
|
+
export function tierAdrFiles(tier) {
|
|
55
|
+
let names;
|
|
56
|
+
try {
|
|
57
|
+
names = readdirSync(tier.directory);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (error.code === "ENOENT") {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return names
|
|
66
|
+
.filter((name) => name.startsWith(`${tier.prefix}-`) && name.endsWith(".md"))
|
|
67
|
+
.map((name) => path.join(tier.directory, name))
|
|
68
|
+
.sort(comparePathComponents);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Lista recursivamente los `*.md` de docs/adr, ordenados por componentes de
|
|
73
|
+
* ruta como el `sorted(ADR_DIR.rglob("*.md"))` del gate original.
|
|
74
|
+
* @param {string} directory
|
|
75
|
+
* @returns {string[]}
|
|
76
|
+
*/
|
|
77
|
+
export function markdownFiles(directory) {
|
|
78
|
+
const files = [];
|
|
79
|
+
visitDirectory(directory, files);
|
|
80
|
+
return files.sort(comparePathComponents);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Acumula los `*.md` de un directorio y sus descendientes.
|
|
85
|
+
* @param {string} directory
|
|
86
|
+
* @param {string[]} files
|
|
87
|
+
* @returns {void}
|
|
88
|
+
*/
|
|
89
|
+
function visitDirectory(directory, files) {
|
|
90
|
+
let entries;
|
|
91
|
+
try {
|
|
92
|
+
entries = readdirSync(directory, { withFileTypes: true });
|
|
93
|
+
} catch (error) {
|
|
94
|
+
if (error.code === "ENOENT") {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (const entry of entries) {
|
|
101
|
+
const fullPath = path.join(directory, entry.name);
|
|
102
|
+
if (entry.isDirectory()) {
|
|
103
|
+
visitDirectory(fullPath, files);
|
|
104
|
+
} else if (entry.name.endsWith(".md")) {
|
|
105
|
+
files.push(fullPath);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Clasifica un archivo resuelto en su tier (o null si está fuera del registro).
|
|
112
|
+
* @param {{ adrDir: string, tiers: Array<{ prefix: string, segment: string }> }} registry
|
|
113
|
+
* @param {string} resolved
|
|
114
|
+
* @returns {string | null}
|
|
115
|
+
*/
|
|
116
|
+
export function targetTier(registry, resolved) {
|
|
117
|
+
const relative = path.relative(registry.adrDir, resolved);
|
|
118
|
+
if (!isInsideAdrDir(relative)) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const parts = relative === "" ? [] : relative.split(path.sep);
|
|
123
|
+
if (parts.length >= 2) {
|
|
124
|
+
const tier = registry.tiers.find(({ segment }) => segment === parts[0]);
|
|
125
|
+
if (tier) {
|
|
126
|
+
return tier.prefix;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const name = parts.length > 0 ? parts[parts.length - 1] : "";
|
|
131
|
+
return isMetaName(name) ? "meta" : "project";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* ¿La ruta relativa cae dentro de docs/adr?
|
|
136
|
+
* @param {string} relative
|
|
137
|
+
* @returns {boolean}
|
|
138
|
+
*/
|
|
139
|
+
function isInsideAdrDir(relative) {
|
|
140
|
+
return (
|
|
141
|
+
relative === "" ||
|
|
142
|
+
(relative !== ".." &&
|
|
143
|
+
!relative.startsWith(`..${path.sep}`) &&
|
|
144
|
+
!path.isAbsolute(relative))
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* ¿El nombre pertenece al meta-ADR o a un índice?
|
|
150
|
+
* @param {string} name
|
|
151
|
+
* @returns {boolean}
|
|
152
|
+
*/
|
|
153
|
+
function isMetaName(name) {
|
|
154
|
+
return name.startsWith("ADR-0000") || name === "index.md";
|
|
155
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Acumulador de violaciones del gate.
|
|
3
|
+
*
|
|
4
|
+
* Las reglas comparten un único reporte para que el orden de ejecución sea
|
|
5
|
+
* exactamente el de la salida (jerarquia, enlaces, frontmatter, indices,
|
|
6
|
+
* hardcoded): invertirlo cambia los golden files (T-017).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Crea el reporte de una ejecución.
|
|
11
|
+
* @returns {{ add: (rule: string, message: string) => void, violations: string[] }}
|
|
12
|
+
*/
|
|
13
|
+
export function createReport() {
|
|
14
|
+
const violations = [];
|
|
15
|
+
return {
|
|
16
|
+
add(rule, message) {
|
|
17
|
+
violations.push(`[${rule}] ${message}`);
|
|
18
|
+
},
|
|
19
|
+
violations,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regla `enlaces`: todo enlace markdown interno relativo a un `*.md` resuelve a
|
|
3
|
+
* un archivo existente.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
|
|
9
|
+
import { linkTargets, resolveLink } from "../links.mjs";
|
|
10
|
+
import { markdownFiles } from "../registry.mjs";
|
|
11
|
+
import { readText } from "../text.mjs";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Ejecuta la regla sobre todos los markdown del registro ADR.
|
|
15
|
+
* @param {ReturnType<import("../registry.mjs").createRegistry>} registry
|
|
16
|
+
* @param {ReturnType<import("../report.mjs").createReport>} report
|
|
17
|
+
* @returns {void}
|
|
18
|
+
*/
|
|
19
|
+
export function ruleEnlaces(registry, report) {
|
|
20
|
+
for (const md of markdownFiles(registry.adrDir)) {
|
|
21
|
+
const text = readText(md);
|
|
22
|
+
for (const target of linkTargets(text)) {
|
|
23
|
+
const resolved = resolveLink(md, target);
|
|
24
|
+
if (resolved === null || existsSync(resolved)) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
report.add(
|
|
28
|
+
"enlaces",
|
|
29
|
+
`${path.relative(registry.root, md)} enlaza a un archivo inexistente: ${target}`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regla `frontmatter`: el título H1 sigue `# <TIER>-<NNN>: Título` y los campos
|
|
3
|
+
* `originally` / `Enriquecido desde` usan la ortografía exacta.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
|
|
8
|
+
import { tierAdrFiles } from "../registry.mjs";
|
|
9
|
+
import {
|
|
10
|
+
ENRICHED_RE,
|
|
11
|
+
ENRICHED_WRONG_RE,
|
|
12
|
+
H1_RE,
|
|
13
|
+
ORIGINALLY_RE,
|
|
14
|
+
ORIGINALLY_WRONG_RE,
|
|
15
|
+
pyStrip,
|
|
16
|
+
readText,
|
|
17
|
+
splitLines,
|
|
18
|
+
} from "../text.mjs";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Ejecuta la regla sobre los tres tiers.
|
|
22
|
+
* @param {ReturnType<import("../registry.mjs").createRegistry>} registry
|
|
23
|
+
* @param {ReturnType<import("../report.mjs").createReport>} report
|
|
24
|
+
* @returns {void}
|
|
25
|
+
*/
|
|
26
|
+
export function ruleFrontmatter(registry, report) {
|
|
27
|
+
for (const tier of registry.tiers) {
|
|
28
|
+
for (const adr of tierAdrFiles(tier)) {
|
|
29
|
+
checkFrontmatter({ registry, adr, report });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Comprueba el H1 y los campos del frontmatter de un ADR.
|
|
36
|
+
* @param {{ registry: object, adr: string, report: object }} parent
|
|
37
|
+
* @returns {void}
|
|
38
|
+
*/
|
|
39
|
+
function checkFrontmatter(parent) {
|
|
40
|
+
const text = readText(parent.adr);
|
|
41
|
+
const lines = splitLines(text);
|
|
42
|
+
const context = {
|
|
43
|
+
...parent,
|
|
44
|
+
text,
|
|
45
|
+
lines,
|
|
46
|
+
rel: path.relative(parent.registry.root, parent.adr),
|
|
47
|
+
firstLine: lines[0] ?? "",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
checkTitle(context);
|
|
51
|
+
checkOriginally(context);
|
|
52
|
+
checkEnriched(context);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Comprueba que el H1 siga `# <TIER>-<NNN>: Título`.
|
|
57
|
+
* @param {object} context
|
|
58
|
+
* @returns {void}
|
|
59
|
+
*/
|
|
60
|
+
function checkTitle(context) {
|
|
61
|
+
if (!H1_RE.test(context.firstLine)) {
|
|
62
|
+
context.report.add(
|
|
63
|
+
"frontmatter",
|
|
64
|
+
`${context.rel}: el título H1 no sigue \`# <TIER>-<NNN>: Título\``,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Comprueba que `originally` exista y esté en minúsculas.
|
|
71
|
+
* @param {object} context
|
|
72
|
+
* @returns {void}
|
|
73
|
+
*/
|
|
74
|
+
function checkOriginally(context) {
|
|
75
|
+
if (!ORIGINALLY_RE.test(context.text)) {
|
|
76
|
+
context.report.add(
|
|
77
|
+
"frontmatter",
|
|
78
|
+
`${context.rel}: falta el campo \`**originally**:\` (minúsculas)`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const spelling = {
|
|
83
|
+
wrong: ORIGINALLY_WRONG_RE,
|
|
84
|
+
right: ORIGINALLY_RE,
|
|
85
|
+
};
|
|
86
|
+
if (hasWrongSpelling(context.lines, spelling)) {
|
|
87
|
+
context.report.add(
|
|
88
|
+
"frontmatter",
|
|
89
|
+
`${context.rel}: \`originally\` debe ir en minúsculas`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Comprueba la ortografía del campo opcional `Enriquecido desde`.
|
|
96
|
+
* @param {object} context
|
|
97
|
+
* @returns {void}
|
|
98
|
+
*/
|
|
99
|
+
function checkEnriched(context) {
|
|
100
|
+
const spelling = {
|
|
101
|
+
wrong: ENRICHED_WRONG_RE,
|
|
102
|
+
right: ENRICHED_RE,
|
|
103
|
+
};
|
|
104
|
+
if (hasWrongSpelling(context.lines, spelling)) {
|
|
105
|
+
context.report.add(
|
|
106
|
+
"frontmatter",
|
|
107
|
+
`${context.rel}: el campo opcional debe escribirse \`**Enriquecido desde**:\``,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* ¿Alguna línea usa la variante incorrecta sin la correcta?
|
|
114
|
+
* @param {string[]} lines
|
|
115
|
+
* @param {{ wrong: RegExp, right: RegExp }} spelling
|
|
116
|
+
* @returns {boolean}
|
|
117
|
+
*/
|
|
118
|
+
function hasWrongSpelling(lines, spelling) {
|
|
119
|
+
for (const line of lines) {
|
|
120
|
+
const stripped = pyStrip(line);
|
|
121
|
+
if (spelling.wrong.test(stripped) && !spelling.right.test(stripped)) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
126
|
+
}
|