oficina-opencode 0.0.0-stage → 2.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.
Files changed (117) hide show
  1. package/DESIGN.md +145 -0
  2. package/LICENSE +21 -0
  3. package/README.md +670 -2
  4. package/agents/oficina-architect.md +72 -0
  5. package/agents/oficina-commander.md +108 -0
  6. package/agents/oficina-critico.md +148 -0
  7. package/agents/oficina-director.md +160 -0
  8. package/agents/oficina-guardian.md +128 -0
  9. package/agents/oficina-integrator.md +98 -0
  10. package/agents/oficina-verificador.md +88 -0
  11. package/commands/oficina.md +36 -0
  12. package/dist/cli.d.ts +12 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +394 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/core/briefing.d.ts +115 -0
  17. package/dist/core/briefing.d.ts.map +1 -0
  18. package/dist/core/briefing.js +410 -0
  19. package/dist/core/briefing.js.map +1 -0
  20. package/dist/core/bus.d.ts +132 -0
  21. package/dist/core/bus.d.ts.map +1 -0
  22. package/dist/core/bus.js +250 -0
  23. package/dist/core/bus.js.map +1 -0
  24. package/dist/core/catalog.d.ts +303 -0
  25. package/dist/core/catalog.d.ts.map +1 -0
  26. package/dist/core/catalog.js +816 -0
  27. package/dist/core/catalog.js.map +1 -0
  28. package/dist/core/dispatch.d.ts +110 -0
  29. package/dist/core/dispatch.d.ts.map +1 -0
  30. package/dist/core/dispatch.js +301 -0
  31. package/dist/core/dispatch.js.map +1 -0
  32. package/dist/core/factory.d.ts +74 -0
  33. package/dist/core/factory.d.ts.map +1 -0
  34. package/dist/core/factory.js +243 -0
  35. package/dist/core/factory.js.map +1 -0
  36. package/dist/core/fsx.d.ts +39 -0
  37. package/dist/core/fsx.d.ts.map +1 -0
  38. package/dist/core/fsx.js +113 -0
  39. package/dist/core/fsx.js.map +1 -0
  40. package/dist/core/gates.d.ts +97 -0
  41. package/dist/core/gates.d.ts.map +1 -0
  42. package/dist/core/gates.js +467 -0
  43. package/dist/core/gates.js.map +1 -0
  44. package/dist/core/leases.d.ts +46 -0
  45. package/dist/core/leases.d.ts.map +1 -0
  46. package/dist/core/leases.js +94 -0
  47. package/dist/core/leases.js.map +1 -0
  48. package/dist/core/log.d.ts +30 -0
  49. package/dist/core/log.d.ts.map +1 -0
  50. package/dist/core/log.js +43 -0
  51. package/dist/core/log.js.map +1 -0
  52. package/dist/core/mesa.d.ts +82 -0
  53. package/dist/core/mesa.d.ts.map +1 -0
  54. package/dist/core/mesa.js +178 -0
  55. package/dist/core/mesa.js.map +1 -0
  56. package/dist/core/office.d.ts +208 -0
  57. package/dist/core/office.d.ts.map +1 -0
  58. package/dist/core/office.js +618 -0
  59. package/dist/core/office.js.map +1 -0
  60. package/dist/core/paths.d.ts +67 -0
  61. package/dist/core/paths.d.ts.map +1 -0
  62. package/dist/core/paths.js +136 -0
  63. package/dist/core/paths.js.map +1 -0
  64. package/dist/core/retry.d.ts +41 -0
  65. package/dist/core/retry.d.ts.map +1 -0
  66. package/dist/core/retry.js +86 -0
  67. package/dist/core/retry.js.map +1 -0
  68. package/dist/core/roster.d.ts +47 -0
  69. package/dist/core/roster.d.ts.map +1 -0
  70. package/dist/core/roster.js +146 -0
  71. package/dist/core/roster.js.map +1 -0
  72. package/dist/core/router.d.ts +67 -0
  73. package/dist/core/router.d.ts.map +1 -0
  74. package/dist/core/router.js +186 -0
  75. package/dist/core/router.js.map +1 -0
  76. package/dist/core/state.d.ts +89 -0
  77. package/dist/core/state.d.ts.map +1 -0
  78. package/dist/core/state.js +303 -0
  79. package/dist/core/state.js.map +1 -0
  80. package/dist/core/types.d.ts +333 -0
  81. package/dist/core/types.d.ts.map +1 -0
  82. package/dist/core/types.js +27 -0
  83. package/dist/core/types.js.map +1 -0
  84. package/dist/hooks/compacting.d.ts +18 -0
  85. package/dist/hooks/compacting.d.ts.map +1 -0
  86. package/dist/hooks/compacting.js +72 -0
  87. package/dist/hooks/compacting.js.map +1 -0
  88. package/dist/hooks/scopeGuard.d.ts +39 -0
  89. package/dist/hooks/scopeGuard.d.ts.map +1 -0
  90. package/dist/hooks/scopeGuard.js +114 -0
  91. package/dist/hooks/scopeGuard.js.map +1 -0
  92. package/dist/hooks/sessionIdle.d.ts +35 -0
  93. package/dist/hooks/sessionIdle.d.ts.map +1 -0
  94. package/dist/hooks/sessionIdle.js +110 -0
  95. package/dist/hooks/sessionIdle.js.map +1 -0
  96. package/dist/hooks/systemTransform.d.ts +18 -0
  97. package/dist/hooks/systemTransform.d.ts.map +1 -0
  98. package/dist/hooks/systemTransform.js +63 -0
  99. package/dist/hooks/systemTransform.js.map +1 -0
  100. package/dist/index.d.ts +36 -0
  101. package/dist/index.d.ts.map +1 -0
  102. package/dist/index.js +103 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/tools/index.d.ts +22 -0
  105. package/dist/tools/index.d.ts.map +1 -0
  106. package/dist/tools/index.js +854 -0
  107. package/dist/tools/index.js.map +1 -0
  108. package/docs/ARCHITECTURE.md +258 -0
  109. package/docs/QUE-ES.md +337 -0
  110. package/examples/opencode.json +7 -0
  111. package/package.json +81 -4
  112. package/skills/oficina/README.md +120 -0
  113. package/skills/oficina/SKILL.md +251 -0
  114. package/skills/oficina/reference/mesh.md +345 -0
  115. package/skills/oficina/reference/protocol.md +342 -0
  116. package/skills/oficina/reference/roles.md +171 -0
  117. package/skills/oficina/reference/templates.md +278 -0
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Factory: creación de roles que el catálogo no cubre.
3
+ *
4
+ * ## Por qué una factory y no un prompt genérico
5
+ *
6
+ * Un rol fabricado tiene que ser **indistinguible en calidad** de uno del
7
+ * catálogo. Si el catálogo de agency-agents tiene 306 agentes con briefing de
8
+ * 10 secciones, un rol fabricado con un prompt de 5 líneas se nota: es
9
+ * monótono, no tiene criterio propio, y el resto de la malla lo trata como
10
+ * un agente de segunda.
11
+ *
12
+ * Por eso la factory emite **exactamente la misma estructura** que agency-agents:
13
+ * Identity & Memory, Core Mission, Critical Rules, Technical Deliverables,
14
+ * Workflow Process, Communication Style, Learning & Memory, Success Metrics,
15
+ * Advanced Capabilities. El parser del catálogo no distingue el origen.
16
+ *
17
+ * ## Qué hace de un briefing bueno
18
+ *
19
+ * No es largo: es **específico**. Un briefing que dice "sos un experto en X"
20
+ * no sirve para nada. Uno que dice qué mirás primero, qué error típico cometés
21
+ * y qué entregás, sirve.
22
+ */
23
+ import { capabilityTokens } from "./catalog.js";
24
+ import { shortId } from "./fsx.js";
25
+ export const FACTORY_DISPLAY_FALLBACK = "Especialista";
26
+ /**
27
+ * Template de un agente fabricado.
28
+ *
29
+ * La estructura es la de agency-agents a propósito: mismo orden, mismas
30
+ * secciones, mismo nivel de especificidad.
31
+ */
32
+ export const FACTORY_PROMPT_TEMPLATE = `# {{display_name}} Agent Personality
33
+
34
+ You are **{{display_name}}**, {{role_phrase}} {{mission_phrase}}
35
+
36
+ ## Your Identity & Memory
37
+
38
+ - **Role**: {{role_phrase}}
39
+ - **Personality**: {{personality}}
40
+ - **Memory**: {{memory}}
41
+ - **Experience**: {{experience}}
42
+
43
+ ## Your Core Mission
44
+
45
+ {{core_mission}}
46
+
47
+ ## Critical Rules You Must Follow
48
+
49
+ {{critical_rules}}
50
+
51
+ ## Your Technical Deliverables
52
+
53
+ {{technical_deliverables}}
54
+
55
+ ## Your Workflow Process
56
+
57
+ ### Step 1: Understand the Terrain
58
+ {{step_1}}
59
+
60
+ ### Step 2: Decide the Approach
61
+ {{step_2}}
62
+
63
+ ### Step 3: Execute Within Scope
64
+ {{step_3}}
65
+
66
+ ### Step 4: Verify and Hand Off
67
+ {{step_4}}
68
+
69
+ ## Your Communication Style
70
+
71
+ {{communication_style}}
72
+
73
+ ## Learning & Memory
74
+
75
+ Remember and build rigor in:
76
+ {{learning}}
77
+
78
+ ## Your Success Metrics
79
+
80
+ You're successful when:
81
+ {{success_metrics}}
82
+
83
+ ## Advanced Capabilities
84
+
85
+ {{advanced_capabilities}}
86
+
87
+ ## Context of This Run
88
+
89
+ {{objective}}
90
+ `;
91
+ /** Reglas base que todos los agentes fabricados comparten. */
92
+ const BASE_RULES = [
93
+ "**Scope is a hard boundary, not a suggestion.** Touch only what your card authorizes. The engine blocks the rest.",
94
+ "**No evidence, no work.** A claim without the real command output is a hypothesis.",
95
+ "**Never review your own work.** Another agent does that, and the engine will not let you.",
96
+ "**Ask before you guess.** If the context you need is not in your briefing, request it on the bus.",
97
+ "**Say what you did not do.** A handoff that hides its gaps is worse than one that names them.",
98
+ ];
99
+ /**
100
+ * Fabrica una ficha a partir del template.
101
+ *
102
+ * El prompt generado no es genérico: incluye las capabilities concretas, el
103
+ * scope, el objetivo de la corrida y los modos de fallo del rol. Un agente
104
+ * fabricado con contexto es usable; uno con un prompt vacío no sirve.
105
+ */
106
+ export function createFicha(input) {
107
+ const displayName = input.displayName ?? titleize(input.role);
108
+ const capabilities = input.capabilities.length > 0
109
+ ? input.capabilities
110
+ : [...capabilityTokens(input.role)];
111
+ const mission = input.mission ?? `Resolver el trabajo que se te asigne en esta corrida.`;
112
+ const failureModes = input.failureModes ?? defaultFailureModes(input.role);
113
+ const source = {
114
+ kind: "factory",
115
+ sourcePrompt: renderPrompt(input, displayName, capabilities, mission, failureModes),
116
+ vibe: `Rol fabricado para esta corrida: ${capabilities.slice(0, 3).join(", ")}.`,
117
+ missions: [mission],
118
+ deliverables: [
119
+ "Un entregable concreto con el detalle suficiente para que otro agente lo retome sin preguntar nada",
120
+ "Evidencia ejecutable de lo que se hizo",
121
+ ],
122
+ rules: BASE_RULES,
123
+ };
124
+ return {
125
+ id: shortId("e"),
126
+ role: input.role,
127
+ displayName,
128
+ source,
129
+ capabilities,
130
+ tools: ["read", "glob", "grep", "edit", "write", "bash", "task"],
131
+ scope: {
132
+ mayTouch: input.scope?.mayTouch ?? ["**"],
133
+ forbidden: input.scope?.forbidden ?? ["**/*.env", "**/*.env.*", "**/.env"],
134
+ },
135
+ canDelegate: input.canDelegate ?? false,
136
+ delegateBudget: input.delegateBudget ?? 0,
137
+ peers: input.peers ?? [],
138
+ mustNot: [
139
+ "no editar archivos fuera de may_touch",
140
+ "no tocar archivos de forbidden",
141
+ "no aprobar tu propio trabajo",
142
+ "no declarar DONE sin handoff.md y evidence.md",
143
+ "no editar otros agentes' artifacts",
144
+ ],
145
+ onFinish: "idle-join",
146
+ escalateTo: input.escalateTo ?? "integrator",
147
+ };
148
+ }
149
+ /** Cómo suena un agente con un rol mal definido. */
150
+ function defaultFailureModes(role) {
151
+ return [
152
+ `Actuar sobre supuestos en vez de sobre lo que el briefing dice: el rol "${role}" tiene un alcance que no se negocia`,
153
+ "Reportar avance sin evidencia: la card vuelve al trabajo igual",
154
+ ];
155
+ }
156
+ function renderPrompt(input, displayName, capabilities, mission, failureModes) {
157
+ const rolePhrase = `un especialista en ${capabilities.join(", ") || input.role}`;
158
+ const missionPhrase = `que resuelve ${mission.toLowerCase()}.`;
159
+ return FACTORY_PROMPT_TEMPLATE.replaceAll("{{display_name}}", displayName)
160
+ .replaceAll("{{role_phrase}}", rolePhrase)
161
+ .replaceAll("{{mission_phrase}}", missionPhrase)
162
+ .replaceAll("{{personality}}", "Directo y sin rodeos. Preferís la solución más simple que cumple el requisito, y decís explícitamente cuando una regla no aplica.")
163
+ .replaceAll("{{memory}}", "Trackeás las decisiones ya tomadas en la corrida, los archivos que ya existen y las restricciones descubiertas, para no repetir trabajo ni contradecir lo anterior.")
164
+ .replaceAll("{{experience}}", `Trabajo de punta a punta en ${capabilities.join(", ") || input.role}: explorar, decidir, implementar y verificar, siempre dentro de un scope declarado.`)
165
+ .replaceAll("{{core_mission}}", [
166
+ `### ${titleize(input.role)}`,
167
+ `- Ejecutá la card asignada con foco en: ${capabilities.join(", ") || "el objetivo de la card"}`,
168
+ "- Dejá el resultado en el formato que el briefing pide: handoff y evidencia",
169
+ "- Pedí ayuda en el bus en cuanto detectes que la tarea se sale de tu dominio",
170
+ ].join("\n"))
171
+ .replaceAll("{{critical_rules}}", BASE_RULES.map((r, i) => `${i + 1}. ${r}`).join("\n"))
172
+ .replaceAll("{{technical_deliverables}}", [
173
+ "### Handoff",
174
+ "- Qué se hizo, en concreto y con paths de archivo",
175
+ "- Qué decisiones se tomaron y por qué",
176
+ "- Qué quedó afuera y qué necesita el siguiente",
177
+ "",
178
+ "### Evidencia",
179
+ "- La salida real de los comandos ejecutados, con su exit code",
180
+ "- Qué quedó sin verificar y por qué",
181
+ ].join("\n"))
182
+ .replaceAll("{{step_1}}", "Leé el briefing completo. Identificá lo que no sabés y pedilo por el bus antes de tocar nada.")
183
+ .replaceAll("{{step_2}}", "Decidí el enfoque más simple que cumple los criterios de aceptación. Anotá la decisión en el handoff.")
184
+ .replaceAll("{{step_3}}", "Implementá dentro del territorio declarado. Si el scope no alcanza para la solución, pedí ampliación — no te la-expiendas.")
185
+ .replaceAll("{{step_4}}", "Correr los comandos, pegar la salida real, escribir el handoff y entregar la card.")
186
+ .replaceAll("{{communication_style}}", [
187
+ '- Arrancás por lo concreto: qué vas a hacer, en qué archivos, y con qué criterio.',
188
+ "- Cuando algo no cierra, decís exactamente qué falta y a quién le corresponde, sin rodeos.",
189
+ "- No decís «está listo» sin el comando que lo demuestra.",
190
+ ].join("\n"))
191
+ .replaceAll("{{learning}}", [
192
+ `- Los patrones de ${capabilities.slice(0, 2).join(" y ") || input.role} que se repiten en este repo`,
193
+ "- Las trampas del codebase que ya te comieron una vez",
194
+ "- Las decisiones que funcionararon y las que no, para no repetir el experimento",
195
+ ].join("\n"))
196
+ .replaceAll("{{success_metrics}}", [
197
+ `- Los criterios de aceptación de la card se cumplen y están demostrados con evidencia`,
198
+ `- El control de calidad de la card pasa en verde`,
199
+ "- Nadie tiene que volver a preguntar lo que dejaste escrito en el handoff",
200
+ "- No tocaste nada fuera de tu scope",
201
+ ].join("\n"))
202
+ .replaceAll("{{advanced_capabilities}}", [
203
+ "### Deep Work",
204
+ `- Aplicar ${capabilities.join(", ") || "el dominio del rol"} más allá del caso obvio: detectar el problema de raíz en vez de parchear el síntoma`,
205
+ "",
206
+ "### Failure Modes",
207
+ ...failureModes.map((f) => `- ${f}`),
208
+ ].join("\n"))
209
+ .replaceAll("{{objective}}", input.objective
210
+ ? `**Objetivo de la corrida:** ${input.objective}\n\n**Misión de tu card:** ${mission}\n`
211
+ : `**Misión de tu card:** ${mission}\n`);
212
+ }
213
+ /** "frontend-developer" → "Frontend Developer". */
214
+ export function titleize(slug) {
215
+ return slug
216
+ .split(/[^a-zA-Z0-9]+/)
217
+ .filter(Boolean)
218
+ .map((w) => w[0].toUpperCase() + w.slice(1).toLowerCase())
219
+ .join(" ");
220
+ }
221
+ export class CandidateRegistry {
222
+ candidates = new Map();
223
+ record(role, at) {
224
+ const existing = this.candidates.get(role);
225
+ if (existing) {
226
+ existing.uses += 1;
227
+ existing.lastUsed = at;
228
+ }
229
+ else {
230
+ this.candidates.set(role, { role, uses: 1, lastUsed: at });
231
+ }
232
+ }
233
+ /** Roles que se usaron lo suficiente para promoverlos. */
234
+ promotable(threshold = 3) {
235
+ return [...this.candidates.values()]
236
+ .filter((c) => c.uses >= threshold)
237
+ .sort((a, b) => b.uses - a.uses);
238
+ }
239
+ all() {
240
+ return [...this.candidates.values()].sort((a, b) => b.uses - a.uses);
241
+ }
242
+ }
243
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/core/factory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * IO atómico.
3
+ *
4
+ * El bus es append-only y varios agentes leen y escriben a la vez. Un rename
5
+ * POSIX/Windows sobre un archivo temporal es atómico: un lector ve el archivo
6
+ * viejo completo o el nuevo completo, nunca un JSON partido. Ese detalle es la
7
+ * diferencia entre "el bus anda" y "el bus anda y de vez en cuando traga un
8
+ * error de parse que nadie entiende".
9
+ */
10
+ /** Escribe un archivo de forma atómica: tmp + rename. */
11
+ export declare function writeAtomic(filePath: string, contents: string): Promise<void>;
12
+ /** Escribe JSON de forma atómica, con newline final. */
13
+ export declare function writeJsonAtomic(filePath: string, value: unknown): Promise<void>;
14
+ /**
15
+ * Lee JSON. Devuelve `undefined` si el archivo no existe o está corrupto.
16
+ *
17
+ * Un archivo corrupto no debe tumbar la corrida: se loguea y se sigue con lo
18
+ * que hubiera. Perder un artefacto es malo; perder la oficina entera es peor.
19
+ */
20
+ export declare function readJson<T>(filePath: string): Promise<T | undefined>;
21
+ /** Lee texto. Devuelve `undefined` si no existe. */
22
+ export declare function readText(filePath: string): Promise<string | undefined>;
23
+ /** Existe sin lanzar. */
24
+ export declare function exists(filePath: string): boolean;
25
+ /** Crea un directorio recursivamente (idempotente). */
26
+ export declare function ensureDir(dirPath: string): Promise<void>;
27
+ /** Lista archivos de un directorio. Devuelve `[]` si no existe. */
28
+ export declare function listFiles(dirPath: string): Promise<string[]>;
29
+ /** Lista subdirectorios de un directorio. Devuelve `[]` si no existe. */
30
+ export declare function listDirs(dirPath: string): Promise<string[]>;
31
+ /** Elimina un archivo si existe. */
32
+ export declare function removeIfExists(filePath: string): Promise<void>;
33
+ /** Id corto y único, con prefijo. */
34
+ export declare function shortId(prefix: string): string;
35
+ /** Hash estable de un string, para claves de idempotencia. */
36
+ export declare function stableHash(input: string): string;
37
+ /** Timestamp ISO. Inyectable para tests. */
38
+ export declare function nowIso(clock?: () => number): string;
39
+ //# sourceMappingURL=fsx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fsx.d.ts","sourceRoot":"","sources":["../../src/core/fsx.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,yDAAyD;AACzD,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUnF;AAED,wDAAwD;AACxD,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAErF;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAe1E;AAED,oDAAoD;AACpD,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAO5E;AAED,yBAAyB;AACzB,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,uDAAuD;AACvD,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9D;AAED,mEAAmE;AACnE,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAOlE;AAED,yEAAyE;AACzE,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAQjE;AAED,oCAAoC;AACpC,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpE;AAED,qCAAqC;AACrC,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,4CAA4C;AAC5C,wBAAgB,MAAM,CAAC,KAAK,GAAE,MAAM,MAAiB,GAAG,MAAM,CAE7D"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * IO atómico.
3
+ *
4
+ * El bus es append-only y varios agentes leen y escriben a la vez. Un rename
5
+ * POSIX/Windows sobre un archivo temporal es atómico: un lector ve el archivo
6
+ * viejo completo o el nuevo completo, nunca un JSON partido. Ese detalle es la
7
+ * diferencia entre "el bus anda" y "el bus anda y de vez en cuando traga un
8
+ * error de parse que nadie entiende".
9
+ */
10
+ import { createHash, randomBytes } from "node:crypto";
11
+ import { existsSync } from "node:fs";
12
+ import fs from "node:fs/promises";
13
+ import path from "node:path";
14
+ /** Escribe un archivo de forma atómica: tmp + rename. */
15
+ export async function writeAtomic(filePath, contents) {
16
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
17
+ const tmp = `${filePath}.${randomBytes(6).toString("hex")}.tmp`;
18
+ try {
19
+ await fs.writeFile(tmp, contents, "utf8");
20
+ await fs.rename(tmp, filePath);
21
+ }
22
+ catch (err) {
23
+ await fs.rm(tmp, { force: true }).catch(() => { });
24
+ throw err;
25
+ }
26
+ }
27
+ /** Escribe JSON de forma atómica, con newline final. */
28
+ export async function writeJsonAtomic(filePath, value) {
29
+ await writeAtomic(filePath, `${JSON.stringify(value, null, 2)}\n`);
30
+ }
31
+ /**
32
+ * Lee JSON. Devuelve `undefined` si el archivo no existe o está corrupto.
33
+ *
34
+ * Un archivo corrupto no debe tumbar la corrida: se loguea y se sigue con lo
35
+ * que hubiera. Perder un artefacto es malo; perder la oficina entera es peor.
36
+ */
37
+ export async function readJson(filePath) {
38
+ try {
39
+ const raw = await fs.readFile(filePath, "utf8");
40
+ return JSON.parse(raw);
41
+ }
42
+ catch (err) {
43
+ const code = err.code;
44
+ if (code === "ENOENT")
45
+ return undefined;
46
+ if (err instanceof SyntaxError) {
47
+ // Archivo corrupto o escritura a medio hacer. Se aparta y se sigue.
48
+ const quarantine = `${filePath}.corrupt-${Date.now()}`;
49
+ await fs.rename(filePath, quarantine).catch(() => { });
50
+ return undefined;
51
+ }
52
+ throw err;
53
+ }
54
+ }
55
+ /** Lee texto. Devuelve `undefined` si no existe. */
56
+ export async function readText(filePath) {
57
+ try {
58
+ return await fs.readFile(filePath, "utf8");
59
+ }
60
+ catch (err) {
61
+ if (err.code === "ENOENT")
62
+ return undefined;
63
+ throw err;
64
+ }
65
+ }
66
+ /** Existe sin lanzar. */
67
+ export function exists(filePath) {
68
+ return existsSync(filePath);
69
+ }
70
+ /** Crea un directorio recursivamente (idempotente). */
71
+ export async function ensureDir(dirPath) {
72
+ await fs.mkdir(dirPath, { recursive: true });
73
+ }
74
+ /** Lista archivos de un directorio. Devuelve `[]` si no existe. */
75
+ export async function listFiles(dirPath) {
76
+ try {
77
+ return await fs.readdir(dirPath);
78
+ }
79
+ catch (err) {
80
+ if (err.code === "ENOENT")
81
+ return [];
82
+ throw err;
83
+ }
84
+ }
85
+ /** Lista subdirectorios de un directorio. Devuelve `[]` si no existe. */
86
+ export async function listDirs(dirPath) {
87
+ try {
88
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
89
+ return entries.filter((e) => e.isDirectory()).map((e) => e.name);
90
+ }
91
+ catch (err) {
92
+ if (err.code === "ENOENT")
93
+ return [];
94
+ throw err;
95
+ }
96
+ }
97
+ /** Elimina un archivo si existe. */
98
+ export async function removeIfExists(filePath) {
99
+ await fs.rm(filePath, { force: true, recursive: true });
100
+ }
101
+ /** Id corto y único, con prefijo. */
102
+ export function shortId(prefix) {
103
+ return `${prefix}-${randomBytes(4).toString("hex")}`;
104
+ }
105
+ /** Hash estable de un string, para claves de idempotencia. */
106
+ export function stableHash(input) {
107
+ return createHash("sha256").update(input).digest("hex").slice(0, 16);
108
+ }
109
+ /** Timestamp ISO. Inyectable para tests. */
110
+ export function nowIso(clock = Date.now) {
111
+ return new Date(clock()).toISOString();
112
+ }
113
+ //# sourceMappingURL=fsx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fsx.js","sourceRoot":"","sources":["../../src/core/fsx.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Gates: verificación ejecutable, no opinada.
3
+ *
4
+ * Un gate que dice "debería compilar" no es un gate. Acá se corren comandos
5
+ * de verdad, se captura la salida real y se decide por exit code. La salida
6
+ * se pega en el artefacto para que un humano pueda auditarla.
7
+ *
8
+ * Las 6 fases vienen de la skill `verification-loop`:
9
+ * build → typecheck → lint → test → security grep → diff review.
10
+ *
11
+ * Reglas de honestidad (no negociables):
12
+ * - Nunca PASS en una fase que no se corrió.
13
+ * - Nunca output inventado.
14
+ * - N/A siempre con motivo explícito.
15
+ * - Una fase aplicable en FAIL = gate FAIL. No se promedia.
16
+ */
17
+ import type { GatePhase, GatePhaseResult, GateResult } from "./types.js";
18
+ /** Configuración de un gate. */
19
+ export interface Tooling {
20
+ packageManager: "npm" | "pnpm" | "yarn" | "bun" | null;
21
+ hasBuild: boolean;
22
+ hasTypecheck: boolean;
23
+ hasLint: boolean;
24
+ hasTest: boolean;
25
+ isPython: boolean;
26
+ isGo: boolean;
27
+ isRust: boolean;
28
+ hasGit: boolean;
29
+ /** Descripción de qué se detect��, para el informe. */
30
+ detected: string[];
31
+ }
32
+ export interface CommandRunner {
33
+ (command: string, args: string[], cwd: string): Promise<{
34
+ code: number;
35
+ stdout: string;
36
+ stderr: string;
37
+ }>;
38
+ }
39
+ /** Runner real por defecto. */
40
+ export declare const defaultRunner: CommandRunner;
41
+ /** Detecta el tooling del proyecto leyendo sus manifiestos. */
42
+ export declare function detectTooling(projectRoot: string): Promise<Tooling>;
43
+ /** Ejecuta una fase y clasifica el resultado. */
44
+ export declare function runPhase(phase: GatePhase, command: string, args: string[], cwd: string, runner?: CommandRunner, timeoutNote?: string): Promise<GatePhaseResult>;
45
+ /** Ejecuta las 6 fases técnicas. */
46
+ export declare function runTechnicalGates(projectRoot: string, tooling: Tooling, runner?: CommandRunner, scope?: string[]): Promise<GatePhaseResult[]>;
47
+ /**
48
+ * Patrones de detección de secretos.
49
+ *
50
+ * Se aplican EN CÓDIGO, no shelling out a `grep`.
51
+ *
52
+ * Razón: `grep` no existe en Windows (viene con Git Bash, no con el sistema),
53
+ * y un gate de seguridad que depende de una tool opcional del SO es un gate
54
+ * que falla en Windows por razones equivocadas. Además, escanear en código
55
+ * permite manejar rutas con espacios, filtrar binarios y controlar el ruido.
56
+ */
57
+ export declare const SECRET_PATTERNS: {
58
+ label: string;
59
+ pattern: RegExp;
60
+ }[];
61
+ export interface SecretHit {
62
+ file: string;
63
+ line: number;
64
+ label: string;
65
+ match: string;
66
+ /** El valor, redactado. Los secretos no se imprimen completos. */
67
+ redacted: string;
68
+ }
69
+ /** Redacta un valor: solo se ven los primeros y últimos 4 caracteres. */
70
+ export declare function redact(value: string): string;
71
+ /**
72
+ * Escanea un directorio en busca de secretos.
73
+ *
74
+ * Devuelve los hits con el valor redactado. El valor crudo no sale de acá:
75
+ * un log de gate que imprime la credencial completa la acaba de filtrar.
76
+ */
77
+ export declare function scanForSecrets(root: string, scope: string[]): Promise<SecretHit[]>;
78
+ /**
79
+ * Corre el gate de seguridad.
80
+ *
81
+ * Distinto del gate técnico: audita trust boundaries y secretos. Un FAIL acá
82
+ * bloquea la card aunque el técnico esté verde.
83
+ */
84
+ export declare function runSecurityGate(projectRoot: string, scope: string[], _runner?: CommandRunner): Promise<GatePhaseResult[]>;
85
+ /** Consolida los resultados en un veredicto. */
86
+ export declare function consolidate(cardId: string, technical: GatePhaseResult[], security: GatePhaseResult[]): GateResult;
87
+ /**
88
+ * ¿La fase de tests corrió y pasó con al menos un test?
89
+ *
90
+ * Un gate que pasa con cero tests es un gate verde vacío. Los runners
91
+ * imprimen el conteo en formatos distintos ("# tests 5", "5 passed",
92
+ * "Tests: 5"), así que se buscan ambos órdenes.
93
+ */
94
+ export declare function testsActuallyRan(technical: GatePhaseResult[]): boolean;
95
+ /** Renderiza el gate como markdown para el artefacto. */
96
+ export declare function renderGate(result: GateResult): string;
97
+ //# sourceMappingURL=gates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../../src/core/gates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAqB,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAG3F,gCAAgC;AAChC,MAAM,WAAW,OAAO;IACtB,cAAc,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,IAAI,CAAA;IACtD,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,OAAO,CAAA;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;IACf,uDAAuD;IACvD,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC1G;AAED,+BAA+B;AAC/B,eAAO,MAAM,aAAa,EAAE,aAexB,CAAA;AAEJ,+DAA+D;AAC/D,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA8DzE;AAgCD,iDAAiD;AACjD,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,aAA6B,EACrC,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,eAAe,CAAC,CAe1B;AAOD,oCAAoC;AACpC,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,OAAO,EAChB,MAAM,GAAE,aAA6B,EACrC,KAAK,GAAE,MAAM,EAAO,GACnB,OAAO,CAAC,eAAe,EAAE,CAAC,CA+E5B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAa/D,CAAA;AAeD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,yEAAyE;AACzE,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG5C;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAqCxF;AAmBD;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,GAAE,aAA6B,GACrC,OAAO,CAAC,eAAe,EAAE,CAAC,CAqC5B;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,UAAU,CAqBjH;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CActE;AAED,yDAAyD;AACzD,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA2CrD"}