ostacky 0.9.1 → 0.9.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 +14 -12
- package/assets/agents/ostacky.md +5 -5
- package/assets/commands/install-stack.md +2 -2
- package/assets/docs/ostacky-reference.md +7 -3
- package/assets/mcp/ostacky-controller/index.js +96 -11
- package/assets/mcp/ostacky-controller/package.json +1 -1
- package/assets/plugins/engram.ts +7 -3
- package/assets/plugins/{ostacky-plugin.ts → ostacky-controller/index.ts} +31 -5
- package/assets/plugins/{tiered.ts → ostacky-controller/tiered.ts} +1 -1
- package/dist/cli.js +117 -61
- package/manifest.json +28 -28
- package/package.json +2 -8
- /package/assets/plugins/{controller-core.ts → ostacky-controller/controller-core.ts} +0 -0
- /package/assets/plugins/{security.ts → ostacky-controller/security.ts} +0 -0
package/README.md
CHANGED
|
@@ -145,6 +145,8 @@ Actualizaciones disponibles
|
|
|
145
145
|
|
|
146
146
|
Solo descarga los items que cambiaron de versión.
|
|
147
147
|
|
|
148
|
+
> **Nota:** `@latest` y `update` son cosas distintas. `npx ostacky@latest` fuerza a descargar la **última versión publicada** del instalador (el `@latest` es el tag de npm) y, sin subcomando, abre el menú interactivo. `npx ostacky update` corre la **acción de actualizar** (trae el manifest remoto y actualiza lo instalado según el lockfile) con la versión del instalador que npx resuelva (puede ser cacheada). Para ambas garantías, combinalos: `npx ostacky@latest update`.
|
|
149
|
+
|
|
148
150
|
### Desinstalar
|
|
149
151
|
|
|
150
152
|
```bash
|
|
@@ -246,37 +248,37 @@ Tras instalar (`--scope local`), el proyecto queda así:
|
|
|
246
248
|
|
|
247
249
|
```json
|
|
248
250
|
{
|
|
249
|
-
"version": "0.9.
|
|
251
|
+
"version": "0.9.3",
|
|
250
252
|
"lockedAt": "2025-01-01T00:00:00.000Z",
|
|
251
253
|
"repo": "JaimeHoracio/Ostacky",
|
|
252
|
-
"tag": "v0.9.
|
|
254
|
+
"tag": "v0.9.3",
|
|
253
255
|
"agents": {
|
|
254
256
|
"ostacky": {
|
|
255
|
-
"version": "0.9.
|
|
257
|
+
"version": "0.9.3",
|
|
256
258
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
257
259
|
"sha256": "abc123..."
|
|
258
260
|
}
|
|
259
261
|
},
|
|
260
262
|
"commands": {
|
|
261
263
|
"install-stack": {
|
|
262
|
-
"version": "0.9.
|
|
264
|
+
"version": "0.9.3",
|
|
263
265
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
264
266
|
"sha256": "def456..."
|
|
265
267
|
},
|
|
266
268
|
"opsx-sync": {
|
|
267
|
-
"version": "0.9.
|
|
269
|
+
"version": "0.9.3",
|
|
268
270
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
269
271
|
"sha256": "ghi789..."
|
|
270
272
|
}
|
|
271
273
|
},
|
|
272
274
|
"skills": {
|
|
273
|
-
"brainstorming": { "version": "0.9.
|
|
274
|
-
"execution-mode-evaluation": { "version": "0.9.
|
|
275
|
-
"openspec-propose": { "version": "0.9.
|
|
275
|
+
"brainstorming": { "version": "0.9.3", ... },
|
|
276
|
+
"execution-mode-evaluation": { "version": "0.9.3", ... },
|
|
277
|
+
"openspec-propose": { "version": "0.9.3", ... }
|
|
276
278
|
},
|
|
277
279
|
"mcpServers": {
|
|
278
|
-
"ostacky-controller": { "version": "0.9.
|
|
279
|
-
"openspec": { "version": "0.9.
|
|
280
|
+
"ostacky-controller": { "version": "0.9.3", ... },
|
|
281
|
+
"openspec": { "version": "0.9.3", ... }
|
|
280
282
|
}
|
|
281
283
|
}
|
|
282
284
|
```
|
|
@@ -308,7 +310,7 @@ Es opcional y solo necesario si algo falló durante la instalación o si querés
|
|
|
308
310
|
## Seguridad
|
|
309
311
|
|
|
310
312
|
- `opencode.jsonc` se versiona en el repo para compartir permisos y MCP de forma reproducible.
|
|
311
|
-
- Las URLs de descarga usan **tags de GitHub** (ej. `v0.9.
|
|
313
|
+
- Las URLs de descarga usan **tags de GitHub** (ej. `v0.9.3`), nunca `main` — instalaciones reproducibles
|
|
312
314
|
- Cada path de archivo descargado es validado para prevenir **path traversal**
|
|
313
315
|
- Los archivos incluyen **checksum SHA-256** opcional; si el manifest lo define, el contenido se verifica antes de escribir
|
|
314
316
|
- El cache local (`.opencode/cache/`) también valida integridad al servir archivos cacheados
|
|
@@ -365,7 +367,7 @@ CodeGraph está instalado en `.opencode/tools/codegraph/bin/codegraph` y se conf
|
|
|
365
367
|
| `.opencode/tools/codegraph/bin/codegraph status` | Muestra estado del index y archivos pendientes |
|
|
366
368
|
| `.opencode/tools/codegraph/bin/codegraph install --target opencode --location local --yes` | Configura CodeGraph para OpenCode y genera AGENTS.md |
|
|
367
369
|
|
|
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.9.
|
|
370
|
+
> **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.9.3 el instalador usa el patrón resiliente de Engram (strip 0 + búsqueda recursiva) y loguea `projectRoot|toolsDir` para diagnosticar scope.
|
|
369
371
|
|
|
370
372
|
## Licencia
|
|
371
373
|
|
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.9.
|
|
4
|
+
version: 0.9.3
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Sos **Ostacky v0.9.
|
|
7
|
+
Sos **Ostacky v0.9.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.9.
|
|
9
|
+
> **Versión:** `0.9.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.9.3"** (o `v0.9.3` si te piden solo el número). No inventes otra versión.
|
|
10
10
|
|
|
11
11
|
## Reglas innegociables
|
|
12
12
|
|
|
@@ -85,13 +85,13 @@ Router `brainstorming`↔`OpenSpec` por `level`/`estLines`/`fileCount`/`hasAPI`
|
|
|
85
85
|
|
|
86
86
|
1. `skill(execution-mode-evaluation)` en memoria, reusa discovery.
|
|
87
87
|
2. Mostrar análisis → `¿Procedo?` → `record_execution_analysis` → `consume_execution_decision`.
|
|
88
|
-
3. Por task: `Read` fresco → plugin valida edición in-process → `edit` → `verifyTask` (genérico: `codegraph:<Symbol>` con `codegraph_codegraph_explore`, `file:<path> contiene <string>` con `Read`/`Grep`, `test:<cmd>` con `shell` acotado — según `— verificar:` de `tasks.md`) → solo si `verifyTask.ok` → `complete_task`. **NUNCA marques `complete_task` a ojo**; si `verifyTask` falla, reintentá el fix.
|
|
88
|
+
3. Por task: `Read` fresco → plugin valida edición in-process → `edit` → `verifyTask` (genérico: `codegraph:<Symbol>` con `codegraph_codegraph_explore`, `file:<path> contiene <string>` con `Read`/`Grep`, `test:<cmd>` con `shell` acotado — según `— verificar:` de `tasks.md`) → solo si `verifyTask.ok` → `complete_task`. **NUNCA marques `complete_task` a ojo**; si `verifyTask` falla, reintentá el fix. Vale para SPEC y DIRECT, INLINE y SUBAGENTS.
|
|
89
89
|
|
|
90
90
|
### 5. Sync y cierre
|
|
91
91
|
|
|
92
92
|
1. Tests + review
|
|
93
93
|
2. `saveSessionClose` → `mem_session_summary` + `set_handoff` paralelo
|
|
94
|
-
3. `verifyIntegrity` → **si `pending.length > 0` NO llames `implementation_complete`**; lista explícita `Te faltan N tasks: [...]` y pide `complete_task`. Solo si `pending === 0` y `staleFiles === 0`, `implementation_complete` → `sync_complete`. **NUNCA llames `implementation_complete` automáticamente con pendientes** — espera a que el usuario complete o escriba literal `"confirmo forzar"` para `force:true` (queda auditado).
|
|
94
|
+
3. `verifyIntegrity` → **si `pending.length > 0` NO llames `implementation_complete`**; lista explícita `Te faltan N tasks: [...]` y pide `complete_task`. Si `staleFiles.length > 0` por refino post-complete (archivo ya correcto, sin edición pendiente): llamá `refresh_fingerprint({filePath})` por cada archivo y reintentá `implementation_complete` sin `force`. Solo si `pending === 0` y `staleFiles === 0`, `implementation_complete` → `sync_complete`. **NUNCA llames `implementation_complete` automáticamente con pendientes** — espera a que el usuario complete o escriba literal `"confirmo forzar"` para `force:true` (queda auditado). Vale para SPEC y DIRECT, INLINE y SUBAGENTS.
|
|
95
95
|
|
|
96
96
|
## Guardrails
|
|
97
97
|
|
|
@@ -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.9.
|
|
8
|
+
**Nota:** A partir de v0.9.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
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.9.
|
|
14
|
+
## Scope de instalación — local vs global (desde v0.9.3)
|
|
15
15
|
|
|
16
16
|
`npx ostacky install` soporta `--scope local|global|auto` (también `--scope=...`):
|
|
17
17
|
|
|
@@ -48,6 +48,10 @@ Allowlist: `.env.example/.template/.sample` nunca bloquea. `extractPathsFromBash
|
|
|
48
48
|
|
|
49
49
|
`content` requerido salvo `content:"hash:"+fastFingerprint` cuando `lastValidated.filePath==filePath && fingerprint==hash` y fingerprint coincide con disco → EDITABLE sin body. Hash stale → CONFLICT `stale fingerprint`.
|
|
50
50
|
|
|
51
|
+
## refresh_fingerprint (revalidación sin churn)
|
|
52
|
+
|
|
53
|
+
Tras refino post-complete (archivo ya correcto, sin edición pendiente): `refresh_fingerprint({filePath})` o `refresh_fingerprint({taskId})` re-sincroniza `tasks[].fileHash` + `fileFingerprints` con disco, sin `oldString/newString`. Vale para SPEC y DIRECT, en `EXECUTING_INLINE`, `EXECUTING_SUBAGENTS` y `SPECIFICATION`. Luego `verifyIntegrity.ok` → `implementation_complete` sin `force`.
|
|
54
|
+
|
|
51
55
|
## Enforcement (plugin)
|
|
52
56
|
|
|
53
57
|
El plugin hace cumplir `PENDING` en `ctx.tool.hook("execute.before")`; `lastCheck={revision, result}` cachea ALLOW por revisión, revalida si cambia o >5 tools; `BLOCKED` nunca cacheado. Métricas `stateCheckCount` cuentan checks del plugin (no del LLM).
|
|
@@ -64,15 +68,15 @@ Principio: **eficacia > recorte** — si recorte rompiera caché y saliera más
|
|
|
64
68
|
|
|
65
69
|
## Security single-source
|
|
66
70
|
|
|
67
|
-
`src/security.ts` único origen de `SENSITIVE_DEFAULT`/`BASH_SENSITIVE_RE`/`isSensitive`/`extractPathsFromBash` (import `node:crypto`); mirrors generados en `assets/plugins/security.ts` (solo Sensitive guard, sin crypto) y `assets/mcp/ostacky-controller/security.js` vía `bun run scripts/sync-controller-core.ts`. `ostacky-
|
|
71
|
+
`src/security.ts` único origen de `SENSITIVE_DEFAULT`/`BASH_SENSITIVE_RE`/`isSensitive`/`extractPathsFromBash` (import `node:crypto`); mirrors generados en `assets/plugins/ostacky-controller/security.ts` (solo Sensitive guard, sin crypto) y `assets/mcp/ostacky-controller/security.js` vía `bun run scripts/sync-controller-core.ts`. `assets/plugins/ostacky-controller/index.ts` importa de `./security.ts` self-contained (no `../../src`). `BASH_SENSITIVE_RE` arriba. `OSTACKY_SENSITIVE_PATTERNS` override.
|
|
68
72
|
|
|
69
73
|
## Tiered single-source
|
|
70
74
|
|
|
71
|
-
`src/tiered.ts` único origen de `isTrivial(msg,state)` + `getControllerState(dir)`. `
|
|
75
|
+
`src/tiered.ts` único origen de `isTrivial(msg,state)` + `getControllerState(dir)`. `index.ts` importa de `./tiered.ts` mirror (generado vía `sync-controller-core.ts`), `engram.ts` inlined (misma regex, evita import dinámico). No duplicar regex. Ver `assets/plugins/ostacky-controller/` y `assets/plugins/engram.ts`.
|
|
72
76
|
|
|
73
77
|
## Controller single-source
|
|
74
78
|
|
|
75
|
-
`src/controller-core.ts` CANÓNICO para `STATES/TRANSITIONS/DEFAULT_STATE`; mirrors generados en `assets/plugins/controller-core.ts` (TS) y `assets/mcp/ostacky-controller/controller-core.js` (JS strippado) vía `bun run scripts/sync-controller-core.ts` (prebuild). No editar mirrors. `
|
|
79
|
+
`src/controller-core.ts` CANÓNICO para `STATES/TRANSITIONS/DEFAULT_STATE`; mirrors generados en `assets/plugins/ostacky-controller/controller-core.ts` (TS) y `assets/mcp/ostacky-controller/controller-core.js` (JS strippado) vía `bun run scripts/sync-controller-core.ts` (prebuild). No editar mirrors. `index.ts` importa de `./controller-core.ts` self-contained. Import siempre `./security.ts` (el server V2 no resuelve `.js→.ts`).
|
|
76
80
|
|
|
77
81
|
## Prompt-efficiency
|
|
78
82
|
|
|
@@ -411,6 +411,22 @@ function fastFingerprint(filePath) {
|
|
|
411
411
|
}
|
|
412
412
|
}
|
|
413
413
|
|
|
414
|
+
// Refresh honesto sin churn: resuelve a absoluto vía projectRoot para no depender de cwd.
|
|
415
|
+
// Usado por stale-checks, complete_task y refreshFingerprint (fix post-complete refine).
|
|
416
|
+
function fingerprintFor(filePath, statePath) {
|
|
417
|
+
try {
|
|
418
|
+
if (!filePath) return null;
|
|
419
|
+
const projectRoot = getProjectRoot(statePath);
|
|
420
|
+
const abs =
|
|
421
|
+
filePath.startsWith('/') || /^[A-Za-z]:/.test(filePath)
|
|
422
|
+
? resolve(filePath)
|
|
423
|
+
: resolve(projectRoot, filePath);
|
|
424
|
+
return fastFingerprint(abs);
|
|
425
|
+
} catch {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
414
430
|
class OstackyController {
|
|
415
431
|
#statePath;
|
|
416
432
|
#state;
|
|
@@ -1697,14 +1713,14 @@ class OstackyController {
|
|
|
1697
1713
|
try {
|
|
1698
1714
|
for (const [taskId, info] of Object.entries(this.#state.tasks || {})) {
|
|
1699
1715
|
if (info.status !== 'COMPLETED' || !info.filePath || !info.fileHash) continue;
|
|
1700
|
-
const current =
|
|
1716
|
+
const current = fingerprintFor(info.filePath, this.#statePath);
|
|
1701
1717
|
if (!current) staleFiles.push(`${taskId}:${info.filePath} (missing)`);
|
|
1702
1718
|
else if (current !== info.fileHash) staleFiles.push(`${taskId}:${info.filePath} (stale fingerprint)`);
|
|
1703
1719
|
seenFp2.add(info.filePath);
|
|
1704
1720
|
}
|
|
1705
1721
|
for (const [fp, stored] of Object.entries(this.#state.fileFingerprints || {})) {
|
|
1706
1722
|
if (seenFp2.has(fp)) continue;
|
|
1707
|
-
const cur =
|
|
1723
|
+
const cur = fingerprintFor(fp, this.#statePath);
|
|
1708
1724
|
if (!cur) staleFiles.push(`${fp} (missing)`);
|
|
1709
1725
|
else if (cur !== stored) staleFiles.push(`${fp} (stale fingerprint)`);
|
|
1710
1726
|
}
|
|
@@ -1764,7 +1780,7 @@ class OstackyController {
|
|
|
1764
1780
|
verificationFailed: verificationFailed.length ? verificationFailed : undefined,
|
|
1765
1781
|
current_state: this.#state.state,
|
|
1766
1782
|
attempted_transition: 'implementation_complete',
|
|
1767
|
-
suggestion: `${detail}
|
|
1783
|
+
suggestion: `${detail} Si refinaste archivos tras el complete (fingerprint stale), llamá refresh_fingerprint({filePath}) por cada archivo y reintentá implementation_complete sin force. Solo si hay edición real pendiente: Read fresco → validate_edit → edit → complete_task. Solo si querés descartar trabajo pendiente, escribí literal "confirmo forzar" en tu mensaje y reintentá con {force:true}. No propongo cancelar; propongo completar.`,
|
|
1768
1784
|
};
|
|
1769
1785
|
}
|
|
1770
1786
|
if (hasBlocking && force) {
|
|
@@ -1785,7 +1801,7 @@ class OstackyController {
|
|
|
1785
1801
|
verificationFailed: verificationFailed.length ? verificationFailed : undefined,
|
|
1786
1802
|
current_state: this.#state.state,
|
|
1787
1803
|
attempted_transition: 'implementation_complete',
|
|
1788
|
-
suggestion: `${detail} Para forzar el cierre, escribí literal "confirmo forzar" en tu mensaje (quedará auditado) y reintentá con {force:true}. Si no querés forzar,
|
|
1804
|
+
suggestion: `${detail} Para forzar el cierre, escribí literal "confirmo forzar" en tu mensaje (quedará auditado) y reintentá con {force:true}. Si no querés forzar y es solo stale por refino, llamá refresh_fingerprint({filePath}) y reintentá sin force.`,
|
|
1789
1805
|
};
|
|
1790
1806
|
}
|
|
1791
1807
|
const all = [...pending, ...staleFiles, ...verificationFailed].join(',');
|
|
@@ -1969,14 +1985,14 @@ class OstackyController {
|
|
|
1969
1985
|
try {
|
|
1970
1986
|
for (const [taskId, info] of Object.entries(this.#state.tasks || {})) {
|
|
1971
1987
|
if (info.status !== 'COMPLETED' || !info.filePath || !info.fileHash) continue;
|
|
1972
|
-
const current =
|
|
1988
|
+
const current = fingerprintFor(info.filePath, this.#statePath);
|
|
1973
1989
|
if (!current) staleFiles.push(`${taskId}:${info.filePath} (missing)`);
|
|
1974
1990
|
else if (current !== info.fileHash) staleFiles.push(`${taskId}:${info.filePath} (stale fingerprint)`);
|
|
1975
1991
|
seenFp.add(info.filePath);
|
|
1976
1992
|
}
|
|
1977
1993
|
for (const [fp, stored] of Object.entries(this.#state.fileFingerprints || {})) {
|
|
1978
1994
|
if (seenFp.has(fp)) continue;
|
|
1979
|
-
const current =
|
|
1995
|
+
const current = fingerprintFor(fp, this.#statePath);
|
|
1980
1996
|
if (!current) staleFiles.push(`${fp} (missing)`);
|
|
1981
1997
|
else if (current !== stored) staleFiles.push(`${fp} (stale fingerprint)`);
|
|
1982
1998
|
}
|
|
@@ -2448,11 +2464,11 @@ class OstackyController {
|
|
|
2448
2464
|
}
|
|
2449
2465
|
if (!this.#state.tasks) this.#state.tasks = {};
|
|
2450
2466
|
|
|
2451
|
-
// O6: Use fast fingerprint if no hash provided
|
|
2452
|
-
const effectiveHash = fileHash || (filePath ?
|
|
2467
|
+
// O6: Use fast fingerprint if no hash provided (absoluto vía projectRoot)
|
|
2468
|
+
const effectiveHash = fileHash || (filePath ? fingerprintFor(filePath, this.#statePath) : null);
|
|
2453
2469
|
// 1.6: fingerprint obligatorio si archivo existe
|
|
2454
2470
|
if (filePath) {
|
|
2455
|
-
const existsCheck =
|
|
2471
|
+
const existsCheck = fingerprintFor(filePath, this.#statePath);
|
|
2456
2472
|
if (existsCheck && !effectiveHash) {
|
|
2457
2473
|
return { error: 'fingerprint required: file exists but fileHash is null' };
|
|
2458
2474
|
}
|
|
@@ -2561,6 +2577,58 @@ class OstackyController {
|
|
|
2561
2577
|
};
|
|
2562
2578
|
}
|
|
2563
2579
|
|
|
2580
|
+
/**
|
|
2581
|
+
* Refresh honesto sin churn: re-sincroniza fingerprints con disco tras refino
|
|
2582
|
+
* post-complete. Vale para SPEC y DIRECT, en EXECUTING_INLINE, EXECUTING_SUBAGENTS
|
|
2583
|
+
* y SPECIFICATION. No exige oldString/newString ni reeditar.
|
|
2584
|
+
*/
|
|
2585
|
+
async refreshFingerprint({ filePath, taskId } = {}) {
|
|
2586
|
+
this.#load();
|
|
2587
|
+
const allowed = ['EXECUTING_INLINE', 'EXECUTING_SUBAGENTS', 'SPECIFICATION'];
|
|
2588
|
+
if (!allowed.includes(this.#state.state)) {
|
|
2589
|
+
return { error: `Cannot refresh fingerprint from state ${this.#state.state}`, ok: false };
|
|
2590
|
+
}
|
|
2591
|
+
if (taskId && !isValidTaskId(taskId)) return { error: `invalid taskId: ${taskId}`, ok: false };
|
|
2592
|
+
let target = filePath || null;
|
|
2593
|
+
if (!target && taskId && this.#state.tasks?.[taskId]?.filePath) {
|
|
2594
|
+
target = this.#state.tasks[taskId].filePath;
|
|
2595
|
+
}
|
|
2596
|
+
if (!target) return { error: 'filePath or taskId with file is required', ok: false };
|
|
2597
|
+
if (!isPathInsideProject(target, this.#statePath)) {
|
|
2598
|
+
return { error: `filePath outside projectRoot: ${target}`, ok: false, filePath: target };
|
|
2599
|
+
}
|
|
2600
|
+
if (this.isSensitiveFile(target) && !this.#state.allowedFiles?.[target]) {
|
|
2601
|
+
return { error: `BLOCKED: File ${target} requires check_file_access`, ok: false, filePath: target };
|
|
2602
|
+
}
|
|
2603
|
+
const projectRoot = getProjectRoot(this.#statePath);
|
|
2604
|
+
const abs =
|
|
2605
|
+
target.startsWith('/') || /^[A-Za-z]:/.test(target) ? resolve(target) : resolve(projectRoot, target);
|
|
2606
|
+
if (!existsSync(abs)) return { error: `file not found: ${target}`, ok: false, filePath: target };
|
|
2607
|
+
const current = fingerprintFor(target, this.#statePath);
|
|
2608
|
+
if (!current) return { error: `cannot fingerprint: ${target}`, ok: false, filePath: target };
|
|
2609
|
+
const updatedTasks = [];
|
|
2610
|
+
if (!this.#state.fileFingerprints) this.#state.fileFingerprints = {};
|
|
2611
|
+
this.#state.fileFingerprints[target] = current;
|
|
2612
|
+
if (taskId && this.#state.tasks?.[taskId]) {
|
|
2613
|
+
this.#state.tasks[taskId].fileHash = current;
|
|
2614
|
+
if (!this.#state.tasks[taskId].filePath) this.#state.tasks[taskId].filePath = target;
|
|
2615
|
+
updatedTasks.push(taskId);
|
|
2616
|
+
}
|
|
2617
|
+
for (const [tid, info] of Object.entries(this.#state.tasks || {})) {
|
|
2618
|
+
if (info.filePath === target && !updatedTasks.includes(tid)) {
|
|
2619
|
+
info.fileHash = current;
|
|
2620
|
+
updatedTasks.push(tid);
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
await this.#persist();
|
|
2624
|
+
await this.#audit(
|
|
2625
|
+
'EXECUTING',
|
|
2626
|
+
'refresh_fingerprint',
|
|
2627
|
+
`filePath=${target} tasks=${updatedTasks.join(',') || '-'}`
|
|
2628
|
+
);
|
|
2629
|
+
return { ok: true, filePath: target, fingerprint: current, updatedTasks };
|
|
2630
|
+
}
|
|
2631
|
+
|
|
2564
2632
|
async verifyTask({ taskId, filePath: filePathParam } = {}) {
|
|
2565
2633
|
this.#load();
|
|
2566
2634
|
if (!taskId) return { error: 'taskId required' };
|
|
@@ -2785,7 +2853,7 @@ function safeHandler(fn, options = {}) {
|
|
|
2785
2853
|
|
|
2786
2854
|
const server = new McpServer({
|
|
2787
2855
|
name: 'ostacky-controller',
|
|
2788
|
-
version: '0.9.
|
|
2856
|
+
version: '0.9.3',
|
|
2789
2857
|
});
|
|
2790
2858
|
|
|
2791
2859
|
server.registerTool(
|
|
@@ -3326,6 +3394,23 @@ server.registerTool(
|
|
|
3326
3394
|
})
|
|
3327
3395
|
);
|
|
3328
3396
|
|
|
3397
|
+
server.registerTool(
|
|
3398
|
+
'refresh_fingerprint',
|
|
3399
|
+
{
|
|
3400
|
+
description:
|
|
3401
|
+
'Re-sincroniza fingerprints con disco tras refino post-complete, sin reeditar. ' +
|
|
3402
|
+
'Vale para SPEC y DIRECT, en EXECUTING_INLINE, EXECUTING_SUBAGENTS y SPECIFICATION.',
|
|
3403
|
+
inputSchema: z.object({
|
|
3404
|
+
filePath: z.string().optional().describe('File path refinado tras complete.'),
|
|
3405
|
+
taskId: z.string().optional().describe('Task ID (si se omite filePath se usa su archivo).'),
|
|
3406
|
+
}),
|
|
3407
|
+
},
|
|
3408
|
+
safeHandler(async ({ filePath, taskId }) => {
|
|
3409
|
+
log('tool:refresh_fingerprint', { filePath, taskId });
|
|
3410
|
+
return await controller.refreshFingerprint({ filePath, taskId });
|
|
3411
|
+
})
|
|
3412
|
+
);
|
|
3413
|
+
|
|
3329
3414
|
/**
|
|
3330
3415
|
* Graceful shutdown: clean up tmp/lock files and flush state.
|
|
3331
3416
|
*/
|
|
@@ -3357,7 +3442,7 @@ function setupGracefulShutdown(ctrl) {
|
|
|
3357
3442
|
}
|
|
3358
3443
|
|
|
3359
3444
|
async function main() {
|
|
3360
|
-
log('Starting ostacky-controller MCP v0.9.
|
|
3445
|
+
log('Starting ostacky-controller MCP v0.9.3...');
|
|
3361
3446
|
log('State path:', { path: statePath });
|
|
3362
3447
|
// Clean up stale tmp/lock files from previous runs
|
|
3363
3448
|
cleanupTmpFiles(statePath);
|
package/assets/plugins/engram.ts
CHANGED
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
* hooks (event.sessionID) rather than relying on a session.created event.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { Plugin }
|
|
17
|
+
// NOTA: sin `import { Plugin }` runtime a propósito — el server V2 no resuelve
|
|
18
|
+
// `@opencode/plugin` desde `.opencode/plugins/` y `Plugin.define()` es
|
|
19
|
+
// passthrough ({id, setup}). `import type` se borra al transpilar.
|
|
20
|
+
import type { Plugin } from "@opencode/plugin"
|
|
18
21
|
import { join, dirname, basename, delimiter } from "node:path"
|
|
19
22
|
import { readFileSync, writeFileSync, renameSync, mkdirSync, existsSync } from "node:fs"
|
|
20
23
|
import { spawn, spawnSync } from "node:child_process"
|
|
@@ -197,7 +200,8 @@ function stripJsoncComments(text: string): string {
|
|
|
197
200
|
|
|
198
201
|
// ─── Plugin ──────────────────────────────────────────────────────────────────
|
|
199
202
|
|
|
200
|
-
|
|
203
|
+
// Objeto literal directo (ver nota en imports).
|
|
204
|
+
export default {
|
|
201
205
|
id: "engram",
|
|
202
206
|
async setup(ctx) {
|
|
203
207
|
const directory = ctx.location.directory
|
|
@@ -645,4 +649,4 @@ export default Plugin.define({
|
|
|
645
649
|
|
|
646
650
|
return () => eventController.abort()
|
|
647
651
|
},
|
|
648
|
-
}
|
|
652
|
+
}
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
* CodeGraph preventivo: bloquea Read/Grep masivo sin Discovery hit.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { Plugin } from "@opencode/plugin"
|
|
14
|
+
// NOTA: sin `import { Plugin } from "@opencode/plugin"` a propósito — el server
|
|
15
|
+
// V2 no resuelve ese paquete desde `.opencode/plugins/` (Die ResolveMessage) y
|
|
16
|
+
// `Plugin.define()` es passthrough ({id, setup}). Objeto literal + `import type`
|
|
17
|
+
// (solo tipos, borrado al transpilar) cargan sin dependencias externas.
|
|
18
|
+
import type { Plugin } from "@opencode/plugin"
|
|
15
19
|
import { readFileSync, writeFileSync, renameSync, mkdirSync, existsSync, statSync, readdirSync, unlinkSync } from "node:fs"
|
|
16
20
|
import { join, dirname, basename, resolve, relative, delimiter } from "node:path"
|
|
17
21
|
import { SENSITIVE_DEFAULT, BASH_SENSITIVE_RE, isSensitive, extractPathsFromBash } from "./security.ts"
|
|
@@ -178,7 +182,9 @@ function extractPathsFromPatch(patchText: string): string[] {
|
|
|
178
182
|
|
|
179
183
|
// ─── Plugin ──────────────────────────────────────────────────────────────────
|
|
180
184
|
|
|
181
|
-
|
|
185
|
+
// Objeto literal directo (ver nota en imports): el server V2 acepta
|
|
186
|
+
// `{ id, setup }` sin pasar por `Plugin.define()`.
|
|
187
|
+
export default {
|
|
182
188
|
id: "ostacky-controller",
|
|
183
189
|
async setup(ctx) {
|
|
184
190
|
const directory = ctx.location.directory
|
|
@@ -374,9 +380,27 @@ export default Plugin.define({
|
|
|
374
380
|
const isCodeFile = /\.(ts|js|tsx|jsx|mts|cts)$/i.test(targetPath) || targetPath.includes("src/") || targetPath.includes("assets/") || args?.pattern?.includes("*.ts")
|
|
375
381
|
// harden-task-integrity 1.3: eximir reads de tasks.md del gate (no requiere CodeGraph)
|
|
376
382
|
const isSpecTasksPath = targetPath.includes("openspec/changes") || targetPath.includes("openspec/specs")
|
|
383
|
+
// Docs y markdown nunca son código: no exigir Discovery (fix over-blocking assets/docs)
|
|
384
|
+
const isDocsPath = targetPath.includes("assets/docs") || targetPath.includes("/docs/") || /\.md$/i.test(targetPath) || /\.json$/i.test(targetPath)
|
|
377
385
|
// Grep on *.md should not be blocked
|
|
378
386
|
const isLiteralGrep = tool === "grep" && (args?.include?.endsWith(".md") || args?.include?.endsWith(".json"))
|
|
379
|
-
|
|
387
|
+
// Refresh honesto: revalidación post-complete necesita Read fresco sin Discovery hit.
|
|
388
|
+
// Vale para SPEC y DIRECT, INLINE y SUBAGENTS: si el path está trackeado en
|
|
389
|
+
// tasks/fileFingerprints/lastValidated, no exigir Discovery.
|
|
390
|
+
let isTaskTracked = false
|
|
391
|
+
try {
|
|
392
|
+
const st = freshState
|
|
393
|
+
if (st && targetPath) {
|
|
394
|
+
const fps = Object.keys(st.fileFingerprints || {})
|
|
395
|
+
const taskFiles = Object.values(st.tasks || {}).map((t: any) => t.filePath).filter(Boolean)
|
|
396
|
+
const lvFile = (st.lastValidated as any)?.filePath || null
|
|
397
|
+
isTaskTracked =
|
|
398
|
+
fps.some((fp) => targetPath.endsWith(fp) || fp.endsWith(targetPath) || targetPath.includes(fp) || fp.includes(targetPath)) ||
|
|
399
|
+
taskFiles.some((fp: string) => targetPath.endsWith(fp) || fp.endsWith(targetPath) || targetPath.includes(fp) || fp.includes(targetPath)) ||
|
|
400
|
+
(lvFile ? targetPath.endsWith(lvFile) || lvFile.endsWith(targetPath) : false)
|
|
401
|
+
}
|
|
402
|
+
} catch {}
|
|
403
|
+
if (isCodeFile && !isLiteralGrep && !isSpecTasksPath && !isDocsPath && !isTaskTracked) {
|
|
380
404
|
const hasDiscoveryHit = discoveryHitByRequest.get(sessionId) ?? getDiscoveryCacheHit(directory)
|
|
381
405
|
const codegraphOk = isCodegraphAvailable(directory)
|
|
382
406
|
if (codegraphOk && !hasDiscoveryHit) {
|
|
@@ -420,7 +444,9 @@ export default Plugin.define({
|
|
|
420
444
|
// ── 3.5) Shell file-mutation gate (harden-task-integrity: shell mutante requiere validate_edit) ──
|
|
421
445
|
if (tool === "shell" && freshState && ["EXECUTING_INLINE", "EXECUTING_SUBAGENTS"].includes(freshState.state)) {
|
|
422
446
|
const cmdForMutation: string = args?.command || args?.cmd || ""
|
|
423
|
-
|
|
447
|
+
// Fix falso positivo: `2>&1`, `1>&2`, `2>/dev/null` son redirects de stderr, no mutación.
|
|
448
|
+
const cmdSansStderr = cmdForMutation.replace(/2>&1/g, "").replace(/1>&2/g, "").replace(/2>\s*\/dev\/null/g, "")
|
|
449
|
+
const isMutating = /(^|[^0-9&])>{1,2}\s*(?!&)\S+|\bsed\b[^|;]*-i|\btruncate\b|\btee\b|\bcp\s+|\bmv\s+|python.*open.*w/.test(cmdSansStderr)
|
|
424
450
|
if (isMutating) {
|
|
425
451
|
const mPaths = extractPathsFromBash(cmdForMutation)
|
|
426
452
|
for (const p of mPaths) {
|
|
@@ -711,4 +737,4 @@ export default Plugin.define({
|
|
|
711
737
|
eventController.abort()
|
|
712
738
|
}
|
|
713
739
|
},
|
|
714
|
-
}
|
|
740
|
+
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
/**
|
|
7
7
|
* Tiered helpers — single source of truth for trivial detection y niveles.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* Consumido por el plugin ostacky-controller/index.ts y engram.ts (mirror en package dir).
|
|
10
10
|
* No duplicar regex. Cache-friendly: isTrivial no muta system[0], solo decide hint.
|
|
11
11
|
* LEVEL_THRESHOLDS es la única definición de niveles (D6).
|
|
12
12
|
*/
|
package/dist/cli.js
CHANGED
|
@@ -621,31 +621,31 @@ var init_fs = __esm(() => {
|
|
|
621
621
|
var manifest_default;
|
|
622
622
|
var init_manifest = __esm(() => {
|
|
623
623
|
manifest_default = {
|
|
624
|
-
version: "0.9.
|
|
624
|
+
version: "0.9.3",
|
|
625
625
|
repo: "JaimeHoracio/Ostacky",
|
|
626
|
-
tag: "v0.9.
|
|
626
|
+
tag: "v0.9.3",
|
|
627
627
|
agents: [
|
|
628
628
|
{
|
|
629
629
|
name: "ostacky",
|
|
630
630
|
file: "assets/agents/ostacky.md",
|
|
631
|
-
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.9.
|
|
632
|
-
version: "0.9.
|
|
633
|
-
sha256: "
|
|
631
|
+
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.9.3: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
|
|
632
|
+
version: "0.9.3",
|
|
633
|
+
sha256: "51f1deb14c75c5c0b25a77d8ec871e951b4341e4658a735967ba1143baa72f9f"
|
|
634
634
|
}
|
|
635
635
|
],
|
|
636
636
|
commands: [
|
|
637
637
|
{
|
|
638
638
|
name: "install-stack",
|
|
639
639
|
file: "assets/commands/install-stack.md",
|
|
640
|
-
description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.9.
|
|
641
|
-
version: "0.9.
|
|
642
|
-
sha256: "
|
|
640
|
+
description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.9.3: controller plugin como alma hard-gate, Context7 removido del stack.",
|
|
641
|
+
version: "0.9.3",
|
|
642
|
+
sha256: "ccc065dd11b53b1c77acafa86ef9dbf65df8ed3f217193901f8b7818447418c1"
|
|
643
643
|
},
|
|
644
644
|
{
|
|
645
645
|
name: "opsx-sync",
|
|
646
646
|
file: "assets/commands/opsx-sync.md",
|
|
647
647
|
description: "Sincroniza delta specs del change activo sin inicializar CodeGraph si ya existe índice",
|
|
648
|
-
version: "0.9.
|
|
648
|
+
version: "0.9.3",
|
|
649
649
|
sha256: "fe0158478f2ca63b315037a85fc1632b77868532e319af6c7384285441767d64"
|
|
650
650
|
}
|
|
651
651
|
],
|
|
@@ -653,15 +653,15 @@ var init_manifest = __esm(() => {
|
|
|
653
653
|
{
|
|
654
654
|
name: "ostacky-controller",
|
|
655
655
|
file: "assets/mcp/ostacky-controller/",
|
|
656
|
-
description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.9.
|
|
657
|
-
version: "0.9.
|
|
658
|
-
sha256: "
|
|
656
|
+
description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.9.3: 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.",
|
|
657
|
+
version: "0.9.3",
|
|
658
|
+
sha256: "8548f1b13270fbd0fb5e76888c96b38bc39bf0ba3c8b03fbc8196683226eb4b0"
|
|
659
659
|
},
|
|
660
660
|
{
|
|
661
661
|
name: "openspec",
|
|
662
662
|
file: "assets/mcp/openspec/",
|
|
663
663
|
description: "MCP server local para OpenSpec - proposal, apply, archive, sync de cambios",
|
|
664
|
-
version: "0.9.
|
|
664
|
+
version: "0.9.3",
|
|
665
665
|
sha256: "fa4be28bfc1e75db8f1a037e2580f04a60066c80e8e5934e90e1041020d04609"
|
|
666
666
|
}
|
|
667
667
|
],
|
|
@@ -670,105 +670,105 @@ var init_manifest = __esm(() => {
|
|
|
670
670
|
name: "brainstorming",
|
|
671
671
|
file: "assets/skills/brainstorming/SKILL.md",
|
|
672
672
|
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)",
|
|
673
|
-
version: "0.9.
|
|
673
|
+
version: "0.9.3",
|
|
674
674
|
sha256: "f1013a86a8f27914d85a716e23c7fd32db1786d93615e8b0834b13d184308549"
|
|
675
675
|
},
|
|
676
676
|
{
|
|
677
677
|
name: "execution-mode-evaluation",
|
|
678
678
|
file: "assets/skills/execution-mode-evaluation/SKILL.md",
|
|
679
679
|
description: "Skill de análisis de modo de ejecución — output reconciliado con controller snapshot contract (recommendation field)",
|
|
680
|
-
version: "0.9.
|
|
680
|
+
version: "0.9.3",
|
|
681
681
|
sha256: "2158a6864c0912e868a9d720db7fd79441e6cc298e3320833d2527c9727c852e"
|
|
682
682
|
},
|
|
683
683
|
{
|
|
684
684
|
name: "tdd",
|
|
685
685
|
file: "assets/skills/tdd/SKILL.md",
|
|
686
686
|
description: "Skill de test-driven development (Superpowers)",
|
|
687
|
-
version: "0.9.
|
|
687
|
+
version: "0.9.3",
|
|
688
688
|
sha256: "f0ebfbbc43a8868d31a3fd2df37ae7f60fe8add09c6475862395a68269e5ff7f"
|
|
689
689
|
},
|
|
690
690
|
{
|
|
691
691
|
name: "subagent-driven-development",
|
|
692
692
|
file: "assets/skills/subagent-driven-development/SKILL.md",
|
|
693
693
|
description: "Skill de ejecución con subagentes (Superpowers) — ejecuta solo después de confirmación del coordinador Ostacky",
|
|
694
|
-
version: "0.9.
|
|
694
|
+
version: "0.9.3",
|
|
695
695
|
sha256: "1a42d714a9a13faf05f0bf7b580e8d837c2e77a5633839542ccce603023419e8"
|
|
696
696
|
},
|
|
697
697
|
{
|
|
698
698
|
name: "dispatching-parallel-agents",
|
|
699
699
|
file: "assets/skills/dispatching-parallel-agents/SKILL.md",
|
|
700
700
|
description: "Skill de dispatch paralelo de agentes (Superpowers)",
|
|
701
|
-
version: "0.9.
|
|
701
|
+
version: "0.9.3",
|
|
702
702
|
sha256: "7e7b712ef742d5631e302e6a71583e2bbbd33094da9281abfb84b43505fc3ef1"
|
|
703
703
|
},
|
|
704
704
|
{
|
|
705
705
|
name: "review",
|
|
706
706
|
file: "assets/skills/review/SKILL.md",
|
|
707
707
|
description: "Skill de revisión de código (Superpowers)",
|
|
708
|
-
version: "0.9.
|
|
708
|
+
version: "0.9.3",
|
|
709
709
|
sha256: "b19650ed4d1d4d9857a4dd5b7e08e91328a1a1fc9c45bcc2fb600fa9d0213279"
|
|
710
710
|
},
|
|
711
711
|
{
|
|
712
712
|
name: "receiving-code-review",
|
|
713
713
|
file: "assets/skills/receiving-code-review/SKILL.md",
|
|
714
714
|
description: "Skill de recibir y procesar feedback de code review",
|
|
715
|
-
version: "0.9.
|
|
715
|
+
version: "0.9.3",
|
|
716
716
|
sha256: "d761e884e71d8d3476ac734d287cae403a4024506a7d12e7361a448217c0a831"
|
|
717
717
|
},
|
|
718
718
|
{
|
|
719
719
|
name: "openspec-propose",
|
|
720
720
|
file: "assets/skills/openspec-propose/SKILL.md",
|
|
721
721
|
description: "Skill de generación de proposal (OpenSpec)",
|
|
722
|
-
version: "0.9.
|
|
722
|
+
version: "0.9.3",
|
|
723
723
|
sha256: "6a517f750f24c008208156a2d653e97ed30b1e53878aeac5ce394e573db0678f"
|
|
724
724
|
},
|
|
725
725
|
{
|
|
726
726
|
name: "openspec-apply-change",
|
|
727
727
|
file: "assets/skills/openspec-apply-change/SKILL.md",
|
|
728
728
|
description: "Skill de aplicación de change (OpenSpec)",
|
|
729
|
-
version: "0.9.
|
|
729
|
+
version: "0.9.3",
|
|
730
730
|
sha256: "dfc823bf89fc7505e91ab6dee9c1f004be38a410bd3d88fb67b211b1b6cbb1d0"
|
|
731
731
|
},
|
|
732
732
|
{
|
|
733
733
|
name: "openspec-archive-change",
|
|
734
734
|
file: "assets/skills/openspec-archive-change/SKILL.md",
|
|
735
735
|
description: "Skill de archivo de change (OpenSpec)",
|
|
736
|
-
version: "0.9.
|
|
736
|
+
version: "0.9.3",
|
|
737
737
|
sha256: "16e4b561de7747283663fed602e506abf502452c49a8d4b86d7a5539c40f0195"
|
|
738
738
|
},
|
|
739
739
|
{
|
|
740
740
|
name: "openspec-explore",
|
|
741
741
|
file: "assets/skills/openspec-explore/SKILL.md",
|
|
742
742
|
description: "Modo explore para OpenSpec — thinking partner para explorar ideas, investigar problemas y clarificar requisitos antes/durante un cambio",
|
|
743
|
-
version: "0.9.
|
|
743
|
+
version: "0.9.3",
|
|
744
744
|
sha256: "9eafc3a8c693b8d9916867ef764d49e5222da717fde501c957bb3f6c312d2415"
|
|
745
745
|
},
|
|
746
746
|
{
|
|
747
747
|
name: "using-git-worktrees",
|
|
748
748
|
file: "assets/skills/using-git-worktrees/SKILL.md",
|
|
749
749
|
description: "Skill de uso de git worktrees para aislamiento de trabajo",
|
|
750
|
-
version: "0.9.
|
|
750
|
+
version: "0.9.3",
|
|
751
751
|
sha256: "93341bc1b7c053618a8b6dc07e3615b77990d7b549a0201f5835d95fef67ce13"
|
|
752
752
|
},
|
|
753
753
|
{
|
|
754
754
|
name: "using-superpowers",
|
|
755
755
|
file: "assets/skills/using-superpowers/SKILL.md",
|
|
756
756
|
description: "Skill de orquestación de Superpowers skills",
|
|
757
|
-
version: "0.9.
|
|
757
|
+
version: "0.9.3",
|
|
758
758
|
sha256: "7e54536f96d2a379185a10bfc1e970850caa2561b6d8aca7080f0defea0381a4"
|
|
759
759
|
},
|
|
760
760
|
{
|
|
761
761
|
name: "writing-skills",
|
|
762
762
|
file: "assets/skills/writing-skills/SKILL.md",
|
|
763
763
|
description: "Skill de creación y edición de skills",
|
|
764
|
-
version: "0.9.
|
|
764
|
+
version: "0.9.3",
|
|
765
765
|
sha256: "3d76b906cee518a2b809febb70db95697a35b9f368986bb504b4120c3bfb437a"
|
|
766
766
|
},
|
|
767
767
|
{
|
|
768
768
|
name: "graceful-degradation",
|
|
769
769
|
file: "assets/skills/graceful-degradation/SKILL.md",
|
|
770
770
|
description: "Skill de degradación graceful cuando múltiples tools están indisponibles",
|
|
771
|
-
version: "0.9.
|
|
771
|
+
version: "0.9.3",
|
|
772
772
|
sha256: "363449bd9e6f800a0a3168667cf78f767fb105d86e4a4adadcc649d418139303"
|
|
773
773
|
}
|
|
774
774
|
]
|
|
@@ -1178,22 +1178,25 @@ function copyEngramPlugin(projectRoot) {
|
|
|
1178
1178
|
copyFileSync3(pluginSource, join7(pluginsDir, "engram.ts"));
|
|
1179
1179
|
}
|
|
1180
1180
|
function copyOstackyControllerPlugin(projectRoot) {
|
|
1181
|
-
const
|
|
1182
|
-
const coreSource = join7(PACKAGE_ROOT, "assets", "plugins", "controller-core.ts");
|
|
1183
|
-
const securitySource = join7(PACKAGE_ROOT, "assets", "plugins", "security.ts");
|
|
1184
|
-
const tieredSource = join7(PACKAGE_ROOT, "assets", "plugins", "tiered.ts");
|
|
1181
|
+
const packageSource = join7(PACKAGE_ROOT, "assets", "plugins", "ostacky-controller");
|
|
1185
1182
|
const pluginsDir = join7(projectRoot, ".opencode", "plugins");
|
|
1186
|
-
|
|
1187
|
-
|
|
1183
|
+
const packageDest = join7(pluginsDir, "ostacky-controller");
|
|
1184
|
+
if (!existsSync6(join7(packageSource, "index.ts"))) {
|
|
1185
|
+
throw new Error(`Plugin bundleado de OstackyController no encontrado: ${packageSource}`);
|
|
1186
|
+
}
|
|
1187
|
+
mkdirSync4(packageDest, { recursive: true });
|
|
1188
|
+
for (const f of ["index.ts", "controller-core.ts", "security.ts", "tiered.ts"]) {
|
|
1189
|
+
const src = join7(packageSource, f);
|
|
1190
|
+
if (existsSync6(src))
|
|
1191
|
+
copyFileSync3(src, join7(packageDest, f));
|
|
1192
|
+
}
|
|
1193
|
+
for (const f of ["ostacky-plugin.ts", "controller-core.ts", "security.ts", "tiered.ts"]) {
|
|
1194
|
+
const legacy = join7(pluginsDir, f);
|
|
1195
|
+
try {
|
|
1196
|
+
if (existsSync6(legacy))
|
|
1197
|
+
rmSync4(legacy, { force: true });
|
|
1198
|
+
} catch {}
|
|
1188
1199
|
}
|
|
1189
|
-
mkdirSync4(pluginsDir, { recursive: true });
|
|
1190
|
-
copyFileSync3(pluginSource, join7(pluginsDir, "ostacky-plugin.ts"));
|
|
1191
|
-
if (existsSync6(coreSource))
|
|
1192
|
-
copyFileSync3(coreSource, join7(pluginsDir, "controller-core.ts"));
|
|
1193
|
-
if (existsSync6(securitySource))
|
|
1194
|
-
copyFileSync3(securitySource, join7(pluginsDir, "security.ts"));
|
|
1195
|
-
if (existsSync6(tieredSource))
|
|
1196
|
-
copyFileSync3(tieredSource, join7(pluginsDir, "tiered.ts"));
|
|
1197
1200
|
}
|
|
1198
1201
|
function buildEngramDownloadUrl(tag, platform = process.platform, arch = process.arch) {
|
|
1199
1202
|
const target = getEngramReleaseTarget(platform, arch);
|
|
@@ -1506,6 +1509,23 @@ function uninstallStackConfig(paths) {
|
|
|
1506
1509
|
removed.push(".opencode/tools/");
|
|
1507
1510
|
} catch {}
|
|
1508
1511
|
}
|
|
1512
|
+
const ownedPlugins = [
|
|
1513
|
+
"ostacky-controller",
|
|
1514
|
+
"engram.ts",
|
|
1515
|
+
"ostacky-plugin.ts",
|
|
1516
|
+
"controller-core.ts",
|
|
1517
|
+
"security.ts",
|
|
1518
|
+
"tiered.ts"
|
|
1519
|
+
];
|
|
1520
|
+
for (const name of ownedPlugins) {
|
|
1521
|
+
const p = join7(paths.plugins, name);
|
|
1522
|
+
if (existsSync6(p)) {
|
|
1523
|
+
try {
|
|
1524
|
+
rmSync4(p, { recursive: true, force: true });
|
|
1525
|
+
removed.push(`.opencode/plugins/${name}`);
|
|
1526
|
+
} catch {}
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1509
1529
|
if (removed.length === 0) {
|
|
1510
1530
|
return { success: true, message: "No había configuración del stack para remover" };
|
|
1511
1531
|
}
|
|
@@ -1522,13 +1542,15 @@ var init_stack = __esm(() => {
|
|
|
1522
1542
|
});
|
|
1523
1543
|
|
|
1524
1544
|
// src/doctor-v2.ts
|
|
1525
|
-
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
1545
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync3 } from "fs";
|
|
1526
1546
|
import { join as join10, delimiter, isAbsolute } from "path";
|
|
1527
1547
|
function checkDoctorV2(projectRoot) {
|
|
1528
1548
|
const lines = [];
|
|
1529
1549
|
const cwd = projectRoot;
|
|
1530
1550
|
const opencodeDir = findOpenCodeDir(cwd) || join10(cwd, ".opencode");
|
|
1531
1551
|
const pluginPaths = [
|
|
1552
|
+
join10(opencodeDir, "plugins", "ostacky-controller", "index.ts"),
|
|
1553
|
+
join10(cwd, ".opencode", "plugins", "ostacky-controller", "index.ts"),
|
|
1532
1554
|
join10(opencodeDir, "plugins", "ostacky-plugin.ts"),
|
|
1533
1555
|
join10(cwd, ".opencode", "plugins", "ostacky-plugin.ts"),
|
|
1534
1556
|
join10(cwd, "assets", "plugins", "ostacky-plugin.ts")
|
|
@@ -1546,6 +1568,33 @@ function checkDoctorV2(projectRoot) {
|
|
|
1546
1568
|
lines.push(`⚠️ controller: no se pudo leer ${found}`);
|
|
1547
1569
|
}
|
|
1548
1570
|
}
|
|
1571
|
+
const pluginsDir = join10(opencodeDir, "plugins");
|
|
1572
|
+
for (const f of ["controller-core.ts", "security.ts", "tiered.ts"]) {
|
|
1573
|
+
try {
|
|
1574
|
+
const p = join10(pluginsDir, f);
|
|
1575
|
+
if (existsSync8(p) && !readFileSync6(p, "utf-8").includes("export default")) {
|
|
1576
|
+
lines.push(`⚠️ plugins/${f} suelto sin default — el server lo carga como plugin y falla; mové a plugins/ostacky-controller/ o re-corré install (doctor no lo modifica)`);
|
|
1577
|
+
}
|
|
1578
|
+
} catch {}
|
|
1579
|
+
}
|
|
1580
|
+
try {
|
|
1581
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
1582
|
+
const globalPlugins = home ? join10(home, ".config", "opencode", "plugins") : "";
|
|
1583
|
+
if (globalPlugins) {
|
|
1584
|
+
let entries = [];
|
|
1585
|
+
try {
|
|
1586
|
+
entries = readdirSync3(globalPlugins).filter((e) => e.endsWith(".ts"));
|
|
1587
|
+
} catch {}
|
|
1588
|
+
for (const e of entries) {
|
|
1589
|
+
try {
|
|
1590
|
+
const src = readFileSync6(join10(globalPlugins, e), "utf-8");
|
|
1591
|
+
if (src.includes("@opencode-ai/") || !src.includes("export default")) {
|
|
1592
|
+
lines.push(`⚠️ global ${e} con formato V1 (@opencode-ai/* o sin default) — no corre en server V2; actualizalo o borralo a mano (doctor no lo modifica)`);
|
|
1593
|
+
}
|
|
1594
|
+
} catch {}
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
} catch {}
|
|
1549
1598
|
const configPath = findOpenCodeConfig(cwd);
|
|
1550
1599
|
if (!configPath) {
|
|
1551
1600
|
lines.push("ℹ️ config: no hay opencode.json ni opencode.jsonc");
|
|
@@ -1625,7 +1674,7 @@ var init_doctor_v2 = __esm(() => {
|
|
|
1625
1674
|
// package.json
|
|
1626
1675
|
var package_default = {
|
|
1627
1676
|
name: "ostacky",
|
|
1628
|
-
version: "0.9.
|
|
1677
|
+
version: "0.9.3",
|
|
1629
1678
|
description: "Instalador interactivo de agentes y comandos para OpenCode",
|
|
1630
1679
|
type: "module",
|
|
1631
1680
|
bin: {
|
|
@@ -1637,13 +1686,7 @@ var package_default = {
|
|
|
1637
1686
|
build: "bun build src/cli.ts --target=node --format=esm --outfile dist/cli.js && bun scripts/add-shebang.ts",
|
|
1638
1687
|
start: "node dist/cli.js",
|
|
1639
1688
|
test: "bun test",
|
|
1640
|
-
|
|
1641
|
-
"check:skills:fix": "bun run scripts/check-skill-sync.ts --fix",
|
|
1642
|
-
"hash:check": "bun run scripts/update-manifest-hashes.ts --check",
|
|
1643
|
-
"hash:update": "bun run scripts/update-manifest-hashes.ts",
|
|
1644
|
-
"manifest:prepare": "bun run scripts/update-manifest-hashes.ts",
|
|
1645
|
-
"manifest:check": "bun run scripts/update-manifest-hashes.ts --check",
|
|
1646
|
-
prepublishOnly: "bun run scripts/sync-controller-core.ts && bun run manifest:prepare && bun run build"
|
|
1689
|
+
update: "bun run scripts/check-skill-sync.ts && bun run scripts/sync-controller-core.ts && bun run scripts/update-manifest-hashes.ts"
|
|
1647
1690
|
},
|
|
1648
1691
|
files: [
|
|
1649
1692
|
"dist/",
|
|
@@ -2804,7 +2847,7 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath, option
|
|
|
2804
2847
|
params: {
|
|
2805
2848
|
protocolVersion: "2025-03-26",
|
|
2806
2849
|
capabilities: {},
|
|
2807
|
-
clientInfo: { name: "ostacky-installer", version: "0.9.
|
|
2850
|
+
clientInfo: { name: "ostacky-installer", version: "0.9.3" }
|
|
2808
2851
|
}
|
|
2809
2852
|
});
|
|
2810
2853
|
});
|
|
@@ -3145,6 +3188,12 @@ function uninstallAll(paths) {
|
|
|
3145
3188
|
} catch {}
|
|
3146
3189
|
}
|
|
3147
3190
|
}
|
|
3191
|
+
const packageDir = join6(paths.plugins, "ostacky-controller");
|
|
3192
|
+
if (existsSync5(packageDir)) {
|
|
3193
|
+
try {
|
|
3194
|
+
rmSync3(packageDir, { recursive: true, force: true });
|
|
3195
|
+
} catch {}
|
|
3196
|
+
}
|
|
3148
3197
|
clearLockfile(paths.root);
|
|
3149
3198
|
}
|
|
3150
3199
|
|
|
@@ -3377,13 +3426,17 @@ async function doInstallAll(manifest, paths) {
|
|
|
3377
3426
|
const { join } = await import("path");
|
|
3378
3427
|
await Promise.resolve().then(() => init_github());
|
|
3379
3428
|
const { findProjectRoot } = await Promise.resolve().then(() => (init_fs(), {}));
|
|
3380
|
-
const
|
|
3381
|
-
const
|
|
3382
|
-
if (existsSync(
|
|
3383
|
-
mkdirSync(
|
|
3384
|
-
|
|
3429
|
+
const packageSrc = join(PACKAGE_ROOT, "assets", "plugins", "ostacky-controller");
|
|
3430
|
+
const packageDest = join(paths.plugins, "ostacky-controller");
|
|
3431
|
+
if (existsSync(join(packageSrc, "index.ts"))) {
|
|
3432
|
+
mkdirSync(packageDest, { recursive: true });
|
|
3433
|
+
for (const f of ["index.ts", "controller-core.ts", "security.ts", "tiered.ts"]) {
|
|
3434
|
+
const s = join(packageSrc, f);
|
|
3435
|
+
if (existsSync(s))
|
|
3436
|
+
copyFileSync(s, join(packageDest, f));
|
|
3437
|
+
}
|
|
3385
3438
|
}
|
|
3386
|
-
for (const legacy of ["ostacky-guard.ts", "ostacky-controller.ts"]) {
|
|
3439
|
+
for (const legacy of ["ostacky-plugin.ts", "controller-core.ts", "security.ts", "tiered.ts", "ostacky-guard.ts", "ostacky-controller.ts"]) {
|
|
3387
3440
|
const lp = join(paths.plugins, legacy);
|
|
3388
3441
|
if (existsSync(lp))
|
|
3389
3442
|
try {
|
|
@@ -4412,7 +4465,7 @@ async function runUninstallMcpCommand(name, scope) {
|
|
|
4412
4465
|
|
|
4413
4466
|
// src/cli.ts
|
|
4414
4467
|
init_fs();
|
|
4415
|
-
import { existsSync as existsSync9, statSync as statSync3, readFileSync as readFileSync7, readdirSync as
|
|
4468
|
+
import { existsSync as existsSync9, statSync as statSync3, readFileSync as readFileSync7, readdirSync as readdirSync4 } from "node:fs";
|
|
4416
4469
|
import { join as join11, dirname as dirname8 } from "node:path";
|
|
4417
4470
|
var HELP = `
|
|
4418
4471
|
ostacky — Instalador de agentes, comandos, skills y MCPs para OpenCode
|
|
@@ -4500,6 +4553,9 @@ async function runDoctorCommand() {
|
|
|
4500
4553
|
}
|
|
4501
4554
|
};
|
|
4502
4555
|
const pluginPaths = [
|
|
4556
|
+
join11(cwd, "assets", "plugins", "ostacky-controller", "index.ts"),
|
|
4557
|
+
join11(opencodeDir, "plugins", "ostacky-controller", "index.ts"),
|
|
4558
|
+
join11(cwd, ".opencode", "plugins", "ostacky-controller", "index.ts"),
|
|
4503
4559
|
join11(cwd, "assets", "plugins", "ostacky-plugin.ts"),
|
|
4504
4560
|
join11(opencodeDir, "plugins", "ostacky-plugin.ts"),
|
|
4505
4561
|
join11(cwd, ".opencode", "plugins", "ostacky-plugin.ts"),
|
|
@@ -4643,7 +4699,7 @@ async function runDoctorCommand() {
|
|
|
4643
4699
|
if (!existsSync9(cacheDir)) {
|
|
4644
4700
|
console.log("ℹ️ cache: no cache dir yet (ok)");
|
|
4645
4701
|
} else {
|
|
4646
|
-
const files =
|
|
4702
|
+
const files = readdirSync4(cacheDir);
|
|
4647
4703
|
let total = 0;
|
|
4648
4704
|
for (const f of files) {
|
|
4649
4705
|
try {
|
|
@@ -4707,7 +4763,7 @@ async function runDoctorCommand() {
|
|
|
4707
4763
|
check("honesty: 7 SHALL", hasHonesty);
|
|
4708
4764
|
if (!hasHonesty)
|
|
4709
4765
|
console.log(" Expected: ## Principios de honestidad (SHALL) in ostacky.md");
|
|
4710
|
-
const pluginPath = join11(cwd, "assets", "plugins", "ostacky-
|
|
4766
|
+
const pluginPath = join11(cwd, "assets", "plugins", "ostacky-controller", "index.ts");
|
|
4711
4767
|
if (existsSync9(pluginPath)) {
|
|
4712
4768
|
const plugin = readFileSync7(pluginPath, "utf-8");
|
|
4713
4769
|
const hasSpecGuard = plugin.includes("getDiscoverySnapshot") && plugin.includes("specSnapshot");
|
package/manifest.json
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.9.
|
|
2
|
+
"version": "0.9.3",
|
|
3
3
|
"repo": "JaimeHoracio/Ostacky",
|
|
4
|
-
"tag": "v0.9.
|
|
4
|
+
"tag": "v0.9.3",
|
|
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.9.
|
|
10
|
-
"version": "0.9.
|
|
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.9.3: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
|
|
10
|
+
"version": "0.9.3",
|
|
11
|
+
"sha256": "51f1deb14c75c5c0b25a77d8ec871e951b4341e4658a735967ba1143baa72f9f"
|
|
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.9.
|
|
19
|
-
"version": "0.9.
|
|
20
|
-
"sha256": "
|
|
18
|
+
"description": "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.9.3: controller plugin como alma hard-gate, Context7 removido del stack.",
|
|
19
|
+
"version": "0.9.3",
|
|
20
|
+
"sha256": "ccc065dd11b53b1c77acafa86ef9dbf65df8ed3f217193901f8b7818447418c1"
|
|
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.9.
|
|
26
|
+
"version": "0.9.3",
|
|
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.9.
|
|
35
|
-
"version": "0.9.
|
|
36
|
-
"sha256": "
|
|
34
|
+
"description": "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.9.3: 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.9.3",
|
|
36
|
+
"sha256": "8548f1b13270fbd0fb5e76888c96b38bc39bf0ba3c8b03fbc8196683226eb4b0"
|
|
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.9.
|
|
42
|
+
"version": "0.9.3",
|
|
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.9.
|
|
51
|
+
"version": "0.9.3",
|
|
52
52
|
"sha256": "f1013a86a8f27914d85a716e23c7fd32db1786d93615e8b0834b13d184308549"
|
|
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.9.
|
|
58
|
+
"version": "0.9.3",
|
|
59
59
|
"sha256": "2158a6864c0912e868a9d720db7fd79441e6cc298e3320833d2527c9727c852e"
|
|
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.9.
|
|
65
|
+
"version": "0.9.3",
|
|
66
66
|
"sha256": "f0ebfbbc43a8868d31a3fd2df37ae7f60fe8add09c6475862395a68269e5ff7f"
|
|
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.9.
|
|
72
|
+
"version": "0.9.3",
|
|
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.9.
|
|
79
|
+
"version": "0.9.3",
|
|
80
80
|
"sha256": "7e7b712ef742d5631e302e6a71583e2bbbd33094da9281abfb84b43505fc3ef1"
|
|
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.9.
|
|
86
|
+
"version": "0.9.3",
|
|
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.9.
|
|
93
|
+
"version": "0.9.3",
|
|
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.9.
|
|
100
|
+
"version": "0.9.3",
|
|
101
101
|
"sha256": "6a517f750f24c008208156a2d653e97ed30b1e53878aeac5ce394e573db0678f"
|
|
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.9.
|
|
107
|
+
"version": "0.9.3",
|
|
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.9.
|
|
114
|
+
"version": "0.9.3",
|
|
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.9.
|
|
121
|
+
"version": "0.9.3",
|
|
122
122
|
"sha256": "9eafc3a8c693b8d9916867ef764d49e5222da717fde501c957bb3f6c312d2415"
|
|
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.9.
|
|
128
|
+
"version": "0.9.3",
|
|
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.9.
|
|
135
|
+
"version": "0.9.3",
|
|
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.9.
|
|
142
|
+
"version": "0.9.3",
|
|
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.9.
|
|
149
|
+
"version": "0.9.3",
|
|
150
150
|
"sha256": "363449bd9e6f800a0a3168667cf78f767fb105d86e4a4adadcc649d418139303"
|
|
151
151
|
}
|
|
152
152
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ostacky",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "Instalador interactivo de agentes y comandos para OpenCode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,13 +12,7 @@
|
|
|
12
12
|
"build": "bun build src/cli.ts --target=node --format=esm --outfile dist/cli.js && bun scripts/add-shebang.ts",
|
|
13
13
|
"start": "node dist/cli.js",
|
|
14
14
|
"test": "bun test",
|
|
15
|
-
"
|
|
16
|
-
"check:skills:fix": "bun run scripts/check-skill-sync.ts --fix",
|
|
17
|
-
"hash:check": "bun run scripts/update-manifest-hashes.ts --check",
|
|
18
|
-
"hash:update": "bun run scripts/update-manifest-hashes.ts",
|
|
19
|
-
"manifest:prepare": "bun run scripts/update-manifest-hashes.ts",
|
|
20
|
-
"manifest:check": "bun run scripts/update-manifest-hashes.ts --check",
|
|
21
|
-
"prepublishOnly": "bun run scripts/sync-controller-core.ts && bun run manifest:prepare && bun run build"
|
|
15
|
+
"update": "bun run scripts/check-skill-sync.ts && bun run scripts/sync-controller-core.ts && bun run scripts/update-manifest-hashes.ts"
|
|
22
16
|
},
|
|
23
17
|
"files": [
|
|
24
18
|
"dist/",
|
|
File without changes
|
|
File without changes
|