ostacky 0.8.1 → 0.8.3
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 +21 -23
- package/assets/agents/ostacky.md +18 -3
- package/assets/commands/install-stack.md +15 -115
- package/assets/docs/ostacky-reference.md +0 -2
- package/assets/mcp/ostacky-controller/controller-core.js +206 -0
- package/assets/mcp/ostacky-controller/index.js +166 -164
- package/assets/mcp/ostacky-controller/package.json +1 -1
- package/assets/plugins/controller-core.ts +206 -0
- package/assets/plugins/ostacky-plugin.ts +12 -124
- package/assets/skills/brainstorming/SKILL.md +6 -4
- package/assets/skills/graceful-degradation/SKILL.md +0 -9
- package/dist/cli.js +537 -720
- package/manifest.json +151 -151
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -110,15 +110,13 @@ Detecta automáticamente el directorio `.opencode/` del proyecto (o lo crea) y m
|
|
|
110
110
|
### Instalar todo
|
|
111
111
|
|
|
112
112
|
```bash
|
|
113
|
-
npx ostacky install # local
|
|
114
|
-
npx ostacky install --scope local # <proyecto>/.opencode
|
|
115
|
-
npx ostacky install --scope global # ~/.config/opencode (XDG/APPDATA en Windows)
|
|
116
|
-
npx ostacky install --scope auto # local si existe .opencode/.git, si no global
|
|
113
|
+
npx ostacky install # siempre local en <proyecto>/.opencode
|
|
114
|
+
npx ostacky install --scope local # <proyecto>/.opencode (único scope soportado)
|
|
117
115
|
```
|
|
118
116
|
|
|
119
|
-
Descarga todos los agentes y commands definidos en el manifest y los escribe en `.
|
|
117
|
+
Descarga todos los agentes y commands definidos en el manifest y los escribe en `<proyecto>/.opencode`. Además copia los plugins **Ostacky-owned** `ostacky-plugin.ts` + `engram.ts` en `.opencode/plugins/` (el legacy `ostacky-guard.ts` fue fusionado en `ostacky-plugin.ts` y ya no se instala; `ostacky-controller.ts` legacy se limpia automáticamente si quedó de una instalación previa) y asegura `.gitignore` con ` .opencode/tools/, .codegraph/, .opencode/cache/, ostacky-state.json*`.
|
|
120
118
|
|
|
121
|
-
> **
|
|
119
|
+
> **Instalación siempre local:** Ostacky vive por proyecto/worktree (CodeGraph index `.codegraph/` y `ostacky-state.json` aislados). Si ves `C:\Users\...\ .opencode\tools\codegraph` y esperabas `D:\mi-proyecto\.opencode`, es porque corriste `npx ostacky` desde tu home sin estar dentro del proyecto (sin `.git`). Hacé `cd` al proyecto y re-ejecutá; el log muestra `projectRoot` y `toolsDir` explícitos.
|
|
122
120
|
|
|
123
121
|
### Agregar agentes o commands individualmente
|
|
124
122
|
|
|
@@ -150,10 +148,8 @@ Solo descarga los items que cambiaron de versión.
|
|
|
150
148
|
### Desinstalar
|
|
151
149
|
|
|
152
150
|
```bash
|
|
153
|
-
npx ostacky uninstall #
|
|
151
|
+
npx ostacky uninstall # qué borrar en <proyecto>/.opencode
|
|
154
152
|
npx ostacky uninstall --scope local # fuerza scope local
|
|
155
|
-
npx ostacky uninstall --scope global # fuerza scope global
|
|
156
|
-
npx ostacky uninstall --scope auto # auto
|
|
157
153
|
```
|
|
158
154
|
|
|
159
155
|
**Safe-delete:** solo borra lo trackeado en `.opencode/ostacky-lock.json` (agentes, commands, skills, MCPs) — nunca toca componentes previos del usuario que no estén en el lockfile. Antes de borrar muestra preview con `Scope: <ruta>` + lista de paths y pide confirmación. Los plugins Ostacky-owned (`ostacky-plugin.ts`, `engram.ts` + legacy `ostacky-guard.ts`/`ostacky-controller.ts` si quedaron) se limpian automáticamente via allowlist, nunca se borran plugins custom.
|
|
@@ -163,7 +159,7 @@ npx ostacky uninstall --scope auto # auto
|
|
|
163
159
|
#### Desinstalar un agente puntual
|
|
164
160
|
|
|
165
161
|
```bash
|
|
166
|
-
npx ostacky uninstall agent <nombre> # también admite --scope local
|
|
162
|
+
npx ostacky uninstall agent <nombre> # también admite --scope local
|
|
167
163
|
npx ostacky uninstall agent # sin nombre → selector de instalados
|
|
168
164
|
```
|
|
169
165
|
|
|
@@ -176,7 +172,7 @@ npx ostacky uninstall agent ostacky
|
|
|
176
172
|
#### Desinstalar un command puntual
|
|
177
173
|
|
|
178
174
|
```bash
|
|
179
|
-
npx ostacky uninstall command <nombre> # también admite --scope
|
|
175
|
+
npx ostacky uninstall command <nombre> # también admite --scope local
|
|
180
176
|
npx ostacky uninstall command # sin nombre → selector
|
|
181
177
|
```
|
|
182
178
|
|
|
@@ -191,7 +187,7 @@ Si no especificás el nombre, el CLI te muestra un selector con los items instal
|
|
|
191
187
|
#### Desinstalar todo el stack (tools + config)
|
|
192
188
|
|
|
193
189
|
```bash
|
|
194
|
-
npx ostacky uninstall-stack #
|
|
190
|
+
npx ostacky uninstall-stack # limpia mcp.codegraph/engram de opencode.json + .codegraph/ + .opencode/tools/
|
|
195
191
|
npx ostacky uninstall-stack --scope local
|
|
196
192
|
```
|
|
197
193
|
|
|
@@ -250,37 +246,37 @@ Tras instalar (`--scope local`), el proyecto queda así:
|
|
|
250
246
|
|
|
251
247
|
```json
|
|
252
248
|
{
|
|
253
|
-
"version": "0.8.
|
|
249
|
+
"version": "0.8.3",
|
|
254
250
|
"lockedAt": "2025-01-01T00:00:00.000Z",
|
|
255
251
|
"repo": "JaimeHoracio/Ostacky",
|
|
256
|
-
"tag": "v0.8.
|
|
252
|
+
"tag": "v0.8.3",
|
|
257
253
|
"agents": {
|
|
258
254
|
"ostacky": {
|
|
259
|
-
"version": "0.8.
|
|
255
|
+
"version": "0.8.3",
|
|
260
256
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
261
257
|
"sha256": "abc123..."
|
|
262
258
|
}
|
|
263
259
|
},
|
|
264
260
|
"commands": {
|
|
265
261
|
"install-stack": {
|
|
266
|
-
"version": "0.8.
|
|
262
|
+
"version": "0.8.3",
|
|
267
263
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
268
264
|
"sha256": "def456..."
|
|
269
265
|
},
|
|
270
266
|
"opsx-sync": {
|
|
271
|
-
"version": "0.8.
|
|
267
|
+
"version": "0.8.3",
|
|
272
268
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
273
269
|
"sha256": "ghi789..."
|
|
274
270
|
}
|
|
275
271
|
},
|
|
276
272
|
"skills": {
|
|
277
|
-
"brainstorming": { "version": "0.8.
|
|
278
|
-
"execution-mode-evaluation": { "version": "0.8.
|
|
279
|
-
"openspec-propose": { "version": "0.8.
|
|
273
|
+
"brainstorming": { "version": "0.8.3", ... },
|
|
274
|
+
"execution-mode-evaluation": { "version": "0.8.3", ... },
|
|
275
|
+
"openspec-propose": { "version": "0.8.3", ... }
|
|
280
276
|
},
|
|
281
277
|
"mcpServers": {
|
|
282
|
-
"ostacky-controller": { "version": "0.8.
|
|
283
|
-
"openspec": { "version": "0.8.
|
|
278
|
+
"ostacky-controller": { "version": "0.8.3", ... },
|
|
279
|
+
"openspec": { "version": "0.8.3", ... }
|
|
284
280
|
}
|
|
285
281
|
}
|
|
286
282
|
```
|
|
@@ -312,7 +308,7 @@ Es opcional y solo necesario si algo falló durante la instalación o si querés
|
|
|
312
308
|
## Seguridad
|
|
313
309
|
|
|
314
310
|
- `opencode.jsonc` se versiona en el repo para compartir permisos y MCP de forma reproducible.
|
|
315
|
-
- Las URLs de descarga usan **tags de GitHub** (ej. `v0.8.
|
|
311
|
+
- Las URLs de descarga usan **tags de GitHub** (ej. `v0.8.3`), nunca `main` — instalaciones reproducibles
|
|
316
312
|
- Cada path de archivo descargado es validado para prevenir **path traversal**
|
|
317
313
|
- Los archivos incluyen **checksum SHA-256** opcional; si el manifest lo define, el contenido se verifica antes de escribir
|
|
318
314
|
- El cache local (`.opencode/cache/`) también valida integridad al servir archivos cacheados
|
|
@@ -369,6 +365,8 @@ CodeGraph está instalado en `.opencode/tools/codegraph/bin/codegraph` y se conf
|
|
|
369
365
|
| `.opencode/tools/codegraph/bin/codegraph status` | Muestra estado del index y archivos pendientes |
|
|
370
366
|
| `.opencode/tools/codegraph/bin/codegraph install --target opencode --location local --yes` | Configura CodeGraph para OpenCode y genera AGENTS.md |
|
|
371
367
|
|
|
368
|
+
> **Windows:** si ves `Command failed: cmd.exe /d /c call ... codegraph.cmd init -i` durante `npx ostacky install`, es un _warning_ no fatal — el binario se instaló pero el índice no se pudo crear. Reintentá con `npx ostacky install-stack --scope local` o ejecutá manualmente `.opencode\tools\codegraph\bin\codegraph.exe init -i` (o `codegraph.cmd` si no hay `.exe`) dentro del proyecto. Desde v0.8.3 el instalador usa el patrón resiliente de Engram (strip 0 + búsqueda recursiva) y loguea `projectRoot|toolsDir` para diagnosticar scope.
|
|
369
|
+
|
|
372
370
|
## Licencia
|
|
373
371
|
|
|
374
372
|
MIT
|
package/assets/agents/ostacky.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Orquestador principal — rutea por nivel, orquesta CodeGraph + OpenSpec + Superpowers.
|
|
3
3
|
mode: primary
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.3
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Sos **Ostacky v0.8.
|
|
7
|
+
Sos **Ostacky v0.8.3**, orquestás, no implementás. Interpretás, clasificás (0/0+1/1+), ruteás y coordinás.
|
|
8
8
|
|
|
9
|
-
> **Versión:** `0.8.
|
|
9
|
+
> **Versión:** `0.8.3` (sincronizada desde `package.json` vía `scripts/sync-version.ts`). Cuando te pregunten qué versión tenés, qué versión sos, o `¿qué versión tenés?` / `version` / `¿en qué versión estás?`, respondé exactamente: **"Ostacky v0.8.3"** (o `v0.8.3` si te piden solo el número). No inventes otra versión.
|
|
10
10
|
|
|
11
11
|
## Reglas innegociables
|
|
12
12
|
|
|
@@ -18,6 +18,16 @@ Sos **Ostacky v0.8.1**, orquestás, no implementás. Interpretás, clasificás (
|
|
|
18
18
|
|
|
19
19
|
> Ver `assets/docs/ostacky-reference.md` para TRANSITIONS, TTL y métricas. Tiered LITE/TIER1/FULL vía suffix hint.
|
|
20
20
|
|
|
21
|
+
## Principios de honestidad (SHALL)
|
|
22
|
+
|
|
23
|
+
1. **Engram contradiction check SHALL.** Antes de proponer o discutir cambios (Nivel 0+1/1+, eximido si `isTrivial && DONE`), SHALL `mem_search` por keywords del pedido (max 5 keywords = sustantivos del pedido + `topic_key` del change activo si lo hay); si hit `type:decision|architecture` con contradicción semántica (ej: pide Zustand y hay #571 “usar Redux por X”), SHALL mostrar diff `“Antes decidimos X el <fecha> por Z (topic_key), ahora pedís ¬X”`, llamar `request_clarification` y esperar. Si Engram `degraded`/timeout → SHALL advertir “sin memoria” y continuar (no block). Si usuario confirma override → SHALL `mem_save` mismo `topic_key` + `mem_compare supersedes` + `record_user_confirmation`.
|
|
24
|
+
2. **Solo propuestas que ayudan SHALL.** Toda propuesta SHALL incluir `por qué ayuda + tradeoff + evidencia` (CodeGraph symbol, Engram hit) o literal `“no verificado”` + best practice 2026. No sugerir por sugerir.
|
|
25
|
+
3. **Pocas honestas > muchas de relleno SHALL.** Si solo hay una opción honesta, dar una. Si hay 2-3, tabla `coste|riesgo|complejidad`. No inventar para llenar.
|
|
26
|
+
4. **Si no hay propuesta honesta SHALL decirlo.** Literal: `“No hay propuesta honesta que aporte vs no hacer nada en este contexto.”`
|
|
27
|
+
5. **Si dudás SHALL preguntar.** Ante ambigüedad aunque el pedido parezca claro, SHALL una pregunta clarificadora (una por turno, natural, sin tool, STOP) y esperar. No asumir.
|
|
28
|
+
6. **Verificar antes de afirmar SHALL.** No acordar sin chequear código/docs. Citar evidencia o admitir `“no pude verificar en disco”`.
|
|
29
|
+
7. **YAGNI scope SHALL.** No proponer refactor oportunista fuera del pedido; si lo ves, mencionar `“fuera de scope: …”` sin implementarlo.
|
|
30
|
+
|
|
21
31
|
## Stack
|
|
22
32
|
|
|
23
33
|
- **Controller** (plugin `ostacky-plugin.ts`): state machine in-process, hard gates.
|
|
@@ -62,6 +72,11 @@ Preguntar nivel y `consume_route_decision`.
|
|
|
62
72
|
|
|
63
73
|
Router `brainstorming`↔`OpenSpec` por `level`/`estLines`/`fileCount`/`hasAPI` (no keywords). `1+` no-downgradeable → `skill(brainstorming)` genera `design.md ## Alternatives`; downgradeable → `docs/...` + `DIRECT`.
|
|
64
74
|
|
|
75
|
+
**SHALL sin ambigüedad (spec iterativo + sync proactiva):**
|
|
76
|
+
|
|
77
|
+
- Antes de crear/editar `openspec/changes/<id>/{proposal.md,design.md,tasks.md}` **O** `docs/superpowers/specs/*.md`: si existe → SHALL `read` fresco de TODOS y SHALL `edit` (no `write`); `write` solo si no existía. Para `open-explore` sin archivo → SHALL `mem_save topic_key:brainstorm/<hash>` por iteración. `getDiscoverySnapshot` no aplica a specs/docs.
|
|
78
|
+
- Al final de cada turno de brainstorming/spec con decisiones nuevas no reflejadas en disco: SHALL listar cálido `Noté que lo que acordamos (X por Z) aún no está en <archivo>: 1) ...` (max 3) y SHALL proponer en UNA sola pregunta `¿Querés que agregue [X, Y] a <archivo> e implemente <mejor propuesta> —la recomiendo por <tradeoff/evidencia>—?` (respetando Regla 5). Si no hay delta, no proponer. Eximido si `isTrivial`.
|
|
79
|
+
|
|
65
80
|
### 4. Execution
|
|
66
81
|
|
|
67
82
|
1. `skill(execution-mode-evaluation)` en memoria, reusa discovery.
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Instala CodeGraph, skills curadas, OpenSpec
|
|
2
|
+
description: Instala CodeGraph, skills curadas, OpenSpec y Engram localmente para OpenCode únicamente
|
|
3
3
|
agent: build
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Instala el stack tecnológico de desarrollo para OpenCode. **IMPORTANTE:** las herramientas se instalan por separado (cada una con su propio CLI/comando). `npx ostacky install` solo instala el agente y commands de Ostacky en `.opencode/`. Este comando (`/install-stack`) es la guía de referencia para la instalación manual completa paso a paso.
|
|
7
7
|
|
|
8
|
-
**Nota:** A partir de v0.8.
|
|
8
|
+
**Nota:** A partir de v0.8.3, `npx ostacky install` ya instala automáticamente el stack completo (CodeGraph, OpenSpec, Engram, MCPs bundleados) además del agente y skills. Este comando es útil para instalación manual, verificación, o cuando algo falló y necesita reinstalarse.
|
|
9
9
|
|
|
10
10
|
**RESTRICCIÓN ABSOLUTA:** instalar ÚNICAMENTE para OpenCode. Está terminantemente prohibido crear o modificar archivos en `.claude/`, `.kiro/`, `.cursor/`, `.gemini/`, `.codex/`, `.antigravity/`, `.windsurf/` o cualquier otro directorio de plataformas externas.
|
|
11
11
|
|
|
12
|
-
**Origen del set curado:** el set de 15 skills referenciado en `assets/agents/ostacky.md` está bundleado en `assets/skills/` dentro del paquete npm.
|
|
12
|
+
**Origen del set curado:** el set de 15 skills referenciado en `assets/agents/ostacky.md` está bundleado en `assets/skills/` dentro del paquete npm. La definición del set y su trazabilidad viven en `manifest.json` y `.opencode/ostacky-lock.json`.
|
|
13
13
|
|
|
14
|
-
## Scope de instalación — local vs global (desde v0.8.
|
|
14
|
+
## Scope de instalación — local vs global (desde v0.8.3)
|
|
15
15
|
|
|
16
16
|
`npx ostacky install` soporta `--scope local|global|auto` (también `--scope=...`):
|
|
17
17
|
|
|
@@ -164,7 +164,7 @@ Ostacky automáticamente detecta la ausencia del controller y opera en modo degr
|
|
|
164
164
|
|
|
165
165
|
## Paso 2 — Skills curadas (bundleadas)
|
|
166
166
|
|
|
167
|
-
Las **15 skills curadas** están bundleadas dentro del paquete Ostacky en `assets/skills/`. No se descargan ni clonan; ya vienen en el paquete npm.
|
|
167
|
+
Las **15 skills curadas** están bundleadas dentro del paquete Ostacky en `assets/skills/`. No se descargan ni clonan; ya vienen en el paquete npm.
|
|
168
168
|
|
|
169
169
|
Copiá cada skill bundleada a `.opencode/skills/<nombre>/` preservando la estructura interna (incluyendo `SKILL.md` y cualquier subdirectorio como `scripts/` o `references/`):
|
|
170
170
|
|
|
@@ -215,11 +215,6 @@ Leé `opencode.json` (o `opencode.jsonc`) en la raíz del proyecto.
|
|
|
215
215
|
"command": [".opencode/tools/engram/bin/engram", "mcp"],
|
|
216
216
|
"enabled": true
|
|
217
217
|
},
|
|
218
|
-
"context7": {
|
|
219
|
-
"type": "remote",
|
|
220
|
-
"url": "https://mcp.context7.com/mcp",
|
|
221
|
-
"enabled": true
|
|
222
|
-
},
|
|
223
218
|
"ostacky-controller": {
|
|
224
219
|
"type": "local",
|
|
225
220
|
"command": ["node", ".opencode/mcp/ostacky-controller/index.js"],
|
|
@@ -353,99 +348,6 @@ rm -rf ~/.engram/
|
|
|
353
348
|
|
|
354
349
|
---
|
|
355
350
|
|
|
356
|
-
## Paso 6 — Context7
|
|
357
|
-
|
|
358
|
-
[Context7](https://context7.com) provee documentación actualizada de librerías y APIs directamente en el contexto del agente. Se instala como un CLI vía `npx`, sin dependencias globales ni MCP server necesario (aunque también soporta MCP).
|
|
359
|
-
|
|
360
|
-
**RESTRICCIÓN:** configurar ÚNICAMENTE para OpenCode. Está terminantemente prohibido crear archivos en `.claude/`, `.kiro/`, `.cursor/`, `.gemini/`, `.codex/`, `.antigravity/`, `.windsurf/` o cualquier otro directorio de plataformas externas.
|
|
361
|
-
|
|
362
|
-
### Verificar instalación actual
|
|
363
|
-
|
|
364
|
-
Chequeá si Context7 ya está configurado para OpenCode:
|
|
365
|
-
|
|
366
|
-
```bash
|
|
367
|
-
ls -la .opencode/skills/context7/ 2>/dev/null || echo "no-instalado"
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
También podés verificar si el MCP server de Context7 está en `opencode.json`:
|
|
371
|
-
|
|
372
|
-
```bash
|
|
373
|
-
grep -c "context7" opencode.json 2>/dev/null || echo "no-configurado"
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
### Instalar
|
|
377
|
-
|
|
378
|
-
**Opción recomendada — setup automático (CLI + skills):**
|
|
379
|
-
|
|
380
|
-
```bash
|
|
381
|
-
npx ctx7 setup --opencode
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
Este comando:
|
|
385
|
-
|
|
386
|
-
- Autentica vía OAuth y genera una API key
|
|
387
|
-
- Instala un skill en `.opencode/skills/context7/` que el agente Ostacky usa automáticamente
|
|
388
|
-
- Pregunta si preferís modo CLI + Skills o MCP
|
|
389
|
-
- **NO** toca `.claude/`, `.cursor/`, `.gemini/` ni ninguna otra plataforma
|
|
390
|
-
|
|
391
|
-
**Alternativa — solo MCP (si preferís el server remoto):**
|
|
392
|
-
|
|
393
|
-
Agregá manualmente la entrada MCP en `opencode.json`:
|
|
394
|
-
|
|
395
|
-
```json
|
|
396
|
-
{
|
|
397
|
-
"mcp": {
|
|
398
|
-
"context7": {
|
|
399
|
-
"type": "remote",
|
|
400
|
-
"url": "https://mcp.context7.com/mcp"
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
Si tenés una API key de Context7 (recomendado para mejores rate limits):
|
|
407
|
-
|
|
408
|
-
```json
|
|
409
|
-
{
|
|
410
|
-
"mcp": {
|
|
411
|
-
"context7": {
|
|
412
|
-
"type": "remote",
|
|
413
|
-
"url": "https://mcp.context7.com/mcp",
|
|
414
|
-
"headers": {
|
|
415
|
-
"CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}"
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
### Desinstalar
|
|
423
|
-
|
|
424
|
-
Para remover la configuración generada por `npx ctx7 setup`:
|
|
425
|
-
|
|
426
|
-
```bash
|
|
427
|
-
npx ctx7 remove
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
Esto elimina el skill y la configuración de Context7. Si instalaste el CLI globalmente con `npm install -g ctx7`, también necesitás:
|
|
431
|
-
|
|
432
|
-
```bash
|
|
433
|
-
npm uninstall -g ctx7
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
Para remover la entrada MCP manual, editá `opencode.json` y eliminá el bloque `mcp.context7`.
|
|
437
|
-
|
|
438
|
-
### Cómo lo usa Ostacky
|
|
439
|
-
|
|
440
|
-
El skill de Context7 instalado le indica al agente Ostacky que use Context7 automáticamente cuando necesite documentación de librerías, APIs o frameworks. También se puede invocar explícitamente:
|
|
441
|
-
|
|
442
|
-
```
|
|
443
|
-
usá context7 para mostrarme la API de autenticación de Supabase
|
|
444
|
-
use context7 to find Next.js 15 app router examples
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
---
|
|
448
|
-
|
|
449
351
|
## Estructura de herramientas
|
|
450
352
|
|
|
451
353
|
Cada herramienta se instala en su propia carpeta dentro de `.opencode/` para mantener una instalación limpia y aislada. El installer crea automáticamente `.opencode/tools/<nombre>/` para cada herramienta externa:
|
|
@@ -481,10 +383,9 @@ Cada herramienta se instala en su propia carpeta dentro de `.opencode/` para man
|
|
|
481
383
|
│ ├── using-superpowers/
|
|
482
384
|
│ ├── writing-skills/
|
|
483
385
|
│ └── graceful-degradation/
|
|
484
|
-
├── tools/ #
|
|
485
|
-
│ ├── codegraph/ #
|
|
486
|
-
│
|
|
487
|
-
│ └── context7/ # Config de Context7
|
|
386
|
+
├── tools/ # Binarios locales de herramientas externas
|
|
387
|
+
│ ├── codegraph/ # Binario local de CodeGraph
|
|
388
|
+
│ └── engram/ # Binario local de Engram
|
|
488
389
|
└── plugins/ # Plugins de OpenCode
|
|
489
390
|
```
|
|
490
391
|
|
|
@@ -493,24 +394,23 @@ Cada herramienta se instala en su propia carpeta dentro de `.opencode/` para man
|
|
|
493
394
|
- `.codegraph/` (índice de CodeGraph) vive en la raíz del proyecto — CodeGraph lo espera ahí.
|
|
494
395
|
- El binario de CodeGraph es **local al proyecto** en `.opencode/tools/codegraph/bin/`; en Windows puede ser `codegraph.cmd`. No se instala globalmente.
|
|
495
396
|
- El binario de Engram es **local al proyecto** en `.opencode/tools/engram/bin/engram` (o `engram.exe` en Windows). No se instala globalmente.
|
|
496
|
-
-
|
|
397
|
+
- El binary de CodeGraph y Engram vive siempre en `<proyecto>/.opencode/tools/` por reproducibilidad, nunca global.
|
|
497
398
|
- El controller publicado se bundlea como un único `index.js`; durante desarrollo el installer instala sus dependencias en staging y valida el servidor antes de activarlo.
|
|
498
399
|
|
|
499
400
|
## Verificación final
|
|
500
401
|
|
|
501
402
|
Confirmá que:
|
|
502
403
|
|
|
503
|
-
1. `.opencode/skills/` contiene las 15 skills curadas
|
|
404
|
+
1. `.opencode/skills/` contiene las 15 skills curadas
|
|
504
405
|
2. `.opencode/commands/` contiene los commands bundleados por Ostacky (`install-stack`, `opsx-sync`) y los 4 commands generados por OpenSpec (`opsx-apply`, `opsx-archive`, `opsx-explore`, `opsx-propose`) si OpenSpec fue inicializado
|
|
505
|
-
3. `opencode.json` (o `.jsonc`) tiene los bloques MCP: `codegraph`, `engram`, `
|
|
406
|
+
3. `opencode.json` (o `.jsonc`) tiene los bloques MCP: `codegraph`, `engram`, `ostacky-controller` — sin campo `plugin`
|
|
506
407
|
4. `.codegraph/` existe en la raíz del proyecto (índice local de CodeGraph)
|
|
507
408
|
5. El launcher local de CodeGraph funciona (`codegraph.cmd --version` en Windows o `codegraph --version` en Unix)
|
|
508
409
|
6. El binario local de Engram funciona (`engram.exe --version` en Windows o `engram --version` en Unix)
|
|
509
|
-
7.
|
|
510
|
-
8.
|
|
511
|
-
9.
|
|
512
|
-
10.
|
|
513
|
-
11. Un `AGENTS.md` preexistente en la raíz del proyecto se preserva sin cambios
|
|
410
|
+
7. OpenSpec generó sus commands/skills para OpenCode mediante `openspec init --tools opencode` (si se usó)
|
|
411
|
+
8. `.opencode/tools/` contiene subdirectorios para `codegraph/` y `engram/`
|
|
412
|
+
9. **NO existen** archivos generados en `.claude/`, `.kiro/`, `.cursor/`, `.gemini/`, `.codex/` ni ningún directorio de otra plataforma
|
|
413
|
+
10. Un `AGENTS.md` preexistente en la raíz del proyecto se preserva sin cambios
|
|
514
414
|
|
|
515
415
|
Reportá el estado de cada componente con ✓ o ✗.
|
|
516
416
|
|
|
@@ -26,7 +26,6 @@ BLOCKED: replan→INTERPRETATION_PENDING, abandon→DONE
|
|
|
26
26
|
| codegraph_* | 10s | 1 | Engram → Read+Glob |
|
|
27
27
|
| controller_* | 5s | 1 | degraded |
|
|
28
28
|
| engram_* | 5s | 1 | sin memoria |
|
|
29
|
-
| context7_* | 10s | 1 | sin docs |
|
|
30
29
|
|
|
31
30
|
## Cache
|
|
32
31
|
|
|
@@ -75,5 +74,4 @@ Principio: **eficacia > recorte** — si recorte rompiera caché y saliera más
|
|
|
75
74
|
|
|
76
75
|
- `ostacky.md` 109→72 líneas (diet estable cacheable). Tiered vía suffix, no reemplazo `system[0]`.
|
|
77
76
|
- `controller` descriptions <150 chars
|
|
78
|
-
- `context7` lazy: `enabled:false` default, trigger `docs|api|lib|Context7` habilita
|
|
79
77
|
- `MEMORY_INSTRUCTIONS` lazy: siempre pointer (~1 línea) en `system.transform`; full vive en `assets/docs/engram-protocol.md` on-demand via `Read` (ahorro ~1.2k en FULL, trivial ya era pointer)
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* controller-core — Single source of truth para TRANSITIONS, STATES, DEFAULT_STATE y helpers.
|
|
3
|
+
* Extraído de assets/mcp/ostacky-controller/index.js y assets/plugins/ostacky-plugin.ts
|
|
4
|
+
* para eliminar duplicación (D1). Ambos importan de acá.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { SENSITIVE_DEFAULT } from "./security.js";
|
|
8
|
+
|
|
9
|
+
// --- Constants (headroom generoso) ---
|
|
10
|
+
export const MAX_TASKS = 100;
|
|
11
|
+
export const MAX_TASKS_DEFAULT = 100;
|
|
12
|
+
export const MAX_TASKS_CAP = 500;
|
|
13
|
+
export const MAX_SNAPSHOT_JSON_LENGTH = 50 * 1024;
|
|
14
|
+
export const MAX_STATE_FILE_SIZE = 2 * 1024 * 1024;
|
|
15
|
+
export const DEGRADED_THRESHOLD = 3;
|
|
16
|
+
|
|
17
|
+
export const STATES = Object.freeze({
|
|
18
|
+
INTERPRETATION_PENDING: "INTERPRETATION_PENDING",
|
|
19
|
+
CLARIFICATION_PENDING: "CLARIFICATION_PENDING",
|
|
20
|
+
DISCOVERY: "DISCOVERY",
|
|
21
|
+
ROUTE_DECISION_PENDING: "ROUTE_DECISION_PENDING",
|
|
22
|
+
SPECIFICATION: "SPECIFICATION",
|
|
23
|
+
EXECUTION_ANALYSIS: "EXECUTION_ANALYSIS",
|
|
24
|
+
EXECUTION_DECISION_PENDING: "EXECUTION_DECISION_PENDING",
|
|
25
|
+
EXECUTING_INLINE: "EXECUTING_INLINE",
|
|
26
|
+
EXECUTING_SUBAGENTS: "EXECUTING_SUBAGENTS",
|
|
27
|
+
SYNC: "SYNC",
|
|
28
|
+
DONE: "DONE",
|
|
29
|
+
BLOCKED: "BLOCKED",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export const TRANSITIONS = {
|
|
33
|
+
INTERPRETATION_PENDING: [
|
|
34
|
+
{ via: "request_clarification", to: "CLARIFICATION_PENDING" },
|
|
35
|
+
{ via: "proceed_to_discovery", to: "DISCOVERY" },
|
|
36
|
+
{ via: "record_discovery", to: "ROUTE_DECISION_PENDING" },
|
|
37
|
+
{ via: "block", to: "BLOCKED" },
|
|
38
|
+
],
|
|
39
|
+
CLARIFICATION_PENDING: [
|
|
40
|
+
{ via: "record_clarification", to: "DISCOVERY" },
|
|
41
|
+
{ via: "block", to: "BLOCKED" },
|
|
42
|
+
{ via: "abandon", to: "BLOCKED" },
|
|
43
|
+
],
|
|
44
|
+
DISCOVERY: [
|
|
45
|
+
{ via: "record_discovery", to: "ROUTE_DECISION_PENDING" },
|
|
46
|
+
{ via: "block", to: "BLOCKED" },
|
|
47
|
+
{ via: "abandon", to: "BLOCKED" },
|
|
48
|
+
],
|
|
49
|
+
ROUTE_DECISION_PENDING: [
|
|
50
|
+
{ via: "consume_route_decision", to: "SPECIFICATION", choice: "SPEC" },
|
|
51
|
+
{ via: "consume_route_decision", to: "EXECUTION_ANALYSIS", choice: "DIRECT" },
|
|
52
|
+
{ via: "block", to: "BLOCKED" },
|
|
53
|
+
{ via: "abandon", to: "BLOCKED" },
|
|
54
|
+
],
|
|
55
|
+
SPECIFICATION: [
|
|
56
|
+
{ via: "spec_complete", to: "EXECUTION_ANALYSIS" },
|
|
57
|
+
{ via: "block", to: "BLOCKED" },
|
|
58
|
+
{ via: "abandon", to: "BLOCKED" },
|
|
59
|
+
],
|
|
60
|
+
EXECUTION_ANALYSIS: [
|
|
61
|
+
{ via: "record_execution_analysis", to: "EXECUTION_DECISION_PENDING" },
|
|
62
|
+
{ via: "block", to: "BLOCKED" },
|
|
63
|
+
{ via: "abandon", to: "BLOCKED" },
|
|
64
|
+
],
|
|
65
|
+
EXECUTION_DECISION_PENDING: [
|
|
66
|
+
{ via: "consume_execution_decision", to: "EXECUTING_INLINE", mode: "INLINE" },
|
|
67
|
+
{ via: "consume_execution_decision", to: "EXECUTING_SUBAGENTS", mode: "SUBAGENT_DRIVEN" },
|
|
68
|
+
{ via: "block", to: "BLOCKED" },
|
|
69
|
+
{ via: "abandon", to: "BLOCKED" },
|
|
70
|
+
],
|
|
71
|
+
EXECUTING_INLINE: [
|
|
72
|
+
{ via: "implementation_complete", to: "SYNC" },
|
|
73
|
+
{ via: "block", to: "BLOCKED" },
|
|
74
|
+
],
|
|
75
|
+
EXECUTING_SUBAGENTS: [
|
|
76
|
+
{ via: "implementation_complete", to: "SYNC" },
|
|
77
|
+
{ via: "block", to: "BLOCKED" },
|
|
78
|
+
],
|
|
79
|
+
BLOCKED: [
|
|
80
|
+
{ via: "replan", to: "INTERPRETATION_PENDING" },
|
|
81
|
+
{ via: "abandon", to: "DONE" },
|
|
82
|
+
],
|
|
83
|
+
SYNC: [
|
|
84
|
+
{ via: "sync_complete", to: "DONE" },
|
|
85
|
+
{ via: "block", to: "BLOCKED" },
|
|
86
|
+
],
|
|
87
|
+
DONE: [],
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const TERMINAL_STATES = Object.freeze([
|
|
91
|
+
STATES.INTERPRETATION_PENDING,
|
|
92
|
+
STATES.CLARIFICATION_PENDING,
|
|
93
|
+
STATES.BLOCKED,
|
|
94
|
+
STATES.DONE,
|
|
95
|
+
]);
|
|
96
|
+
|
|
97
|
+
export const DEFAULT_STATE = {
|
|
98
|
+
state: STATES.INTERPRETATION_PENDING,
|
|
99
|
+
revision: 0,
|
|
100
|
+
requestId: null,
|
|
101
|
+
changeId: null,
|
|
102
|
+
routeDecisionId: null,
|
|
103
|
+
routeChoice: null,
|
|
104
|
+
level: null,
|
|
105
|
+
executionDecisionId: null,
|
|
106
|
+
executionMode: null,
|
|
107
|
+
snapshots: { codegraph: null, execution: null },
|
|
108
|
+
tasks: {},
|
|
109
|
+
fileFingerprints: {},
|
|
110
|
+
error: null,
|
|
111
|
+
lastHandoff: null,
|
|
112
|
+
expectedTasks: null,
|
|
113
|
+
expectedTaskCount: null,
|
|
114
|
+
auditSeq: 0,
|
|
115
|
+
degraded: false,
|
|
116
|
+
schemaVersion: 2,
|
|
117
|
+
stateOversizedCount: 0,
|
|
118
|
+
codegraphBypassCount: 0,
|
|
119
|
+
degradedEditsCount: 0,
|
|
120
|
+
cacheHitCount: 0,
|
|
121
|
+
cacheMissCount: 0,
|
|
122
|
+
tokenSavingEstimate: 0,
|
|
123
|
+
discoveryCacheHitCount: 0,
|
|
124
|
+
redundantCallCount: 0,
|
|
125
|
+
cacheMissWithoutPutCount: 0,
|
|
126
|
+
stateCheckCount: 0,
|
|
127
|
+
toolCallCount: 0,
|
|
128
|
+
lastProposal: null,
|
|
129
|
+
allowedFiles: {},
|
|
130
|
+
deniedFiles: {},
|
|
131
|
+
sensitivePatterns: [...SENSITIVE_DEFAULT],
|
|
132
|
+
sensitiveAccess: { allowed: 0, denied: 0, blockedAttempts: 0 },
|
|
133
|
+
staleContentAttempts: 0,
|
|
134
|
+
completeWithoutValidateCount: 0,
|
|
135
|
+
toolTimeoutCount: 0,
|
|
136
|
+
lastToolDurationMs: 0,
|
|
137
|
+
stateDurationMs: 0,
|
|
138
|
+
subagentFailedCount: 0,
|
|
139
|
+
lastValidated: null,
|
|
140
|
+
pendingFileAccess: {},
|
|
141
|
+
lastHeartbeat: 0,
|
|
142
|
+
watchdogEnabled: true,
|
|
143
|
+
ts: Date.now(),
|
|
144
|
+
specNotInSync: false,
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export function safeJsonStringify(obj, pretty = false) {
|
|
148
|
+
const seen = new WeakSet();
|
|
149
|
+
try {
|
|
150
|
+
return JSON.stringify(
|
|
151
|
+
obj,
|
|
152
|
+
(key, value) => {
|
|
153
|
+
if (typeof value === "object" && value !== null) {
|
|
154
|
+
if (seen.has(value)) return "[Circular]";
|
|
155
|
+
seen.add(value);
|
|
156
|
+
}
|
|
157
|
+
return value;
|
|
158
|
+
},
|
|
159
|
+
pretty ? 2 : undefined
|
|
160
|
+
);
|
|
161
|
+
} catch (e) {
|
|
162
|
+
return `[Unstringifiable: ${e.message}]`;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const SENSITIVE_REDACT_RE = /(apiKey|secret|token|password|api_key)/i;
|
|
167
|
+
|
|
168
|
+
export function redactForLog(data) {
|
|
169
|
+
if (!data || typeof data !== "object") return data;
|
|
170
|
+
try {
|
|
171
|
+
const str = safeJsonStringify(data);
|
|
172
|
+
if (SENSITIVE_REDACT_RE.test(str)) {
|
|
173
|
+
const copy = JSON.parse(str);
|
|
174
|
+
const redactRecursively = (obj) => {
|
|
175
|
+
if (!obj || typeof obj !== "object") return;
|
|
176
|
+
for (const k of Object.keys(obj)) {
|
|
177
|
+
if (SENSITIVE_REDACT_RE.test(k)) obj[k] = "[REDACTED]";
|
|
178
|
+
else if (typeof obj[k] === "object") redactRecursively(obj[k]);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
redactRecursively(copy);
|
|
182
|
+
return copy;
|
|
183
|
+
}
|
|
184
|
+
return data;
|
|
185
|
+
} catch {
|
|
186
|
+
return data;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function getMaxTasks() {
|
|
191
|
+
const raw = process.env.OSTACKY_MAX_TASKS;
|
|
192
|
+
if (raw == null || raw === "") return MAX_TASKS_DEFAULT;
|
|
193
|
+
const n = parseInt(raw, 10);
|
|
194
|
+
if (Number.isNaN(n) || n <= 0) return MAX_TASKS_DEFAULT;
|
|
195
|
+
if (n > MAX_TASKS_CAP) return MAX_TASKS_CAP;
|
|
196
|
+
return n;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function getAuditRetention() {
|
|
200
|
+
const raw = process.env.OSTACKY_AUDIT_RETENTION;
|
|
201
|
+
if (raw == null || raw === "") return 500;
|
|
202
|
+
const n = parseInt(raw, 10);
|
|
203
|
+
if (Number.isNaN(n) || n <= 0) return 500;
|
|
204
|
+
if (n > 2000) return 2000;
|
|
205
|
+
return n;
|
|
206
|
+
}
|