@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,220 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EXEC_AFK = exports.STATE_COMPLETED = exports.STATE_IN_DEV = exports.STATE_READY = void 0;
4
+ exports.glab = glab;
5
+ exports.glabJson = glabJson;
6
+ exports.glabExec = glabExec;
7
+ exports.verifyAuth = verifyAuth;
8
+ exports.projectPathFromRemote = projectPathFromRemote;
9
+ exports.getProjectPath = getProjectPath;
10
+ exports.encodeProjectPath = encodeProjectPath;
11
+ exports.getIssue = getIssue;
12
+ exports.getIssueComments = getIssueComments;
13
+ exports.getLinkedChildren = getLinkedChildren;
14
+ exports.extractBlockers = extractBlockers;
15
+ exports.isBlocked = isBlocked;
16
+ exports.isReady = isReady;
17
+ exports.selectNextIssue = selectNextIssue;
18
+ exports.claim = claim;
19
+ exports.markDone = markDone;
20
+ exports.resetOrphan = resetOrphan;
21
+ const node_child_process_1 = require("node:child_process");
22
+ const ship_output_1 = require("./ship.output");
23
+ // ── Labels (A-037) ────────────────────────────────────────────────────────────
24
+ exports.STATE_READY = "state::ready";
25
+ exports.STATE_IN_DEV = "state::in-development";
26
+ exports.STATE_COMPLETED = "state::completed";
27
+ exports.EXEC_AFK = "exec::AFK";
28
+ const GLAB_TIMEOUT_MS = 30000;
29
+ const JSON_PREVIEW_LENGTH = 200;
30
+ const COMMENT_HISTORY_LIMIT = 20;
31
+ function glab(args) {
32
+ return (0, node_child_process_1.execSync)(`glab ${args.join(" ")} 2>&1`, {
33
+ encoding: "utf-8",
34
+ stdio: ["pipe", "pipe", "pipe"],
35
+ timeout: GLAB_TIMEOUT_MS,
36
+ shell: "/bin/bash",
37
+ });
38
+ }
39
+ function glabJson(args) {
40
+ const output = glab(args);
41
+ const trimmed = output.trim();
42
+ try {
43
+ return JSON.parse(trimmed);
44
+ }
45
+ catch {
46
+ const match = trimmed.match(/(\{[\s\S]*\}|\[[\s\S]*\])/);
47
+ if (match)
48
+ return JSON.parse(match[0]);
49
+ throw new Error(`Failed to parse JSON from glab output: ${trimmed.slice(0, JSON_PREVIEW_LENGTH)}`);
50
+ }
51
+ }
52
+ // glab via execFileSync (no shell) — safe for titles/descriptions with spaces.
53
+ function glabExec(args) {
54
+ return (0, node_child_process_1.execFileSync)("glab", args, {
55
+ encoding: "utf-8",
56
+ stdio: ["pipe", "pipe", "pipe"],
57
+ timeout: GLAB_TIMEOUT_MS,
58
+ });
59
+ }
60
+ function verifyAuth() {
61
+ const output = glab(["auth", "status"]);
62
+ if (!output.includes("Token found")) {
63
+ throw new Error("glab is not authenticated. Run 'glab auth login' first.");
64
+ }
65
+ }
66
+ /**
67
+ * Extrae el path completo del proyecto (`namespace/proyecto`) de un remote de git.
68
+ * Conserva todos los segmentos del namespace —los grupos anidados no se truncan—
69
+ * y soporta HTTPS, `ssh://` y la forma SCP (`git@host:path`).
70
+ */
71
+ function projectPathFromRemote(remote) {
72
+ return remote
73
+ .trim()
74
+ .replace(/^[a-z][a-z0-9+.-]*:\/\//i, "") // esquema (https://, ssh://)
75
+ .replace(/^[^/@]+@/, "") // usuario@
76
+ .replace(/^[^/:]+(?::\d+)?[:/]/, "") // host[:puerto] + separador
77
+ .replace(/\.git$/, "")
78
+ .replace(/\/+$/, "");
79
+ }
80
+ function getProjectPath() {
81
+ const remote = (0, node_child_process_1.execSync)("git remote get-url origin 2>/dev/null", {
82
+ encoding: "utf-8",
83
+ stdio: ["pipe", "pipe", "pipe"],
84
+ }).trim();
85
+ if (!remote)
86
+ throw new Error("Not in a git repository with a remote");
87
+ const project = projectPathFromRemote(remote);
88
+ if (!project.includes("/"))
89
+ throw new Error(`Could not parse project path from remote: ${remote}`);
90
+ return project;
91
+ }
92
+ function encodeProjectPath(project) {
93
+ return encodeURIComponent(project);
94
+ }
95
+ function getIssue(iid) {
96
+ const json = glabJson(["issue", "view", String(iid), "--output", "json"]);
97
+ return {
98
+ iid: json.iid ?? 0,
99
+ title: json.title || "Unknown",
100
+ description: json.description || "",
101
+ state: json.state || "unknown",
102
+ labels: json.labels || [],
103
+ };
104
+ }
105
+ function getIssueComments(iid) {
106
+ const json = glabJson(["issue", "view", String(iid), "--comments", "--output", "json"]);
107
+ const notes = [];
108
+ const discussions = json.discussions || [];
109
+ for (const discussion of discussions) {
110
+ for (const note of discussion.notes || []) {
111
+ if (!note.system) {
112
+ const author = note.author?.username || "unknown";
113
+ notes.push(`${author}: ${note.body}`);
114
+ }
115
+ }
116
+ }
117
+ return notes.slice(-COMMENT_HISTORY_LIMIT).join("\n");
118
+ }
119
+ function getLinkedChildren(projectEncoded, parentIid) {
120
+ const apiPath = `projects/${projectEncoded}/issues/${parentIid}/links`;
121
+ const json = glabJson(["api", apiPath]);
122
+ if (!Array.isArray(json))
123
+ return [];
124
+ return json.map((issue) => {
125
+ const item = issue;
126
+ return {
127
+ iid: item.iid ?? 0,
128
+ title: item.title || "Unknown",
129
+ description: item.description || "",
130
+ state: item.state || "unknown",
131
+ labels: item.labels || [],
132
+ };
133
+ });
134
+ }
135
+ // ── Frontier (deterministic; the orchestrator owns it) ────────────────────────
136
+ function extractBlockers(description) {
137
+ const lines = description.split("\n");
138
+ let inBlockerSection = false;
139
+ const refs = [];
140
+ for (const line of lines) {
141
+ if (line.startsWith("# Bloqueado por")) {
142
+ inBlockerSection = true;
143
+ continue;
144
+ }
145
+ if (inBlockerSection) {
146
+ if (line.startsWith("#"))
147
+ break;
148
+ const match = line.match(/#(\d+)/);
149
+ if (match)
150
+ refs.push(parseInt(match[1], 10));
151
+ }
152
+ }
153
+ return [...new Set(refs)];
154
+ }
155
+ function isBlocked(issue, fetchIssue = getIssue) {
156
+ const blockers = extractBlockers(issue.description);
157
+ if (issue.description.toLowerCase().includes("ninguno - puede iniciarse")) {
158
+ return false;
159
+ }
160
+ if (blockers.length === 0)
161
+ return false;
162
+ for (const ref of blockers) {
163
+ try {
164
+ const blocker = fetchIssue(ref);
165
+ if (!blocker.labels.includes(exports.STATE_COMPLETED)) {
166
+ return true;
167
+ }
168
+ }
169
+ catch {
170
+ return true; // can't fetch the blocker → treat as blocked
171
+ }
172
+ }
173
+ return false;
174
+ }
175
+ function isReady(child) {
176
+ return (child.state === "opened" &&
177
+ child.labels.includes(exports.STATE_READY) &&
178
+ child.labels.includes(exports.EXEC_AFK));
179
+ }
180
+ function selectNextIssue(children, fetchIssue = getIssue) {
181
+ for (const child of children) {
182
+ if (!isReady(child))
183
+ continue;
184
+ if (isBlocked(child, fetchIssue)) {
185
+ (0, ship_output_1.writeError)(` ⏳ Issue #${child.iid} is blocked — skipping`);
186
+ continue;
187
+ }
188
+ return child;
189
+ }
190
+ return null;
191
+ }
192
+ // ── State transitions (the orchestrator owns every label change) ──────────────
193
+ function claim(iid) {
194
+ // Atomic: the label transition is what prevents a second ship from re-picking it.
195
+ glab(["issue", "update", String(iid), "--label", exports.STATE_IN_DEV, "--unlabel", exports.STATE_READY]);
196
+ try {
197
+ glab(["issue", "update", String(iid), "--assignee", "@me"]);
198
+ }
199
+ catch {
200
+ // assignee is visibility, not correctness — non-fatal
201
+ }
202
+ }
203
+ function markDone(iid, context) {
204
+ glab(["issue", "update", String(iid), "--label", exports.STATE_COMPLETED, "--unlabel", exports.STATE_IN_DEV]);
205
+ glabExec([
206
+ "issue", "note", String(context.parentIid),
207
+ "--message", `ship: completado #${iid}. ${context.summary}`,
208
+ ]);
209
+ }
210
+ function resetOrphan(iid) {
211
+ // A leftover in-development child from an interrupted run → back to ready.
212
+ glab(["issue", "update", String(iid), "--label", exports.STATE_READY, "--unlabel", exports.STATE_IN_DEV]);
213
+ try {
214
+ glab(["issue", "update", String(iid), "--unassign", "@me"]);
215
+ }
216
+ catch {
217
+ // non-fatal
218
+ }
219
+ }
220
+ //# sourceMappingURL=ship.tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ship.tracker.js","sourceRoot":"","sources":["../../src/ship/ship.tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * CLI de derivación de versión para los scripts de release (A-033 §7).
3
+ *
4
+ * Uso: `node dist-node/version.cli.js <base>` — lee los subjects de commit por
5
+ * stdin (uno por línea) y escribe por stdout la próxima versión `major.minor.patch`.
6
+ * Sale con código 0 si hubo bump; con código 1 si ningún commit mueve versión.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=version.cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.cli.d.ts","sourceRoot":"","sources":["../src/version.cli.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ /**
3
+ * CLI de derivación de versión para los scripts de release (A-033 §7).
4
+ *
5
+ * Uso: `node dist-node/version.cli.js <base>` — lee los subjects de commit por
6
+ * stdin (uno por línea) y escribe por stdout la próxima versión `major.minor.patch`.
7
+ * Sale con código 0 si hubo bump; con código 1 si ningún commit mueve versión.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ const node_fs_1 = require("node:fs");
11
+ const version_1 = require("./version");
12
+ function main() {
13
+ const argv = process.argv.slice(2);
14
+ const base = argv[0] ?? "0.0.0";
15
+ let subjects = argv.slice(1);
16
+ if (subjects.length === 0) {
17
+ subjects = (0, node_fs_1.readFileSync)(0, "utf-8")
18
+ .split("\n")
19
+ .map((line) => line.trim())
20
+ .filter((line) => line.length > 0);
21
+ }
22
+ const level = (0, version_1.classifyCommits)(subjects);
23
+ if (level === "none") {
24
+ process.exitCode = 1;
25
+ return;
26
+ }
27
+ process.stdout.write(`${(0, version_1.bumpVersion)(base, level)}\n`);
28
+ }
29
+ main();
30
+ //# sourceMappingURL=version.cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.cli.js","sourceRoot":"","sources":["../src/version.cli.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAEH,qCAAuC;AACvC,uCAAyD;AAEzD,SAAS,IAAI;IACX,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;IAEhC,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,QAAQ,GAAG,IAAA,sBAAY,EAAC,CAAC,EAAE,OAAO,CAAC;aAChC,KAAK,CAAC,IAAI,CAAC;aACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,KAAK,GAAG,IAAA,yBAAe,EAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;QACrB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAA,qBAAW,EAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;AACxD,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Derivación de versión SemVer a partir de los tipos de Conventional Commits
3
+ * (A-033 §7): `feat`→minor, `fix`→patch, breaking (`!` o `BREAKING CHANGE:`)→major.
4
+ *
5
+ * Funciones puras: ninguna toca el sistema de archivos ni el shell. El script de
6
+ * release las invoca para calcular la próxima versión; los tests las ejercen
7
+ * directamente sobre listas de mensajes de commit.
8
+ */
9
+ export type BumpLevel = "major" | "minor" | "patch" | "none";
10
+ /**
11
+ * Clasifica un único mensaje de commit (subject + body) según Conventional Commits.
12
+ * El breaking change se detecta por el `!` del header o por el footer `BREAKING CHANGE:`.
13
+ */
14
+ export declare function classifyCommit(message: string): BumpLevel;
15
+ /**
16
+ * Clasifica una lista de commits devolviendo el nivel más alto (major > minor > patch > none).
17
+ */
18
+ export declare function classifyCommits(messages: string[]): BumpLevel;
19
+ /**
20
+ * Aplica el bump a una versión `major.minor.patch` (ignora sufijos como `-beta`).
21
+ * Devuelve la versión de entrada sin cambios si no puede parsearse.
22
+ */
23
+ export declare function bumpVersion(version: string, level: BumpLevel): string;
24
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAI7D;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAazD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAS,CAS7D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,CAoBrE"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ /**
3
+ * Derivación de versión SemVer a partir de los tipos de Conventional Commits
4
+ * (A-033 §7): `feat`→minor, `fix`→patch, breaking (`!` o `BREAKING CHANGE:`)→major.
5
+ *
6
+ * Funciones puras: ninguna toca el sistema de archivos ni el shell. El script de
7
+ * release las invoca para calcular la próxima versión; los tests las ejercen
8
+ * directamente sobre listas de mensajes de commit.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.classifyCommit = classifyCommit;
12
+ exports.classifyCommits = classifyCommits;
13
+ exports.bumpVersion = bumpVersion;
14
+ const HEADER_RE = /^(\w+)(\([^)]*\))?(!)?:/;
15
+ /**
16
+ * Clasifica un único mensaje de commit (subject + body) según Conventional Commits.
17
+ * El breaking change se detecta por el `!` del header o por el footer `BREAKING CHANGE:`.
18
+ */
19
+ function classifyCommit(message) {
20
+ const header = message.split("\n")[0]?.trim() ?? "";
21
+ const match = header.match(HEADER_RE);
22
+ if (!match)
23
+ return "none";
24
+ const type = match[1];
25
+ const bang = match[3] === "!";
26
+ const breaking = /BREAKING CHANGE:/i.test(message);
27
+ if (breaking || bang)
28
+ return "major";
29
+ if (type === "feat")
30
+ return "minor";
31
+ if (type === "fix")
32
+ return "patch";
33
+ return "none";
34
+ }
35
+ /**
36
+ * Clasifica una lista de commits devolviendo el nivel más alto (major > minor > patch > none).
37
+ */
38
+ function classifyCommits(messages) {
39
+ let level = "none";
40
+ for (const message of messages) {
41
+ const current = classifyCommit(message);
42
+ if (current === "major")
43
+ return "major";
44
+ if (current === "minor")
45
+ level = "minor";
46
+ else if (current === "patch" && level === "none")
47
+ level = "patch";
48
+ }
49
+ return level;
50
+ }
51
+ /**
52
+ * Aplica el bump a una versión `major.minor.patch` (ignora sufijos como `-beta`).
53
+ * Devuelve la versión de entrada sin cambios si no puede parsearse.
54
+ */
55
+ function bumpVersion(version, level) {
56
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)/);
57
+ if (!match)
58
+ return version;
59
+ let major = Number(match[1]);
60
+ let minor = Number(match[2]);
61
+ let patch = Number(match[3]);
62
+ if (level === "major") {
63
+ major += 1;
64
+ minor = 0;
65
+ patch = 0;
66
+ }
67
+ else if (level === "minor") {
68
+ minor += 1;
69
+ patch = 0;
70
+ }
71
+ else if (level === "patch") {
72
+ patch += 1;
73
+ }
74
+ return `${major}.${minor}.${patch}`;
75
+ }
76
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;AAUH,wCAaC;AAKD,0CASC;AAMD,kCAoBC;AA3DD,MAAM,SAAS,GAAG,yBAAyB,CAAC;AAE5C;;;GAGG;AACH,SAAgB,cAAc,CAAC,OAAe;IAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACpD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACtB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;IAC9B,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEnD,IAAI,QAAQ,IAAI,IAAI;QAAE,OAAO,OAAO,CAAC;IACrC,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,OAAO,CAAC;IACpC,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,OAAO,CAAC;IACnC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAgB,eAAe,CAAC,QAAkB;IAChD,IAAI,KAAK,GAAc,MAAM,CAAC;IAC9B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACxC,IAAI,OAAO,KAAK,OAAO;YAAE,OAAO,OAAO,CAAC;QACxC,IAAI,OAAO,KAAK,OAAO;YAAE,KAAK,GAAG,OAAO,CAAC;aACpC,IAAI,OAAO,KAAK,OAAO,IAAI,KAAK,KAAK,MAAM;YAAE,KAAK,GAAG,OAAO,CAAC;IACpE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CAAC,OAAe,EAAE,KAAgB;IAC3D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACpD,IAAI,CAAC,KAAK;QAAE,OAAO,OAAO,CAAC;IAE3B,IAAI,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7B,IAAI,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7B,IAAI,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7B,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACtB,KAAK,IAAI,CAAC,CAAC;QACX,KAAK,GAAG,CAAC,CAAC;QACV,KAAK,GAAG,CAAC,CAAC;IACZ,CAAC;SAAM,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QAC7B,KAAK,IAAI,CAAC,CAAC;QACX,KAAK,GAAG,CAAC,CAAC;IACZ,CAAC;SAAM,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QAC7B,KAAK,IAAI,CAAC,CAAC;IACb,CAAC;IAED,OAAO,GAAG,KAAK,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;AACtC,CAAC"}
@@ -0,0 +1,115 @@
1
+ # ADR-0000: Proceso y formato de los ADRs
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-08-13
6
+
7
+ **originally**: imolko
8
+
9
+ **tags**: arquitectura, tooling
10
+
11
+ ## Contexto
12
+
13
+ El repositorio Guarura mantiene un registro de decisiones de arquitectura (ADR) distribuido en varios tiers y decenas de archivos. Hasta ahora la información sobre *cómo* se escriben y gobiernan esos ADRs vivía dispersa en las secciones "Formato" y "Tiers" de `docs/adr/index.md`, sin respaldo de decisión: no estaba escrito por qué se usa el formato de Michael Nygard, por qué existen cuatro tiers, ni qué reglas se aplican para mantener la consistencia.
14
+
15
+ Sin un ADR que canonice el proceso, cada decisión nueva corre el riesgo de:
16
+
17
+ - usar un formato distinto (por ejemplo, un frontmatter YAML en lugar de las líneas `**Campo**: valor` del proyecto);
18
+ - romper la jerarquía de referencias entre tiers;
19
+ - omitir campos obligatorios como `originally` o las etiquetas;
20
+ - introducir enlaces rotos o listas duplicadas que el gate detecta.
21
+
22
+ Este documento es el **meta-ADR**: define el proceso y el formato que el resto de ADRs debe seguir. Vive en la raíz de `docs/adr/` y usa el ID `0000` precisamente porque está **fuera** de la jerarquía A→T/P→G: define esa jerarquía y, por lo tanto, no pertenece a ninguno de sus tiers. Por su nombre no es detectado por el gate de consistencia, lo cual es correcto.
23
+
24
+ ## Decisión
25
+
26
+ ### Formato: Michael Nygard con frontmatter del proyecto
27
+
28
+ Cada ADR sigue el formato de **Michael Nygard**, con tres secciones de contenido:
29
+
30
+ - **Contexto**: situación que motiva la decisión (fuerzas, restricciones, problema).
31
+ - **Decisión**: qué se decidió y por qué.
32
+ - **Consecuencias**: implicaciones positivas y negativas de la decisión.
33
+
34
+ Cada ADR cubre **una única decisión ortogonal**. Ampliar el alcance sobre el mismo eje — por ejemplo, extender una regla de value-objects a entidades y agregados — se hace en el mismo ADR; una decisión de un eje distinto — por ejemplo, la validación de artefactos de dominio frente al contrato de configuración de la aplicación — vive en su propio ADR. Un ADR que acumula dos ejes se divide.
35
+
36
+ Además del título H1 (`# <ID>: <Título descriptivo>`), cada ADR lleva un **frontmatter del proyecto** como líneas `**Campo**: valor` inmediatamente después del título:
37
+
38
+ | Campo | Obligatorio | Descripción |
39
+ |-------|-------------|-------------|
40
+ | `**Estado**` | Sí | Uno de: `Aceptado`, `Propuesto`, `Deprecado`, `Reemplazado`. |
41
+ | `**Fecha**` | Sí | Fecha de la decisión (formato `YYYY-MM-DD` o `YYYY-MM`). |
42
+ | `**originally**` | Sí | Procedencia original de la decisión (ID fuente, en minúsculas). |
43
+ | `**Enriquecido desde**` | No | Fuente de enriquecimiento posterior (cuando aplica). |
44
+ | `**tags**` | Sí (tier A hoy) | De una a tres etiquetas del vocabulario en [A-043](./foundational/A-043-vocabulario-etiquetas-adrs.md). |
45
+
46
+ El gate valida el formato H1 y la ortografía exacta de `originally` (minúsculas) y `Enriquecido desde` (capitalización exacta) para los ADRs de los tiers A/T/P/G.
47
+
48
+ ### Jerarquía de tiers: A → T/P → tier de proyecto
49
+
50
+ Los ADRs se organizan en tres tiers de metodología más el tier de proyecto de cada consumidor, según su alcance:
51
+
52
+ | Tier | Ubicación | Alcance |
53
+ |------|-----------|---------|
54
+ | **Fundacional (A)** | [`foundational/`](./foundational/index.md) | Decisiones metodológicas agnósticas al lenguaje (Clean Architecture, TDD, comandos y consultas, DDD). Aplican a todos los proyectos de Imolko. |
55
+ | **TypeScript (T)** | [`typescript/`](./typescript/index.md) | Decisiones específicas del ecosistema TypeScript/Zod/Node.js. |
56
+ | **Python (P)** | [`python/`](./python/index.md) | Decisiones específicas del ecosistema Python (FastAPI, SQLAlchemy, Pydantic). |
57
+ | **Tier de proyecto** | `docs/adr/` (raíz) u otro directorio del consumidor | Decisiones específicas del dominio del proyecto consumidor. El prefijo es propio de cada proyecto (por ejemplo `G` para Guarura) y no forma parte de la metodología distribuida ([A-052](./foundational/A-052-distribucion-metodologia-paquete-versionado.md)). |
58
+
59
+ **Reglas de referencia** (jerarquía estricta):
60
+
61
+ - Los ADRs **A** no referencian ADRs T, P ni del tier de proyecto.
62
+ - Los ADRs **T** y **P** pueden referenciar A, pero no se referencian entre sí ni al tier de proyecto.
63
+ - El **tier de proyecto** puede referenciar A, T y P.
64
+
65
+ La numeración es **estable**: los IDs existentes no se renumeran. Los IDs omitidos intencionalmente (por ejemplo A-021) no se reutilizan.
66
+
67
+ ### Fases narrativas del tier fundacional
68
+
69
+ Los ADRs fundacionales (A-XXX) se agrupan en fases narrativas; el orden y el agrupamiento exactos viven en [`foundational/index.md`](./foundational/index.md), que es quien porta la narrativa. Las fases son una organización de lectura; no cambian la numeración ni los tiers.
70
+
71
+ ### Gate de consistencia
72
+
73
+ La consistencia del registro se verifica con [`scripts/verify-adr-consistency.py`](../../scripts/verify-adr-consistency.py), un script de solo lectura que se ejecuta desde la raíz del repositorio:
74
+
75
+ ```bash
76
+ python3 scripts/verify-adr-consistency.py
77
+ ```
78
+
79
+ El gate valida **cinco reglas** y debe salir con código `0` y cero violaciones:
80
+
81
+ | Regla | Qué valida |
82
+ |-------|------------|
83
+ | `jerarquia` | Los ADRs no referencian tiers prohibidos según la jerarquía A→T/P→tier de proyecto. |
84
+ | `enlaces` | Todos los enlaces markdown internos (relativos, `*.md`) resuelven a un archivo existente. |
85
+ | `frontmatter` | El título sigue `# <TIER>-<NNN>: Título` y los campos `originally` / `Enriquecido desde` usan la ortografía correcta. |
86
+ | `indices` | Cada ADR aparece en el índice de su tier y el índice no lista ADRs inexistentes. |
87
+ | `hardcoded` | Los ADRs no duplican listas cuya fuente canónica vive en otro archivo (workspaces/dependencias → `package.json`, skills → paquete `@imolko/ultra-agent` y su materializador, release → `domain/scripts/release*.sh`). |
88
+
89
+ El gate y su salida `0` son la condición de aprobación no negociable para cualquier cambio en `docs/adr/`.
90
+
91
+ ### Ciclo de vida
92
+
93
+ Cada ADR transita por un ciclo de vida simple:
94
+
95
+ 1. **Propuesto**: la decisión se propone y se discute.
96
+ 2. **Aceptado**: la decisión queda en vigor y su `**Estado**` es `Aceptado`.
97
+ 3. **Reemplazado** o **Deprecado**: cuando una decisión posterior la sustituye o queda obsoleta, se actualiza su `**Estado**` y se enlaza al ADR que la reemplaza (en prosa markdown, sin campos prev/next).
98
+
99
+ Reglas de numeración:
100
+
101
+ - El siguiente ADR de un tier toma el siguiente número correlativo (`A-NNN`, `T-NNN`, `P-NNN`, o el prefijo propio del tier de proyecto).
102
+ - Los IDs omitidos intencionalmente (por ejemplo A-021) **no se reutilizan**: permanecen omitidos para preservar la estabilidad de los IDs existentes.
103
+
104
+ ## Consecuencias
105
+
106
+ ### Positivas
107
+
108
+ - **Proceso canonizado**: el formato, la jerarquía y el gate dejan de vivir dispersos y pasan a tener respaldo de decisión.
109
+ - **Onboarding más corto**: un colaborador nuevo lee un único ADR para entender cómo contribuir decisiones.
110
+ - **Consistencia ejecutable**: el gate automatiza la verificación de las cinco reglas, con salida 0 como criterio de aceptación.
111
+ - **Jerarquía clara**: las reglas de referencia entre tiers evitan acoplamientos incorrectos (por ejemplo, un ADR fundacional citando uno de Guarura).
112
+
113
+ ### Negativas
114
+
115
+ - **Un archivo más que mantener**: el meta-ADR debe actualizarse si cambia el proceso (por ejemplo, si se añade una regla al gate).
@@ -0,0 +1,88 @@
1
+ # A-001: Clean Architecture con 4 capas
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2025-02-25
6
+ **originally**: imolko
7
+ **Enriquecido desde**: Cortex ADR 004 — Clean Architecture feature structure with ports & drivers
8
+
9
+ **tags**: arquitectura
10
+
11
+ ## Contexto
12
+
13
+ Los proyectos de Imolko necesitan una estructura que:
14
+
15
+ - Separe claramente las reglas de negocio de los detalles de infraestructura
16
+ - Permita probar el dominio de forma aislada (sin base de datos, sin HTTP, sin frameworks)
17
+ - Facilite el reemplazo de tecnologías (base de datos, transporte, UI) sin afectar la lógica de negocio
18
+ - Soporte múltiples formas de despliegue (nodo local, servidor central, workers)
19
+ - Escale a 15+ features sin degenerar en caos estructural
20
+
21
+ ## Decisión
22
+
23
+ Adoptar **Clean Architecture** con 4 capas concéntricas, inspirada en la arquitectura hexagonal (puertos y adaptadores) y los principios de DDD. Las reglas de negocio puras viven en el dominio; los casos de uso las orquestan a través de puertos, y la infraestructura es un detalle de implementación.
24
+
25
+ ### Estructura global
26
+
27
+ ```
28
+ domain/ # Capa más interna — reglas de negocio puras
29
+ features/ # Casos de uso — slices verticales independientes
30
+ shared-infra/ # Drivers y esquemas de persistencia por tecnología
31
+ representations/ # Formas de wire por protocolo
32
+ apps/ # Unidades desplegables independientes
33
+ ```
34
+
35
+ ### Capa 1: domain
36
+
37
+ Contiene las reglas de negocio puras. Artefactos DDD:
38
+
39
+ - Value objects, entidades, agregados (aggregate roots)
40
+ - Servicios de dominio
41
+ - Especificaciones
42
+ - Eventos de dominio
43
+
44
+ **Dependencias mínimas**: solo librerías de validación y result-type. Sin dependencias de infraestructura, frameworks HTTP, ni bases de datos.
45
+
46
+ ### Capa 2: features
47
+
48
+ Cada feature es un slice vertical autocontenido que vive bajo `features/` a nivel de workspace. Su anatomía (puertos de dominio, adaptadores y driver ports) y la mecánica Puerto→Adaptador→Driver port están en [A-025](./A-025-anatomia-mecanica-feature-puertos-adaptadores-drivers.md). Su portabilidad entre apps y su composición en wiring están en [A-024](./A-024-features-slices-verticales-portables.md).
49
+
50
+ ### Capa 3: shared-infra
51
+
52
+ La infraestructura compartida entre features vive en `shared-infra/`, un directorio que agrupa un paquete por tecnología (`shared-infra/mongo/`, `shared-infra/postgres/`, …). Cada paquete contiene los drivers que implementan los driver ports que las features declaran, junto con sus esquemas de persistencia. Las formas de wire (`representations/`) viven en su propio paquete por protocolo (`representations/graphql/`, `representations/protobuf/`, …), junto a `shared-infra/`. Las features nunca importan estos paquetes. El catálogo completo está en [A-026](./A-026-infraestructura-compartida.md).
53
+
54
+ ### Capa 4: apps
55
+
56
+ Unidades desplegables independientes. Cada app selecciona un conjunto de features y las empaqueta para despliegue componiéndolas en su capa de wiring. Ejemplos: un nodo local para el almacén, un servidor central de reporting, un worker que procesa eventos de sistemas externos.
57
+
58
+ El patrón de wiring entry-point está en [A-027](./A-027-patron-wiring-entry-point.md).
59
+
60
+ ### Dirección de dependencias
61
+
62
+ Las dependencias siempre apuntan hacia adentro: el dominio no depende de ninguna
63
+ capa exterior; `representations/<protocol>/` importa solo el dominio; `shared-infra/<tech>/`
64
+ importa el dominio y los driver ports que
65
+ las features declaran, nunca al revés. El driver de `shared-infra/<tech>/` implementa el driver
66
+ port que la feature define; la feature nunca importa
67
+ `shared-infra/` ni `representations/`.
68
+
69
+ La regla de que las features nunca importan
70
+ del interior de otras features — el acoplamiento ocurre
71
+ solo en tiempo de wiring — vive en
72
+ [A-024](./A-024-features-slices-verticales-portables.md).
73
+
74
+ ## Consecuencias
75
+
76
+ ### Positivas
77
+
78
+ - **Dominio aislado**: las reglas de negocio se pueden probar sin infraestructura.
79
+ - **Flexibilidad tecnológica**: cambiar de base de datos o protocolo no afecta el dominio — reemplazar un driver toca solo `drivers/<tech>/` de la feature y, cuando lo comparte, el paquete `shared-infra/<tech>/`.
80
+ - **Despliegues independientes**: cada app se despliega por separado.
81
+ - **Desarrollo paralelo**: múltiples features pueden desarrollarse simultáneamente sin conflictos.
82
+ - **Testabilidad**: cada capa se prueba de forma aislada con dobles de prueba.
83
+
84
+ ### Negativas
85
+
86
+ - **Mapeo entre capas**: requiere DTOs y mapeo de datos entre capas (dominio ↔ aplicación ↔ infraestructura).
87
+ - **Curva de aprendizaje**: el equipo debe entender la arquitectura y respetar la dirección de las dependencias (siempre hacia adentro).
88
+ - **Disciplina requerida**: mantener los ports puros y los drivers aislados requiere revisión constante.
@@ -0,0 +1,58 @@
1
+ # A-002: Separación de comandos y consultas
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2025-02-25
6
+
7
+ **originally**: imolko
8
+
9
+ **tags**: arquitectura
10
+
11
+ ## Contexto
12
+
13
+ Un sistema expone casos de uso de dos naturalezas: los que **cambian el estado** del dominio y los que **responden preguntas**. Sin un criterio explícito para distinguirlos, ambas naturalezas se mezclan en el código — operaciones que escriben y devuelven datos a la vez, consultas con efectos secundarios — y los nombres derivan hacia verbos técnicos (CRUD) en lugar del lenguaje del negocio.
14
+
15
+ Las consultas no son un caso menor: muchas involucran reglas de negocio (p. ej. una fórmula de disponibilidad) y deben modelarse con el mismo rigor semántico que los comandos.
16
+
17
+ ## Decisión
18
+
19
+ Separar **comandos** (operaciones que cambian el estado) de **consultas** (operaciones que retornan datos) en la estructura de features, usando **lenguaje ubicuo** en los nombres de los casos de uso.
20
+
21
+ ### Clasificación command vs query
22
+
23
+ La clasificación se infiere del nombre del caso de uso por convención de nomenclatura:
24
+
25
+ | Tipo | Definición | Criterio |
26
+ |---|---|---|
27
+ | `command` | Modifica el estado del sistema | El nombre comienza con un verbo de acción: `registrar-*`, `agregar-*`, `eliminar-*`, `modificar-*`, `asignar-*`, `recibir-*`, `transferir-*` |
28
+ | `query` | Consulta o valida sin modificar estado | El nombre comienza con un verbo de consulta: `consultar-*`, `validar-*`, `verificar-*`, `filtrar-*`, `listar-*`, `calcular-*` |
29
+
30
+ Esta taxonomía permite que cualquier desarrollador clasifique nuevos casos de uso de forma consistente con solo inspeccionar el nombre. Un caso de uso `command` **nunca** debe retornar datos de lectura como propósito principal; un caso de uso `query` **nunca** debe tener efectos secundarios observables.
31
+
32
+ El campo `type` en el frontmatter del feature documenta esta clasificación. El esquema de ese frontmatter se define en [A-032](./A-032-domain-artifact-documentation-format.md).
33
+
34
+ ### Principios
35
+
36
+ 1. **Separación estructural**: cada operación (comando o consulta) es un feature independiente en `features/<caso-de-uso>/` (anatomía en [A-025](./A-025-anatomia-mecanica-feature-puertos-adaptadores-drivers.md)). No hay features "mixtas" que lean y escriban en el mismo caso de uso.
37
+ 2. **Semántica de negocio**: los casos de uso se nombran con verbos del dominio, no con verbos CRUD ([A-029](./A-029-verbos-intencion-metodos-lado-negocio.md)):
38
+ - ✅ `registrar-pedido`, `consultar-disponibilidad`
39
+ - ❌ `createStockMovement`, `getInventory`
40
+
41
+ ### Alcance
42
+
43
+ La separación es **estructural y de nombrado**: clasifica cada caso de uso y lo aísla en su feature, sin prescribir la infraestructura de lectura. La persistencia de lectura y escritura no se segrega. La optimización de las consultas (vistas materializadas, cachés, índices) y su proyección desde eventos son responsabilidad del driver, no de esta decisión ([A-010](./A-010-propiedad-emision-eventos-dominio.md)).
44
+
45
+ Cuando las lecturas se sirven de proyecciones reconstruidas desde eventos, la consistencia depende de la naturaleza de la lectura: la que respalda un **invariante de un comando** (una verificación que el comando debe respetar) es **síncrona** — un índice actualizado en la misma transacción de la escritura —; la que respalda una **consulta o reporte** es **eventual** — una proyección mantenida por un suscriptor del stream. La primera no puede quedar eventual sin arriesgar el invariante; la segunda no necesita ser síncrona.
46
+
47
+ ## Consecuencias
48
+
49
+ ### Positivas
50
+
51
+ - **Lenguaje ubicuo en el código**: los nombres de features reflejan directamente las operaciones del negocio
52
+ - **Features enfocadas**: cada caso de uso tiene una sola responsabilidad (comandar o consultar)
53
+ - **Estructura predecible**: cualquier desarrollador sabe que `features/consultar-*` son consultas y `features/<verbo>-*` son comandos
54
+
55
+ ### Negativas
56
+
57
+ - **Optimización de lecturas delegada al driver**: la eficiencia de las consultas depende del driver que se use; la optimización es responsabilidad de cada driver
58
+ - **Features numerosas**: cada consulta es un feature separado, y la navegación requiere disciplina de nombres