ostacky 0.8.0 → 0.8.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 +54 -17
- package/assets/agents/ostacky.md +3 -3
- package/assets/commands/install-stack.md +2 -2
- package/assets/mcp/ostacky-controller/index.js +2 -2
- package/assets/mcp/ostacky-controller/package.json +1 -1
- package/assets/plugins/ostacky-plugin.ts +48 -0
- package/dist/cli.js +198 -66
- package/manifest.json +28 -28
- package/package.json +1 -1
- package/assets/plugins/ostacky-guard.ts +0 -18
package/README.md
CHANGED
|
@@ -116,7 +116,9 @@ npx ostacky install --scope global # ~/.config/opencode (XDG/APPDATA en Windows
|
|
|
116
116
|
npx ostacky install --scope auto # local si existe .opencode/.git, si no global
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
-
Descarga todos los agentes y commands definidos en el manifest y los escribe en `.opencode/` (scope `local`) o en `~/.config/opencode` (`global`).
|
|
119
|
+
Descarga todos los agentes y commands definidos en el manifest y los escribe en `.opencode/` (scope `local`) o en `~/.config/opencode` (`global`). 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).
|
|
120
|
+
|
|
121
|
+
> **Coherencia local/global:** aunque elijas `global`, los plugins y herramientas (`tools/` con CodeGraph/Engram) permanecen siempre en `<proyecto>/.opencode` local para el hard-gate por worktree. En global solo se escribe el scope global + un espejo local de plugins. Para stack completo por proyecto ejecutá `npx ostacky install --scope local` dentro de cada repo.
|
|
120
122
|
|
|
121
123
|
### Agregar agentes o commands individualmente
|
|
122
124
|
|
|
@@ -148,15 +150,21 @@ Solo descarga los items que cambiaron de versión.
|
|
|
148
150
|
### Desinstalar
|
|
149
151
|
|
|
150
152
|
```bash
|
|
151
|
-
npx ostacky uninstall
|
|
153
|
+
npx ostacky uninstall # pregunta local vs global, luego qué borrar
|
|
154
|
+
npx ostacky uninstall --scope local # fuerza scope local
|
|
155
|
+
npx ostacky uninstall --scope global # fuerza scope global
|
|
156
|
+
npx ostacky uninstall --scope auto # auto
|
|
152
157
|
```
|
|
153
158
|
|
|
154
|
-
|
|
159
|
+
**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.
|
|
160
|
+
|
|
161
|
+
> Si el lockfile no existe o está vacío → `No hay nada instalado.` y no borra nada.
|
|
155
162
|
|
|
156
163
|
#### Desinstalar un agente puntual
|
|
157
164
|
|
|
158
165
|
```bash
|
|
159
|
-
npx ostacky uninstall agent <nombre>
|
|
166
|
+
npx ostacky uninstall agent <nombre> # también admite --scope local|global|auto
|
|
167
|
+
npx ostacky uninstall agent # sin nombre → selector de instalados
|
|
160
168
|
```
|
|
161
169
|
|
|
162
170
|
Por ejemplo:
|
|
@@ -168,7 +176,8 @@ npx ostacky uninstall agent ostacky
|
|
|
168
176
|
#### Desinstalar un command puntual
|
|
169
177
|
|
|
170
178
|
```bash
|
|
171
|
-
npx ostacky uninstall command <nombre>
|
|
179
|
+
npx ostacky uninstall command <nombre> # también admite --scope
|
|
180
|
+
npx ostacky uninstall command # sin nombre → selector
|
|
172
181
|
```
|
|
173
182
|
|
|
174
183
|
Por ejemplo:
|
|
@@ -179,6 +188,15 @@ npx ostacky uninstall command install-stack
|
|
|
179
188
|
|
|
180
189
|
Si no especificás el nombre, el CLI te muestra un selector con los items instalados para que elijas cuáles desinstalar (puede ser uno o varios).
|
|
181
190
|
|
|
191
|
+
#### Desinstalar todo el stack (tools + config)
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
npx ostacky uninstall-stack # pregunta scope, limpia mcp.codegraph/engram de opencode.json + .codegraph/ + .opencode/tools/
|
|
195
|
+
npx ostacky uninstall-stack --scope local
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
No toca binarios globales ni datos de Engram, solo la configuración del proyecto.
|
|
199
|
+
|
|
182
200
|
### Otros
|
|
183
201
|
|
|
184
202
|
```bash
|
|
@@ -188,7 +206,7 @@ npx ostacky --help # muestra la ayuda
|
|
|
188
206
|
|
|
189
207
|
## Estructura generada
|
|
190
208
|
|
|
191
|
-
Tras instalar, el proyecto queda así:
|
|
209
|
+
Tras instalar (`--scope local`), el proyecto queda así:
|
|
192
210
|
|
|
193
211
|
```
|
|
194
212
|
.opencode/
|
|
@@ -212,44 +230,63 @@ Tras instalar, el proyecto queda así:
|
|
|
212
230
|
│ ├── using-superpowers/
|
|
213
231
|
│ ├── writing-skills/
|
|
214
232
|
│ └── graceful-degradation/
|
|
215
|
-
|
|
233
|
+
├── plugins/
|
|
234
|
+
│ ├── ostacky-plugin.ts ← controller hard-gate (fusiona guard legacy)
|
|
235
|
+
│ └── engram.ts ← plugin Engram
|
|
236
|
+
├── mcp/
|
|
237
|
+
│ ├── ostacky-controller/ ← MCP thin (observabilidad)
|
|
238
|
+
│ └── openspec/
|
|
239
|
+
├── tools/
|
|
240
|
+
│ ├── codegraph/bin/codegraph
|
|
241
|
+
│ └── engram/bin/engram
|
|
242
|
+
├── cache/codegraph/ ← cache local CodeGraph/Discovery
|
|
243
|
+
├── ostacky-state.json ← estado por worktree (aislado)
|
|
244
|
+
└── ostacky-lock.json ← versiones instaladas (agentes, commands, skills, mcpServers)
|
|
216
245
|
```
|
|
217
246
|
|
|
247
|
+
> `assets/plugins/ostacky-guard.ts` fue **fusionado en `ostacky-plugin.ts` y eliminado** (re-export legacy). Fresh install solo escribe `ostacky-plugin.ts` + `engram.ts`; si venís de una versión previa con `ostacky-guard.ts` o `ostacky-controller.ts` legacy, el installer los elimina automáticamente.
|
|
248
|
+
|
|
218
249
|
### ostacky-lock.json
|
|
219
250
|
|
|
220
251
|
```json
|
|
221
252
|
{
|
|
222
|
-
"version": "0.8.
|
|
253
|
+
"version": "0.8.1",
|
|
223
254
|
"lockedAt": "2025-01-01T00:00:00.000Z",
|
|
224
255
|
"repo": "JaimeHoracio/Ostacky",
|
|
225
|
-
"tag": "v0.8.
|
|
256
|
+
"tag": "v0.8.1",
|
|
226
257
|
"agents": {
|
|
227
258
|
"ostacky": {
|
|
228
|
-
"version": "0.8.
|
|
259
|
+
"version": "0.8.1",
|
|
229
260
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
230
261
|
"sha256": "abc123..."
|
|
231
262
|
}
|
|
232
263
|
},
|
|
233
264
|
"commands": {
|
|
234
265
|
"install-stack": {
|
|
235
|
-
"version": "0.8.
|
|
266
|
+
"version": "0.8.1",
|
|
236
267
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
237
268
|
"sha256": "def456..."
|
|
238
269
|
},
|
|
239
270
|
"opsx-sync": {
|
|
240
|
-
"version": "0.8.
|
|
271
|
+
"version": "0.8.1",
|
|
241
272
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
242
273
|
"sha256": "ghi789..."
|
|
243
274
|
}
|
|
244
275
|
},
|
|
245
276
|
"skills": {
|
|
246
|
-
"brainstorming": { "version": "0.8.
|
|
247
|
-
"execution-mode-evaluation": { "version": "0.8.
|
|
248
|
-
"openspec-propose": { "version": "0.8.
|
|
277
|
+
"brainstorming": { "version": "0.8.1", ... },
|
|
278
|
+
"execution-mode-evaluation": { "version": "0.8.1", ... },
|
|
279
|
+
"openspec-propose": { "version": "0.8.1", ... }
|
|
280
|
+
},
|
|
281
|
+
"mcpServers": {
|
|
282
|
+
"ostacky-controller": { "version": "0.8.1", ... },
|
|
283
|
+
"openspec": { "version": "0.8.1", ... }
|
|
249
284
|
}
|
|
250
285
|
}
|
|
251
286
|
```
|
|
252
287
|
|
|
288
|
+
`plugins/` (`ostacky-plugin.ts`, `engram.ts`) y `tools/` **no** se trackean en el lockfile — son allowlist Ostacky-owned y se gestionan via `uninstall` (allowlist) y `uninstall-stack`.
|
|
289
|
+
|
|
253
290
|
Se recomienda agregar `ostacky-lock.json` al control de versiones para que el equipo instale exactamente las mismas versiones.
|
|
254
291
|
|
|
255
292
|
## Después de la instalación
|
|
@@ -275,7 +312,7 @@ Es opcional y solo necesario si algo falló durante la instalación o si querés
|
|
|
275
312
|
## Seguridad
|
|
276
313
|
|
|
277
314
|
- `opencode.jsonc` se versiona en el repo para compartir permisos y MCP de forma reproducible.
|
|
278
|
-
- Las URLs de descarga usan **tags de GitHub** (ej. `v0.8.
|
|
315
|
+
- Las URLs de descarga usan **tags de GitHub** (ej. `v0.8.1`), nunca `main` — instalaciones reproducibles
|
|
279
316
|
- Cada path de archivo descargado es validado para prevenir **path traversal**
|
|
280
317
|
- Los archivos incluyen **checksum SHA-256** opcional; si el manifest lo define, el contenido se verifica antes de escribir
|
|
281
318
|
- El cache local (`.opencode/cache/`) también valida integridad al servir archivos cacheados
|
|
@@ -291,7 +328,7 @@ Es opcional y solo necesario si algo falló durante la instalación o si querés
|
|
|
291
328
|
- Variable `OSTACKY_SENSITIVE_PATTERNS` overridea los patrones por defecto (`**/.env*`, `**/.secrets/**`, `**/*.pem`, `**/*.key`, `**/.aws/**`, `**/.ssh/**`, `**/credentials.json`, `**/.npmrc`).
|
|
292
329
|
- Ejemplo: `OSTACKY_SENSITIVE_PATTERNS="**/.env*,**/.secrets/**" bunx ostacky doctor` — `doctor` imprime el patrón efectivo.
|
|
293
330
|
- Allowlist: `.env.example`, `.env.template`, `.env.sample` nunca se bloquean.
|
|
294
|
-
- Fuente única: `src/security.ts` (`SENSITIVE_DEFAULT`, `isSensitive`, `BASH_SENSITIVE_RE`) — guard
|
|
331
|
+
- Fuente única: `src/security.ts` (`SENSITIVE_DEFAULT`, `isSensitive`, `BASH_SENSITIVE_RE`) — `ostacky-plugin.ts` importa de ahí (legacy `ostacky-guard.ts` eliminado, fusionado en el plugin). Ver `doctor` para verificar.
|
|
295
332
|
|
|
296
333
|
#### Aislamiento de worktrees (harness-prod-hardening)
|
|
297
334
|
|
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.1
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Sos **Ostacky v0.8.
|
|
7
|
+
Sos **Ostacky v0.8.1**, 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.1` (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.1"** (o `v0.8.1` si te piden solo el número). No inventes otra versión.
|
|
10
10
|
|
|
11
11
|
## Reglas innegociables
|
|
12
12
|
|
|
@@ -5,13 +5,13 @@ agent: build
|
|
|
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.1, `npx ostacky install` ya instala automáticamente el stack completo (CodeGraph, OpenSpec, Engram, Context7, 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
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. Context7 agrega su propio skill vía `npx ctx7 setup --opencode`. 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.1)
|
|
15
15
|
|
|
16
16
|
`npx ostacky install` soporta `--scope local|global|auto` (también `--scope=...`):
|
|
17
17
|
|
|
@@ -2371,7 +2371,7 @@ function safeHandler(fn, options = {}) {
|
|
|
2371
2371
|
|
|
2372
2372
|
const server = new McpServer({
|
|
2373
2373
|
name: 'ostacky-controller',
|
|
2374
|
-
version: '0.8.
|
|
2374
|
+
version: '0.8.1',
|
|
2375
2375
|
});
|
|
2376
2376
|
|
|
2377
2377
|
server.registerTool(
|
|
@@ -2971,7 +2971,7 @@ function setupGracefulShutdown(ctrl) {
|
|
|
2971
2971
|
}
|
|
2972
2972
|
|
|
2973
2973
|
async function main() {
|
|
2974
|
-
log('Starting ostacky-controller MCP v0.8.
|
|
2974
|
+
log('Starting ostacky-controller MCP v0.8.1...');
|
|
2975
2975
|
log('State path:', { path: statePath });
|
|
2976
2976
|
// Clean up stale tmp/lock files from previous runs
|
|
2977
2977
|
cleanupTmpFiles(statePath);
|
|
@@ -20,6 +20,10 @@ import { isTrivial } from "../../src/tiered.ts"
|
|
|
20
20
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
21
21
|
|
|
22
22
|
const MAX_STATE_FILE_SIZE = 2 * 1024 * 1024
|
|
23
|
+
const PING_INTERVAL_MS = 60_000
|
|
24
|
+
const IDLE_THRESHOLD_MS = 45_000
|
|
25
|
+
const PURPLE_TENUE = "\x1b[38;5;183m"
|
|
26
|
+
const PURPLE_RESET = "\x1b[0m"
|
|
23
27
|
|
|
24
28
|
const STATES = Object.freeze({
|
|
25
29
|
INTERPRETATION_PENDING: "INTERPRETATION_PENDING",
|
|
@@ -254,6 +258,9 @@ function isCodegraphAvailable(directory: string): boolean {
|
|
|
254
258
|
const trivialBySession = new Map<string, boolean>()
|
|
255
259
|
// Track discovery hit per requestId to avoid blocking after hit
|
|
256
260
|
const discoveryHitByRequest = new Map<string, boolean>()
|
|
261
|
+
// ─── Heartbeat ping — evita sensación de trancado en tareas largas ──
|
|
262
|
+
let lastPingTs = 0
|
|
263
|
+
let pingInterval: ReturnType<typeof setInterval> | null = null
|
|
257
264
|
|
|
258
265
|
// ─── Plugin ──────────────────────────────────────────────────────────────────
|
|
259
266
|
|
|
@@ -267,6 +274,30 @@ export const OstackyController: Plugin = async (ctx) => {
|
|
|
267
274
|
let lastCheck: { revision: number; result: string } | null = null
|
|
268
275
|
let checkCount = 0
|
|
269
276
|
|
|
277
|
+
// Heartbeat ping — purple tenue, evita sensación de trancado en tareas largas
|
|
278
|
+
if (!pingInterval) {
|
|
279
|
+
pingInterval = setInterval(async () => {
|
|
280
|
+
try {
|
|
281
|
+
const s = readState(ctx.directory)
|
|
282
|
+
if (!s || !["EXECUTING_INLINE", "EXECUTING_SUBAGENTS", "SYNC"].includes(s.state)) return
|
|
283
|
+
const now = Date.now()
|
|
284
|
+
const lastHeartbeat = s.lastHeartbeat || s.ts || now
|
|
285
|
+
const idle = now - lastHeartbeat
|
|
286
|
+
if (idle < IDLE_THRESHOLD_MS) return
|
|
287
|
+
if (now - lastPingTs < PING_INTERVAL_MS) return
|
|
288
|
+
lastPingTs = now
|
|
289
|
+
const completed = Object.values(s.tasks || {}).filter((t: any) => t.status === "COMPLETED").length
|
|
290
|
+
const total = s.expectedTaskCount ?? s.expectedTasks?.length ?? "?"
|
|
291
|
+
const pending = Array.isArray(s.expectedTasks) ? s.expectedTasks.filter((id: string) => !s.tasks?.[id] || s.tasks[id].status !== "COMPLETED").length : "?"
|
|
292
|
+
const msg = `🟣 ${PURPLE_TENUE}[OSTACKY]${PURPLE_RESET} ⏳ Sigo trabajando — ${s.state} • ${completed}/${total} (${pending} pendientes) • hace ${Math.round(idle/1000)}s sin output`
|
|
293
|
+
try { await (ctx as any).client?.tui?.showToast?.({ body: { message: msg, variant: "info" } } as any) } catch {}
|
|
294
|
+
try { await (ctx as any).client?.app?.log?.({ body: { service: "ostacky-ping", level: "info", message: msg } } as any) } catch {}
|
|
295
|
+
try { const st = readState(ctx.directory); if (st) { (st as any).lastPingTs = now; persistState(ctx.directory, st) } } catch {}
|
|
296
|
+
} catch {}
|
|
297
|
+
}, 30_000)
|
|
298
|
+
if (pingInterval && typeof (pingInterval as any).unref === 'function') (pingInterval as any).unref()
|
|
299
|
+
}
|
|
300
|
+
|
|
270
301
|
return {
|
|
271
302
|
// ── Tiered: suffix hint on user message (cache-friendly, no system replace) ──
|
|
272
303
|
"chat.message": async (input: any, output: any) => {
|
|
@@ -527,6 +558,18 @@ export const OstackyController: Plugin = async (ctx) => {
|
|
|
527
558
|
const s = readState((input as any).ctx?.directory ?? "")
|
|
528
559
|
} catch {}
|
|
529
560
|
}
|
|
561
|
+
// Heartbeat + color purple tenue: Ostacky vs modelo (fácil)
|
|
562
|
+
try {
|
|
563
|
+
const dir = ctx.directory
|
|
564
|
+
const s = readState(dir)
|
|
565
|
+
if (s) {
|
|
566
|
+
s.lastHeartbeat = Date.now()
|
|
567
|
+
try { persistState(dir, s) } catch {}
|
|
568
|
+
if (["EXECUTING_INLINE", "EXECUTING_SUBAGENTS", "SYNC"].includes(s.state) && output && typeof output.title === "string" && output.title && !output.title.includes("🟣")) {
|
|
569
|
+
output.title = `🟣 ${PURPLE_TENUE}[OSTACKY]${PURPLE_RESET} ${output.title}`
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
} catch {}
|
|
530
573
|
},
|
|
531
574
|
|
|
532
575
|
// ── Observable tools (MCP thin replacement) ──
|
|
@@ -622,6 +665,11 @@ export const OstackyController: Plugin = async (ctx) => {
|
|
|
622
665
|
}
|
|
623
666
|
},
|
|
624
667
|
|
|
668
|
+
dispose: async () => {
|
|
669
|
+
try { if (pingInterval) clearInterval(pingInterval) } catch {}
|
|
670
|
+
pingInterval = null
|
|
671
|
+
},
|
|
672
|
+
|
|
625
673
|
"experimental.session.compacting": async (input: any, output: any) => {
|
|
626
674
|
try {
|
|
627
675
|
const statePath = getStatePath(ctx.directory)
|
package/dist/cli.js
CHANGED
|
@@ -744,31 +744,31 @@ var init_fs = __esm(() => {
|
|
|
744
744
|
var manifest_default;
|
|
745
745
|
var init_manifest = __esm(() => {
|
|
746
746
|
manifest_default = {
|
|
747
|
-
version: "0.8.
|
|
747
|
+
version: "0.8.1",
|
|
748
748
|
repo: "JaimeHoracio/Ostacky",
|
|
749
|
-
tag: "v0.8.
|
|
749
|
+
tag: "v0.8.1",
|
|
750
750
|
agents: [
|
|
751
751
|
{
|
|
752
752
|
name: "ostacky",
|
|
753
753
|
file: "assets/agents/ostacky.md",
|
|
754
|
-
description: "Orquestador con recuperación automática (nunca se congela), ruteo por nivel de impacto, controller MCP con SDK oficial, edición segura con fallback inline, y delegación en OpenSpec + Superpowers. v0.8.
|
|
755
|
-
version: "0.8.
|
|
756
|
-
sha256: "
|
|
754
|
+
description: "Orquestador con recuperación automática (nunca se congela), ruteo por nivel de impacto, controller MCP con SDK oficial, edición segura con fallback inline, y delegación en OpenSpec + Superpowers. v0.8.1: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
|
|
755
|
+
version: "0.8.1",
|
|
756
|
+
sha256: "1dea56ffe3866e830c5138b44ff3e7531324ddd2784b1d34a8956614a53c5ec9"
|
|
757
757
|
}
|
|
758
758
|
],
|
|
759
759
|
commands: [
|
|
760
760
|
{
|
|
761
761
|
name: "install-stack",
|
|
762
762
|
file: "assets/commands/install-stack.md",
|
|
763
|
-
description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.8.
|
|
764
|
-
version: "0.8.
|
|
765
|
-
sha256: "
|
|
763
|
+
description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.8.1: controller plugin como alma hard-gate, Context7 removido del stack.",
|
|
764
|
+
version: "0.8.1",
|
|
765
|
+
sha256: "43ad96a63ceab8730cf0459838e7fad2953333307cfc664a849ca39f7ba7d532"
|
|
766
766
|
},
|
|
767
767
|
{
|
|
768
768
|
name: "opsx-sync",
|
|
769
769
|
file: "assets/commands/opsx-sync.md",
|
|
770
770
|
description: "Sincroniza delta specs del change activo sin inicializar CodeGraph si ya existe índice",
|
|
771
|
-
version: "0.8.
|
|
771
|
+
version: "0.8.1",
|
|
772
772
|
sha256: "fe0158478f2ca63b315037a85fc1632b77868532e319af6c7384285441767d64"
|
|
773
773
|
}
|
|
774
774
|
],
|
|
@@ -776,15 +776,15 @@ var init_manifest = __esm(() => {
|
|
|
776
776
|
{
|
|
777
777
|
name: "ostacky-controller",
|
|
778
778
|
file: "assets/mcp/ostacky-controller/",
|
|
779
|
-
description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.8.
|
|
780
|
-
version: "0.8.
|
|
781
|
-
sha256: "
|
|
779
|
+
description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.8.1: 22 tools (incluye set_handoff, get_handoff, clear_handoff, get_available_transitions funcional). Bugfixes: consecutiveFailures real, lastHandoff state, defaultChoice persistido. Robustez: degraded mode automático tras 3 fallos, persistence condicional para Nivel 0, prune de skills obsoletas.",
|
|
780
|
+
version: "0.8.1",
|
|
781
|
+
sha256: "ec554bc97f9d9b1e64c0b42813547dedc923e86e326c43ae87afab88ba249b90"
|
|
782
782
|
},
|
|
783
783
|
{
|
|
784
784
|
name: "openspec",
|
|
785
785
|
file: "assets/mcp/openspec/",
|
|
786
786
|
description: "MCP server local para OpenSpec - proposal, apply, archive, sync de cambios",
|
|
787
|
-
version: "0.8.
|
|
787
|
+
version: "0.8.1",
|
|
788
788
|
sha256: "fa4be28bfc1e75db8f1a037e2580f04a60066c80e8e5934e90e1041020d04609"
|
|
789
789
|
}
|
|
790
790
|
],
|
|
@@ -793,105 +793,105 @@ var init_manifest = __esm(() => {
|
|
|
793
793
|
name: "brainstorming",
|
|
794
794
|
file: "assets/skills/brainstorming/SKILL.md",
|
|
795
795
|
description: "Skill unificado de pensamiento con dos modos: creative-design (producción de diseño → transición a implementación directa o openspec-propose) y open-exploration (exploración libre)",
|
|
796
|
-
version: "0.8.
|
|
796
|
+
version: "0.8.1",
|
|
797
797
|
sha256: "87f8d6ed28205f9272792d3865d8cd3232ab5e511a604d6d63d41e3a02a5f422"
|
|
798
798
|
},
|
|
799
799
|
{
|
|
800
800
|
name: "execution-mode-evaluation",
|
|
801
801
|
file: "assets/skills/execution-mode-evaluation/SKILL.md",
|
|
802
802
|
description: "Skill de análisis de modo de ejecución — output reconciliado con controller snapshot contract (recommendation field)",
|
|
803
|
-
version: "0.8.
|
|
803
|
+
version: "0.8.1",
|
|
804
804
|
sha256: "7b89dda29927c88f1eb13ffcea541a12423384c172f66c4f3d9b61efe0c7a163"
|
|
805
805
|
},
|
|
806
806
|
{
|
|
807
807
|
name: "tdd",
|
|
808
808
|
file: "assets/skills/tdd/SKILL.md",
|
|
809
809
|
description: "Skill de test-driven development (Superpowers)",
|
|
810
|
-
version: "0.8.
|
|
810
|
+
version: "0.8.1",
|
|
811
811
|
sha256: "aa412298980b7826165c211145c1b8e9135f68f36247bb3cb96d0a0eae274486"
|
|
812
812
|
},
|
|
813
813
|
{
|
|
814
814
|
name: "subagent-driven-development",
|
|
815
815
|
file: "assets/skills/subagent-driven-development/SKILL.md",
|
|
816
816
|
description: "Skill de ejecución con subagentes (Superpowers) — ejecuta solo después de confirmación del coordinador Ostacky",
|
|
817
|
-
version: "0.8.
|
|
817
|
+
version: "0.8.1",
|
|
818
818
|
sha256: "1a42d714a9a13faf05f0bf7b580e8d837c2e77a5633839542ccce603023419e8"
|
|
819
819
|
},
|
|
820
820
|
{
|
|
821
821
|
name: "dispatching-parallel-agents",
|
|
822
822
|
file: "assets/skills/dispatching-parallel-agents/SKILL.md",
|
|
823
823
|
description: "Skill de dispatch paralelo de agentes (Superpowers)",
|
|
824
|
-
version: "0.8.
|
|
824
|
+
version: "0.8.1",
|
|
825
825
|
sha256: "3c8a66d51ae2e719e877d02c3dac32bd804722c3bb9227c258ecae78252a20ab"
|
|
826
826
|
},
|
|
827
827
|
{
|
|
828
828
|
name: "review",
|
|
829
829
|
file: "assets/skills/review/SKILL.md",
|
|
830
830
|
description: "Skill de revisión de código (Superpowers)",
|
|
831
|
-
version: "0.8.
|
|
831
|
+
version: "0.8.1",
|
|
832
832
|
sha256: "b19650ed4d1d4d9857a4dd5b7e08e91328a1a1fc9c45bcc2fb600fa9d0213279"
|
|
833
833
|
},
|
|
834
834
|
{
|
|
835
835
|
name: "receiving-code-review",
|
|
836
836
|
file: "assets/skills/receiving-code-review/SKILL.md",
|
|
837
837
|
description: "Skill de recibir y procesar feedback de code review",
|
|
838
|
-
version: "0.8.
|
|
838
|
+
version: "0.8.1",
|
|
839
839
|
sha256: "d761e884e71d8d3476ac734d287cae403a4024506a7d12e7361a448217c0a831"
|
|
840
840
|
},
|
|
841
841
|
{
|
|
842
842
|
name: "openspec-propose",
|
|
843
843
|
file: "assets/skills/openspec-propose/SKILL.md",
|
|
844
844
|
description: "Skill de generación de proposal (OpenSpec)",
|
|
845
|
-
version: "0.8.
|
|
845
|
+
version: "0.8.1",
|
|
846
846
|
sha256: "bb59100b9fd3c9f9a1ec6509fa975ec55bf7fc737df4fe73bb3e9bbc217b83f7"
|
|
847
847
|
},
|
|
848
848
|
{
|
|
849
849
|
name: "openspec-apply-change",
|
|
850
850
|
file: "assets/skills/openspec-apply-change/SKILL.md",
|
|
851
851
|
description: "Skill de aplicación de change (OpenSpec)",
|
|
852
|
-
version: "0.8.
|
|
852
|
+
version: "0.8.1",
|
|
853
853
|
sha256: "dfc823bf89fc7505e91ab6dee9c1f004be38a410bd3d88fb67b211b1b6cbb1d0"
|
|
854
854
|
},
|
|
855
855
|
{
|
|
856
856
|
name: "openspec-archive-change",
|
|
857
857
|
file: "assets/skills/openspec-archive-change/SKILL.md",
|
|
858
858
|
description: "Skill de archivo de change (OpenSpec)",
|
|
859
|
-
version: "0.8.
|
|
859
|
+
version: "0.8.1",
|
|
860
860
|
sha256: "16e4b561de7747283663fed602e506abf502452c49a8d4b86d7a5539c40f0195"
|
|
861
861
|
},
|
|
862
862
|
{
|
|
863
863
|
name: "openspec-explore",
|
|
864
864
|
file: "assets/skills/openspec-explore/SKILL.md",
|
|
865
865
|
description: "Modo explore para OpenSpec — thinking partner para explorar ideas, investigar problemas y clarificar requisitos antes/durante un cambio",
|
|
866
|
-
version: "0.8.
|
|
866
|
+
version: "0.8.1",
|
|
867
867
|
sha256: "37ae4aaf17ea71a395bab6dc4d9d61b9a49d7910f6692535ae8553244c46880b"
|
|
868
868
|
},
|
|
869
869
|
{
|
|
870
870
|
name: "using-git-worktrees",
|
|
871
871
|
file: "assets/skills/using-git-worktrees/SKILL.md",
|
|
872
872
|
description: "Skill de uso de git worktrees para aislamiento de trabajo",
|
|
873
|
-
version: "0.8.
|
|
873
|
+
version: "0.8.1",
|
|
874
874
|
sha256: "93341bc1b7c053618a8b6dc07e3615b77990d7b549a0201f5835d95fef67ce13"
|
|
875
875
|
},
|
|
876
876
|
{
|
|
877
877
|
name: "using-superpowers",
|
|
878
878
|
file: "assets/skills/using-superpowers/SKILL.md",
|
|
879
879
|
description: "Skill de orquestación de Superpowers skills",
|
|
880
|
-
version: "0.8.
|
|
880
|
+
version: "0.8.1",
|
|
881
881
|
sha256: "7e54536f96d2a379185a10bfc1e970850caa2561b6d8aca7080f0defea0381a4"
|
|
882
882
|
},
|
|
883
883
|
{
|
|
884
884
|
name: "writing-skills",
|
|
885
885
|
file: "assets/skills/writing-skills/SKILL.md",
|
|
886
886
|
description: "Skill de creación y edición de skills",
|
|
887
|
-
version: "0.8.
|
|
887
|
+
version: "0.8.1",
|
|
888
888
|
sha256: "3d76b906cee518a2b809febb70db95697a35b9f368986bb504b4120c3bfb437a"
|
|
889
889
|
},
|
|
890
890
|
{
|
|
891
891
|
name: "graceful-degradation",
|
|
892
892
|
file: "assets/skills/graceful-degradation/SKILL.md",
|
|
893
893
|
description: "Skill de degradación graceful cuando múltiples tools están indisponibles",
|
|
894
|
-
version: "0.8.
|
|
894
|
+
version: "0.8.1",
|
|
895
895
|
sha256: "40f929e8032b70d51b3548bddcc383b931d6044fd9d4acce8a5b9f7acd014f59"
|
|
896
896
|
}
|
|
897
897
|
]
|
|
@@ -1691,7 +1691,7 @@ var init_stack = __esm(() => {
|
|
|
1691
1691
|
// package.json
|
|
1692
1692
|
var package_default = {
|
|
1693
1693
|
name: "ostacky",
|
|
1694
|
-
version: "0.8.
|
|
1694
|
+
version: "0.8.1",
|
|
1695
1695
|
description: "Instalador interactivo de agentes y comandos para OpenCode",
|
|
1696
1696
|
type: "module",
|
|
1697
1697
|
bin: {
|
|
@@ -2866,7 +2866,7 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath, option
|
|
|
2866
2866
|
params: {
|
|
2867
2867
|
protocolVersion: "2025-03-26",
|
|
2868
2868
|
capabilities: {},
|
|
2869
|
-
clientInfo: { name: "ostacky-installer", version: "0.8.
|
|
2869
|
+
clientInfo: { name: "ostacky-installer", version: "0.8.1" }
|
|
2870
2870
|
}
|
|
2871
2871
|
});
|
|
2872
2872
|
});
|
|
@@ -3175,12 +3175,13 @@ function uninstallAll(paths) {
|
|
|
3175
3175
|
for (const name of Object.keys(lockfile.mcpServers ?? {})) {
|
|
3176
3176
|
uninstallMcpServer(name, paths);
|
|
3177
3177
|
}
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3178
|
+
const ostackyPlugins = ["ostacky-plugin.ts", "engram.ts", "ostacky-guard.ts", "ostacky-controller.ts"];
|
|
3179
|
+
for (const file of ostackyPlugins) {
|
|
3180
|
+
const fp = join6(paths.plugins, file);
|
|
3181
|
+
if (existsSync5(fp)) {
|
|
3182
|
+
try {
|
|
3183
|
+
unlinkSync2(fp);
|
|
3184
|
+
} catch {}
|
|
3184
3185
|
}
|
|
3185
3186
|
}
|
|
3186
3187
|
clearLockfile(paths.root);
|
|
@@ -3446,7 +3447,7 @@ async function doInstallAll(manifest, paths) {
|
|
|
3446
3447
|
}
|
|
3447
3448
|
}
|
|
3448
3449
|
try {
|
|
3449
|
-
const { copyFileSync: copyFileSync4, mkdirSync: mkdirSync5, existsSync: existsSync8 } = await import("fs");
|
|
3450
|
+
const { copyFileSync: copyFileSync4, mkdirSync: mkdirSync5, existsSync: existsSync8, rmSync: rmSync5 } = await import("fs");
|
|
3450
3451
|
const { join: join9 } = await import("path");
|
|
3451
3452
|
const { PACKAGE_ROOT: PACKAGE_ROOT2 } = await Promise.resolve().then(() => (init_github(), exports_github));
|
|
3452
3453
|
const { findProjectRoot: findProjectRoot3 } = await Promise.resolve().then(() => (init_fs(), exports_fs));
|
|
@@ -3456,10 +3457,12 @@ async function doInstallAll(manifest, paths) {
|
|
|
3456
3457
|
mkdirSync5(paths.plugins, { recursive: true });
|
|
3457
3458
|
copyFileSync4(src, dest);
|
|
3458
3459
|
}
|
|
3459
|
-
const
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3460
|
+
for (const legacy of ["ostacky-guard.ts", "ostacky-controller.ts"]) {
|
|
3461
|
+
const lp = join9(paths.plugins, legacy);
|
|
3462
|
+
if (existsSync8(lp))
|
|
3463
|
+
try {
|
|
3464
|
+
rmSync5(lp, { force: true });
|
|
3465
|
+
} catch {}
|
|
3463
3466
|
}
|
|
3464
3467
|
const srcEng = join9(PACKAGE_ROOT2, "assets", "plugins", "engram.ts");
|
|
3465
3468
|
const destEng = join9(paths.plugins, "engram.ts");
|
|
@@ -3474,10 +3477,15 @@ async function doInstallAll(manifest, paths) {
|
|
|
3474
3477
|
mkdirSync5(localPlugins, { recursive: true });
|
|
3475
3478
|
if (existsSync8(src))
|
|
3476
3479
|
copyFileSync4(src, join9(localPlugins, "ostacky-plugin.ts"));
|
|
3477
|
-
else if (existsSync8(legacySrc))
|
|
3478
|
-
copyFileSync4(legacySrc, join9(localPlugins, "ostacky-controller.ts"));
|
|
3479
3480
|
if (existsSync8(srcEng))
|
|
3480
3481
|
copyFileSync4(srcEng, join9(localPlugins, "engram.ts"));
|
|
3482
|
+
for (const legacy of ["ostacky-guard.ts", "ostacky-controller.ts"]) {
|
|
3483
|
+
const lp = join9(localPlugins, legacy);
|
|
3484
|
+
if (existsSync8(lp))
|
|
3485
|
+
try {
|
|
3486
|
+
rmSync5(lp, { force: true });
|
|
3487
|
+
} catch {}
|
|
3488
|
+
}
|
|
3481
3489
|
} catch {}
|
|
3482
3490
|
}
|
|
3483
3491
|
} catch {}
|
|
@@ -3718,10 +3726,10 @@ async function doUninstallTotal(paths) {
|
|
|
3718
3726
|
for (const name of Object.keys(lockfile.mcpServers ?? {})) {
|
|
3719
3727
|
pathsToDelete.push(join9(paths.mcp, name));
|
|
3720
3728
|
}
|
|
3721
|
-
ye(pathsToDelete.join(`
|
|
3722
|
-
`), `Se eliminarán ${pathsToDelete.length}
|
|
3729
|
+
ye([`Scope: ${paths.root}`, ...pathsToDelete].join(`
|
|
3730
|
+
`), `Se eliminarán ${pathsToDelete.length} item(s) trackeados en lockfile (safe-delete)`);
|
|
3723
3731
|
const confirm = await me({
|
|
3724
|
-
message: `¿Confirmar desinstalación de ${pathsToDelete.length} item(s)?`
|
|
3732
|
+
message: `¿Confirmar desinstalación de ${pathsToDelete.length} item(s) en ${paths.root}?`
|
|
3725
3733
|
});
|
|
3726
3734
|
onCancel(confirm);
|
|
3727
3735
|
if (!confirm) {
|
|
@@ -3729,7 +3737,7 @@ async function doUninstallTotal(paths) {
|
|
|
3729
3737
|
return;
|
|
3730
3738
|
}
|
|
3731
3739
|
uninstallAll(paths);
|
|
3732
|
-
v2.success(`${pathsToDelete.length} item(s) eliminado(s).`);
|
|
3740
|
+
v2.success(`${pathsToDelete.length} item(s) eliminado(s) + plugins Ostacky-owned limpiados.`);
|
|
3733
3741
|
const cleanEngram = await me({
|
|
3734
3742
|
message: "¿Deseas remover la configuración de Engram del proyecto (mcp.engram)?"
|
|
3735
3743
|
});
|
|
@@ -4010,9 +4018,122 @@ async function doUninstallMcpByName(name, paths) {
|
|
|
4010
4018
|
}
|
|
4011
4019
|
}
|
|
4012
4020
|
|
|
4021
|
+
// src/opencode.ts
|
|
4022
|
+
init_fs();
|
|
4023
|
+
import { execSync, execFileSync as execFileSync4 } from "node:child_process";
|
|
4024
|
+
function isOpencodeInstalled() {
|
|
4025
|
+
if (isCommandAvailable("opencode"))
|
|
4026
|
+
return true;
|
|
4027
|
+
try {
|
|
4028
|
+
execFileSync4("opencode", ["--version"], { stdio: "ignore" });
|
|
4029
|
+
return true;
|
|
4030
|
+
} catch {
|
|
4031
|
+
return false;
|
|
4032
|
+
}
|
|
4033
|
+
}
|
|
4034
|
+
function getOpencodeInstallCommand(platform = process.platform, _arch = process.arch) {
|
|
4035
|
+
if (platform === "win32") {
|
|
4036
|
+
return {
|
|
4037
|
+
display: "npm install -g opencode-ai",
|
|
4038
|
+
command: "npm",
|
|
4039
|
+
args: ["install", "-g", "opencode-ai"],
|
|
4040
|
+
note: "Alternativas Windows: choco install opencode | scoop install opencode | mise use -g github:anomalyco/opencode (ver https://opencode.ai/download). WSL recomendado."
|
|
4041
|
+
};
|
|
4042
|
+
}
|
|
4043
|
+
if (platform === "darwin") {
|
|
4044
|
+
return {
|
|
4045
|
+
display: "curl -fsSL https://opencode.ai/install | bash",
|
|
4046
|
+
command: "bash",
|
|
4047
|
+
args: ["-c", "curl -fsSL https://opencode.ai/install | bash"],
|
|
4048
|
+
note: "Alternativa macOS: brew install anomalyco/tap/opencode (tap oficial, más actualizado que brew install opencode)"
|
|
4049
|
+
};
|
|
4050
|
+
}
|
|
4051
|
+
return {
|
|
4052
|
+
display: "curl -fsSL https://opencode.ai/install | bash",
|
|
4053
|
+
command: "bash",
|
|
4054
|
+
args: ["-c", "curl -fsSL https://opencode.ai/install | bash"],
|
|
4055
|
+
note: "Alternativas Linux: npm install -g opencode-ai | bun add -g opencode-ai | brew install anomalyco/tap/opencode | paru -S opencode (Arch)"
|
|
4056
|
+
};
|
|
4057
|
+
}
|
|
4058
|
+
async function ensureOpencodeInstalled() {
|
|
4059
|
+
if (isOpencodeInstalled())
|
|
4060
|
+
return;
|
|
4061
|
+
const platform = process.platform;
|
|
4062
|
+
const info = getOpencodeInstallCommand(platform);
|
|
4063
|
+
v2.warn("OpenCode no detectado en este sistema.");
|
|
4064
|
+
ye(`${info.display}
|
|
4065
|
+
Docs: https://opencode.ai/download${info.note ? `
|
|
4066
|
+
${info.note}` : ""}`, `Instalación requerida (${platform})`);
|
|
4067
|
+
const shouldInstall = await me({
|
|
4068
|
+
message: "Ostacky no funciona sin OpenCode. ¿Querés instalar OpenCode ahora?",
|
|
4069
|
+
initialValue: true
|
|
4070
|
+
});
|
|
4071
|
+
if (BD(shouldInstall) || !shouldInstall) {
|
|
4072
|
+
fe("Instalación cancelada. Instalá OpenCode manualmente y volvé a ejecutar: https://opencode.ai/download");
|
|
4073
|
+
process.exit(1);
|
|
4074
|
+
}
|
|
4075
|
+
const spin = L2();
|
|
4076
|
+
spin.start(`Instalando OpenCode (${info.display})...`);
|
|
4077
|
+
try {
|
|
4078
|
+
if (platform === "win32") {
|
|
4079
|
+
execSync("npm install -g opencode-ai", { stdio: "inherit", shell: "cmd.exe" });
|
|
4080
|
+
} else {
|
|
4081
|
+
if (!isCommandAvailable("curl")) {
|
|
4082
|
+
spin.stop("curl no disponible");
|
|
4083
|
+
v2.warn("curl no está instalado — se intentará con npm como fallback.");
|
|
4084
|
+
execSync("npm install -g opencode-ai", { stdio: "inherit", shell: "/bin/bash" });
|
|
4085
|
+
} else {
|
|
4086
|
+
execSync("curl -fsSL https://opencode.ai/install | bash", { stdio: "inherit", shell: "/bin/bash" });
|
|
4087
|
+
}
|
|
4088
|
+
}
|
|
4089
|
+
spin.stop("Instalación ejecutada, verificando...");
|
|
4090
|
+
} catch (e2) {
|
|
4091
|
+
spin.stop("Fallo la instalación automática.");
|
|
4092
|
+
const msg = e2.message ?? String(e2);
|
|
4093
|
+
v2.error(`No se pudo instalar OpenCode automáticamente: ${msg}`);
|
|
4094
|
+
if (platform === "win32") {
|
|
4095
|
+
ye([
|
|
4096
|
+
"Intentá manualmente una de estas opciones:",
|
|
4097
|
+
" npm install -g opencode-ai",
|
|
4098
|
+
" choco install opencode",
|
|
4099
|
+
" scoop install opencode",
|
|
4100
|
+
" (WSL) curl -fsSL https://opencode.ai/install | bash",
|
|
4101
|
+
"Luego verificá: opencode --version",
|
|
4102
|
+
"Docs: https://opencode.ai/download"
|
|
4103
|
+
].join(`
|
|
4104
|
+
`), "Acción manual requerida");
|
|
4105
|
+
} else {
|
|
4106
|
+
ye([
|
|
4107
|
+
"Intentá manualmente:",
|
|
4108
|
+
` ${info.display}`,
|
|
4109
|
+
" npm install -g opencode-ai (si no tenés curl)",
|
|
4110
|
+
" brew install anomalyco/tap/opencode (macOS/Linux con brew)",
|
|
4111
|
+
"Luego verificá: opencode --version",
|
|
4112
|
+
"Docs: https://opencode.ai/download"
|
|
4113
|
+
].join(`
|
|
4114
|
+
`), "Acción manual requerida");
|
|
4115
|
+
}
|
|
4116
|
+
process.exit(1);
|
|
4117
|
+
}
|
|
4118
|
+
if (!isOpencodeInstalled()) {
|
|
4119
|
+
v2.error("OpenCode aún no está disponible en el PATH después de la instalación.");
|
|
4120
|
+
ye([
|
|
4121
|
+
"Probá cerrar y reabrir la terminal y ejecutar:",
|
|
4122
|
+
" opencode --version",
|
|
4123
|
+
"Si persiste, instalá manualmente:",
|
|
4124
|
+
` ${info.display}`,
|
|
4125
|
+
"Docs: https://opencode.ai/download"
|
|
4126
|
+
].join(`
|
|
4127
|
+
`), "Verificación falló");
|
|
4128
|
+
process.exit(1);
|
|
4129
|
+
}
|
|
4130
|
+
v2.success("OpenCode instalado correctamente ✓");
|
|
4131
|
+
}
|
|
4132
|
+
|
|
4013
4133
|
// src/prompts/index.ts
|
|
4014
4134
|
async function runInteractiveMenu(scope) {
|
|
4015
4135
|
we(" OpenCode Installer ");
|
|
4136
|
+
await ensureOpencodeInstalled();
|
|
4016
4137
|
const manifest = await loadManifest();
|
|
4017
4138
|
const paths = await resolveOpenCodePaths(scope ?? null);
|
|
4018
4139
|
if (!paths) {
|
|
@@ -4092,6 +4213,7 @@ async function runInteractiveMenu(scope) {
|
|
|
4092
4213
|
}
|
|
4093
4214
|
async function runInstallCommand(scope) {
|
|
4094
4215
|
we(" OpenCode Installer ");
|
|
4216
|
+
await ensureOpencodeInstalled();
|
|
4095
4217
|
const manifest = await loadManifest();
|
|
4096
4218
|
const paths = await resolveOpenCodePaths(scope ?? null);
|
|
4097
4219
|
if (!paths) {
|
|
@@ -4105,6 +4227,7 @@ async function runInstallCommand(scope) {
|
|
|
4105
4227
|
}
|
|
4106
4228
|
async function runAddAgentCommand(scope) {
|
|
4107
4229
|
we(" OpenCode Installer ");
|
|
4230
|
+
await ensureOpencodeInstalled();
|
|
4108
4231
|
const manifest = await loadManifest();
|
|
4109
4232
|
const paths = await resolveOpenCodePaths(scope ?? null);
|
|
4110
4233
|
if (!paths) {
|
|
@@ -4117,6 +4240,7 @@ async function runAddAgentCommand(scope) {
|
|
|
4117
4240
|
}
|
|
4118
4241
|
async function runAddCommandCommand(scope) {
|
|
4119
4242
|
we(" OpenCode Installer ");
|
|
4243
|
+
await ensureOpencodeInstalled();
|
|
4120
4244
|
const manifest = await loadManifest();
|
|
4121
4245
|
const paths = await resolveOpenCodePaths(scope ?? null);
|
|
4122
4246
|
if (!paths) {
|
|
@@ -4129,6 +4253,7 @@ async function runAddCommandCommand(scope) {
|
|
|
4129
4253
|
}
|
|
4130
4254
|
async function runAddSkillCommand(scope) {
|
|
4131
4255
|
we(" OpenCode Installer ");
|
|
4256
|
+
await ensureOpencodeInstalled();
|
|
4132
4257
|
const manifest = await loadManifest();
|
|
4133
4258
|
const paths = await resolveOpenCodePaths(scope ?? null);
|
|
4134
4259
|
if (!paths) {
|
|
@@ -4141,6 +4266,7 @@ async function runAddSkillCommand(scope) {
|
|
|
4141
4266
|
}
|
|
4142
4267
|
async function runAddMcpCommand(scope) {
|
|
4143
4268
|
we(" OpenCode Installer ");
|
|
4269
|
+
await ensureOpencodeInstalled();
|
|
4144
4270
|
const manifest = await loadManifest();
|
|
4145
4271
|
const paths = await resolveOpenCodePaths(scope ?? null);
|
|
4146
4272
|
if (!paths) {
|
|
@@ -4152,6 +4278,7 @@ async function runAddMcpCommand(scope) {
|
|
|
4152
4278
|
fe("Listo.");
|
|
4153
4279
|
}
|
|
4154
4280
|
async function runInstallStackCommand(scope) {
|
|
4281
|
+
await ensureOpencodeInstalled();
|
|
4155
4282
|
if (scope === "global") {
|
|
4156
4283
|
v2.error("install-stack requiere scope local; el stack vive en <proyecto>/.opencode/tools");
|
|
4157
4284
|
fe("Usá: npx ostacky install-stack --scope local");
|
|
@@ -4203,6 +4330,7 @@ async function runUninstallStackCommand(scope) {
|
|
|
4203
4330
|
}
|
|
4204
4331
|
async function runUpdateCommand(scope) {
|
|
4205
4332
|
we(" OpenCode Installer ");
|
|
4333
|
+
await ensureOpencodeInstalled();
|
|
4206
4334
|
const manifest = await loadLatestManifest();
|
|
4207
4335
|
const paths = await resolveOpenCodePaths(scope ?? null);
|
|
4208
4336
|
if (!paths) {
|
|
@@ -4366,7 +4494,7 @@ async function runUninstallMcpCommand(name, scope) {
|
|
|
4366
4494
|
// src/cli.ts
|
|
4367
4495
|
init_fs();
|
|
4368
4496
|
import { existsSync as existsSync8, statSync as statSync3, readFileSync as readFileSync6, readdirSync as readdirSync3 } from "node:fs";
|
|
4369
|
-
import { join as
|
|
4497
|
+
import { join as join10, dirname as dirname8 } from "node:path";
|
|
4370
4498
|
var HELP = `
|
|
4371
4499
|
ostacky — Instalador de agentes, comandos, skills y MCPs para OpenCode
|
|
4372
4500
|
|
|
@@ -4431,8 +4559,8 @@ var argvNoScope = withoutScopeArgs(process.argv);
|
|
|
4431
4559
|
var [, , cmd, subcmd] = argvNoScope;
|
|
4432
4560
|
async function runDoctorCommand() {
|
|
4433
4561
|
const cwd = process.cwd();
|
|
4434
|
-
const opencodeDir = findOpenCodeDir(cwd) ||
|
|
4435
|
-
const statePath =
|
|
4562
|
+
const opencodeDir = findOpenCodeDir(cwd) || join10(cwd, ".opencode");
|
|
4563
|
+
const statePath = join10(opencodeDir, "ostacky-state.json");
|
|
4436
4564
|
let hasError = false;
|
|
4437
4565
|
let hasWarn = false;
|
|
4438
4566
|
const check = (label, ok, warn = false) => {
|
|
@@ -4447,12 +4575,12 @@ async function runDoctorCommand() {
|
|
|
4447
4575
|
}
|
|
4448
4576
|
};
|
|
4449
4577
|
const pluginPaths = [
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4578
|
+
join10(cwd, "assets", "plugins", "ostacky-plugin.ts"),
|
|
4579
|
+
join10(opencodeDir, "plugins", "ostacky-plugin.ts"),
|
|
4580
|
+
join10(cwd, ".opencode", "plugins", "ostacky-plugin.ts"),
|
|
4581
|
+
join10(cwd, "assets", "plugins", "ostacky-controller.ts"),
|
|
4582
|
+
join10(opencodeDir, "plugins", "ostacky-controller.ts"),
|
|
4583
|
+
join10(cwd, ".opencode", "plugins", "ostacky-controller.ts")
|
|
4456
4584
|
];
|
|
4457
4585
|
const pluginActive = pluginPaths.some((p2) => existsSync8(p2));
|
|
4458
4586
|
try {
|
|
@@ -4525,8 +4653,8 @@ async function runDoctorCommand() {
|
|
|
4525
4653
|
check(`controller: ${e2.message}`, false);
|
|
4526
4654
|
}
|
|
4527
4655
|
try {
|
|
4528
|
-
const lockPid =
|
|
4529
|
-
const lockTs =
|
|
4656
|
+
const lockPid = join10(opencodeDir, "ostacky-state.json.lock.pid");
|
|
4657
|
+
const lockTs = join10(opencodeDir, "ostacky-state.json.lock.timestamp");
|
|
4530
4658
|
if (existsSync8(lockPid) || existsSync8(lockTs)) {
|
|
4531
4659
|
let ageStr = "";
|
|
4532
4660
|
try {
|
|
@@ -4551,15 +4679,15 @@ async function runDoctorCommand() {
|
|
|
4551
4679
|
}
|
|
4552
4680
|
const tools = ["codegraph", "engram"];
|
|
4553
4681
|
for (const t of tools) {
|
|
4554
|
-
const p2 =
|
|
4682
|
+
const p2 = join10(opencodeDir, "tools", t, "bin", t);
|
|
4555
4683
|
const pExe = p2 + ".exe";
|
|
4556
4684
|
check(`tool ${t}: ${existsSync8(p2) || existsSync8(pExe) ? "found" : "missing"}`, existsSync8(p2) || existsSync8(pExe), true);
|
|
4557
4685
|
}
|
|
4558
4686
|
try {
|
|
4559
|
-
const manifest = JSON.parse(readFileSync6(
|
|
4687
|
+
const manifest = JSON.parse(readFileSync6(join10(cwd, "manifest.json"), "utf-8"));
|
|
4560
4688
|
const expected = manifest.mcpServers?.find((x2) => x2.name === "ostacky-controller")?.sha256;
|
|
4561
4689
|
if (expected) {
|
|
4562
|
-
const actual = computeTreeHash(
|
|
4690
|
+
const actual = computeTreeHash(join10(cwd, "assets", "mcp", "ostacky-controller"));
|
|
4563
4691
|
check(`manifest hash: ${expected.slice(0, 8)} vs actual ${actual.slice(0, 8)}`, expected === actual);
|
|
4564
4692
|
if (expected !== actual)
|
|
4565
4693
|
console.log(" Run: bun run hash:update");
|
|
@@ -4574,7 +4702,7 @@ async function runDoctorCommand() {
|
|
|
4574
4702
|
} catch {}
|
|
4575
4703
|
}
|
|
4576
4704
|
try {
|
|
4577
|
-
const cacheDir =
|
|
4705
|
+
const cacheDir = join10(opencodeDir, "cache", "codegraph");
|
|
4578
4706
|
if (!existsSync8(cacheDir)) {
|
|
4579
4707
|
console.log("ℹ️ cache: no cache dir yet (ok)");
|
|
4580
4708
|
} else {
|
|
@@ -4582,7 +4710,7 @@ async function runDoctorCommand() {
|
|
|
4582
4710
|
let total = 0;
|
|
4583
4711
|
for (const f2 of files) {
|
|
4584
4712
|
try {
|
|
4585
|
-
total += statSync3(
|
|
4713
|
+
total += statSync3(join10(cacheDir, f2)).size;
|
|
4586
4714
|
} catch {}
|
|
4587
4715
|
}
|
|
4588
4716
|
const totalMB = (total / 1048576).toFixed(2);
|
|
@@ -4603,7 +4731,7 @@ async function runDoctorCommand() {
|
|
|
4603
4731
|
console.log(`⚠️ cache: check failed ${e2.message}`);
|
|
4604
4732
|
}
|
|
4605
4733
|
try {
|
|
4606
|
-
const secPath =
|
|
4734
|
+
const secPath = join10(cwd, "src", "security.ts");
|
|
4607
4735
|
if (!existsSync8(secPath)) {
|
|
4608
4736
|
console.log("⚠️ src/security.ts: missing (source-of-truth)");
|
|
4609
4737
|
hasWarn = true;
|
|
@@ -4635,8 +4763,8 @@ async function runDoctorCommand() {
|
|
|
4635
4763
|
async function runStatusCommand(args) {
|
|
4636
4764
|
const isJson = args.includes("--json");
|
|
4637
4765
|
const cwd = process.cwd();
|
|
4638
|
-
const opencodeDir = findOpenCodeDir(cwd) ||
|
|
4639
|
-
const statePath =
|
|
4766
|
+
const opencodeDir = findOpenCodeDir(cwd) || join10(cwd, ".opencode");
|
|
4767
|
+
const statePath = join10(opencodeDir, "ostacky-state.json");
|
|
4640
4768
|
if (!existsSync8(statePath)) {
|
|
4641
4769
|
console.log(isJson ? JSON.stringify({ error: "no state" }) : "No state file");
|
|
4642
4770
|
return;
|
|
@@ -4659,6 +4787,10 @@ async function runStatusCommand(args) {
|
|
|
4659
4787
|
}
|
|
4660
4788
|
}
|
|
4661
4789
|
async function main() {
|
|
4790
|
+
const needsOpencode = !cmd || cmd === "install" || cmd === "install-stack" || cmd === "update" || cmd === "add" && ["agent", "command", "skill", "mcp"].includes(subcmd ?? "");
|
|
4791
|
+
if (needsOpencode) {
|
|
4792
|
+
await ensureOpencodeInstalled();
|
|
4793
|
+
}
|
|
4662
4794
|
switch (cmd) {
|
|
4663
4795
|
case "install":
|
|
4664
4796
|
await runInstallCommand(scope);
|
package/manifest.json
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.8.
|
|
2
|
+
"version": "0.8.1",
|
|
3
3
|
"repo": "JaimeHoracio/Ostacky",
|
|
4
|
-
"tag": "v0.8.
|
|
4
|
+
"tag": "v0.8.1",
|
|
5
5
|
"agents": [
|
|
6
6
|
{
|
|
7
7
|
"name": "ostacky",
|
|
8
8
|
"file": "assets/agents/ostacky.md",
|
|
9
|
-
"description": "Orquestador con recuperación automática (nunca se congela), ruteo por nivel de impacto, controller MCP con SDK oficial, edición segura con fallback inline, y delegación en OpenSpec + Superpowers. v0.8.
|
|
10
|
-
"version": "0.8.
|
|
11
|
-
"sha256": "
|
|
9
|
+
"description": "Orquestador con recuperación automática (nunca se congela), ruteo por nivel de impacto, controller MCP con SDK oficial, edición segura con fallback inline, y delegación en OpenSpec + Superpowers. v0.8.1: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
|
|
10
|
+
"version": "0.8.1",
|
|
11
|
+
"sha256": "1dea56ffe3866e830c5138b44ff3e7531324ddd2784b1d34a8956614a53c5ec9"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
14
14
|
"commands": [
|
|
15
15
|
{
|
|
16
16
|
"name": "install-stack",
|
|
17
17
|
"file": "assets/commands/install-stack.md",
|
|
18
|
-
"description": "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.8.
|
|
19
|
-
"version": "0.8.
|
|
20
|
-
"sha256": "
|
|
18
|
+
"description": "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.8.1: controller plugin como alma hard-gate, Context7 removido del stack.",
|
|
19
|
+
"version": "0.8.1",
|
|
20
|
+
"sha256": "43ad96a63ceab8730cf0459838e7fad2953333307cfc664a849ca39f7ba7d532"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"name": "opsx-sync",
|
|
24
24
|
"file": "assets/commands/opsx-sync.md",
|
|
25
25
|
"description": "Sincroniza delta specs del change activo sin inicializar CodeGraph si ya existe índice",
|
|
26
|
-
"version": "0.8.
|
|
26
|
+
"version": "0.8.1",
|
|
27
27
|
"sha256": "fe0158478f2ca63b315037a85fc1632b77868532e319af6c7384285441767d64"
|
|
28
28
|
}
|
|
29
29
|
],
|
|
@@ -31,15 +31,15 @@
|
|
|
31
31
|
{
|
|
32
32
|
"name": "ostacky-controller",
|
|
33
33
|
"file": "assets/mcp/ostacky-controller/",
|
|
34
|
-
"description": "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.8.
|
|
35
|
-
"version": "0.8.
|
|
36
|
-
"sha256": "
|
|
34
|
+
"description": "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.8.1: 22 tools (incluye set_handoff, get_handoff, clear_handoff, get_available_transitions funcional). Bugfixes: consecutiveFailures real, lastHandoff state, defaultChoice persistido. Robustez: degraded mode automático tras 3 fallos, persistence condicional para Nivel 0, prune de skills obsoletas.",
|
|
35
|
+
"version": "0.8.1",
|
|
36
|
+
"sha256": "ec554bc97f9d9b1e64c0b42813547dedc923e86e326c43ae87afab88ba249b90"
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
"name": "openspec",
|
|
40
40
|
"file": "assets/mcp/openspec/",
|
|
41
41
|
"description": "MCP server local para OpenSpec - proposal, apply, archive, sync de cambios",
|
|
42
|
-
"version": "0.8.
|
|
42
|
+
"version": "0.8.1",
|
|
43
43
|
"sha256": "fa4be28bfc1e75db8f1a037e2580f04a60066c80e8e5934e90e1041020d04609"
|
|
44
44
|
}
|
|
45
45
|
],
|
|
@@ -48,105 +48,105 @@
|
|
|
48
48
|
"name": "brainstorming",
|
|
49
49
|
"file": "assets/skills/brainstorming/SKILL.md",
|
|
50
50
|
"description": "Skill unificado de pensamiento con dos modos: creative-design (producción de diseño → transición a implementación directa o openspec-propose) y open-exploration (exploración libre)",
|
|
51
|
-
"version": "0.8.
|
|
51
|
+
"version": "0.8.1",
|
|
52
52
|
"sha256": "87f8d6ed28205f9272792d3865d8cd3232ab5e511a604d6d63d41e3a02a5f422"
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"name": "execution-mode-evaluation",
|
|
56
56
|
"file": "assets/skills/execution-mode-evaluation/SKILL.md",
|
|
57
57
|
"description": "Skill de análisis de modo de ejecución — output reconciliado con controller snapshot contract (recommendation field)",
|
|
58
|
-
"version": "0.8.
|
|
58
|
+
"version": "0.8.1",
|
|
59
59
|
"sha256": "7b89dda29927c88f1eb13ffcea541a12423384c172f66c4f3d9b61efe0c7a163"
|
|
60
60
|
},
|
|
61
61
|
{
|
|
62
62
|
"name": "tdd",
|
|
63
63
|
"file": "assets/skills/tdd/SKILL.md",
|
|
64
64
|
"description": "Skill de test-driven development (Superpowers)",
|
|
65
|
-
"version": "0.8.
|
|
65
|
+
"version": "0.8.1",
|
|
66
66
|
"sha256": "aa412298980b7826165c211145c1b8e9135f68f36247bb3cb96d0a0eae274486"
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
"name": "subagent-driven-development",
|
|
70
70
|
"file": "assets/skills/subagent-driven-development/SKILL.md",
|
|
71
71
|
"description": "Skill de ejecución con subagentes (Superpowers) — ejecuta solo después de confirmación del coordinador Ostacky",
|
|
72
|
-
"version": "0.8.
|
|
72
|
+
"version": "0.8.1",
|
|
73
73
|
"sha256": "1a42d714a9a13faf05f0bf7b580e8d837c2e77a5633839542ccce603023419e8"
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
"name": "dispatching-parallel-agents",
|
|
77
77
|
"file": "assets/skills/dispatching-parallel-agents/SKILL.md",
|
|
78
78
|
"description": "Skill de dispatch paralelo de agentes (Superpowers)",
|
|
79
|
-
"version": "0.8.
|
|
79
|
+
"version": "0.8.1",
|
|
80
80
|
"sha256": "3c8a66d51ae2e719e877d02c3dac32bd804722c3bb9227c258ecae78252a20ab"
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
"name": "review",
|
|
84
84
|
"file": "assets/skills/review/SKILL.md",
|
|
85
85
|
"description": "Skill de revisión de código (Superpowers)",
|
|
86
|
-
"version": "0.8.
|
|
86
|
+
"version": "0.8.1",
|
|
87
87
|
"sha256": "b19650ed4d1d4d9857a4dd5b7e08e91328a1a1fc9c45bcc2fb600fa9d0213279"
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
90
|
"name": "receiving-code-review",
|
|
91
91
|
"file": "assets/skills/receiving-code-review/SKILL.md",
|
|
92
92
|
"description": "Skill de recibir y procesar feedback de code review",
|
|
93
|
-
"version": "0.8.
|
|
93
|
+
"version": "0.8.1",
|
|
94
94
|
"sha256": "d761e884e71d8d3476ac734d287cae403a4024506a7d12e7361a448217c0a831"
|
|
95
95
|
},
|
|
96
96
|
{
|
|
97
97
|
"name": "openspec-propose",
|
|
98
98
|
"file": "assets/skills/openspec-propose/SKILL.md",
|
|
99
99
|
"description": "Skill de generación de proposal (OpenSpec)",
|
|
100
|
-
"version": "0.8.
|
|
100
|
+
"version": "0.8.1",
|
|
101
101
|
"sha256": "bb59100b9fd3c9f9a1ec6509fa975ec55bf7fc737df4fe73bb3e9bbc217b83f7"
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
104
|
"name": "openspec-apply-change",
|
|
105
105
|
"file": "assets/skills/openspec-apply-change/SKILL.md",
|
|
106
106
|
"description": "Skill de aplicación de change (OpenSpec)",
|
|
107
|
-
"version": "0.8.
|
|
107
|
+
"version": "0.8.1",
|
|
108
108
|
"sha256": "dfc823bf89fc7505e91ab6dee9c1f004be38a410bd3d88fb67b211b1b6cbb1d0"
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
"name": "openspec-archive-change",
|
|
112
112
|
"file": "assets/skills/openspec-archive-change/SKILL.md",
|
|
113
113
|
"description": "Skill de archivo de change (OpenSpec)",
|
|
114
|
-
"version": "0.8.
|
|
114
|
+
"version": "0.8.1",
|
|
115
115
|
"sha256": "16e4b561de7747283663fed602e506abf502452c49a8d4b86d7a5539c40f0195"
|
|
116
116
|
},
|
|
117
117
|
{
|
|
118
118
|
"name": "openspec-explore",
|
|
119
119
|
"file": "assets/skills/openspec-explore/SKILL.md",
|
|
120
120
|
"description": "Modo explore para OpenSpec — thinking partner para explorar ideas, investigar problemas y clarificar requisitos antes/durante un cambio",
|
|
121
|
-
"version": "0.8.
|
|
121
|
+
"version": "0.8.1",
|
|
122
122
|
"sha256": "37ae4aaf17ea71a395bab6dc4d9d61b9a49d7910f6692535ae8553244c46880b"
|
|
123
123
|
},
|
|
124
124
|
{
|
|
125
125
|
"name": "using-git-worktrees",
|
|
126
126
|
"file": "assets/skills/using-git-worktrees/SKILL.md",
|
|
127
127
|
"description": "Skill de uso de git worktrees para aislamiento de trabajo",
|
|
128
|
-
"version": "0.8.
|
|
128
|
+
"version": "0.8.1",
|
|
129
129
|
"sha256": "93341bc1b7c053618a8b6dc07e3615b77990d7b549a0201f5835d95fef67ce13"
|
|
130
130
|
},
|
|
131
131
|
{
|
|
132
132
|
"name": "using-superpowers",
|
|
133
133
|
"file": "assets/skills/using-superpowers/SKILL.md",
|
|
134
134
|
"description": "Skill de orquestación de Superpowers skills",
|
|
135
|
-
"version": "0.8.
|
|
135
|
+
"version": "0.8.1",
|
|
136
136
|
"sha256": "7e54536f96d2a379185a10bfc1e970850caa2561b6d8aca7080f0defea0381a4"
|
|
137
137
|
},
|
|
138
138
|
{
|
|
139
139
|
"name": "writing-skills",
|
|
140
140
|
"file": "assets/skills/writing-skills/SKILL.md",
|
|
141
141
|
"description": "Skill de creación y edición de skills",
|
|
142
|
-
"version": "0.8.
|
|
142
|
+
"version": "0.8.1",
|
|
143
143
|
"sha256": "3d76b906cee518a2b809febb70db95697a35b9f368986bb504b4120c3bfb437a"
|
|
144
144
|
},
|
|
145
145
|
{
|
|
146
146
|
"name": "graceful-degradation",
|
|
147
147
|
"file": "assets/skills/graceful-degradation/SKILL.md",
|
|
148
148
|
"description": "Skill de degradación graceful cuando múltiples tools están indisponibles",
|
|
149
|
-
"version": "0.8.
|
|
149
|
+
"version": "0.8.1",
|
|
150
150
|
"sha256": "40f929e8032b70d51b3548bddcc383b931d6044fd9d4acce8a5b9f7acd014f59"
|
|
151
151
|
}
|
|
152
152
|
]
|
package/package.json
CHANGED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deprecated Fusionado en ostacky-plugin.ts — re-export legacy.
|
|
3
|
-
* Single source: importa desde src/security.ts vía controller.
|
|
4
|
-
* Fresh install solo escribe ostacky-plugin.ts + engram.ts.
|
|
5
|
-
* Este archivo no debe ser instalado por ostacky install (deprecado).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { Plugin } from "@opencode-ai/plugin"
|
|
9
|
-
|
|
10
|
-
// Re-export controller como guard por compatibilidad — no duplica isSensitive/BASH_SENSITIVE_RE
|
|
11
|
-
export { OstackyController as OstackyGuard } from "./ostacky-plugin.ts"
|
|
12
|
-
|
|
13
|
-
// También export default por compatibilidad con loaders que esperan default
|
|
14
|
-
import { OstackyController } from "./ostacky-plugin.ts"
|
|
15
|
-
export default OstackyController
|
|
16
|
-
|
|
17
|
-
// Nota: isSensitive, BASH_SENSITIVE_RE, extractPathsFromBash vienen de src/security.ts
|
|
18
|
-
// a través de ostacky-plugin.ts, no se copian aquí (verificación check:security).
|