@imolko/ultra-agent 0.1.0-beta

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 (239) hide show
  1. package/README.md +93 -0
  2. package/bin/cli.js +2 -0
  3. package/dist-node/bin.d.ts +2 -0
  4. package/dist-node/bin.d.ts.map +1 -0
  5. package/dist-node/bin.js +5 -0
  6. package/dist-node/bin.js.map +1 -0
  7. package/dist-node/cli.d.ts +41 -0
  8. package/dist-node/cli.d.ts.map +1 -0
  9. package/dist-node/cli.js +170 -0
  10. package/dist-node/cli.js.map +1 -0
  11. package/dist-node/index.d.ts +14 -0
  12. package/dist-node/index.d.ts.map +1 -0
  13. package/dist-node/index.js +40 -0
  14. package/dist-node/index.js.map +1 -0
  15. package/dist-node/init-lint.d.ts +43 -0
  16. package/dist-node/init-lint.d.ts.map +1 -0
  17. package/dist-node/init-lint.js +84 -0
  18. package/dist-node/init-lint.js.map +1 -0
  19. package/dist-node/manifest.d.ts +33 -0
  20. package/dist-node/manifest.d.ts.map +1 -0
  21. package/dist-node/manifest.js +59 -0
  22. package/dist-node/manifest.js.map +1 -0
  23. package/dist-node/materializer.d.ts +52 -0
  24. package/dist-node/materializer.d.ts.map +1 -0
  25. package/dist-node/materializer.js +194 -0
  26. package/dist-node/materializer.js.map +1 -0
  27. package/dist-node/package-root.d.ts +5 -0
  28. package/dist-node/package-root.d.ts.map +1 -0
  29. package/dist-node/package-root.js +17 -0
  30. package/dist-node/package-root.js.map +1 -0
  31. package/dist-node/payload.d.ts +22 -0
  32. package/dist-node/payload.d.ts.map +1 -0
  33. package/dist-node/payload.js +49 -0
  34. package/dist-node/payload.js.map +1 -0
  35. package/dist-node/pointer-hub.d.ts +22 -0
  36. package/dist-node/pointer-hub.d.ts.map +1 -0
  37. package/dist-node/pointer-hub.js +50 -0
  38. package/dist-node/pointer-hub.js.map +1 -0
  39. package/dist-node/publication.cli.d.ts +9 -0
  40. package/dist-node/publication.cli.d.ts.map +1 -0
  41. package/dist-node/publication.cli.js +17 -0
  42. package/dist-node/publication.cli.js.map +1 -0
  43. package/dist-node/publication.d.ts +23 -0
  44. package/dist-node/publication.d.ts.map +1 -0
  45. package/dist-node/publication.js +47 -0
  46. package/dist-node/publication.js.map +1 -0
  47. package/dist-node/reconcile.cli.d.ts +11 -0
  48. package/dist-node/reconcile.cli.d.ts.map +1 -0
  49. package/dist-node/reconcile.cli.js +39 -0
  50. package/dist-node/reconcile.cli.js.map +1 -0
  51. package/dist-node/reconcile.d.ts +30 -0
  52. package/dist-node/reconcile.d.ts.map +1 -0
  53. package/dist-node/reconcile.js +51 -0
  54. package/dist-node/reconcile.js.map +1 -0
  55. package/dist-node/ship/prompts/fix.md +22 -0
  56. package/dist-node/ship/prompts/implement.md +34 -0
  57. package/dist-node/ship/prompts/review.md +28 -0
  58. package/dist-node/ship/ship.agent.d.ts +22 -0
  59. package/dist-node/ship/ship.agent.d.ts.map +1 -0
  60. package/dist-node/ship/ship.agent.js +142 -0
  61. package/dist-node/ship/ship.agent.js.map +1 -0
  62. package/dist-node/ship/ship.args.d.ts +15 -0
  63. package/dist-node/ship/ship.args.d.ts.map +1 -0
  64. package/dist-node/ship/ship.args.js +93 -0
  65. package/dist-node/ship/ship.args.js.map +1 -0
  66. package/dist-node/ship/ship.context.d.ts +12 -0
  67. package/dist-node/ship/ship.context.d.ts.map +1 -0
  68. package/dist-node/ship/ship.context.js +3 -0
  69. package/dist-node/ship/ship.context.js.map +1 -0
  70. package/dist-node/ship/ship.d.ts +4 -0
  71. package/dist-node/ship/ship.d.ts.map +1 -0
  72. package/dist-node/ship/ship.js +221 -0
  73. package/dist-node/ship/ship.js.map +1 -0
  74. package/dist-node/ship/ship.mr.d.ts +9 -0
  75. package/dist-node/ship/ship.mr.d.ts.map +1 -0
  76. package/dist-node/ship/ship.mr.js +171 -0
  77. package/dist-node/ship/ship.mr.js.map +1 -0
  78. package/dist-node/ship/ship.output.d.ts +9 -0
  79. package/dist-node/ship/ship.output.d.ts.map +1 -0
  80. package/dist-node/ship/ship.output.js +21 -0
  81. package/dist-node/ship/ship.output.js.map +1 -0
  82. package/dist-node/ship/ship.tracker.d.ts +37 -0
  83. package/dist-node/ship/ship.tracker.d.ts.map +1 -0
  84. package/dist-node/ship/ship.tracker.js +220 -0
  85. package/dist-node/ship/ship.tracker.js.map +1 -0
  86. package/dist-node/version.cli.d.ts +9 -0
  87. package/dist-node/version.cli.d.ts.map +1 -0
  88. package/dist-node/version.cli.js +30 -0
  89. package/dist-node/version.cli.js.map +1 -0
  90. package/dist-node/version.d.ts +24 -0
  91. package/dist-node/version.d.ts.map +1 -0
  92. package/dist-node/version.js +76 -0
  93. package/dist-node/version.js.map +1 -0
  94. package/docs/adr/ADR-0000-proceso-y-formato-de-adrs.md +115 -0
  95. package/docs/adr/foundational/A-001-clean-architecture-4-capas.md +88 -0
  96. package/docs/adr/foundational/A-002-cqrs-semantico.md +58 -0
  97. package/docs/adr/foundational/A-003-tdd.md +97 -0
  98. package/docs/adr/foundational/A-005-either-return-custom-methods.md +80 -0
  99. package/docs/adr/foundational/A-006-feature-completion-criteria.md +47 -0
  100. package/docs/adr/foundational/A-007-data-contract-fail-fast.md +109 -0
  101. package/docs/adr/foundational/A-008-bounded-context-decomposition.md +130 -0
  102. package/docs/adr/foundational/A-009-use-case-taxonomy.md +99 -0
  103. package/docs/adr/foundational/A-010-propiedad-emision-eventos-dominio.md +95 -0
  104. package/docs/adr/foundational/A-011-characterization-first-refactoring.md +90 -0
  105. package/docs/adr/foundational/A-012-helm-mecanismo-primario-despliegue.md +67 -0
  106. package/docs/adr/foundational/A-013-contrato-settings-unica-fuente-configuracion.md +74 -0
  107. package/docs/adr/foundational/A-014-generacion-artefactos-despliegue-desde-contrato-settings.md +75 -0
  108. package/docs/adr/foundational/A-015-cloudevents-estandar-eventos.md +85 -0
  109. package/docs/adr/foundational/A-016-cicd-gitlab-pipeline-raiz-pipelines-modulares.md +92 -0
  110. package/docs/adr/foundational/A-017-taxonomia-repositorios-librerias-sistemas.md +93 -0
  111. package/docs/adr/foundational/A-018-practicas-build-imagenes-docker.md +85 -0
  112. package/docs/adr/foundational/A-019-convenciones-autoria-helm-charts.md +97 -0
  113. package/docs/adr/foundational/A-020-entorno-desarrollo-estandarizado-devcontainer.md +58 -0
  114. package/docs/adr/foundational/A-022-formato-reporte-tests-ctrf.md +55 -0
  115. package/docs/adr/foundational/A-023-composicion-bloques-prompt-agentes.md +65 -0
  116. package/docs/adr/foundational/A-024-features-slices-verticales-portables.md +41 -0
  117. package/docs/adr/foundational/A-025-anatomia-mecanica-feature-puertos-adaptadores-drivers.md +104 -0
  118. package/docs/adr/foundational/A-026-infraestructura-compartida.md +44 -0
  119. package/docs/adr/foundational/A-027-patron-wiring-entry-point.md +67 -0
  120. package/docs/adr/foundational/A-029-verbos-intencion-metodos-lado-negocio.md +54 -0
  121. package/docs/adr/foundational/A-030-global-development-tooling.md +52 -0
  122. package/docs/adr/foundational/A-031-ubiquitous-language.md +64 -0
  123. package/docs/adr/foundational/A-032-domain-artifact-documentation-format.md +128 -0
  124. package/docs/adr/foundational/A-033-estandar-mensajes-commit.md +127 -0
  125. package/docs/adr/foundational/A-034-canonical-skill-set.md +64 -0
  126. package/docs/adr/foundational/A-035-captura-ideas-reanclaje-candies.md +51 -0
  127. package/docs/adr/foundational/A-036-adopcion-wayfinder-ortogonalidad-labels.md +37 -0
  128. package/docs/adr/foundational/A-037-formalizacion-taxonomia-labels.md +98 -0
  129. package/docs/adr/foundational/A-038-issues-referencian-skills-nombre.md +54 -0
  130. package/docs/adr/foundational/A-039-pipeline-ship-issues-hijos-spec.md +64 -0
  131. package/docs/adr/foundational/A-040-punteros-configuracion-repo-skills.md +44 -0
  132. package/docs/adr/foundational/A-041-estrategia-de-ramas.md +45 -0
  133. package/docs/adr/foundational/A-042-formato-documentos-issue-tracker.md +78 -0
  134. package/docs/adr/foundational/A-043-vocabulario-etiquetas-adrs.md +42 -0
  135. package/docs/adr/foundational/A-044-composicion-funcional-procesos-operaciones.md +44 -0
  136. package/docs/adr/foundational/A-045-guardrails-aplicables-no-directrices.md +48 -0
  137. package/docs/adr/foundational/A-046-metricas-de-forma-y-legibilidad-del-codigo.md +50 -0
  138. package/docs/adr/foundational/A-047-dependencias-explicitas-sin-globales-ambientales.md +40 -0
  139. package/docs/adr/foundational/A-048-cobertura-minima-codigo.md +39 -0
  140. package/docs/adr/foundational/A-049-materializacion-bucle-guardrails-extension-nativa-pi.md +49 -0
  141. package/docs/adr/foundational/A-050-el-caso-de-uso-pide-al-dominio-no-lee-su-representacion.md +50 -0
  142. package/docs/adr/foundational/A-051-orden-imports-por-distancia.md +47 -0
  143. package/docs/adr/foundational/A-052-distribucion-metodologia-paquete-versionado.md +42 -0
  144. package/docs/adr/foundational/A-053-errores-compartidos-entre-features-dos-hogares-por-capa.md +43 -0
  145. package/docs/adr/foundational/A-054-contrato-costura-driver-port-raw-data-canal-error.md +65 -0
  146. package/docs/adr/foundational/index.md +98 -0
  147. package/docs/adr/index.md +19 -0
  148. package/docs/adr/python/P-001-dependencias-por-feature-fastapi-depends.md +63 -0
  149. package/docs/adr/python/P-002-inyeccion-token-por-request-sin-persistirlo.md +35 -0
  150. package/docs/adr/python/P-003-sqlalchemy-async-connection-pooling.md +59 -0
  151. package/docs/adr/python/P-004-serializer-json-custom-modelos-pydantic.md +47 -0
  152. package/docs/adr/python/P-005-patrones-pitfalls-nicegui.md +148 -0
  153. package/docs/adr/python/P-006-convenciones-pytest.md +96 -0
  154. package/docs/adr/python/P-007-ci-python-alineacion-poetry-version-unica.md +55 -0
  155. package/docs/adr/python/P-008-empaquetado-infraestructura-compartida-por-tecnologia.md +38 -0
  156. package/docs/adr/python/index.md +14 -0
  157. package/docs/adr/typescript/T-001-ddd-artifact-validation-zod-primitives.md +136 -0
  158. package/docs/adr/typescript/T-002-test-documentation-jsdoc.md +133 -0
  159. package/docs/adr/typescript/T-003-readme-formatting-domain-artifacts.md +51 -0
  160. package/docs/adr/typescript/T-005-input-optionality-use-case-not-entity.md +130 -0
  161. package/docs/adr/typescript/T-006-small-enums-inlined-zod-regex.md +77 -0
  162. package/docs/adr/typescript/T-007-controller-input-zod-schema.md +79 -0
  163. package/docs/adr/typescript/T-008-expressive-use-case-pipe.md +207 -0
  164. package/docs/adr/typescript/T-009-mdx-brace-escaping.md +80 -0
  165. package/docs/adr/typescript/T-010-stack-tooling-typescript-dominio.md +53 -0
  166. package/docs/adr/typescript/T-011-ultra-reporter-herramienta-canonica-documentacion.md +52 -0
  167. package/docs/adr/typescript/T-012-npm-workspaces-estructura-monorepo-clean-architecture.md +54 -0
  168. package/docs/adr/typescript/T-013-definicion-eventos-versionados-ultra-ddd.md +45 -0
  169. package/docs/adr/typescript/T-014-publicacion-distribucion-librerias-npm-semver.md +53 -0
  170. package/docs/adr/typescript/T-015-method-placement-definition.md +35 -0
  171. package/docs/adr/typescript/T-016-contrato-settings-zod.md +34 -0
  172. package/docs/adr/typescript/T-017-characterization-tests-golden-files.md +39 -0
  173. package/docs/adr/typescript/T-018-procedencia-campos-frontmatter.md +55 -0
  174. package/docs/adr/typescript/T-019-ultra-generator-herramienta-canonica-generacion.md +35 -0
  175. package/docs/adr/typescript/T-020-ultra-settings-herramienta-canonica-exportacion-despliegue.md +36 -0
  176. package/docs/adr/typescript/T-021-pipe-flujo-datos-operadores-semantica-contexto-inmutable.md +105 -0
  177. package/docs/adr/typescript/T-022-construction-is-execution-single-boundary.md +112 -0
  178. package/docs/adr/typescript/T-023-registry-cli-declara-dependencias-reales.md +84 -0
  179. package/docs/adr/typescript/T-024-paquete-ultra-agent-manifiesto-pi-peers-cli.md +39 -0
  180. package/docs/adr/typescript/T-025-publicacion-npm-trusted-publishing-procedencia.md +59 -0
  181. package/docs/adr/typescript/index.md +30 -0
  182. package/eslint/index.mjs +721 -0
  183. package/package.json +94 -0
  184. package/pi/extensions/handoff/README.md +92 -0
  185. package/pi/extensions/handoff/handoff-prompt.txt +9 -0
  186. package/pi/extensions/handoff/index.ts +296 -0
  187. package/pi/extensions/handoff/package.json +12 -0
  188. package/pi/extensions/qa-guardrail/README.md +108 -0
  189. package/pi/extensions/qa-guardrail/adapters/cli.ts +100 -0
  190. package/pi/extensions/qa-guardrail/adapters/eslint.ts +90 -0
  191. package/pi/extensions/qa-guardrail/adapters/registry.ts +45 -0
  192. package/pi/extensions/qa-guardrail/baseline.ts +74 -0
  193. package/pi/extensions/qa-guardrail/cerco.ts +134 -0
  194. package/pi/extensions/qa-guardrail/check.ts +185 -0
  195. package/pi/extensions/qa-guardrail/config.ts +189 -0
  196. package/pi/extensions/qa-guardrail/delta.ts +52 -0
  197. package/pi/extensions/qa-guardrail/feedback.ts +26 -0
  198. package/pi/extensions/qa-guardrail/index.ts +311 -0
  199. package/pi/extensions/qa-guardrail/nstop.ts +82 -0
  200. package/pi/extensions/qa-guardrail/package.json +12 -0
  201. package/pi/extensions/qa-guardrail/selection.ts +98 -0
  202. package/pi/extensions/qa-guardrail/types.ts +64 -0
  203. package/scripts/copy-assets.sh +10 -0
  204. package/scripts/reconcile-tags.sh +94 -0
  205. package/scripts/release-beta.sh +64 -0
  206. package/scripts/release-build.sh +53 -0
  207. package/scripts/release.sh +51 -0
  208. package/scripts/verify-adr-consistency.py +217 -0
  209. package/skills/code-review/SKILL.md +66 -0
  210. package/skills/codebase-design/SKILL.md +46 -0
  211. package/skills/configure-repo/SKILL.md +33 -0
  212. package/skills/diagnose-bug/SKILL.md +63 -0
  213. package/skills/domain-modeling/SKILL.md +56 -0
  214. package/skills/grill-me/SKILL.md +34 -0
  215. package/skills/i-have-an-idea/SKILL.md +166 -0
  216. package/skills/implement/SKILL.md +22 -0
  217. package/skills/research/SKILL.md +17 -0
  218. package/skills/ship/SKILL.md +26 -0
  219. package/skills/spike/SKILL.md +27 -0
  220. package/skills/tdd/SKILL.md +68 -0
  221. package/skills/tdd/references/deep-modules.md +53 -0
  222. package/skills/tdd/references/interface-design.md +74 -0
  223. package/skills/tdd/references/mocking.md +80 -0
  224. package/skills/tdd/references/refactoring.md +49 -0
  225. package/skills/tdd/references/tests.md +184 -0
  226. package/skills/to-specs/SKILL.md +141 -0
  227. package/skills/to-tasks/SKILL.md +143 -0
  228. package/skills/triage/SKILL.md +73 -0
  229. package/skills/ultra-generator/SKILL.md +263 -0
  230. package/skills/ultra-generator/references/aggregate-root.md +149 -0
  231. package/skills/ultra-generator/references/domain-event.md +174 -0
  232. package/skills/ultra-generator/references/entity.md +133 -0
  233. package/skills/ultra-generator/references/service.md +92 -0
  234. package/skills/ultra-generator/references/value-object.md +135 -0
  235. package/skills/wayfinder/SKILL.md +201 -0
  236. package/skills/workflow/SKILL.md +31 -0
  237. package/skills/writing-for-agents/SKILL-MECHANICS.md +32 -0
  238. package/skills/writing-for-agents/SKILL.md +86 -0
  239. package/skills/writing-for-agents/references/adrs.md +19 -0
@@ -0,0 +1,721 @@
1
+ /**
2
+ * Preset flat-config del tier A — reglas ejecutables de forma, legibilidad y
3
+ * arquitectura.
4
+ *
5
+ * Materializa, como configuración de ESLint, las decisiones canónicas del
6
+ * registro:
7
+ * - A-001/A-024/A-025/A-026/A-027: dirección de dependencias entre las capas
8
+ * (`domain`, `feature`, `shared-infra`, `representation`, `app`), frameworks
9
+ * de infraestructura vetados en las capas internas, y tipos sin especificar
10
+ * en los ports.
11
+ * - A-046: métricas de forma y legibilidad (parámetros, líneas, complejidad,
12
+ * anidamiento, sentencias, números mágicos, tipos por archivo, identificadores
13
+ * e igualdad estricta).
14
+ * - A-047: sin globales ambientales (`console`, `process.env`).
15
+ * - A-050: el caso de uso habla en términos del dominio; no lee la
16
+ * representación serializada (`getPrimitive`/`getPayload`/`getSnapshot`) ni
17
+ * decide comparando `status`/`state`/`type`.
18
+ * - A-051: orden de imports por distancia, con el prefijo del paquete interno
19
+ * como grupo `internal`.
20
+ * - A-053: el catálogo compartido de errores (`feature-error`) es un hogar
21
+ * hermano de las features, importable por ellas sin violar boundaries.
22
+ * - A-054: la costura del driver port es raw data; ningún objeto con
23
+ * comportamiento ni hecho de dominio sin confirmar cruza el puerto.
24
+ *
25
+ * El preset es un módulo componible: el consumidor lo importa, lo invoca con su
26
+ * prefijo interno y compone sus reglas de proyecto encima. No escribe archivos
27
+ * ni lintea por sí mismo — el único ejecutor sigue siendo `qa-guardrail`
28
+ * (A-045/A-049).
29
+ *
30
+ * Uso:
31
+ * ```js
32
+ * // eslint.config.mjs del consumidor
33
+ * import ultra from "@imolko/ultra-agent/eslint";
34
+ *
35
+ * export default [
36
+ * ...ultra({ internal: "@acme/*" }),
37
+ * // reglas de proyecto del consumidor
38
+ * ];
39
+ * ```
40
+ */
41
+
42
+ import tsParser from "@typescript-eslint/parser";
43
+ import tsPlugin from "@typescript-eslint/eslint-plugin";
44
+ import importX from "eslint-plugin-import-x";
45
+ import boundaries from "eslint-plugin-boundaries";
46
+
47
+ /** Archivos que el preset cubre por defecto. */
48
+ export const PRESET_FILES = ["**/*.{ts,tsx,js,mjs,cjs}"];
49
+
50
+ /** Carpetas y archivos que el preset ignora por defecto. */
51
+ export const PRESET_IGNORES = [
52
+ "**/node_modules/**",
53
+ "**/dist/**",
54
+ "**/build/**",
55
+ "**/coverage/**",
56
+ "temp-*/**",
57
+ ".ultra-reporter/**",
58
+ ".nx/**",
59
+ ".pi/**",
60
+ "scenarios/**",
61
+ "docs/**",
62
+ "eslint.config.mjs",
63
+ ];
64
+
65
+ /**
66
+ * Capas canónicas de A-001 y el glob que las identifica por defecto.
67
+ *
68
+ * `domain`, `shared-infra`, `representations` y `apps` son un elemento por glob;
69
+ * `feature` captura cada slice (`features/<caso-de-uso>`) como un elemento
70
+ * distinto para que la matriz pueda vetar el acoplamiento entre features (A-024).
71
+ * El consumidor puede sobreescribir cualquier glob vía `layers`.
72
+ */
73
+ export const DEFAULT_LAYERS = Object.freeze({
74
+ domain: "domain/**",
75
+ feature: "features/*",
76
+ "shared-infra": "shared-infra/*",
77
+ representation: "representations/*",
78
+ app: "apps/*",
79
+ });
80
+
81
+ /** Nombres de capa, en el orden de A-001. */
82
+ export const LAYER_TYPES = Object.freeze(Object.keys(DEFAULT_LAYERS));
83
+
84
+ /**
85
+ * Tipo de elemento del catálogo compartido de errores de infraestructura
86
+ * (A-053): un módulo hermano de los slices de feature, no una feature. Las
87
+ * features lo importan sin violar «una feature nunca importa otra feature».
88
+ */
89
+ export const FEATURE_ERROR_TYPE = "feature-error";
90
+
91
+ /**
92
+ * Glob por defecto del catálogo compartido de errores (A-053). Se deriva del
93
+ * glob de `feature` cuando este termina en `/*`; el consumidor puede
94
+ * sobreescribirlo explícitamente vía `layers[FEATURE_ERROR_TYPE]`.
95
+ */
96
+ export const DEFAULT_FEATURE_ERROR_GLOB = "features/errors/**";
97
+
98
+ /**
99
+ * Frameworks de infraestructura vetados en las capas internas: el dominio no los
100
+ * importa (A-001) y una feature es tech-free (A-025).
101
+ */
102
+ export const INFRA_FRAMEWORKS = Object.freeze([
103
+ // Patrones con `/**` para vetar también los imports profundos (p. ej.
104
+ // `@nestjs/common/decorators`): minimatch no cruza `/` con un solo `*`.
105
+ "@nestjs/**",
106
+ "mongoose",
107
+ "pg",
108
+ "postgres",
109
+ "typeorm",
110
+ "sequelize",
111
+ "knex",
112
+ "prisma",
113
+ "@prisma/**",
114
+ "graphql",
115
+ "@apollo/**",
116
+ "apollo-server*",
117
+ "apollo-server**",
118
+ "express",
119
+ "fastify",
120
+ "rxjs",
121
+ "ioredis",
122
+ "redis",
123
+ "mongodb",
124
+ "kafkajs",
125
+ "amqplib",
126
+ ]);
127
+
128
+ const DOMAIN_FRAMEWORK_MESSAGE =
129
+ "El dominio no importa frameworks de infraestructura (A-001): solo validación y result-type.";
130
+ const FEATURE_FRAMEWORK_MESSAGE =
131
+ "La feature es tech-free (A-025): el driver tecnológico vive en shared-infra/ y se inyecta por el driver port.";
132
+
133
+ /**
134
+ * Driver ports: la costura raw (A-025/A-054). Además de los tipos sin
135
+ * especificar, se aplican los selectores de costura raw.
136
+ */
137
+ export const DRIVER_PORT_FILES = Object.freeze([
138
+ "**/driver.port.ts",
139
+ "**/*.driver.port.ts",
140
+ "**/service.port.ts",
141
+ "**/*.service.port.ts",
142
+ ]);
143
+
144
+ /**
145
+ * Puertos de dominio (`use-case/*.port.ts`). A-025 exige que un puerto de
146
+ * dominio hable en conceptos de dominio y que nunca use `any`/`unknown`; el
147
+ * bloque no aplica los selectores raw (el dominio sí usa tipos con
148
+ * comportamiento). Los globs se derivan del glob de `feature` para respetar el
149
+ * override del consumidor.
150
+ *
151
+ * @param {string} featureGlob
152
+ * @returns {string[]}
153
+ */
154
+ export function domainPortFileGlobs(featureGlob) {
155
+ return [`${featureGlob}/use-case/**/*.port.ts`];
156
+ }
157
+
158
+ /** Selector de globales ambientales (A-047). */
159
+ const AMBIENT_SYNTAX = {
160
+ selector: "MemberExpression[object.name='process'][property.name='env']",
161
+ message:
162
+ "Acceso directo a process.env prohibido (A-047). Inyecta la configuración por el contrato de settings.",
163
+ };
164
+
165
+ /** Tipos sin especificar vetados en los ports (A-025). */
166
+ const UNTYPED_PORT_SYNTAX = [
167
+ {
168
+ selector: "TSAnyKeyword",
169
+ message: "Los ports no usan `any` (A-025): declara el raw data de la costura.",
170
+ },
171
+ {
172
+ selector: "TSUnknownKeyword",
173
+ message: "Los ports no usan `unknown` (A-025): declara el raw data de la costura.",
174
+ },
175
+ ];
176
+
177
+ /**
178
+ * Patrones por defecto de las formas raw que sí cruzan la costura del driver
179
+ * port (A-054): mementos/snapshots, la envolvente CloudEvent, DTOs y demás data
180
+ * plana; el canal de error (`Execution`/`Validation`, cualquier `*Error`), la
181
+ * promesa y las utilidades genéricas del tier.
182
+ *
183
+ * Son fragmentos de expresión regular (sin anclas; el patrón final las añade).
184
+ * El consumidor puede extenderlos vía `rawSeamTypes` para sus propias formas
185
+ * raw (A-052: el preset sirve a cualquier consumidor, no a la nomenclatura de
186
+ * un proyecto concreto).
187
+ */
188
+ const DEFAULT_RAW_SEAM_TYPES = Object.freeze([
189
+ ".*(?:Snapshot|Memento|Payload|DTO|Dto|Data|Event|CloudEvent|Props|Record|Row|Model|Schema|Filters|Filter|Query|Result)",
190
+ ".*Error",
191
+ "Error",
192
+ "Promise",
193
+ "Execution",
194
+ "Validation",
195
+ "TaskExecution",
196
+ "TaskValidation",
197
+ "Result",
198
+ "Array",
199
+ "ReadonlyArray",
200
+ "Readonly",
201
+ "Record",
202
+ "Partial",
203
+ "Pick",
204
+ "Omit",
205
+ "Map",
206
+ "Set",
207
+ "Date",
208
+ "Buffer",
209
+ "Uint8Array",
210
+ "URL",
211
+ "RegExp",
212
+ ]);
213
+
214
+ /**
215
+ * Compone el patrón de los tipos que **sí** cruzan la costura raw (A-054) a
216
+ * partir de los defaults y de los patrones extra del consumidor.
217
+ *
218
+ * @param {string[]} extra Fragmentos de regex del consumidor.
219
+ * @returns {string}
220
+ */
221
+ function rawSeamTypePattern(extra) {
222
+ return `^(?:${[...DEFAULT_RAW_SEAM_TYPES, ...extra].join("|")})$`;
223
+ }
224
+
225
+ /**
226
+ * Normaliza y valida los patrones raw extra del consumidor.
227
+ *
228
+ * @param {unknown} rawSeamTypes
229
+ * @returns {string[]}
230
+ */
231
+ function requireRawSeamTypes(rawSeamTypes) {
232
+ if (rawSeamTypes === undefined) {
233
+ return [];
234
+ }
235
+ if (
236
+ !Array.isArray(rawSeamTypes) ||
237
+ rawSeamTypes.some((pattern) => typeof pattern !== "string" || pattern.trim() === "")
238
+ ) {
239
+ throw new Error(
240
+ "El preset @imolko/ultra-agent/eslint espera `rawSeamTypes` como array de patrones de tipo no vacíos.",
241
+ );
242
+ }
243
+ return rawSeamTypes.map((pattern) => pattern.trim());
244
+ }
245
+
246
+ /**
247
+ * Selectores de la costura raw del driver port (A-054): ningún objeto con
248
+ * comportamiento (agregado, entidad o value object) ni hecho de dominio sin
249
+ * confirmar cruza el puerto. El adaptador produce la forma raw.
250
+ *
251
+ * El primer selector es un heurístico de nomenclatura: marca toda referencia de
252
+ * tipo que no encaja en las formas raw conocidas (o en las que declare el
253
+ * consumidor vía `rawSeamTypes`). No distingue con certeza un objeto con
254
+ * comportamiento de un DTO plano de nombre no listado; A-054 mantiene esa
255
+ * detección como deuda de guardrail y la revisión sigue siendo la autoridad.
256
+ *
257
+ * @param {string[]} extra Fragmentos de regex extra del consumidor.
258
+ * @returns {Array<{ selector: string, message: string }>}
259
+ */
260
+ function seamSyntax(extra) {
261
+ const raw = rawSeamTypePattern(extra).replaceAll("/", "\\/");
262
+ return [
263
+ {
264
+ selector: "TSTypeReference[typeName.name!=/" + raw + "/]",
265
+ message:
266
+ "La costura del driver port es raw data (A-054): ningún agregado, entidad ni value object del dominio cruza el puerto. Usa el memento/snapshot o un DTO plano, o declara tu forma raw en `rawSeamTypes`.",
267
+ },
268
+ {
269
+ selector: "Identifier[name='UncommittedEvent']",
270
+ message:
271
+ "La costura del driver port recibe la envolvente raw (A-054): el hecho de dominio sin confirmar no cruza el puerto; el adaptador construye la ocurrencia.",
272
+ },
273
+ {
274
+ selector: "Identifier[name='eventClass']",
275
+ message:
276
+ "El driver port no conoce la referencia de clase del hecho (A-054): el adaptador produce la envolvente raw; el puerto no arrastra `eventClass`.",
277
+ },
278
+ ];
279
+ }
280
+
281
+ /**
282
+ * Selectores del caso de uso que no lee la representación (A-050): prohíbe
283
+ * invocar los getters de la representación serializada y decidir comparando un
284
+ * campo de estado (`status`/`state`/`type`) en lugar de un predicado del dominio.
285
+ */
286
+ const USE_CASE_SYNTAX = [
287
+ {
288
+ selector: "CallExpression[callee.property.name=/^(getPrimitive|getPayload|getSnapshot)$/]",
289
+ message:
290
+ "El caso de uso no lee la representación serializada del dominio (A-050): pide el hecho al dominio (predicados, consultas, fábricas); la traducción a la wire la hace la frontera.",
291
+ },
292
+ {
293
+ selector: "BinaryExpression[operator=/^[!=]=?=?$/][left.property.name=/^(status|state|type)$/]",
294
+ message:
295
+ "El caso de uso no decide comparando un campo de estado de la representación (A-050): usa un predicado del dominio (p. ej. claim.isOpen()).",
296
+ },
297
+ {
298
+ selector: "BinaryExpression[operator=/^[!=]=?=?$/][right.property.name=/^(status|state|type)$/]",
299
+ message:
300
+ "El caso de uso no decide comparando un campo de estado de la representación (A-050): usa un predicado del dominio (p. ej. claim.isOpen()).",
301
+ },
302
+ ];
303
+
304
+ /**
305
+ * Reglas de forma y legibilidad (A-046) y dependencias explícitas (A-047).
306
+ * Son agnósticas al prefijo de paquete interno y a las capas, por eso viven
307
+ * fuera de la fábrica.
308
+ */
309
+ export const STYLE_RULES = {
310
+ // A-046 — métricas de forma.
311
+ "max-params": ["error", 2],
312
+ "max-lines-per-function": ["error", { max: 50, skipBlankLines: true }],
313
+ "max-lines": ["error", { max: 250, skipBlankLines: true }],
314
+ "no-magic-numbers": [
315
+ "error",
316
+ {
317
+ detectObjects: false,
318
+ enforceConst: true,
319
+ ignore: [0, 1, -1, 2],
320
+ ignoreArrayIndexes: true,
321
+ },
322
+ ],
323
+ complexity: ["error", 10],
324
+ "max-depth": ["error", 4],
325
+ "max-statements": ["error", 20],
326
+ "max-classes-per-file": ["error", 1],
327
+ "ultra/one-type-per-file": "error",
328
+ "id-length": ["error", { min: 2 }],
329
+ eqeqeq: ["error", "always"],
330
+
331
+ // A-047 — sin globales ambientales.
332
+ "no-console": "error",
333
+ "no-restricted-syntax": ["error", AMBIENT_SYNTAX],
334
+ };
335
+
336
+ /** Tipos que definen un tipo con nombre a nivel de archivo. */
337
+ const TYPE_DECLARATION_TYPES = new Set([
338
+ "ClassDeclaration",
339
+ "TSInterfaceDeclaration",
340
+ "TSTypeAliasDeclaration",
341
+ "TSEnumDeclaration",
342
+ ]);
343
+
344
+ /**
345
+ * Reconoce una declaración de tipo, desenvolviendo el `export` que la envuelve.
346
+ *
347
+ * @param {{ type?: string, declaration?: unknown } | undefined} node
348
+ * @returns {boolean}
349
+ */
350
+ function isTypeDeclaration(node) {
351
+ if (!node || typeof node.type !== "string") {
352
+ return false;
353
+ }
354
+ if (TYPE_DECLARATION_TYPES.has(node.type)) {
355
+ return true;
356
+ }
357
+ if (node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration") {
358
+ return isTypeDeclaration(node.declaration);
359
+ }
360
+ return false;
361
+ }
362
+
363
+ /**
364
+ * Regla local `ultra/one-type-per-file` (A-046 §8). `max-classes-per-file` solo
365
+ * cuenta clases; esta regla extiende la métrica a interfaces, alias de tipo y
366
+ * enums para que «un tipo principal por archivo» sea verificable de verdad.
367
+ */
368
+ const ONE_TYPE_PER_FILE_RULE = {
369
+ meta: {
370
+ type: "problem",
371
+ docs: { description: "Un tipo principal por archivo (A-046 §8)." },
372
+ schema: [],
373
+ messages: {
374
+ tooMany:
375
+ "Un tipo principal por archivo (A-046 §8): mueve el tipo adicional a su propio archivo.",
376
+ },
377
+ },
378
+ create(context) {
379
+ return {
380
+ Program(node) {
381
+ const declarations = node.body.filter(isTypeDeclaration);
382
+ for (const extra of declarations.slice(1)) {
383
+ context.report({ node: extra, messageId: "tooMany" });
384
+ }
385
+ },
386
+ };
387
+ },
388
+ };
389
+
390
+ /**
391
+ * Plugin local del preset: aloja las reglas que materializan una métrica de
392
+ * A-046 que el core de ESLint no cubre, sin introducir un segundo ejecutor.
393
+ */
394
+ const ULTRA_PLUGIN = Object.freeze({
395
+ rules: Object.freeze({ "one-type-per-file": ONE_TYPE_PER_FILE_RULE }),
396
+ });
397
+
398
+ /**
399
+ * Matriz de dependencias entre capas (A-001/A-024/A-025/A-026/A-027). El default
400
+ * es vetar toda dependencia local no declarada; las capas interiores no conocen
401
+ * a las exteriores:
402
+ * - app → domain, feature, shared-infra, representation
403
+ * - feature → domain, feature-error (el catálogo compartido de A-053)
404
+ * - feature-error → domain, feature-error (su propio catálogo)
405
+ * - shared-infra → domain, feature (los driver ports)
406
+ * - representation → domain
407
+ * - domain → domain
408
+ */
409
+ const LAYER_DEPENDENCY_POLICIES = [
410
+ {
411
+ from: { element: { type: "app" } },
412
+ allow: {
413
+ to: {
414
+ element: {
415
+ types: { anyOf: ["domain", "feature", "shared-infra", "representation"] },
416
+ },
417
+ },
418
+ },
419
+ },
420
+ {
421
+ from: { element: { type: "feature" } },
422
+ allow: {
423
+ to: { element: { types: { anyOf: ["domain", FEATURE_ERROR_TYPE] } } },
424
+ },
425
+ },
426
+ {
427
+ from: { element: { type: FEATURE_ERROR_TYPE } },
428
+ allow: {
429
+ to: { element: { types: { anyOf: ["domain", FEATURE_ERROR_TYPE] } } },
430
+ },
431
+ },
432
+ {
433
+ from: { element: { type: "shared-infra" } },
434
+ allow: { to: { element: { types: { anyOf: ["domain", "feature"] } } } },
435
+ },
436
+ {
437
+ from: { element: { type: "representation" } },
438
+ allow: { to: { element: { type: "domain" } } },
439
+ },
440
+ {
441
+ from: { element: { type: "domain" } },
442
+ allow: { to: { element: { type: "domain" } } },
443
+ },
444
+ ];
445
+
446
+ const LAYER_DEPENDENCIES_OPTIONS = {
447
+ default: "disallow",
448
+ policies: LAYER_DEPENDENCY_POLICIES,
449
+ };
450
+
451
+ /**
452
+ * Construye las reglas de orden de imports por distancia (A-051): builtins,
453
+ * externos, internos, relativos de carpeta lejana a cercana. Dentro de cada
454
+ * grupo, orden alfabético. Los imports de efecto lateral quedan fuera del
455
+ * ordenador (la regla no los mueve).
456
+ *
457
+ * @param {string} internal Prefijo del paquete interno (p. ej. `@acme/*`).
458
+ * @returns {Record<string, unknown>} Reglas de `import-x`.
459
+ */
460
+ export function importRules(internal) {
461
+ return {
462
+ "import-x/order": [
463
+ "error",
464
+ {
465
+ groups: [
466
+ "builtin",
467
+ "external",
468
+ "internal",
469
+ "parent",
470
+ "sibling",
471
+ "index",
472
+ ],
473
+ pathGroups: [{ pattern: internal, group: "internal", position: "before" }],
474
+ // Sin excluir `external`: un paquete con el prefijo interno se
475
+ // re-clasifica como `internal` y se ordena después de los externos.
476
+ pathGroupsExcludedImportTypes: ["builtin"],
477
+ alphabetize: { order: "asc", caseInsensitive: true },
478
+ // A-051: los imports se leen en bloques de distancia; el salto de línea
479
+ // separa cada capa y la funde visualmente si se omite.
480
+ "newlines-between": "always",
481
+ },
482
+ ],
483
+ };
484
+ }
485
+
486
+ /**
487
+ * Valida y normaliza el prefijo del paquete interno.
488
+ *
489
+ * @param {unknown} internal
490
+ * @returns {string}
491
+ */
492
+ function requireInternal(internal) {
493
+ if (typeof internal !== "string" || internal.trim() === "") {
494
+ throw new Error(
495
+ "El preset @imolko/ultra-agent/eslint requiere `internal` (el prefijo del paquete interno, p. ej. \"@acme/*\").",
496
+ );
497
+ }
498
+ return internal.trim();
499
+ }
500
+
501
+ /**
502
+ * Deriva el glob del catálogo compartido de errores (A-053) del glob de las
503
+ * features: `features/*` describe slices hermanas de `features/errors/`. Si el
504
+ * glob no termina en `/*` no se puede derivar y se usa el default.
505
+ *
506
+ * @param {string} featureGlob
507
+ * @returns {string | undefined}
508
+ */
509
+ function deriveFeatureErrorGlob(featureGlob) {
510
+ if (typeof featureGlob === "string" && featureGlob.endsWith("/*")) {
511
+ return `${featureGlob.slice(0, -2)}/errors/**`;
512
+ }
513
+ return undefined;
514
+ }
515
+
516
+ /**
517
+ * Resuelve las capas partiendo de los defaults de A-001 y aplicando los overrides
518
+ * del consumidor. Valida que la capa exista y que el glob sea una cadena no vacía.
519
+ * El catálogo de errores (A-053) se deriva del glob de `feature` salvo que se
520
+ * sobreescriba explícitamente con la clave `feature-error`.
521
+ *
522
+ * @param {unknown} overrides Globs de capa opcionales.
523
+ * @returns {Record<string, string>} Globs de capa completos.
524
+ */
525
+ function resolveLayers(overrides) {
526
+ const layers = { ...DEFAULT_LAYERS };
527
+ if (overrides !== undefined) {
528
+ if (typeof overrides !== "object" || overrides === null || Array.isArray(overrides)) {
529
+ throw new Error(
530
+ "El preset @imolko/ultra-agent/eslint espera `layers` como objeto de globs por capa.",
531
+ );
532
+ }
533
+ for (const [layer, glob] of Object.entries(overrides)) {
534
+ if (layer !== FEATURE_ERROR_TYPE && !Object.hasOwn(DEFAULT_LAYERS, layer)) {
535
+ throw new Error(
536
+ `Capa desconocida en \`layers\`: "${layer}". Capas válidas: ${[
537
+ ...LAYER_TYPES,
538
+ FEATURE_ERROR_TYPE,
539
+ ].join(", ")}.`,
540
+ );
541
+ }
542
+ if (typeof glob !== "string" || glob.trim() === "") {
543
+ throw new Error(`El glob de la capa "${layer}" debe ser una cadena no vacía.`);
544
+ }
545
+ layers[layer] = glob.trim();
546
+ }
547
+ }
548
+ if (layers[FEATURE_ERROR_TYPE] === undefined) {
549
+ layers[FEATURE_ERROR_TYPE] =
550
+ deriveFeatureErrorGlob(layers.feature) ?? DEFAULT_FEATURE_ERROR_GLOB;
551
+ }
552
+ return layers;
553
+ }
554
+
555
+ /**
556
+ * Traduce un glob de capa (patrón de elemento de `eslint-plugin-boundaries`) al
557
+ * conjunto de globs de archivo que ESLint acepta en `files`. Un glob que termina
558
+ * en `/*` describe la carpeta del elemento (p. ej. `features/*`), así que hay que
559
+ * alcanzar sus descendientes; un glob `**` ya los cubre.
560
+ *
561
+ * @param {string} glob
562
+ * @returns {string[]}
563
+ */
564
+ function layerFileGlobs(glob) {
565
+ return glob.endsWith("/*") ? [glob, `${glob}/**`] : [glob];
566
+ }
567
+
568
+ /**
569
+ * Globs de archivo del caso de uso dentro de cada slice de feature (A-025). Se
570
+ * derivan del glob de `feature` para que respeten el override del consumidor.
571
+ *
572
+ * @param {string} featureGlob
573
+ * @returns {string[]}
574
+ */
575
+ function useCaseFileGlobs(featureGlob) {
576
+ return [`${featureGlob}/use-case/**`];
577
+ }
578
+
579
+ /**
580
+ * Describe las capas para `eslint-plugin-boundaries`.
581
+ *
582
+ * @param {Record<string, string>} layers
583
+ * @returns {Array<{ type: string, pattern: string, capture: string[] }>}
584
+ */
585
+ function elementDescriptors(layers) {
586
+ // El catálogo de errores (A-053) va antes que `feature`: `features/errors/**`
587
+ // también encajaría en `features/*`, y el primer descriptor que encaja gana.
588
+ return [FEATURE_ERROR_TYPE, ...LAYER_TYPES].map((type) => ({
589
+ type,
590
+ pattern: layers[type],
591
+ capture: ["elementName"],
592
+ }));
593
+ }
594
+
595
+ /**
596
+ * Crea el array flat-config del tier A.
597
+ *
598
+ * @param {{
599
+ * internal: string,
600
+ * layers?: Record<string, string>,
601
+ * rawSeamTypes?: string[],
602
+ * }} options Opciones del preset. `internal` es obligatorio: el prefijo del
603
+ * paquete interno del consumidor. `layers` sobreescribe los globs de capa
604
+ * (defaults de A-001) y admite la clave `feature-error` para el catálogo de
605
+ * errores de A-053. `rawSeamTypes` extiende, con fragmentos de expresión
606
+ * regular, las formas raw que cruzan el driver port (A-054) cuando el
607
+ * consumidor nombra sus DTOs al margen de los sufijos por defecto.
608
+ * @returns {import("eslint").Linter.Config[]}
609
+ */
610
+ export function createPreset(options) {
611
+ const internal = requireInternal(options?.internal);
612
+ const layers = resolveLayers(options?.layers);
613
+ const rawSeamTypes = requireRawSeamTypes(options?.rawSeamTypes);
614
+
615
+ return [
616
+ { ignores: PRESET_IGNORES },
617
+ {
618
+ files: PRESET_FILES,
619
+ languageOptions: {
620
+ parser: tsParser,
621
+ parserOptions: {
622
+ ecmaVersion: "latest",
623
+ sourceType: "module",
624
+ },
625
+ },
626
+ plugins: {
627
+ // Se registra aunque no habilita reglas propias: resuelve las
628
+ // directivas de supresión de `@typescript-eslint/*` que ya tenga el
629
+ // consumidor y sirve de superficie para que componga sus reglas de
630
+ // proyecto encima del preset (A-052: el preset es componible).
631
+ "@typescript-eslint": tsPlugin,
632
+ "import-x": importX,
633
+ boundaries,
634
+ ultra: ULTRA_PLUGIN,
635
+ },
636
+ linterOptions: {
637
+ reportUnusedDisableDirectives: "off",
638
+ },
639
+ settings: {
640
+ "import-x/resolver": { typescript: { alwaysTryTypes: true } },
641
+ "import-x/extensions": [".ts", ".tsx", ".js", ".mjs", ".cjs"],
642
+ // `eslint-plugin-boundaries` resuelve con el resolver de `import`.
643
+ "import/resolver": { typescript: { alwaysTryTypes: true } },
644
+ "boundaries/elements": elementDescriptors(layers),
645
+ },
646
+ rules: {
647
+ ...STYLE_RULES,
648
+ ...importRules(internal),
649
+ "boundaries/dependencies": ["error", LAYER_DEPENDENCIES_OPTIONS],
650
+ },
651
+ },
652
+ {
653
+ files: layerFileGlobs(layers.domain),
654
+ rules: {
655
+ "no-restricted-imports": [
656
+ "error",
657
+ { patterns: [{ group: [...INFRA_FRAMEWORKS], message: DOMAIN_FRAMEWORK_MESSAGE }] },
658
+ ],
659
+ },
660
+ },
661
+ {
662
+ files: layerFileGlobs(layers.feature),
663
+ rules: {
664
+ "no-restricted-imports": [
665
+ "error",
666
+ { patterns: [{ group: [...INFRA_FRAMEWORKS], message: FEATURE_FRAMEWORK_MESSAGE }] },
667
+ ],
668
+ },
669
+ },
670
+ // A-050 — el caso de uso no lee la representación serializada. Va antes del
671
+ // bloque de ports para que un `*.service.port.ts` conserve las reglas de
672
+ // A-025 (el último bloque que encaja gana). Los tests y el formateo de
673
+ // errores quedan fuera: consumen la representación legítimamente.
674
+ {
675
+ files: useCaseFileGlobs(layers.feature),
676
+ ignores: [
677
+ "**/*.spec.ts",
678
+ "**/*.test.ts",
679
+ "**/*.integration.test.ts",
680
+ "**/test-setup.ts",
681
+ "**/test-helpers.ts",
682
+ "**/test-doubles/**",
683
+ "**/errors/**",
684
+ ],
685
+ rules: {
686
+ "no-restricted-syntax": ["error", AMBIENT_SYNTAX, ...USE_CASE_SYNTAX],
687
+ },
688
+ },
689
+ // A-025 — un puerto de dominio también habla en conceptos de dominio y
690
+ // nunca usa `any`/`unknown`. Va después del bloque de A-050 para añadir la
691
+ // métrica a los `*.port.ts` sin perder los selectores de A-050 que ya
692
+ // recibían, y antes del bloque de driver ports para que un
693
+ // `*.service.port.ts` herede además los selectores de costura.
694
+ {
695
+ files: domainPortFileGlobs(layers.feature),
696
+ rules: {
697
+ "no-restricted-syntax": [
698
+ "error",
699
+ AMBIENT_SYNTAX,
700
+ ...USE_CASE_SYNTAX,
701
+ ...UNTYPED_PORT_SYNTAX,
702
+ ],
703
+ },
704
+ },
705
+ // A-054 — la costura raw del driver port (va al final: es el bloque que gana
706
+ // en los archivos que solapan con los anteriores).
707
+ {
708
+ files: [...DRIVER_PORT_FILES],
709
+ rules: {
710
+ "no-restricted-syntax": [
711
+ "error",
712
+ AMBIENT_SYNTAX,
713
+ ...UNTYPED_PORT_SYNTAX,
714
+ ...seamSyntax(rawSeamTypes),
715
+ ],
716
+ },
717
+ },
718
+ ];
719
+ }
720
+
721
+ export default createPreset;