oficina-opencode 3.0.5 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +240 -208
- package/commands/oficina.md +7 -6
- package/dashboard/.dom-check.html +1257 -0
- package/dashboard/README-DASHBOARD.md +64 -0
- package/dashboard/assets/factory.css +1543 -0
- package/dashboard/assets/tokens.css +208 -0
- package/dashboard/build-kanban-data.mjs +279 -0
- package/dashboard/dashboard.css +753 -0
- package/dashboard/dashboard.html +121 -0
- package/dashboard/dashboard.js +610 -0
- package/dashboard/data/snapshot.json +883 -0
- package/dashboard/debate.html +134 -0
- package/dashboard/factory/build-snapshot.mjs +89 -0
- package/dashboard/factory/factory-app.js +1185 -0
- package/dashboard/factory/factory-core.js +541 -0
- package/dashboard/factory/snapshot.js +850 -0
- package/dashboard/factory.html +350 -0
- package/dashboard/kanban-data.json +671 -0
- package/dashboard/kanban-source.js +643 -0
- package/dashboard/kanban.check.mjs +454 -0
- package/dashboard/kanban.html +1257 -0
- package/dashboard/leadership.html +1008 -0
- package/dashboard/lib/debate-app.js +1149 -0
- package/dashboard/lib/debate-core.js +698 -0
- package/dashboard/lib/debate-data.js +163 -0
- package/dashboard/lib/debate-demo.js +110 -0
- package/dashboard/lib/debate.css +1155 -0
- package/dashboard/lib/leadership-model.js +946 -0
- package/dashboard/probe.mjs +35 -0
- package/dashboard/scripts/serve.mjs +122 -0
- package/dashboard/scripts/snapshot-data.mjs +93 -0
- package/dashboard/scripts/snapshot.mjs +28 -0
- package/dashboard/server.mjs +242 -0
- package/dashboard/shot.mjs +54 -0
- package/dashboard/shots/desktop-gates.png +0 -0
- package/dashboard/shots/desktop-light.png +0 -0
- package/dashboard/shots/desktop-real.png +0 -0
- package/dashboard/shots/mobile.png +0 -0
- package/dashboard/test/factory-core.test.mjs +244 -0
- package/dashboard/tests/debate-core.test.mjs +336 -0
- package/dashboard/tests/leadership-model.test.mjs +404 -0
- package/dist/cli.js +148 -26
- package/dist/cli.js.map +1 -1
- package/dist/core/bus.js +3 -3
- package/dist/core/bus.js.map +1 -1
- package/dist/core/catalog.d.ts +9 -1
- package/dist/core/catalog.d.ts.map +1 -1
- package/dist/core/catalog.js +77 -2
- package/dist/core/catalog.js.map +1 -1
- package/dist/core/dashboard.d.ts +33 -0
- package/dist/core/dashboard.d.ts.map +1 -0
- package/dist/core/dashboard.js +115 -0
- package/dist/core/dashboard.js.map +1 -0
- package/dist/core/dispatch.d.ts +1 -1
- package/dist/core/dispatch.d.ts.map +1 -1
- package/dist/core/dispatch.js +84 -12
- package/dist/core/dispatch.js.map +1 -1
- package/dist/core/docsync.d.ts +0 -9
- package/dist/core/docsync.d.ts.map +1 -1
- package/dist/core/docsync.js +12 -15
- package/dist/core/docsync.js.map +1 -1
- package/dist/core/environment.d.ts +28 -0
- package/dist/core/environment.d.ts.map +1 -0
- package/dist/core/environment.js +80 -0
- package/dist/core/environment.js.map +1 -0
- package/dist/core/factory.d.ts +16 -0
- package/dist/core/factory.d.ts.map +1 -1
- package/dist/core/factory.js +143 -0
- package/dist/core/factory.js.map +1 -1
- package/dist/core/fsx.d.ts +20 -2
- package/dist/core/fsx.d.ts.map +1 -1
- package/dist/core/fsx.js +10 -6
- package/dist/core/fsx.js.map +1 -1
- package/dist/core/gates.d.ts +23 -1
- package/dist/core/gates.d.ts.map +1 -1
- package/dist/core/gates.js +83 -8
- package/dist/core/gates.js.map +1 -1
- package/dist/core/leases.d.ts.map +1 -1
- package/dist/core/leases.js +4 -1
- package/dist/core/leases.js.map +1 -1
- package/dist/core/mesa.d.ts +1 -6
- package/dist/core/mesa.d.ts.map +1 -1
- package/dist/core/mesa.js +1 -6
- package/dist/core/mesa.js.map +1 -1
- package/dist/core/office.d.ts +3 -29
- package/dist/core/office.d.ts.map +1 -1
- package/dist/core/office.js +77 -90
- package/dist/core/office.js.map +1 -1
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +6 -1
- package/dist/core/paths.js.map +1 -1
- package/dist/core/retry.d.ts +2 -8
- package/dist/core/retry.d.ts.map +1 -1
- package/dist/core/retry.js +3 -34
- package/dist/core/retry.js.map +1 -1
- package/dist/core/roster.js +3 -3
- package/dist/core/roster.js.map +1 -1
- package/dist/core/sandbox.d.ts +38 -1
- package/dist/core/sandbox.d.ts.map +1 -1
- package/dist/core/sandbox.js +119 -15
- package/dist/core/sandbox.js.map +1 -1
- package/dist/core/state.d.ts +2 -2
- package/dist/core/state.d.ts.map +1 -1
- package/dist/core/state.js +5 -33
- package/dist/core/state.js.map +1 -1
- package/dist/core/stores.d.ts +3 -13
- package/dist/core/stores.d.ts.map +1 -1
- package/dist/core/stores.js +8 -32
- package/dist/core/stores.js.map +1 -1
- package/dist/core/systemPrompt.d.ts.map +1 -1
- package/dist/core/systemPrompt.js +4 -1
- package/dist/core/systemPrompt.js.map +1 -1
- package/dist/core/tripwire.d.ts +22 -8
- package/dist/core/tripwire.d.ts.map +1 -1
- package/dist/core/tripwire.js +71 -26
- package/dist/core/tripwire.js.map +1 -1
- package/dist/core/types.d.ts +6 -14
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +11 -3
- package/dist/core/types.js.map +1 -1
- package/dist/hooks/scopeGuard.d.ts +15 -1
- package/dist/hooks/scopeGuard.d.ts.map +1 -1
- package/dist/hooks/scopeGuard.js +88 -73
- package/dist/hooks/scopeGuard.js.map +1 -1
- package/dist/tools/index.d.ts +9 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +29 -81
- package/dist/tools/index.js.bak +972 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/v1.d.ts.map +1 -1
- package/dist/v1.js +30 -36
- package/dist/v1.js.map +1 -1
- package/dist/v2.d.ts +5 -0
- package/dist/v2.d.ts.map +1 -1
- package/dist/v2.js +79 -46
- package/dist/v2.js.bak +517 -0
- package/dist/v2.js.map +1 -1
- package/docs/GARANTIAS.md +2 -2
- package/docs/PRUEBA-E2E.md +4 -4
- package/docs/QUE-ES.md +4 -5
- package/docs/SEGURIDAD-REPO.md +83 -0
- package/docs/assets/banner.svg +42 -0
- package/docs/catalog-facts.json +3 -3
- package/docs/superpowers/specs/2026-10-29-factory-skill-creator-and-remove-budget.md +182 -0
- package/package.json +14 -6
package/README.md
CHANGED
|
@@ -1,44 +1,82 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<img src="docs/assets/banner.svg" width="1000" alt="AI-OFFICE — una oficina de agentes para OpenCode donde el trabajo no se detiene cuando el modelo dice «terminé»." />
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<br>
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
<a href="https://www.npmjs.com/package/oficina-opencode"><img src="https://img.shields.io/npm/v/oficina-opencode?style=for-the-badge&labelColor=0d1117&color=cb3837" alt="npm" /></a>
|
|
8
|
+
<a href="https://github.com/SOCRAMbt/AI-OFFICE/blob/main/LICENSE"><img src="https://img.shields.io/badge/licencia-MIT-2ea44f?style=for-the-badge&labelColor=0d1117" alt="licencia MIT" /></a>
|
|
9
|
+
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D22-339933?style=for-the-badge&labelColor=0d1117" alt="node >= 22" /></a>
|
|
10
|
+
<a href="https://github.com/SOCRAMbt/AI-OFFICE/tree/main/tests"><img src="https://img.shields.io/badge/tests-456%20passing-1f6feb?style=for-the-badge&labelColor=0d1117" alt="456 tests passing" /></a>
|
|
11
|
+
<a href="https://github.com/SOCRAMbt/AI-OFFICE/blob/main/tsconfig.json"><img src="https://img.shields.io/badge/typescript-strict-3178c6?style=for-the-badge&labelColor=0d1117" alt="TypeScript strict" /></a>
|
|
12
|
+
|
|
13
|
+
<br>
|
|
14
|
+
|
|
15
|
+
[](https://github.com/SOCRAMbt/AI-OFFICE/actions/workflows/ci.yml)
|
|
16
|
+
[](https://vitest.dev)
|
|
17
|
+
[](https://www.npmjs.com/package/oficina-opencode)
|
|
18
|
+
[](docs/SEGURIDAD-REPO.md)
|
|
19
|
+
[](SECURITY.md)
|
|
20
|
+
[](https://github.com/SOCRAMbt/AI-OFFICE/blob/main/docs/COMPATIBILITY.md)
|
|
13
21
|
|
|
14
22
|
**Una malla de coordinadores + peer mesh sobre un roster de roles.**
|
|
15
23
|
|
|
24
|
+
</div>
|
|
25
|
+
|
|
16
26
|
<!-- BEGIN GENERATED: facts -->
|
|
17
27
|
| | |
|
|
18
28
|
|---|---|
|
|
19
|
-
| **Paquete** | `oficina-opencode` v3.
|
|
20
|
-
| **Tools** |
|
|
29
|
+
| **Paquete** | `oficina-opencode` v3.1.1 |
|
|
30
|
+
| **Tools** | 15 |
|
|
21
31
|
| **Hooks** | 7 |
|
|
22
32
|
| **API de plugin** | `@opencode/plugin@2.1.2` |
|
|
23
|
-
| **Node** | >=
|
|
33
|
+
| **Node** | >=22 |
|
|
24
34
|
| **Catálogo** | 258 agentes resolubles en 18 divisiones |
|
|
25
35
|
| **Divisiones** | academic, design, engineering, finance, game-development, gis, healthcare, marketing, paid-media, product, project-management, research, sales, spatial-computing, specialized, strategy, support, testing |
|
|
26
|
-
|
|
27
|
-
| **Cobertura mínima** | 60% |
|
|
36
|
+
<!-- Catalog source: agency-agents @ 4e3ac3c -->
|
|
28
37
|
<!-- END GENERATED: facts -->
|
|
29
38
|
|
|
30
|
-
>
|
|
31
|
-
> **¿Preferís el porqué técnico?** → [`docs/ARCHITECTURE.md`](https://github.com/SOCRAMbt/AI-OFFICE/blob/main/docs/ARCHITECTURE.md)
|
|
39
|
+
<div align="center">
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
| Documentación |
|
|
42
|
+
|:---:|
|
|
43
|
+
| [⚡ Inicio rápido](#inicio-rapido) · [🧩 El problema](#el-problema) · [🏛️ Qué es](#que-es) · [🏗️ Arquitectura](#arquitectura) · [🧠 Matching de roles](#capa-0) |
|
|
44
|
+
| [⚙️ Dispatch](#el-equipo-se-arma) · [🔒 Scope](#el-scope-es-una-restriccion) · [🛡️ Resiliencia](#resiliencia) · [💰 Costo](#costo) · [📚 Briefing](#el-briefing) |
|
|
45
|
+
| [📮 Bus](#el-bus) · [🧷 Hooks](#los-7-hooks) · [🚦 Gates](#los-7-gates) · [⚖️ Invariantes](#invariantes-duros) · [🧰 Tools](#las-16-tools) · [🤖 Agentes](#los-7-agentes) |
|
|
46
|
+
| [📦 Instalación](#instalacion) · [🚀 Uso](#uso) · [🖥️ CLI](#cli-operacion) · [📁 Estructura](#estructura-de-la-corrida) · [🔐 Seguridad](#seguridad) · [🧪 Testing](#testing) · [📄 Licencia](#licencia) |
|
|
34
47
|
|
|
35
48
|
</div>
|
|
36
49
|
|
|
37
|
-
|
|
50
|
+
> **¿Preferís la versión en humano?** → [`docs/QUE-ES.md`](docs/QUE-ES.md) — qué es, qué hace y por qué, sin jerga.
|
|
51
|
+
> **¿Preferís el porqué técnico?** → [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)
|
|
52
|
+
> **¿Querés saber qué promete y qué no?** → [`docs/GARANTIAS.md`](docs/GARANTIAS.md) — nada de hinted marketing: garantías verificadas y límites escritos.
|
|
38
53
|
|
|
39
|
-
|
|
54
|
+
<a id="inicio-rapido"></a>
|
|
55
|
+
## ⚡ Inicio rápido
|
|
56
|
+
|
|
57
|
+
Tres comandos y la oficina está corriendo dentro de OpenCode:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# 1. Instalar el paquete y desplegar los assets:
|
|
61
|
+
npm install -g oficina-opencode
|
|
62
|
+
oficina install --target ~/.config/opencode
|
|
40
63
|
|
|
41
|
-
|
|
64
|
+
# 2. Habilitar la delegación de subagentes en ~/.config/opencode/opencode.json:
|
|
65
|
+
# { "experimental": { "subagent_depth": 3 } }
|
|
66
|
+
|
|
67
|
+
# 3. Abrir OpenCode en tu proyecto y arrancar la oficina:
|
|
68
|
+
# /oficina Agregar autenticación JWT con refresh rotation
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
La skill se carga, el plugin registra las tools y la corrida arranca sola:
|
|
72
|
+
el Comandante descompone el objetivo en cards, el dispatch crea el equipo de
|
|
73
|
+
especialistas y los arranca en paralelo. Y no se detienen cuando el modelo dice
|
|
74
|
+
«terminé»: se detienen cuando el estado dice que terminó.
|
|
75
|
+
|
|
76
|
+
<a id="el-problema"></a>
|
|
77
|
+
## 🧩 El problema
|
|
78
|
+
|
|
79
|
+
Trabajar con agentes llega con cinco fallas concretas. No son falta de inteligencia: son falta de **estructura**.
|
|
42
80
|
|
|
43
81
|
| Falla | Qué pasa en la práctica |
|
|
44
82
|
|---|---|
|
|
@@ -48,11 +86,12 @@ Working con agents tiene cinco fallas concretas. No son falta de inteligencia: s
|
|
|
48
86
|
| **El contexto se pierde** | Hay que repetir lo que ya se dijo, lo ya se decidió y lo ya se encontró. |
|
|
49
87
|
| **Los subagentes son islands** | No se piden ayuda, no se coordinan, no se benefician del trabajo del otro. |
|
|
50
88
|
|
|
51
|
-
Una skill de markdown no arregla ninguna de las cinco. Un sistema con reglas
|
|
89
|
+
Una skill de markdown no arregla ninguna de las cinco. Un sistema con reglas
|
|
90
|
+
escritas en código, sí: porque **no dependen de que el modelo tenga ganas de
|
|
91
|
+
seguirlas**.
|
|
52
92
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
## Qué es
|
|
93
|
+
<a id="que-es"></a>
|
|
94
|
+
## 🏛️ Qué es
|
|
56
95
|
|
|
57
96
|
**AI-OFFICE** es un plugin de OpenCode que convierte la orquestación en **código ejecutable**, no en instrucciones.
|
|
58
97
|
|
|
@@ -61,7 +100,7 @@ Skill → "Hacé lo que corresponda" → depende de que el modelo
|
|
|
61
100
|
Plugin → máquina de estados + hooks → no depende de la buena voluntad
|
|
62
101
|
```
|
|
63
102
|
|
|
64
|
-
|
|
103
|
+
Cinco piezas lo hacen posible:
|
|
65
104
|
|
|
66
105
|
**1. Un hook que no deja que la sesión muera.** Cuando la sesión queda `idle` y quedan cards sin terminar, el motor manda un prompt sintético y la corrida sigue. El modelo **no puede declarar que terminó**: el estado lo dice.
|
|
67
106
|
|
|
@@ -71,13 +110,10 @@ Cuatro piezas lo hacen posible:
|
|
|
71
110
|
|
|
72
111
|
**4. Invariantes que el código garantiza.** `gate_required_before_done` y `reviewer_neq_owner` no son recomendaciones: `assertInvariants` lanza y la transición no ocurre.
|
|
73
112
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
**5. El roster se arma según el objetivo.** Los roles salen del catálogo real de agency-agents (**306 agentes, 25 divisiones**), matcheados contra lo que la card pide. Y cada agente recibe un **briefing** de 10 secciones con lo que sabe, lo que no, y qué tiene que entregar.
|
|
77
|
-
|
|
78
|
-
---
|
|
113
|
+
**5. El roster se arma según el objetivo.** Los roles salen del catálogo real de agency-agents (**258 agentes, 18 divisiones**), matcheados contra lo que la card pide. Cada agente recibe un **briefing** de 10 secciones con lo que sabe, lo que no, y qué tiene que entregar.
|
|
79
114
|
|
|
80
|
-
|
|
115
|
+
<a id="arquitectura"></a>
|
|
116
|
+
## 🏗️ Arquitectura
|
|
81
117
|
|
|
82
118
|
Cuatro capas. De abajo hacia arriba.
|
|
83
119
|
|
|
@@ -109,11 +145,10 @@ Cuatro capas. De abajo hacia arriba.
|
|
|
109
145
|
└──────────────────────────────────────────────────────────────────────┘
|
|
110
146
|
```
|
|
111
147
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
## Capa 0 — De dónde sale la especialidad
|
|
148
|
+
<a id="capa-0"></a>
|
|
149
|
+
## 🧠 Capa 0 — De dónde sale la especialidad
|
|
115
150
|
|
|
116
|
-
El repo de agency-agents tiene **
|
|
151
|
+
El repo de agency-agents tiene **258 agentes en 18 divisiones**, y cada uno trae un briefing de 10 secciones. La especialidad real **no está en el `description`** del frontmatter: está en el cuerpo.
|
|
117
152
|
|
|
118
153
|
Un agente de statistics declara:
|
|
119
154
|
- `description`: *"Expert in quantitative research methodology..."*
|
|
@@ -160,7 +195,7 @@ Reproducible: `npx tsx scripts/demo-roles.ts`
|
|
|
160
195
|
Un matching textual puede elegir bien al rol y aun así no ser el mejor para la tarea. La pregunta no es *"¿funciona?"* sino **"¿vale la pena?"**. El benchmark compara tres estrategias sobre 21 tareas con resultados de referencia:
|
|
161
196
|
|
|
162
197
|
| Estrategia | hit@1 | hit@3 | MRR |
|
|
163
|
-
|
|
198
|
+
|---|:---:|:---:|:---:|
|
|
164
199
|
| **El matcher de la oficina** | **71%** | 86% | **0.778** |
|
|
165
200
|
| Keywords (los pesos de la v1) | 48% | 81% | 0.623 |
|
|
166
201
|
| Solo el nombre del rol | 52% | 76% | 0.639 |
|
|
@@ -231,9 +266,8 @@ Por eso la factory emite **exactamente la misma estructura**: Identity & Memory,
|
|
|
231
266
|
|
|
232
267
|
Y lo importante: el prompt fabricado **no es genérico**. Lleva las capabilities concretas, el scope, el objetivo de la corrida, los modos de fallo del rol y el contexto de la card.
|
|
233
268
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
## El equipo se arma
|
|
269
|
+
<a id="el-equipo-se-arma"></a>
|
|
270
|
+
## ⚙️ El equipo se arma
|
|
237
271
|
|
|
238
272
|
El flujo completo es: **doy un objetivo → el jefe lo divide → crea los subagentes → arrancan a trabajar juntos**.
|
|
239
273
|
|
|
@@ -257,9 +291,39 @@ El resultado:
|
|
|
257
291
|
|
|
258
292
|
Los **pares libres** son los complementos: están en la mesa, pueden recibir un pedido de ayuda, y pueden reclamar una card que quedó sin dueño.
|
|
259
293
|
|
|
260
|
-
|
|
294
|
+
De aquí la vida de un agente, y el ciclo completo de la corrida:
|
|
295
|
+
|
|
296
|
+
```mermaid
|
|
297
|
+
flowchart TD
|
|
298
|
+
OBJ["👤 Objetivo"] --> PLAN["📋 PLAN<br/>El Comandante descompone en cards"]
|
|
299
|
+
PLAN --> DEP{"Deps<br/>satisfechas?"}
|
|
300
|
+
DEP -->|sí| STANDUP["🗣️ STANDUP<br/>la card lista para trabajar"]
|
|
301
|
+
DEP -->|no| WAIT["⏸️ Espera / escalación"]
|
|
302
|
+
STANDUP --> WORK["🔧 TRABAJO<br/>owner + scope bloqueado"]
|
|
303
|
+
WORK --> ENT["📦 Entrega<br/>handoff.md + evidence.md"]
|
|
304
|
+
ENT --> REV["🔍 AUTO-REVIEW<br/>crítico ≠ owner"]
|
|
305
|
+
REV -->|rechaza| REWORK["♻️ REWORK"]
|
|
306
|
+
REWORK --> WORK
|
|
307
|
+
REV -->|aprueba| GATES["🚦 GATES<br/>7 fases · exit codes reales"]
|
|
308
|
+
GATES -->|FAIL| REWORK
|
|
309
|
+
GATES -->|PASS| DONE["✅ DONE<br/>evidencia vinculada requisito por requisito"]
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
```mermaid
|
|
313
|
+
flowchart LR
|
|
314
|
+
subgraph ciclo["Ciclo de un agente"]
|
|
315
|
+
DEPLOYED --> WORKING
|
|
316
|
+
WORKING -->|terminó| IDLE["IDLE_AVAILABLE"]
|
|
317
|
+
IDLE -->|recibe ayuda| WORKING
|
|
318
|
+
WORKING --> BLOCKED
|
|
319
|
+
BLOCKED --> IDLE
|
|
320
|
+
end
|
|
321
|
+
```
|
|
261
322
|
|
|
262
|
-
|
|
323
|
+
Cuando un agente termina, **ofrece ayuda** para lo que sigue. No queda esperando.
|
|
324
|
+
|
|
325
|
+
<a id="la-mesa"></a>
|
|
326
|
+
### 🪑 La mesa
|
|
263
327
|
|
|
264
328
|
Los subagentes son procesos aislados: no se ven, no saben quién más trabaja, no saben a quién preguntarle. La **mesa** es la vista compartida — vive en disco, así que todos la leen sin memoria compartida.
|
|
265
329
|
|
|
@@ -272,17 +336,7 @@ Los subagentes son procesos aislados: no se ven, no saben quién más trabaja, n
|
|
|
272
336
|
|
|
273
337
|
Y cuando la sesión queda `idle`, el hook de auto-continuación inyecta esa foto en el prompt del agente que arranca. Sin esto, el peer mesh es un bus al que nadie mira.
|
|
274
338
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
```
|
|
278
|
-
DEPLOYED → WORKING → (terminó) → IDLE_AVAILABLE → (ayuda) → WORKING
|
|
279
|
-
↓ ↑
|
|
280
|
-
BLOCKED ──→ IDLE_AVAILABLE ──────────────────┘
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
Cuando un agente termina, **ofrece ayuda** para lo que sigue. No queda esperando.
|
|
284
|
-
|
|
285
|
-
### Hablar por el bus
|
|
339
|
+
#### Hablar por el bus — el triage del receptor
|
|
286
340
|
|
|
287
341
|
El que recibe un pedido de ayuda **hace su propio triage** — no acepta por cortesía:
|
|
288
342
|
|
|
@@ -296,9 +350,8 @@ El que recibe un pedido de ayuda **hace su propio triage** — no acepta por cor
|
|
|
296
350
|
**Anti-deadlock**: máximo 2 saltos en una cadena de ayuda; después escala al Integrador.
|
|
297
351
|
**Anti-monotonía**: si el par A↔B ya se ayudaron 2 veces, el tercer pedido va a un tercero.
|
|
298
352
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
## El scope es una restricción, no una instrucción
|
|
353
|
+
<a id="el-scope-es-una-restriccion"></a>
|
|
354
|
+
## 🔒 El scope es una restricción, no una instrucción
|
|
302
355
|
|
|
303
356
|
La versión anterior del guard comparaba strings: `"...".match(/^src\//)`. Eso se eludía por tres vías, y las tres eran reales.
|
|
304
357
|
|
|
@@ -324,11 +377,10 @@ Además:
|
|
|
324
377
|
- **Los archivos sensibles** (`.env`, `.npmrc`, `.git/**`, claves privadas) nunca son escribibles, pase lo que pase el scope de la card.
|
|
325
378
|
- **El tripwire** fotografía el árbol antes de un comando y compara después: detecta lo que el guard no pudo ver.
|
|
326
379
|
|
|
327
|
-
> Lo que
|
|
380
|
+
> **Lo que no se promete** está en [`docs/GARANTIAS.md`](docs/GARANTIAS.md). Un shell con interpreter embebido puede escribir afuera; el tripwire lo detecta después, pero no lo revierte. Preferimos decirlo a vender un aislamiento que no existe.
|
|
328
381
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
## Una caída no destruye la corrida
|
|
382
|
+
<a id="resiliencia"></a>
|
|
383
|
+
## 🛡️ Una caída no destruye la corrida
|
|
332
384
|
|
|
333
385
|
La oficina escribe en disco, en varios archivos, sin transacción. Un proceso que muere en el momento equivocado deja el estado incoherente. `reconcile()` compara **estado vs artefactos vs filesystem**:
|
|
334
386
|
|
|
@@ -341,27 +393,26 @@ La oficina escribe en disco, en varios archivos, sin transacción. Un proceso qu
|
|
|
341
393
|
| Lease de una card terminada | Se libera. |
|
|
342
394
|
| Agente `working` sobre una card `done` | Se libera el agente. |
|
|
343
395
|
| Card bloqueada por dependencia irresoluble | Se reporta. |
|
|
396
|
+
| `state.json` corrupto | Se pone en cuarentena y se lanza `StateCorruptionError`. **No se crea una corrida vacía encima**: el operador recupera o pide explícitamente una nueva (`oficina init --force-new-run`). |
|
|
344
397
|
|
|
345
|
-
Lo que **no** hace: completar cards ni
|
|
398
|
+
Lo que **no** hace: completar cards, inventar evidencia ni auto-repararse pisando datos. Un sistema que se auto-repara inventando pruebas es peor que uno que dice *"esto está roto"*.
|
|
346
399
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
## El costo se controla, no solo la cantidad de agentes
|
|
400
|
+
<a id="costo"></a>
|
|
401
|
+
## 💰 El costo se controla, no solo la cantidad de agentes
|
|
350
402
|
|
|
351
403
|
Limitar el número de agentes **no** es controlar el costo: un agente que relee el mismo contexto veinte veces cuesta diez veces lo que uno que lo hace bien.
|
|
352
404
|
|
|
353
405
|
- El costo real viene del motor (`AssistantMessage.cost`), no se estima.
|
|
354
406
|
- Se contabiliza por **card**, por **agente** y por **fase** (implementación, review, reparación).
|
|
355
407
|
- Presupuestos por corrida, por card y por fase.
|
|
356
|
-
- Estimación previa a una corrida grande.
|
|
408
|
+
- Estimación previa a una corrida grande (`oficina_cost` en modo `estimate`).
|
|
357
409
|
- Detección de **trabajo redundante**: releer el mismo path, repetir el mismo comando.
|
|
358
410
|
- **Freno de emergencia**: `oficina_stop` detiene la corrida; el auto-continuación y el despacho se niegan mientras esté detenida.
|
|
359
411
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
## Capa 1 — El briefing: qué sabe cada agente antes de arrancar
|
|
412
|
+
<a id="el-briefing"></a>
|
|
413
|
+
## 📚 El briefing: qué sabe cada agente antes de arrancar
|
|
363
414
|
|
|
364
|
-
Un subagente arranca con el contexto vacío. Si el Commander le pasa un prompt
|
|
415
|
+
Un subagente arranca con el contexto vacío. Si el Commander le pasa un prompt suelto (*"implementá el login"*), el agente tiene que adivinar: qué sabe del proyecto, qué espera de él, qué puede tocar, a quién preguntarle si se traba, y qué tiene que entregar. Adivinar es la fuente de todo el trabajo que se repite y de los agentes que se salen del scope.
|
|
365
416
|
|
|
366
417
|
El briefing es el contrato de información. Tiene **orden fijo** y **mínimo verificable**.
|
|
367
418
|
|
|
@@ -370,7 +421,7 @@ El briefing es el contrato de información. Tiene **orden fijo** y **mínimo ver
|
|
|
370
421
|
La información llega de lo más estable a lo más cambiante. Un agente lee de arriba hacia abajo y siempre tiene lo que necesita para el paso siguiente.
|
|
371
422
|
|
|
372
423
|
| # | Sección | Qué le dice |
|
|
373
|
-
|
|
424
|
+
|:-:|---|---|
|
|
374
425
|
| 1 | **Quién sos** | Rol, especialidad de origen, de dónde viene tu briefing, tu vibe |
|
|
375
426
|
| 2 | **Tu misión** | La card exacta, los criterios de aceptación numerados, el control de calidad |
|
|
376
427
|
| 3 | **Lo que ya sabés** | Decisiones tomadas, restricciones descubiertas, piezas construidas, trampas |
|
|
@@ -405,9 +456,8 @@ El briefing se materializa en cuatro archivos en disco, porque un agente no "rec
|
|
|
405
456
|
|
|
406
457
|
La sección 3 se alimenta del **contexto acumulado** de la corrida (`.oficina/context.md`), que registra decisiones, restricciones, piezas construidas y trampas. Es lo que evita que un agente repita lo que ya se decidió — y lo que convierte al bus en algo más que un tablón de avisos.
|
|
407
458
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
## Capa 2 — El bus
|
|
459
|
+
<a id="el-bus"></a>
|
|
460
|
+
## 📮 El bus
|
|
411
461
|
|
|
412
462
|
Los subagentes de OpenCode son **procesos aislados sin memoria compartida**. No pueden hablarse de facto. La solución coherente es un bus append-only sobre disco.
|
|
413
463
|
|
|
@@ -443,20 +493,8 @@ Los subagentes de OpenCode son **procesos aislados sin memoria compartida**. No
|
|
|
443
493
|
| **Broadcast** | `to: ["*"]` al pool | El primero que acepta toma el lease |
|
|
444
494
|
| **Anti-deadlock** | `hops` máximo 2 | Una cadena de ayuda no se enquista |
|
|
445
495
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
No acepta por cortesía. Seis preguntas, en orden:
|
|
449
|
-
|
|
450
|
-
1. ¿Entiendo la tarea? → si no, `HELP_DECLINE` + explicar
|
|
451
|
-
2. ¿Está en mi scope? → si no, `HELP_DECLINE` + sugerir a quién
|
|
452
|
-
3. ¿Puedo hacerlo **ya** sin romper mi card? → si no, `HELP_DECLINE` + «cuando termine»
|
|
453
|
-
4. ¿Tengo el contexto? → si no, `HELP_QUESTION` por el bus
|
|
454
|
-
5. ¿Vale la pena? → si no, `HELP_DECLINE` + alternativa
|
|
455
|
-
6. ¿Tengo presupuesto? → si no, `HELP_DECLINE` + «sin presupuesto»
|
|
456
|
-
|
|
457
|
-
---
|
|
458
|
-
|
|
459
|
-
## Los 7 hooks
|
|
496
|
+
<a id="los-7-hooks"></a>
|
|
497
|
+
## 🧷 Los 7 hooks
|
|
460
498
|
|
|
461
499
|
Acá es donde el protocolo deja de ser una intención.
|
|
462
500
|
|
|
@@ -473,14 +511,13 @@ Acá es donde el protocolo deja de ser una intención.
|
|
|
473
511
|
|
|
474
512
|
El hook de auto-continuación tiene guardas duras: solo reanuda si queda trabajo real, tope de 25 auto-reanudaciones por sesión, cooldown de 1,5 s entre reanudaciones, y nunca reanuda una corrida `paused`, `blocked` o `delivered`.
|
|
475
513
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
## Los 7 gates
|
|
514
|
+
<a id="los-7-gates"></a>
|
|
515
|
+
## 🚦 Los 7 gates
|
|
479
516
|
|
|
480
517
|
Se ejecutan de verdad; el motor interpreta los exit codes.
|
|
481
518
|
|
|
482
519
|
| # | Fase | Node | Python | Go | Rust |
|
|
483
|
-
|
|
520
|
+
|:-:|---|---|---|---|---|
|
|
484
521
|
| 1 | Build | `npm run build` | `python -m build` | `go build ./...` | `cargo build` |
|
|
485
522
|
| 2 | Type check | `npm run typecheck` | `mypy` | `go vet ./...` | `cargo check` |
|
|
486
523
|
| 3 | Lint | `npm run lint` | `ruff` | `golangci-lint` | `cargo clippy` |
|
|
@@ -494,11 +531,11 @@ Se ejecutan de verdad; el motor interpreta los exit codes.
|
|
|
494
531
|
Los seis gates técnicos dicen que **el código está sano**. Dicen nada de si el **objetivo del usuario está cumplido**: un proyecto puede compilar, pasar todos sus tests y tener la autenticación mal porque ningún test contemplaba ese escenario.
|
|
495
532
|
|
|
496
533
|
| Nivel | Qué comprueba |
|
|
497
|
-
|
|
498
|
-
| 1
|
|
499
|
-
| 2
|
|
500
|
-
| 3
|
|
501
|
-
| 4
|
|
534
|
+
|:-:|---|
|
|
535
|
+
| 1 | **Estático** — tipos, lint, secretos, dependencias |
|
|
536
|
+
| 2 | **Comportamiento** — unitarias, integración, regresión, casos límite |
|
|
537
|
+
| 3 | **Requisitos** — cada criterio de aceptación enlazado a su evidencia |
|
|
538
|
+
| 4 | **Auditoría** — revisión independiente, riesgos, coherencia de la evidencia |
|
|
502
539
|
|
|
503
540
|
El gate 7 es el que cierra el círculo: **una card no se cierra si falta evidencia de un requisito obligatorio**, aunque los otros seis estén en verde.
|
|
504
541
|
|
|
@@ -523,9 +560,8 @@ Un artefacto llega a nivel 2; un test, a 2; un gate, a 1 (o 2 si es la fase `tes
|
|
|
523
560
|
- Una fase aplicable en `FAIL` = gate `FAIL`. No se promedia
|
|
524
561
|
- El escaneo de secretos corre **en TypeScript**, no shelling out a `grep` (que no existe en Windows), y **redacta** el valor: un log de gate que imprime la credencial completa la acaba de filtrar
|
|
525
562
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
## Invariantes duros
|
|
563
|
+
<a id="invariantes-duros"></a>
|
|
564
|
+
## ⚖️ Invariantes duros
|
|
529
565
|
|
|
530
566
|
Los implementa el código. Un prompt puede pedirle al modelo que sea cuidadoso; el motor no puede romperlos.
|
|
531
567
|
|
|
@@ -547,9 +583,8 @@ Los implementa el código. Un prompt puede pedirle al modelo que sea cuidadoso;
|
|
|
547
583
|
| `max_review_rejections` | 3 → escalación |
|
|
548
584
|
| `max_cards` · `max_agent_calls` | 20 · 40 por corrida |
|
|
549
585
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
## Los 3 coordinadores
|
|
586
|
+
<a id="los-3-coordinadores"></a>
|
|
587
|
+
## 🎙️ Los 3 coordinadores
|
|
553
588
|
|
|
554
589
|
Un solo coordinador es cuello de botella y punto único de falla.
|
|
555
590
|
|
|
@@ -564,9 +599,8 @@ Un solo coordinador es cuello de botella y punto único de falla.
|
|
|
564
599
|
|
|
565
600
|
Las preguntas de un especialista al coordinador **van por el bus**, no interrumpen al humano. Al usuario solo llega lo que ningún coordinador puede resolver.
|
|
566
601
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
## Los 16 tools
|
|
602
|
+
<a id="las-16-tools"></a>
|
|
603
|
+
## 🧰 Las 16 tools
|
|
570
604
|
|
|
571
605
|
Dieciséis, no treinta. Cada tool que se suma es ruido en el contexto de todos los agentes.
|
|
572
606
|
|
|
@@ -589,23 +623,21 @@ Dieciséis, no treinta. Cada tool que se suma es ruido en el contexto de todos l
|
|
|
589
623
|
| `oficina_cost` | Tokens y USD por card, agente y fase, con los presupuestos |
|
|
590
624
|
| `oficina_stop` | Freno de emergencia: detiene o reanuda la corrida |
|
|
591
625
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
## Los 7 agentes
|
|
626
|
+
<a id="los-7-agentes"></a>
|
|
627
|
+
## 🤖 Los 7 agentes
|
|
595
628
|
|
|
596
629
|
| Agente | Rol | Aprueba? |
|
|
597
|
-
|
|
630
|
+
|---|---|:---:|
|
|
598
631
|
| `oficina-commander` | Scope, objetivo, prioridades | No revisa técnico |
|
|
599
632
|
| `oficina-architect` | Decisiones técnicas cross-cutting | No revisa técnico |
|
|
600
633
|
| `oficina-integrator` | DAG, leases, gates, presupuesto | No revisa técnico |
|
|
601
|
-
| `oficina-critico` | Revisión con confianza calibrada (umbral 80) |
|
|
602
|
-
| `oficina-guardian` | Secretos, inyecciones, deps, auth |
|
|
603
|
-
| `oficina-verificador` | Ejecuta build/typecheck/lint/test |
|
|
634
|
+
| `oficina-critico` | Revisión con confianza calibrada (umbral 80) | **Sí** |
|
|
635
|
+
| `oficina-guardian` | Secretos, inyecciones, deps, auth | **Sí** |
|
|
636
|
+
| `oficina-verificador` | Ejecuta build/typecheck/lint/test | **Sí** |
|
|
604
637
|
| `oficina-director` | Dirección de la oficina v1 (fallback) | No |
|
|
605
638
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
## Instalación
|
|
639
|
+
<a id="instalacion"></a>
|
|
640
|
+
## 📦 Instalación
|
|
609
641
|
|
|
610
642
|
### Desde npm
|
|
611
643
|
|
|
@@ -614,15 +646,9 @@ npm install -g oficina-opencode
|
|
|
614
646
|
oficina install --target ~/.config/opencode
|
|
615
647
|
```
|
|
616
648
|
|
|
617
|
-
`oficina install` copia la skill, los 7 agentes, el comando `/oficina` y el
|
|
618
|
-
**entry point del plugin**.
|
|
649
|
+
`oficina install` copia la skill, los 7 agentes, el comando `/oficina` y el **entry point del plugin**.
|
|
619
650
|
|
|
620
|
-
> **El entry point no es un import pelado.** El loader de plugins de OpenCode
|
|
621
|
-
> v2 no resuelve bare specifiers desde `~/.config/opencode/plugins/`, así que
|
|
622
|
-
> un `export { default } from "oficina-opencode"` falla. El entry que instala
|
|
623
|
-
> el comando **busca el paquete en runtime** —en la config, en la cache de
|
|
624
|
-
> npm de OpenCode, o subiendo desde el propio archivo— y lo importa por ruta
|
|
625
|
-
> absoluta. Por eso reinstalar el paquete en otro lugar no rompe nada.
|
|
651
|
+
> **El entry point no es un import pelado.** El loader de plugins de OpenCode v2 no resuelve bare specifiers desde `~/.config/opencode/plugins/`, así que un `export { default } from "oficina-opencode"` falla. El entry que instala el comando **busca el paquete en runtime** —en la config, en la cache de npm de OpenCode, o subiendo desde el propio archivo— y lo importa por ruta absoluta. Por eso reinstalar el paquete en otro lugar no rompe nada.
|
|
626
652
|
|
|
627
653
|
### Local (desarrollo)
|
|
628
654
|
|
|
@@ -639,19 +665,16 @@ node /ruta/a/AI-OFFICE/dist/cli.js install --target ~/.config/opencode
|
|
|
639
665
|
|
|
640
666
|
### Compatibilidad con la API de plugins
|
|
641
667
|
|
|
642
|
-
**OpenCode v1 y v2 tienen APIs de plugins incompatibles.** No es que cambiara
|
|
643
|
-
una firma: cambió la forma (v1 exporta una función con hooks; v2 exige
|
|
644
|
-
`export default { id, setup(ctx) }`).
|
|
668
|
+
**OpenCode v1 y v2 tienen APIs de plugins incompatibles.** No es que cambiara una firma: cambió la forma (v1 exporta una función con hooks; v2 exige `export default { id, setup(ctx) }`).
|
|
645
669
|
|
|
646
|
-
El motor no depende de ninguna de las dos: define las tools en una forma
|
|
647
|
-
neutra y cada entry la traduce.
|
|
670
|
+
El motor no depende de ninguna de las dos: define las tools en una forma neutra y cada entry la traduce.
|
|
648
671
|
|
|
649
672
|
| Entry | Versión de OpenCode |
|
|
650
673
|
|---|---|
|
|
651
674
|
| `oficina-opencode` | **v2** — la principal |
|
|
652
675
|
| `oficina-opencode/v1` | v1 (legacy) |
|
|
653
676
|
|
|
654
|
-
Detalle completo en [`docs/COMPATIBILITY.md`](
|
|
677
|
+
Detalle completo en [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md).
|
|
655
678
|
|
|
656
679
|
### Configuración
|
|
657
680
|
|
|
@@ -675,9 +698,8 @@ oficina install --target ~/.config/opencode
|
|
|
675
698
|
|
|
676
699
|
Instala la skill, los 7 agentes, el comando y el entry point del plugin.
|
|
677
700
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
## Uso
|
|
701
|
+
<a id="uso"></a>
|
|
702
|
+
## 🚀 Uso
|
|
681
703
|
|
|
682
704
|
Desde la raíz del proyecto:
|
|
683
705
|
|
|
@@ -685,28 +707,10 @@ Desde la raíz del proyecto:
|
|
|
685
707
|
/oficina Agregar autenticación JWT con refresh rotation
|
|
686
708
|
```
|
|
687
709
|
|
|
688
|
-
El comando carga la skill `oficina`, el plugin registra las tools, y la corrida arranca sola.
|
|
689
|
-
|
|
690
|
-
El ciclo:
|
|
691
|
-
|
|
692
|
-
```
|
|
693
|
-
OBJETIVO → PLAN (Comandante)
|
|
694
|
-
↓
|
|
695
|
-
STANDUP — la card con deps satisfechas
|
|
696
|
-
↓
|
|
697
|
-
TRABAJO (owner) → handoff.md + evidence.md
|
|
698
|
-
↓
|
|
699
|
-
AUTO-REVIEW (oficina-critico, ≠ owner)
|
|
700
|
-
↓
|
|
701
|
-
GATES (oficina-verificador + oficina-guardian)
|
|
702
|
-
↓
|
|
703
|
-
┌────────┴────────┐
|
|
704
|
-
DONE REWORK → REPLAN → ESCALADA
|
|
705
|
-
```
|
|
706
|
-
|
|
707
|
-
---
|
|
710
|
+
El comando carga la skill `oficina`, el plugin registra las tools, y la corrida arranca sola. La oficina escribe todo en `.oficina/`: si cerrás OpenCode a mitad de camino, al volver, la corrida retoma donde quedó.
|
|
708
711
|
|
|
709
|
-
|
|
712
|
+
<a id="cli-operacion"></a>
|
|
713
|
+
## 🖥️ CLI — operación
|
|
710
714
|
|
|
711
715
|
```bash
|
|
712
716
|
oficina init [objetivo] # Crea .oficina/ en el proyecto
|
|
@@ -720,9 +724,12 @@ oficina catalog --agency-root <path> # Lista el catálogo de roles disponi
|
|
|
720
724
|
oficina reset --force # Abandona la corrida
|
|
721
725
|
```
|
|
722
726
|
|
|
723
|
-
|
|
727
|
+
Flags útiles: `--json` (salida máquina), `--directory <path>` (otro proyecto),
|
|
728
|
+
`--agency-root <path>` (catálogo alternativo), `--force-new-run`
|
|
729
|
+
(crear corrida nueva sobre un estado corrupto ya puesto en cuarentena).
|
|
724
730
|
|
|
725
|
-
|
|
731
|
+
<a id="estructura-de-la-corrida"></a>
|
|
732
|
+
## 📁 Estructura de la corrida
|
|
726
733
|
|
|
727
734
|
```
|
|
728
735
|
<proyecto>/.oficina/
|
|
@@ -749,9 +756,81 @@ oficina reset --force # Abandona la corrida
|
|
|
749
756
|
|
|
750
757
|
El formato de artefactos es compatible con OFICINA v1 (la skill). El plugin **migra el estado v1 automáticamente**: objetivo, cards y resultados se conservan.
|
|
751
758
|
|
|
759
|
+
Si `state.json` está corrupto, no se destruye: se **pone en cuarentena** y `loadState` lanza `StateCorruptionError` con la ruta exacta del archivo preservado. Recuperar es una decisión del operador, nunca un efecto colateral.
|
|
760
|
+
|
|
761
|
+
<a id="seguridad"></a>
|
|
762
|
+
## 🔐 Seguridad
|
|
763
|
+
|
|
764
|
+
La seguridad de la corrida y la seguridad del paquete son dos frentes distintos, y los dos están cubiertos:
|
|
765
|
+
|
|
766
|
+
| Frente | Mecanismo |
|
|
767
|
+
|---|---|
|
|
768
|
+
| **En la corrida** | Scope guard fail-closed (`realpath` + revalidación), archivos sensibles nunca escribibles, tripwire de detección post-comando, herencia de scope en subagentes, y gates con escaneo de secretos que redacta el valor en los logs |
|
|
769
|
+
| **En el estado** | Escrituras atómicas (`O_EXCL`, `.tmp`+`rename`), leases con TTL+heartbeat, locks por corrida contra doble-claim, y corrupción en cuarentena con `StateCorruptionError` — nunca una corrida vacía encima de datos recuperables |
|
|
770
|
+
| **En el repo** | `CODEOWNERS` (todo el árbol requiere review del owner), Dependabot semanal, branch protection documentada y estado `state.json` de soporte → [`docs/SEGURIDAD-REPO.md`](docs/SEGURIDAD-REPO.md) |
|
|
771
|
+
| **En npm** | Publicación por OIDC con **provenance SLSA** (nada de tokens de larga vida), environment `npm` protegido con aprobación manual, 2FA obligatoria — ver [`docs/SEGURIDAD-REPO.md`](docs/SEGURIDAD-REPO.md) |
|
|
772
|
+
|
|
773
|
+
**¿Encontraste una vulnerabilidad?** No abras un issue público. Seguí la
|
|
774
|
+
[política de seguridad](SECURITY.md): reporta por GitHub Security Advisories
|
|
775
|
+
pestaña *Security → Report a vulnerability*.
|
|
776
|
+
|
|
777
|
+
<a id="testing"></a>
|
|
778
|
+
## 🧪 Testing
|
|
779
|
+
|
|
780
|
+
```bash
|
|
781
|
+
npm test # 456 tests, 27 archivos
|
|
782
|
+
npm run coverage # cobertura por línea
|
|
783
|
+
npm run docs:check # la documentación coincide con el código
|
|
784
|
+
npm run bench:selection # el matcher le gana a las alternativas simples
|
|
785
|
+
npm run typecheck # tsc --noEmit, strict
|
|
786
|
+
npm run build # tsc → dist/
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
| Suite | Cubre |
|
|
790
|
+
|---|---|
|
|
791
|
+
| `bus.test.ts` | Append-only, ack, TTL, idempotencia, broadcast, prioridad, atomicidad |
|
|
792
|
+
| `state.test.ts` | Transiciones, invariantes duros, selección de card, ciclo de corrida |
|
|
793
|
+
| `gates.test.ts` | Detección de tooling, las 7 fases, N/A con motivo, consolidación, redacción |
|
|
794
|
+
| `router.test.ts` | Enrutado, rotación, reviewer ≠ owner, política de 3 golpes, presupuesto |
|
|
795
|
+
| `leases.test.ts` | Adquisición, heartbeat, expiración, double-claim, reasignación |
|
|
796
|
+
| `catalog.test.ts` | Frontmatter, secciones, extracción, matching ponderado, panel, factory |
|
|
797
|
+
| `catalogReal.test.ts` | El catálogo real de agency-agents: estructuras, matching, división |
|
|
798
|
+
| `briefing.test.ts` | Orden, mínimo, las 10 secciones, los 4 artefactos, INCOMPLETO |
|
|
799
|
+
| `office.test.ts` | Ciclo completo end-to-end, invariantes, artefactos en disco |
|
|
800
|
+
| `scopeGuard.test.ts` | Globs, extracción de path, enforcement de scope, fail-closed |
|
|
801
|
+
| `sandbox.test.ts` | **Adversarial**: symlinks, traversal, absolutos, sensibles, shell |
|
|
802
|
+
| `concurrency.test.ts` | Doble claim simultáneo, seq único, idempotencia atómica |
|
|
803
|
+
| `recovery.test.ts` | Entregas perdidas, invariantes vulnerados, huérfanos, reinicio, corrupción en cuarentena |
|
|
804
|
+
| `evidence.test.ts` | El grafo requisito → evidencia y los 4 niveles |
|
|
805
|
+
| `cost.test.ts` | Ledger, presupuestos por fila, trabajo redundante |
|
|
806
|
+
| `tripwire.test.ts` | Detección de escrituras coladas por shell, arm/check, `prune(maxAge)` real |
|
|
807
|
+
| `docsync.test.ts` | La documentación coincide con el código |
|
|
808
|
+
| `plugin.test.ts` | El plugin contra un host mockeado: tools, hooks, auto-resume |
|
|
809
|
+
| `migration.test.ts` | Migración v1 → v2 sin pérdida de datos |
|
|
810
|
+
| `cli.test.ts` | init, status, board, install, audit, reset, idempotencia, estado corrupto |
|
|
811
|
+
| `dispatch.test.ts` | IDs de agente únicos por card sin colisiones, reintentos idempotentes, slugs largos |
|
|
812
|
+
| `sandbox-83.test.ts` | Aserciones semánticas de canonicalización Windows 8.3 |
|
|
813
|
+
|
|
814
|
+
*(27 archivos en total — los suites críticos están listados arriba, los demás cubren paths, IDs, logging y parsing.)*
|
|
815
|
+
|
|
816
|
+
## 📊 Dependencias
|
|
817
|
+
|
|
818
|
+
**Dos, y ninguna es del host:**
|
|
819
|
+
|
|
820
|
+
| Paquete | Para qué |
|
|
821
|
+
|---|---|
|
|
822
|
+
| `@opencode/plugin` | Los tipos y el helper del API de plugins **v2**. Es la dependencia real. |
|
|
823
|
+
| `zod` | Los schemas de los argumentos de las tools. Rango semver `^4.6.7` (mínimo 4.6.7 por CVE). |
|
|
824
|
+
|
|
825
|
+
`@opencode-ai/plugin` (v1) es un **peer opcional**: solo lo necesita el entry `oficina-opencode/v1`, para los hosts que todavía corren la API vieja.
|
|
826
|
+
|
|
827
|
+
El motor (`core/`, `tools/`) no importa ninguno de los dos: define las tools en una forma neutra y cada entry las traduce. Por eso el mismo motor corre en v1 y en v2.
|
|
828
|
+
|
|
829
|
+
Vulnerabilidades y overrides reportados en el [informe de cierre](REMEDIATION_CLOSURE_REPORT.md): **0 en producción** (`npm audit --omit=dev`); las 2 residuales en el árbol dev-only de `@opencode-ai/plugin` quedan documentadas con su justificación técnica.
|
|
830
|
+
|
|
752
831
|
---
|
|
753
832
|
|
|
754
|
-
## Código
|
|
833
|
+
## 🗺️ Código
|
|
755
834
|
|
|
756
835
|
33 archivos TypeScript · 19 módulos en `core/` · 1 toolset · 7 hooks.
|
|
757
836
|
|
|
@@ -794,64 +873,17 @@ src/
|
|
|
794
873
|
└── compacting.ts
|
|
795
874
|
```
|
|
796
875
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
**Dos, y ninguna es del host:**
|
|
800
|
-
|
|
801
|
-
| Paquete | Para qué |
|
|
802
|
-
|---|---|
|
|
803
|
-
| `@opencode/plugin` | Los tipos y el helper del API de plugins **v2**. Es la dependencia real. |
|
|
804
|
-
| `zod` | Los schemas de los argumentos de las tools. Versión pineada para que los tipos no divergan. |
|
|
805
|
-
|
|
806
|
-
`@opencode-ai/plugin` (v1) es un **peer opcional**: solo lo necesita el entry
|
|
807
|
-
`oficina-opencode/v1`, para los hosts que todavía corren la API vieja.
|
|
808
|
-
|
|
809
|
-
El motor (`core/`, `tools/`) no importa ninguno de los dos: define las tools
|
|
810
|
-
en una forma neutra y cada entry las traduce. Por eso el mismo motor corre
|
|
811
|
-
en v1 y en v2.
|
|
812
|
-
|
|
813
|
-
---
|
|
814
|
-
|
|
815
|
-
## Testing
|
|
816
|
-
|
|
817
|
-
```bash
|
|
818
|
-
npm test # 385 tests, 21 archivos
|
|
819
|
-
npm run coverage # cobertura por línea
|
|
820
|
-
npm run docs:check # la documentación coincide con el código
|
|
821
|
-
npm run bench:selection # el matcher le gana a las alternativas simples
|
|
822
|
-
npm run typecheck # tsc --noEmit, strict
|
|
823
|
-
npm run build # tsc → dist/
|
|
824
|
-
```
|
|
876
|
+
<a id="licencia"></a>
|
|
877
|
+
## 📄 Licencia
|
|
825
878
|
|
|
826
|
-
|
|
827
|
-
|---|---|
|
|
828
|
-
| `bus.test.ts` | Append-only, ack, TTL, idempotencia, broadcast, prioridad, atomicidad |
|
|
829
|
-
| `state.test.ts` | Transiciones, invariantes duros, selección de card, ciclo de corrida |
|
|
830
|
-
| `gates.test.ts` | Detección de tooling, las 7 fases, N/A con motivo, consolidación, redacción |
|
|
831
|
-
| `router.test.ts` | Enrutado, rotación, reviewer ≠ owner, política de 3 golpes, presupuesto |
|
|
832
|
-
| `leases.test.ts` | Adquisición, heartbeat, expiración, double-claim, reasignación |
|
|
833
|
-
| `catalog.test.ts` | Frontmatter, secciones, extracción, matching ponderado, panel, factory |
|
|
834
|
-
| `catalogReal.test.ts` | El catálogo real de agency-agents: estructuras, matching, división |
|
|
835
|
-
| `briefing.test.ts` | Orden, mínimo, las 10 secciones, los 4 artefactos, INCOMPLETO |
|
|
836
|
-
| `office.test.ts` | Ciclo completo end-to-end, invariantes, artefactos en disco |
|
|
837
|
-
| `scopeGuard.test.ts` | Globs, extracción de path, enforcement de scope |
|
|
838
|
-
| `sandbox.test.ts` | **Adversarial**: symlinks, traversal, absolutos, sensibles, shell |
|
|
839
|
-
| `concurrency.test.ts` | Doble claim simultáneo, seq único, idempotencia atómica |
|
|
840
|
-
| `recovery.test.ts` | Entregas perdidas, invariantes vulnerados, huérfanos, reinicio |
|
|
841
|
-
| `evidence.test.ts` | El grafo requisito → evidencia y los 4 niveles |
|
|
842
|
-
| `cost.test.ts` | Ledger, presupuestos por fase, trabajo redundante |
|
|
843
|
-
| `tripwire.test.ts` | Detección de escrituras coladas por shell |
|
|
844
|
-
| `docsync.test.ts` | La documentación coincide con el código |
|
|
845
|
-
| `plugin.test.ts` | El plugin contra un host mockeado: tools, hooks, auto-resume |
|
|
846
|
-
| `migration.test.ts` | Migración v1 → v2 sin pérdida de datos |
|
|
847
|
-
| `cli.test.ts` | init, status, board, install, audit, reset, idempotencia |
|
|
879
|
+
MIT — ver [LICENSE](LICENSE).
|
|
848
880
|
|
|
849
881
|
---
|
|
850
882
|
|
|
851
|
-
|
|
883
|
+
<div align="center">
|
|
852
884
|
|
|
853
|
-
|
|
885
|
+
**El diseño se apoya en los patrones de `durable-execution` y `workflow-engine-design`: estado durable antes de los efectos, leases con TTL, transiciones nombradas explícitamente y at-least-once con reconciliación por idempotency key.**
|
|
854
886
|
|
|
855
|
-
|
|
887
|
+
Lo que **no** se promete está escrito en [`docs/GARANTIAS.md`](docs/GARANTIAS.md): un plugin de aplicación no es un sandbox, y un README que vende más de lo que el código hace es peor que uno modesto.
|
|
856
888
|
|
|
857
|
-
|
|
889
|
+
</div>
|