ostacky 0.8.7 → 0.8.8
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 +13 -13
- package/assets/agents/ostacky.md +3 -3
- package/assets/commands/install-stack.md +2 -2
- package/assets/docs/ostacky-reference.md +10 -2
- package/assets/mcp/ostacky-controller/controller-core.js +2 -2
- package/assets/mcp/ostacky-controller/index.js +2 -2
- package/assets/mcp/ostacky-controller/package.json +1 -1
- package/assets/mcp/ostacky-controller/security.js +33 -2
- package/assets/plugins/controller-core.ts +2 -2
- package/assets/plugins/ostacky-plugin.ts +35 -3
- package/assets/plugins/security.ts +118 -0
- package/assets/plugins/tiered.ts +46 -0
- package/assets/skills/dispatching-parallel-agents/SKILL.md +1 -0
- package/assets/skills/openspec-explore/SKILL.md +2 -1
- package/assets/skills/openspec-propose/SKILL.md +3 -1
- package/assets/skills/tdd/SKILL.md +2 -0
- package/dist/cli.js +54 -38
- package/manifest.json +32 -32
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -246,37 +246,37 @@ Tras instalar (`--scope local`), el proyecto queda así:
|
|
|
246
246
|
|
|
247
247
|
```json
|
|
248
248
|
{
|
|
249
|
-
"version": "0.8.
|
|
249
|
+
"version": "0.8.8",
|
|
250
250
|
"lockedAt": "2025-01-01T00:00:00.000Z",
|
|
251
251
|
"repo": "JaimeHoracio/Ostacky",
|
|
252
|
-
"tag": "v0.8.
|
|
252
|
+
"tag": "v0.8.8",
|
|
253
253
|
"agents": {
|
|
254
254
|
"ostacky": {
|
|
255
|
-
"version": "0.8.
|
|
255
|
+
"version": "0.8.8",
|
|
256
256
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
257
257
|
"sha256": "abc123..."
|
|
258
258
|
}
|
|
259
259
|
},
|
|
260
260
|
"commands": {
|
|
261
261
|
"install-stack": {
|
|
262
|
-
"version": "0.8.
|
|
262
|
+
"version": "0.8.8",
|
|
263
263
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
264
264
|
"sha256": "def456..."
|
|
265
265
|
},
|
|
266
266
|
"opsx-sync": {
|
|
267
|
-
"version": "0.8.
|
|
267
|
+
"version": "0.8.8",
|
|
268
268
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
269
269
|
"sha256": "ghi789..."
|
|
270
270
|
}
|
|
271
271
|
},
|
|
272
272
|
"skills": {
|
|
273
|
-
"brainstorming": { "version": "0.8.
|
|
274
|
-
"execution-mode-evaluation": { "version": "0.8.
|
|
275
|
-
"openspec-propose": { "version": "0.8.
|
|
273
|
+
"brainstorming": { "version": "0.8.8", ... },
|
|
274
|
+
"execution-mode-evaluation": { "version": "0.8.8", ... },
|
|
275
|
+
"openspec-propose": { "version": "0.8.8", ... }
|
|
276
276
|
},
|
|
277
277
|
"mcpServers": {
|
|
278
|
-
"ostacky-controller": { "version": "0.8.
|
|
279
|
-
"openspec": { "version": "0.8.
|
|
278
|
+
"ostacky-controller": { "version": "0.8.8", ... },
|
|
279
|
+
"openspec": { "version": "0.8.8", ... }
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
282
|
```
|
|
@@ -308,7 +308,7 @@ Es opcional y solo necesario si algo falló durante la instalación o si querés
|
|
|
308
308
|
## Seguridad
|
|
309
309
|
|
|
310
310
|
- `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.8.
|
|
311
|
+
- Las URLs de descarga usan **tags de GitHub** (ej. `v0.8.8`), nunca `main` — instalaciones reproducibles
|
|
312
312
|
- Cada path de archivo descargado es validado para prevenir **path traversal**
|
|
313
313
|
- Los archivos incluyen **checksum SHA-256** opcional; si el manifest lo define, el contenido se verifica antes de escribir
|
|
314
314
|
- El cache local (`.opencode/cache/`) también valida integridad al servir archivos cacheados
|
|
@@ -324,7 +324,7 @@ Es opcional y solo necesario si algo falló durante la instalación o si querés
|
|
|
324
324
|
- Variable `OSTACKY_SENSITIVE_PATTERNS` overridea los patrones por defecto (`**/.env*`, `**/.secrets/**`, `**/*.pem`, `**/*.key`, `**/.aws/**`, `**/.ssh/**`, `**/credentials.json`, `**/.npmrc`).
|
|
325
325
|
- Ejemplo: `OSTACKY_SENSITIVE_PATTERNS="**/.env*,**/.secrets/**" bunx ostacky doctor` — `doctor` imprime el patrón efectivo.
|
|
326
326
|
- Allowlist: `.env.example`, `.env.template`, `.env.sample` nunca se bloquean.
|
|
327
|
-
- Fuente única: `src/security.ts` (`SENSITIVE_DEFAULT`, `isSensitive`, `BASH_SENSITIVE_RE`) — `ostacky-
|
|
327
|
+
- Fuente única: `src/security.ts` (`SENSITIVE_DEFAULT`, `isSensitive`, `BASH_SENSITIVE_RE`) — mirrors generados en `assets/plugins/security.ts` y `assets/mcp/ostacky-controller/security.js` vía `bun run scripts/sync-controller-core.ts`; `ostacky-plugin.ts` importa de `./security.ts` (self-contained). Ver `doctor` para verificar.
|
|
328
328
|
|
|
329
329
|
#### Aislamiento de worktrees (harness-prod-hardening)
|
|
330
330
|
|
|
@@ -365,7 +365,7 @@ CodeGraph está instalado en `.opencode/tools/codegraph/bin/codegraph` y se conf
|
|
|
365
365
|
| `.opencode/tools/codegraph/bin/codegraph status` | Muestra estado del index y archivos pendientes |
|
|
366
366
|
| `.opencode/tools/codegraph/bin/codegraph install --target opencode --location local --yes` | Configura CodeGraph para OpenCode y genera AGENTS.md |
|
|
367
367
|
|
|
368
|
-
> **Windows:** si ves `Command failed: cmd.exe /d /c call ... codegraph.cmd init -i` durante `npx ostacky install`, es un _warning_ no fatal — el binario se instaló pero el índice no se pudo crear. Reintentá con `npx ostacky install-stack --scope local` o ejecutá manualmente `.opencode\tools\codegraph\bin\codegraph.exe init -i` (o `codegraph.cmd` si no hay `.exe`) dentro del proyecto. Desde v0.8.
|
|
368
|
+
> **Windows:** si ves `Command failed: cmd.exe /d /c call ... codegraph.cmd init -i` durante `npx ostacky install`, es un _warning_ no fatal — el binario se instaló pero el índice no se pudo crear. Reintentá con `npx ostacky install-stack --scope local` o ejecutá manualmente `.opencode\tools\codegraph\bin\codegraph.exe init -i` (o `codegraph.cmd` si no hay `.exe`) dentro del proyecto. Desde v0.8.8 el instalador usa el patrón resiliente de Engram (strip 0 + búsqueda recursiva) y loguea `projectRoot|toolsDir` para diagnosticar scope.
|
|
369
369
|
|
|
370
370
|
## Licencia
|
|
371
371
|
|
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.8
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Sos **Ostacky v0.8.
|
|
7
|
+
Sos **Ostacky v0.8.8**, 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.8` (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.8"** (o `v0.8.8` 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.8, `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.8.
|
|
14
|
+
## Scope de instalación — local vs global (desde v0.8.8)
|
|
15
15
|
|
|
16
16
|
`npx ostacky install` soporta `--scope local|global|auto` (también `--scope=...`):
|
|
17
17
|
|
|
@@ -64,14 +64,22 @@ Principio: **eficacia > recorte** — si recorte rompiera caché y saliera más
|
|
|
64
64
|
|
|
65
65
|
## Security single-source
|
|
66
66
|
|
|
67
|
-
`src/security.ts` único origen de `SENSITIVE_DEFAULT`/`BASH_SENSITIVE_RE`/`isSensitive`/`extractPathsFromBash
|
|
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-plugin.ts` importa de `./security.ts` self-contained (no `../../src`). `BASH_SENSITIVE_RE` arriba. `OSTACKY_SENSITIVE_PATTERNS` override.
|
|
68
68
|
|
|
69
69
|
## Tiered single-source
|
|
70
70
|
|
|
71
|
-
`src/tiered.ts` único origen de `isTrivial(msg,state)` + `getControllerState(dir)`.
|
|
71
|
+
`src/tiered.ts` único origen de `isTrivial(msg,state)` + `getControllerState(dir)`. `ostacky-plugin.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-plugin.ts` y `assets/plugins/engram.ts`.
|
|
72
|
+
|
|
73
|
+
## Controller single-source
|
|
74
|
+
|
|
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. `ostacky-plugin.ts` importa de `./controller-core.ts` self-contained.
|
|
72
76
|
|
|
73
77
|
## Prompt-efficiency
|
|
74
78
|
|
|
75
79
|
- `ostacky.md` 109→72 líneas (diet estable cacheable). Tiered vía suffix, no reemplazo `system[0]`.
|
|
76
80
|
- `controller` descriptions <150 chars
|
|
77
81
|
- `MEMORY_INSTRUCTIONS` lazy: siempre pointer (~1 línea) en `system.transform`; full vive en `assets/docs/engram-protocol.md` on-demand via `Read` (ahorro ~1.2k en FULL, trivial ya era pointer)
|
|
82
|
+
|
|
83
|
+
## Propose Flow (1+)
|
|
84
|
+
|
|
85
|
+
`openspec-propose` SHALL Paso 0: `getDiscoverySnapshot(query)` + `getEngramDedup` → si miss `codegraph_codegraph_explore` + `engram_mem_search` + `putDiscoverySnapshot` **antes** de `openspec new`. Cita símbolos existentes en `proposal/design`; sin esto dispara `WARN:codegraphBypass` y `design.md` alucina API. Ver `assets/skills/openspec-propose/SKILL.md: Paso 0` y `brainstorming` (router por nivel: `brainstorming` decide 0/0+1/1+, `openspec-explore` es stance sin nivel).
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* controller-core — Single source of truth para TRANSITIONS, STATES, DEFAULT_STATE y helpers.
|
|
3
|
-
*
|
|
4
|
-
* para eliminar duplicación (D1). Ambos importan de acá.
|
|
3
|
+
* Generado desde src/controller-core.ts — NO EDITAR. Ejecutá `bun run scripts/sync-controller-core.ts`.
|
|
5
4
|
*/
|
|
6
5
|
|
|
7
6
|
import { SENSITIVE_DEFAULT } from "./security.js";
|
|
@@ -142,6 +141,7 @@ export const DEFAULT_STATE = {
|
|
|
142
141
|
watchdogEnabled: true,
|
|
143
142
|
ts: Date.now(),
|
|
144
143
|
specNotInSync: false,
|
|
144
|
+
engramBypassCount: 0,
|
|
145
145
|
};
|
|
146
146
|
|
|
147
147
|
export function safeJsonStringify(obj, pretty = false) {
|
|
@@ -2576,7 +2576,7 @@ function safeHandler(fn, options = {}) {
|
|
|
2576
2576
|
|
|
2577
2577
|
const server = new McpServer({
|
|
2578
2578
|
name: 'ostacky-controller',
|
|
2579
|
-
version: '0.8.
|
|
2579
|
+
version: '0.8.8',
|
|
2580
2580
|
});
|
|
2581
2581
|
|
|
2582
2582
|
server.registerTool(
|
|
@@ -3176,7 +3176,7 @@ function setupGracefulShutdown(ctrl) {
|
|
|
3176
3176
|
}
|
|
3177
3177
|
|
|
3178
3178
|
async function main() {
|
|
3179
|
-
log('Starting ostacky-controller MCP v0.8.
|
|
3179
|
+
log('Starting ostacky-controller MCP v0.8.8...');
|
|
3180
3180
|
log('State path:', { path: statePath });
|
|
3181
3181
|
// Clean up stale tmp/lock files from previous runs
|
|
3182
3182
|
cleanupTmpFiles(statePath);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* security.js — source-of-truth mirror of src/security.ts for controller (Node)
|
|
3
|
-
* Generado desde src/security.ts —
|
|
3
|
+
* Generado desde src/security.ts — NO EDITAR. Ejecutá `bun run scripts/sync-controller-core.ts`.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
// ─── Sensitive guard — source-of-truth (hardening-v2 D1) ───────────────
|
|
7
|
+
|
|
6
8
|
export const SENSITIVE_DEFAULT = [
|
|
7
9
|
"**/.env*",
|
|
8
10
|
"**/.secrets/**",
|
|
@@ -14,9 +16,20 @@ export const SENSITIVE_DEFAULT = [
|
|
|
14
16
|
"**/.npmrc",
|
|
15
17
|
];
|
|
16
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Regex que detecta acceso sensible en comandos bash.
|
|
21
|
+
* Cubre .env, .secrets, .pem, .key, .aws, .ssh, credentials.json, .npmrc
|
|
22
|
+
* Normalizar antes (strip quotes/backslashes) y testear con `BASH_SENSITIVE_RE.test(normalized)`.
|
|
23
|
+
*/
|
|
17
24
|
export const BASH_SENSITIVE_RE =
|
|
18
25
|
/(?:^|[^a-zA-Z0-9_.-])(\.env(\b|[_.-])|\.secrets\b|\.pem\b|\.key\b|credentials\.json|\.aws\b|\.ssh\b|\.npmrc\b)/i;
|
|
19
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Returns true if filePath is considered sensitive given patterns.
|
|
29
|
+
* - Allowlist: .env.example / .env.template / .env.sample nunca son sensibles.
|
|
30
|
+
* - Normaliza backslashes a "/" para Windows.
|
|
31
|
+
* - patterns: array de globs como SENSITIVE_DEFAULT; si no se pasa usa SENSITIVE_DEFAULT.
|
|
32
|
+
*/
|
|
20
33
|
export function isSensitive(filePath, patterns = SENSITIVE_DEFAULT) {
|
|
21
34
|
if (!filePath) return false;
|
|
22
35
|
const normalized = filePath.replace(/\\/g, "/");
|
|
@@ -38,25 +51,37 @@ export function isSensitive(filePath, patterns = SENSITIVE_DEFAULT) {
|
|
|
38
51
|
if (pat.includes("credentials.json") && lower.endsWith("credentials.json")) return true;
|
|
39
52
|
if (pat.includes(".npmrc") && lower.endsWith(".npmrc")) return true;
|
|
40
53
|
}
|
|
54
|
+
// fallback genérico por extensión
|
|
41
55
|
if (/\.(pem|key)$/i.test(normalized)) return true;
|
|
42
56
|
if (base.startsWith(".env")) return true;
|
|
43
57
|
return false;
|
|
44
58
|
}
|
|
45
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Extrae paths candidatos de un comando bash para chequear sensibilidad.
|
|
62
|
+
* Tokeniza por separadores shell `| ; && || > >> <` y respeta quotes.
|
|
63
|
+
* Normaliza quitando quotes y backslashes para detectar obfuscaciones como .e""nv.
|
|
64
|
+
*/
|
|
46
65
|
export function extractPathsFromBash(cmd) {
|
|
47
66
|
if (!cmd) return [];
|
|
67
|
+
// Normalizar && y || a ; para split único
|
|
48
68
|
const normalized = cmd.replace(/&&/g, ";").replace(/\|\|/g, ";");
|
|
69
|
+
// Split por separadores shell
|
|
49
70
|
const segments = normalized.split(/[|;><\n]+/);
|
|
50
71
|
const paths = [];
|
|
51
72
|
for (const seg of segments) {
|
|
52
73
|
const trimmed = seg.trim();
|
|
53
74
|
if (!trimmed) continue;
|
|
75
|
+
// Tokeniza respetando quotes — captura tokens entre quotes o sin espacios
|
|
54
76
|
const tokens = trimmed.match(/(?:[^\s"'`\\]+|"[^"]*"|'[^']*'|`[^`]*`)+/g) || [];
|
|
55
77
|
for (let token of tokens) {
|
|
78
|
+
// Normalización anti-obfuscación: quitar quotes y backslashes
|
|
56
79
|
const stripped = token.replace(/["'`]/g, "").replace(/\\/g, "");
|
|
57
80
|
if (!stripped) continue;
|
|
58
|
-
|
|
81
|
+
// Filtrar comandos comunes y flags
|
|
82
|
+
if (["cat", "grep", "ls", "echo", "awk", "sed", "cut", "head", "tail", "wc", "find", "xargs", "bash", "sh", "zsh", "env", "printenv", "node", "bun", "npm", "npx", "ls"].includes(stripped)) continue;
|
|
59
83
|
if (stripped.startsWith("-")) continue;
|
|
84
|
+
// Heurística de path: contiene / o . o es .env* o sensible
|
|
60
85
|
const lower = stripped.toLowerCase();
|
|
61
86
|
if (
|
|
62
87
|
stripped.includes("/") ||
|
|
@@ -70,6 +95,7 @@ export function extractPathsFromBash(cmd) {
|
|
|
70
95
|
lower.endsWith("credentials.json") ||
|
|
71
96
|
lower.endsWith(".npmrc")
|
|
72
97
|
) {
|
|
98
|
+
// Limpiar trailing chars como : , )
|
|
73
99
|
const cleaned = stripped.replace(/[,:;)\]]+$/, "");
|
|
74
100
|
if (cleaned) paths.push(cleaned);
|
|
75
101
|
} else if (stripped === ".env") {
|
|
@@ -77,9 +103,14 @@ export function extractPathsFromBash(cmd) {
|
|
|
77
103
|
}
|
|
78
104
|
}
|
|
79
105
|
}
|
|
106
|
+
// También buscar paths con regex global como fallback
|
|
107
|
+
// (detecta .env en strings complejos)
|
|
80
108
|
return [...new Set(paths)];
|
|
81
109
|
}
|
|
82
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Lee patrones sensibles desde env OSTACKY_SENSITIVE_PATTERNS o usa default.
|
|
113
|
+
*/
|
|
83
114
|
export function getSensitivePatterns() {
|
|
84
115
|
const raw = process.env.OSTACKY_SENSITIVE_PATTERNS;
|
|
85
116
|
if (!raw) return SENSITIVE_DEFAULT;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* controller-core — Single source of truth para TRANSITIONS, STATES, DEFAULT_STATE y helpers.
|
|
3
|
-
*
|
|
4
|
-
* para eliminar duplicación (D1). Ambos importan de acá.
|
|
3
|
+
* Generado desde src/controller-core.ts — NO EDITAR. Ejecutá `bun run scripts/sync-controller-core.ts`.
|
|
5
4
|
*/
|
|
6
5
|
|
|
7
6
|
import { SENSITIVE_DEFAULT } from "./security.js";
|
|
@@ -142,6 +141,7 @@ export const DEFAULT_STATE: any = {
|
|
|
142
141
|
watchdogEnabled: true,
|
|
143
142
|
ts: Date.now(),
|
|
144
143
|
specNotInSync: false,
|
|
144
|
+
engramBypassCount: 0,
|
|
145
145
|
};
|
|
146
146
|
|
|
147
147
|
export function safeJsonStringify(obj: any, pretty = false): string {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Mantiene máquina de 13 estados en-process y aplica hard gates en tool.execute.before.
|
|
6
6
|
* MCP queda thin solo para observabilidad (get_*).
|
|
7
7
|
*
|
|
8
|
-
* Single source security:
|
|
8
|
+
* Single source security: mirrors generados desde src/security.ts via scripts/sync-controller-core.ts
|
|
9
9
|
* Cache único: getDiscoverySnapshot es único entrypoint.
|
|
10
10
|
* Tiered cache-friendly: isTrivial sin reemplazar system[0], suffix hint + SKIP.
|
|
11
11
|
* CodeGraph preventivo: bloquea Read/Grep masivo sin Discovery hit.
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
import type { Plugin } from "@opencode-ai/plugin"
|
|
15
15
|
import { readFileSync, writeFileSync, renameSync, mkdirSync, existsSync, statSync, readdirSync, unlinkSync } from "node:fs"
|
|
16
16
|
import { join, dirname, basename, resolve, relative } from "node:path"
|
|
17
|
-
import { SENSITIVE_DEFAULT, BASH_SENSITIVE_RE, isSensitive, extractPathsFromBash } from "
|
|
18
|
-
import { isTrivial } from "
|
|
17
|
+
import { SENSITIVE_DEFAULT, BASH_SENSITIVE_RE, isSensitive, extractPathsFromBash } from "./security.ts"
|
|
18
|
+
import { isTrivial } from "./tiered.ts"
|
|
19
19
|
import { STATES, TRANSITIONS, DEFAULT_STATE } from "./controller-core.ts"
|
|
20
20
|
|
|
21
21
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
@@ -139,6 +139,8 @@ function isCodegraphAvailable(directory: string): boolean {
|
|
|
139
139
|
const trivialBySession = new Map<string, boolean>()
|
|
140
140
|
// Track discovery hit per requestId to avoid blocking after hit
|
|
141
141
|
const discoveryHitByRequest = new Map<string, boolean>()
|
|
142
|
+
// Track Engram hit per session to audit bypass (soft, no BLOCK)
|
|
143
|
+
const engramHitBySession = new Map<string, boolean>()
|
|
142
144
|
// ─── Heartbeat ping — evita sensación de trancado en tareas largas ──
|
|
143
145
|
let lastPingTs = 0
|
|
144
146
|
let pingInterval: ReturnType<typeof setInterval> | null = null
|
|
@@ -279,6 +281,26 @@ export const OstackyController: Plugin = async (ctx) => {
|
|
|
279
281
|
lastCheck = { revision: freshState.revision, result: "ALLOW" }
|
|
280
282
|
}
|
|
281
283
|
|
|
284
|
+
// ── 1.6) Engram soft gate (auditable, no BLOCK) — refuerza SHALL 1 de ostacky.md ──
|
|
285
|
+
// Si propone/cambia nivel sin haber consultado Engram, cuenta bypass (exime trivial+DONE)
|
|
286
|
+
const isEngramRelevantTool = tool.includes("record_discovery") || (tool.includes("openspec") && (tool.includes("propose") || (typeof args?.filePath === "string" && args.filePath.includes("openspec/changes")) || (typeof args?.path === "string" && args.path.includes("openspec/changes"))))
|
|
287
|
+
if (isEngramRelevantTool) {
|
|
288
|
+
const hasEngramHit = engramHitBySession.get(sessionId) ?? false
|
|
289
|
+
const isTrivialForEngram = trivialBySession.get(sessionId) ?? false
|
|
290
|
+
const stateForEngram = freshState
|
|
291
|
+
const shouldAudit = !hasEngramHit && !isTrivialForEngram && stateForEngram && ["DISCOVERY", "ROUTE_DECISION_PENDING", "SPECIFICATION", "INTERPRETATION_PENDING"].includes(stateForEngram.state)
|
|
292
|
+
if (shouldAudit) {
|
|
293
|
+
try {
|
|
294
|
+
const st = readState(ctx.directory)
|
|
295
|
+
if (st) {
|
|
296
|
+
st.engramBypassCount = (st.engramBypassCount || 0) + 1
|
|
297
|
+
// no persist cada vez si es muy frecuente: single-writer ya persiste en after, pero acá persistimos directo para auditoría
|
|
298
|
+
persistState(ctx.directory, st)
|
|
299
|
+
}
|
|
300
|
+
} catch {}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
282
304
|
// ── 1.5) Router determinista: openspec-propose bloquea si 1+ no-downgradeable sin Alternatives ──
|
|
283
305
|
const isOpenspecPropose = tool.includes("openspec") && (tool.includes("propose") || args?.filePath?.includes("openspec/changes") || args?.path?.includes("openspec/changes"))
|
|
284
306
|
if (isOpenspecPropose) {
|
|
@@ -487,8 +509,16 @@ export const OstackyController: Plugin = async (ctx) => {
|
|
|
487
509
|
if (text && !text.includes("null") && text.length > 10) {
|
|
488
510
|
discoveryHitByRequest.set(sessionId, true)
|
|
489
511
|
}
|
|
512
|
+
// Engram hit via discovery snapshot (contiene engramHits)
|
|
513
|
+
if (text && text.includes("engramHits")) {
|
|
514
|
+
engramHitBySession.set(sessionId, true)
|
|
515
|
+
}
|
|
490
516
|
} catch {}
|
|
491
517
|
}
|
|
518
|
+
// Track Engram hit (mem_search / mem_context / dedup) para soft gate 1.6
|
|
519
|
+
if (tool.includes("engram_mem_search") || tool.includes("engram_mem_context") || tool.includes("mem_search") || tool.includes("mem_context") || tool.includes("getEngramDedup") || tool.includes("engram_mem_")) {
|
|
520
|
+
engramHitBySession.set(sessionId, true)
|
|
521
|
+
}
|
|
492
522
|
// Update state metrics for cache hit (best-effort)
|
|
493
523
|
if (tool.includes("getDiscoverySnapshot") && output) {
|
|
494
524
|
try {
|
|
@@ -549,6 +579,7 @@ export const OstackyController: Plugin = async (ctx) => {
|
|
|
549
579
|
tokenSavingEstimate: state?.tokenSavingEstimate ?? 0,
|
|
550
580
|
stateCheckCount: state?.stateCheckCount ?? 0,
|
|
551
581
|
codegraphBypassCount: state?.codegraphBypassCount ?? 0,
|
|
582
|
+
engramBypassCount: state?.engramBypassCount ?? 0,
|
|
552
583
|
revision: state?.revision ?? 0,
|
|
553
584
|
}
|
|
554
585
|
},
|
|
@@ -605,6 +636,7 @@ export const OstackyController: Plugin = async (ctx) => {
|
|
|
605
636
|
if (sid) {
|
|
606
637
|
trivialBySession.delete(sid)
|
|
607
638
|
discoveryHitByRequest.delete(sid)
|
|
639
|
+
engramHitBySession.delete(sid)
|
|
608
640
|
}
|
|
609
641
|
}
|
|
610
642
|
},
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* security.ts — mirror de src/security.ts para plugin (self-contained, solo Sensitive guard)
|
|
3
|
+
* Generado desde src/security.ts — NO EDITAR. Ejecutá `bun run scripts/sync-controller-core.ts`.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// ─── Sensitive guard — source-of-truth (hardening-v2 D1) ───────────────
|
|
7
|
+
|
|
8
|
+
export const SENSITIVE_DEFAULT: string[] = [
|
|
9
|
+
"**/.env*",
|
|
10
|
+
"**/.secrets/**",
|
|
11
|
+
"**/*.pem",
|
|
12
|
+
"**/*.key",
|
|
13
|
+
"**/.aws/**",
|
|
14
|
+
"**/.ssh/**",
|
|
15
|
+
"**/credentials.json",
|
|
16
|
+
"**/.npmrc",
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Regex que detecta acceso sensible en comandos bash.
|
|
21
|
+
* Cubre .env, .secrets, .pem, .key, .aws, .ssh, credentials.json, .npmrc
|
|
22
|
+
* Normalizar antes (strip quotes/backslashes) y testear con `BASH_SENSITIVE_RE.test(normalized)`.
|
|
23
|
+
*/
|
|
24
|
+
export const BASH_SENSITIVE_RE =
|
|
25
|
+
/(?:^|[^a-zA-Z0-9_.-])(\.env(\b|[_.-])|\.secrets\b|\.pem\b|\.key\b|credentials\.json|\.aws\b|\.ssh\b|\.npmrc\b)/i;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Returns true if filePath is considered sensitive given patterns.
|
|
29
|
+
* - Allowlist: .env.example / .env.template / .env.sample nunca son sensibles.
|
|
30
|
+
* - Normaliza backslashes a "/" para Windows.
|
|
31
|
+
* - patterns: array de globs como SENSITIVE_DEFAULT; si no se pasa usa SENSITIVE_DEFAULT.
|
|
32
|
+
*/
|
|
33
|
+
export function isSensitive(filePath: string, patterns: string[] = SENSITIVE_DEFAULT): boolean {
|
|
34
|
+
if (!filePath) return false;
|
|
35
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
36
|
+
const lower = normalized.toLowerCase();
|
|
37
|
+
if (
|
|
38
|
+
lower.endsWith(".env.example") ||
|
|
39
|
+
lower.endsWith(".env.template") ||
|
|
40
|
+
lower.endsWith(".env.sample")
|
|
41
|
+
)
|
|
42
|
+
return false;
|
|
43
|
+
const base = lower.split("/").pop() || "";
|
|
44
|
+
for (const pat of patterns) {
|
|
45
|
+
if (pat.includes(".env") && base.startsWith(".env")) return true;
|
|
46
|
+
if (pat.includes(".secrets") && lower.includes(".secrets")) return true;
|
|
47
|
+
if (pat.includes("*.pem") && lower.endsWith(".pem")) return true;
|
|
48
|
+
if (pat.includes("*.key") && lower.endsWith(".key")) return true;
|
|
49
|
+
if (pat.includes(".aws") && lower.includes(".aws")) return true;
|
|
50
|
+
if (pat.includes(".ssh") && lower.includes(".ssh")) return true;
|
|
51
|
+
if (pat.includes("credentials.json") && lower.endsWith("credentials.json")) return true;
|
|
52
|
+
if (pat.includes(".npmrc") && lower.endsWith(".npmrc")) return true;
|
|
53
|
+
}
|
|
54
|
+
// fallback genérico por extensión
|
|
55
|
+
if (/\.(pem|key)$/i.test(normalized)) return true;
|
|
56
|
+
if (base.startsWith(".env")) return true;
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Extrae paths candidatos de un comando bash para chequear sensibilidad.
|
|
62
|
+
* Tokeniza por separadores shell `| ; && || > >> <` y respeta quotes.
|
|
63
|
+
* Normaliza quitando quotes y backslashes para detectar obfuscaciones como .e""nv.
|
|
64
|
+
*/
|
|
65
|
+
export function extractPathsFromBash(cmd: string): string[] {
|
|
66
|
+
if (!cmd) return [];
|
|
67
|
+
// Normalizar && y || a ; para split único
|
|
68
|
+
const normalized = cmd.replace(/&&/g, ";").replace(/\|\|/g, ";");
|
|
69
|
+
// Split por separadores shell
|
|
70
|
+
const segments = normalized.split(/[|;><\n]+/);
|
|
71
|
+
const paths: string[] = [];
|
|
72
|
+
for (const seg of segments) {
|
|
73
|
+
const trimmed = seg.trim();
|
|
74
|
+
if (!trimmed) continue;
|
|
75
|
+
// Tokeniza respetando quotes — captura tokens entre quotes o sin espacios
|
|
76
|
+
const tokens = trimmed.match(/(?:[^\s"'`\\]+|"[^"]*"|'[^']*'|`[^`]*`)+/g) || [];
|
|
77
|
+
for (let token of tokens) {
|
|
78
|
+
// Normalización anti-obfuscación: quitar quotes y backslashes
|
|
79
|
+
const stripped = token.replace(/["'`]/g, "").replace(/\\/g, "");
|
|
80
|
+
if (!stripped) continue;
|
|
81
|
+
// Filtrar comandos comunes y flags
|
|
82
|
+
if (["cat", "grep", "ls", "echo", "awk", "sed", "cut", "head", "tail", "wc", "find", "xargs", "bash", "sh", "zsh", "env", "printenv", "node", "bun", "npm", "npx", "ls"].includes(stripped)) continue;
|
|
83
|
+
if (stripped.startsWith("-")) continue;
|
|
84
|
+
// Heurística de path: contiene / o . o es .env* o sensible
|
|
85
|
+
const lower = stripped.toLowerCase();
|
|
86
|
+
if (
|
|
87
|
+
stripped.includes("/") ||
|
|
88
|
+
stripped.includes(".") ||
|
|
89
|
+
lower.startsWith(".env") ||
|
|
90
|
+
lower.includes(".secrets") ||
|
|
91
|
+
lower.endsWith(".pem") ||
|
|
92
|
+
lower.endsWith(".key") ||
|
|
93
|
+
lower.includes(".aws") ||
|
|
94
|
+
lower.includes(".ssh") ||
|
|
95
|
+
lower.endsWith("credentials.json") ||
|
|
96
|
+
lower.endsWith(".npmrc")
|
|
97
|
+
) {
|
|
98
|
+
// Limpiar trailing chars como : , )
|
|
99
|
+
const cleaned = stripped.replace(/[,:;)\]]+$/, "");
|
|
100
|
+
if (cleaned) paths.push(cleaned);
|
|
101
|
+
} else if (stripped === ".env") {
|
|
102
|
+
paths.push(stripped);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// También buscar paths con regex global como fallback
|
|
107
|
+
// (detecta .env en strings complejos)
|
|
108
|
+
return [...new Set(paths)];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Lee patrones sensibles desde env OSTACKY_SENSITIVE_PATTERNS o usa default.
|
|
113
|
+
*/
|
|
114
|
+
export function getSensitivePatterns(): string[] {
|
|
115
|
+
const raw = process.env.OSTACKY_SENSITIVE_PATTERNS;
|
|
116
|
+
if (!raw) return SENSITIVE_DEFAULT;
|
|
117
|
+
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
118
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tiered.ts — mirror de src/tiered.ts para plugin (self-contained)
|
|
3
|
+
* Generado desde src/tiered.ts — NO EDITAR. Ejecutá `bun run scripts/sync-controller-core.ts`.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Tiered helpers — single source of truth for trivial detection y niveles.
|
|
8
|
+
*
|
|
9
|
+
* Ambos plugins (ostacky-plugin.ts y engram.ts) importan de acá.
|
|
10
|
+
* No duplicar regex. Cache-friendly: isTrivial no muta system[0], solo decide hint.
|
|
11
|
+
* LEVEL_THRESHOLDS es la única definición de niveles (D6).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export const LEVEL_THRESHOLDS = {
|
|
15
|
+
"0": { maxFiles: 1, maxLines: 15, hasAPI: false, desc: "1 archivo, sin API, <15 líneas" },
|
|
16
|
+
"0+1": { maxFiles: 2, maxLines: 30, hasAPI: false, desc: "1-2 archivos, sin API, <30 líneas" },
|
|
17
|
+
"1+": { maxFiles: Infinity, maxLines: Infinity, hasAPI: true, desc: "API, deps, >30 líneas, cross-module" },
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
export function classifyLevel({ fileCount, estLines, hasAPI }: { fileCount: number; estLines: number; hasAPI: boolean }): "0" | "0+1" | "1+" {
|
|
21
|
+
if (hasAPI || estLines > 30 || fileCount > 2) return "1+";
|
|
22
|
+
if (estLines > 15 || fileCount > 1) return "0+1";
|
|
23
|
+
return "0";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isTrivial(msg: string, state: string): boolean {
|
|
27
|
+
if (!msg || state !== "DONE") return false
|
|
28
|
+
if (msg.trim().length >= 30) return false
|
|
29
|
+
if (!/^(hola|hey|gracias|buenas|hi|hello)\b/i.test(msg.trim())) return false
|
|
30
|
+
if (/(necesito|quiero|agregá|fix|bug|feature|auth|spec|implementar)/i.test(msg)) return false
|
|
31
|
+
return true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getControllerState(directory: string): string {
|
|
35
|
+
try {
|
|
36
|
+
const { readFileSync } = require("node:fs") as typeof import("node:fs")
|
|
37
|
+
const { join } = require("node:path") as typeof import("node:path")
|
|
38
|
+
const statePath =
|
|
39
|
+
process.env.OSTACKY_STATE_PATH || join(directory, ".opencode", "ostacky-state.json")
|
|
40
|
+
const raw = readFileSync(statePath, "utf-8")
|
|
41
|
+
const j = JSON.parse(raw)
|
|
42
|
+
return j.state ?? "DONE"
|
|
43
|
+
} catch {
|
|
44
|
+
return "DONE"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -129,6 +129,7 @@ Return: Summary of what you found and what you fixed.
|
|
|
129
129
|
**Need full context:** Understanding requires seeing entire system
|
|
130
130
|
**Exploratory debugging:** You don't know what's broken yet
|
|
131
131
|
**Shared state:** Agents would interfere (editing same files, using same resources)
|
|
132
|
+
**Ostacky execution:** If `execution-mode-evaluation` already produced `fileClusters/sharedFiles` — **DO NOT use this skill**; use `subagent-driven-development` dispatch por clusters (respeta `sharedFiles` y `sequentialDeps` del Controller, evita pisar mismo archivo desde 2 agentes).
|
|
132
133
|
|
|
133
134
|
## Real Example from Session
|
|
134
135
|
|
|
@@ -39,10 +39,11 @@ Depending on what the user brings, you might:
|
|
|
39
39
|
- Find analogies
|
|
40
40
|
|
|
41
41
|
**Investigate the codebase**
|
|
42
|
-
- Map existing architecture relevant to the discussion
|
|
42
|
+
- Map existing architecture relevant to the discussion (ground with `codegraph_codegraph_explore` + `engram_mem_search` if pre-1+ or without active change)
|
|
43
43
|
- Find integration points
|
|
44
44
|
- Identify patterns already in use
|
|
45
45
|
- Surface hidden complexity
|
|
46
|
+
- **Level note:** Si necesitás ruteo por nivel Ostacky (0/0+1/1+) usa `brainstorming` en vez de este stance; este skill asume ya estás en flujo OpenSpec (1+).
|
|
46
47
|
|
|
47
48
|
**Compare options**
|
|
48
49
|
- Brainstorm multiple approaches
|
|
@@ -26,7 +26,9 @@ When ready to implement, run /opsx-apply
|
|
|
26
26
|
|
|
27
27
|
**Steps**
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
0. **Ground with CodeGraph + Engram (SHALL — Ostacky)** — Antes de `openspec new`, verifica `getDiscoverySnapshot(query)` + `getEngramDedup`. Si miss → `codegraph_codegraph_explore` + `engram_mem_search` + `putDiscoverySnapshot`. Cita símbolos existentes en `proposal/design`; sin esto el `design.md` puede alucinar API inexistente y dispara `WARN:codegraphBypass` en `doctor`.
|
|
30
|
+
|
|
31
|
+
1. **Check Engram for similar changes** — `engram_mem_search` con keywords del *paso 0* (reusar si ya fue hit; no duplicar `mem_search` mismo `requestId`). Si hay change similar previo, surfacealo. Pueden extender trabajo existente en vez de empezar de cero.
|
|
30
32
|
|
|
31
33
|
2. **If no clear input provided, ask what they want to build**
|
|
32
34
|
|
|
@@ -28,6 +28,8 @@ Write the test first. Watch it fail. Write minimal code to pass.
|
|
|
28
28
|
|
|
29
29
|
Thinking "skip TDD just this once"? Stop. That's rationalization.
|
|
30
30
|
|
|
31
|
+
> **Ostacky ground (SHALL):** Antes de RED, verifica `getDiscoverySnapshot(query)` + `getEngramDedup`. Si hit → reusar símbolos/decisiones; si miss → `codegraph_codegraph_explore` + `engram_mem_search` + `putDiscoverySnapshot`. Evita testear API inexistente y respeta `discovery-cache (único)` de `ostacky.md §1`. Ver `execution-mode-evaluation` para cache TTL.
|
|
32
|
+
|
|
31
33
|
## The Iron Law
|
|
32
34
|
|
|
33
35
|
```
|
package/dist/cli.js
CHANGED
|
@@ -186,7 +186,7 @@ var require_picocolors = __commonJS(function(exports, module) {
|
|
|
186
186
|
});
|
|
187
187
|
|
|
188
188
|
// src/security.ts
|
|
189
|
-
import { createHash } from "crypto";
|
|
189
|
+
import { createHash } from "node:crypto";
|
|
190
190
|
function validateFilePath(filePath) {
|
|
191
191
|
if (filePath.includes("..") || filePath.startsWith("/") || filePath.startsWith("\\") || /^[a-zA-Z]:/.test(filePath)) {
|
|
192
192
|
throw new Error(`Ruta de archivo inválida: "${filePath}"`);
|
|
@@ -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.8.
|
|
624
|
+
version: "0.8.8",
|
|
625
625
|
repo: "JaimeHoracio/Ostacky",
|
|
626
|
-
tag: "v0.8.
|
|
626
|
+
tag: "v0.8.8",
|
|
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.8.
|
|
632
|
-
version: "0.8.
|
|
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.8.8: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
|
|
632
|
+
version: "0.8.8",
|
|
633
|
+
sha256: "bac9b7bc91d9d958bee8c6b2e094b1e1124bcc7f3e23cd13769ebbc5766f4747"
|
|
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.8.
|
|
641
|
-
version: "0.8.
|
|
642
|
-
sha256: "
|
|
640
|
+
description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.8.8: controller plugin como alma hard-gate, Context7 removido del stack.",
|
|
641
|
+
version: "0.8.8",
|
|
642
|
+
sha256: "28ddf7ac8a2472faa1a5dbd14e22bc11e0b8715971907b3fab739b9933aa7dad"
|
|
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.8.
|
|
648
|
+
version: "0.8.8",
|
|
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.8.
|
|
657
|
-
version: "0.8.
|
|
658
|
-
sha256: "
|
|
656
|
+
description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.8.8: 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.8.8",
|
|
658
|
+
sha256: "a1d9744ffe70e976c7c96343bf101c1dedf615b27058559a376c0e559a341328"
|
|
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.8.
|
|
664
|
+
version: "0.8.8",
|
|
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.8.
|
|
673
|
+
version: "0.8.8",
|
|
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.8.
|
|
680
|
+
version: "0.8.8",
|
|
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.8.
|
|
688
|
-
sha256: "
|
|
687
|
+
version: "0.8.8",
|
|
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.8.
|
|
694
|
+
version: "0.8.8",
|
|
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.8.
|
|
702
|
-
sha256: "
|
|
701
|
+
version: "0.8.8",
|
|
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.8.
|
|
708
|
+
version: "0.8.8",
|
|
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.8.
|
|
715
|
+
version: "0.8.8",
|
|
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.8.
|
|
723
|
-
sha256: "
|
|
722
|
+
version: "0.8.8",
|
|
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.8.
|
|
729
|
+
version: "0.8.8",
|
|
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.8.
|
|
736
|
+
version: "0.8.8",
|
|
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.8.
|
|
744
|
-
sha256: "
|
|
743
|
+
version: "0.8.8",
|
|
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.8.
|
|
750
|
+
version: "0.8.8",
|
|
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.8.
|
|
757
|
+
version: "0.8.8",
|
|
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.8.
|
|
764
|
+
version: "0.8.8",
|
|
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.8.
|
|
771
|
+
version: "0.8.8",
|
|
772
772
|
sha256: "363449bd9e6f800a0a3168667cf78f767fb105d86e4a4adadcc649d418139303"
|
|
773
773
|
}
|
|
774
774
|
]
|
|
@@ -1155,6 +1155,8 @@ function copyEngramPlugin(projectRoot) {
|
|
|
1155
1155
|
function copyOstackyControllerPlugin(projectRoot) {
|
|
1156
1156
|
const pluginSource = join7(PACKAGE_ROOT, "assets", "plugins", "ostacky-plugin.ts");
|
|
1157
1157
|
const coreSource = join7(PACKAGE_ROOT, "assets", "plugins", "controller-core.ts");
|
|
1158
|
+
const securitySource = join7(PACKAGE_ROOT, "assets", "plugins", "security.ts");
|
|
1159
|
+
const tieredSource = join7(PACKAGE_ROOT, "assets", "plugins", "tiered.ts");
|
|
1158
1160
|
const pluginsDir = join7(projectRoot, ".opencode", "plugins");
|
|
1159
1161
|
if (!existsSync6(pluginSource)) {
|
|
1160
1162
|
throw new Error(`Plugin bundleado de OstackyController no encontrado: ${pluginSource}`);
|
|
@@ -1163,6 +1165,10 @@ function copyOstackyControllerPlugin(projectRoot) {
|
|
|
1163
1165
|
copyFileSync3(pluginSource, join7(pluginsDir, "ostacky-plugin.ts"));
|
|
1164
1166
|
if (existsSync6(coreSource))
|
|
1165
1167
|
copyFileSync3(coreSource, join7(pluginsDir, "controller-core.ts"));
|
|
1168
|
+
if (existsSync6(securitySource))
|
|
1169
|
+
copyFileSync3(securitySource, join7(pluginsDir, "security.ts"));
|
|
1170
|
+
if (existsSync6(tieredSource))
|
|
1171
|
+
copyFileSync3(tieredSource, join7(pluginsDir, "tiered.ts"));
|
|
1166
1172
|
}
|
|
1167
1173
|
function buildEngramDownloadUrl(tag, platform = process.platform, arch = process.arch) {
|
|
1168
1174
|
const target = getEngramReleaseTarget(platform, arch);
|
|
@@ -1492,14 +1498,14 @@ var init_stack = __esm(() => {
|
|
|
1492
1498
|
// package.json
|
|
1493
1499
|
var package_default = {
|
|
1494
1500
|
name: "ostacky",
|
|
1495
|
-
version: "0.8.
|
|
1501
|
+
version: "0.8.8",
|
|
1496
1502
|
description: "Instalador interactivo de agentes y comandos para OpenCode",
|
|
1497
1503
|
type: "module",
|
|
1498
1504
|
bin: {
|
|
1499
1505
|
ostacky: "./dist/cli.js"
|
|
1500
1506
|
},
|
|
1501
1507
|
scripts: {
|
|
1502
|
-
prebuild: "bun run scripts/sync-version.ts",
|
|
1508
|
+
prebuild: "bun run scripts/sync-version.ts && bun run scripts/sync-controller-core.ts",
|
|
1503
1509
|
dev: "bun run src/cli.ts",
|
|
1504
1510
|
build: "bun build src/cli.ts --target=node --format=esm --outfile dist/cli.js && bun scripts/add-shebang.ts",
|
|
1505
1511
|
start: "node dist/cli.js",
|
|
@@ -1510,7 +1516,7 @@ var package_default = {
|
|
|
1510
1516
|
"hash:update": "bun run scripts/update-manifest-hashes.ts",
|
|
1511
1517
|
"manifest:prepare": "bun run scripts/update-manifest-hashes.ts",
|
|
1512
1518
|
"manifest:check": "bun run scripts/update-manifest-hashes.ts --check",
|
|
1513
|
-
prepublishOnly: "bun run manifest:prepare && bun run build"
|
|
1519
|
+
prepublishOnly: "bun run scripts/sync-controller-core.ts && bun run manifest:prepare && bun run build"
|
|
1514
1520
|
},
|
|
1515
1521
|
files: [
|
|
1516
1522
|
"dist/",
|
|
@@ -2669,7 +2675,7 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath, option
|
|
|
2669
2675
|
params: {
|
|
2670
2676
|
protocolVersion: "2025-03-26",
|
|
2671
2677
|
capabilities: {},
|
|
2672
|
-
clientInfo: { name: "ostacky-installer", version: "0.8.
|
|
2678
|
+
clientInfo: { name: "ostacky-installer", version: "0.8.8" }
|
|
2673
2679
|
}
|
|
2674
2680
|
});
|
|
2675
2681
|
});
|
|
@@ -2978,7 +2984,15 @@ function uninstallAll(paths) {
|
|
|
2978
2984
|
for (const name of Object.keys(lockfile.mcpServers ?? {})) {
|
|
2979
2985
|
uninstallMcpServer(name, paths);
|
|
2980
2986
|
}
|
|
2981
|
-
const ostackyPlugins = [
|
|
2987
|
+
const ostackyPlugins = [
|
|
2988
|
+
"ostacky-plugin.ts",
|
|
2989
|
+
"engram.ts",
|
|
2990
|
+
"ostacky-guard.ts",
|
|
2991
|
+
"ostacky-controller.ts",
|
|
2992
|
+
"controller-core.ts",
|
|
2993
|
+
"security.ts",
|
|
2994
|
+
"tiered.ts"
|
|
2995
|
+
];
|
|
2982
2996
|
for (const file of ostackyPlugins) {
|
|
2983
2997
|
const fp = join6(paths.plugins, file);
|
|
2984
2998
|
if (existsSync5(fp)) {
|
|
@@ -4347,6 +4361,8 @@ async function runDoctorCommand() {
|
|
|
4347
4361
|
console.log(`⚠️ degraded: confirmation not audited in controller (degradedEditsCount=${parsed.degradedEditsCount})`);
|
|
4348
4362
|
if (parsed.codegraphBypassCount > 0)
|
|
4349
4363
|
console.log(`⚠️ codegraphBypassCount=${parsed.codegraphBypassCount} (inefficient: codegraph bypass)`);
|
|
4364
|
+
if (parsed.engramBypassCount > 0)
|
|
4365
|
+
console.log(`⚠️ engramBypassCount=${parsed.engramBypassCount} (contradiction check bypassed — sin mem_search)`);
|
|
4350
4366
|
if (parsed.stateOversizedCount > 0)
|
|
4351
4367
|
console.log(`⚠️ stateOversizedCount=${parsed.stateOversizedCount} snapshots perdidos`);
|
|
4352
4368
|
if (parsed.sensitiveAccess)
|
package/manifest.json
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.8.
|
|
2
|
+
"version": "0.8.8",
|
|
3
3
|
"repo": "JaimeHoracio/Ostacky",
|
|
4
|
-
"tag": "v0.8.
|
|
4
|
+
"tag": "v0.8.8",
|
|
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.8: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
|
|
10
|
+
"version": "0.8.8",
|
|
11
|
+
"sha256": "bac9b7bc91d9d958bee8c6b2e094b1e1124bcc7f3e23cd13769ebbc5766f4747"
|
|
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.8: controller plugin como alma hard-gate, Context7 removido del stack.",
|
|
19
|
+
"version": "0.8.8",
|
|
20
|
+
"sha256": "28ddf7ac8a2472faa1a5dbd14e22bc11e0b8715971907b3fab739b9933aa7dad"
|
|
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.8",
|
|
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.8: 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.8",
|
|
36
|
+
"sha256": "a1d9744ffe70e976c7c96343bf101c1dedf615b27058559a376c0e559a341328"
|
|
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.8",
|
|
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.8",
|
|
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.8.
|
|
58
|
+
"version": "0.8.8",
|
|
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.8.
|
|
66
|
-
"sha256": "
|
|
65
|
+
"version": "0.8.8",
|
|
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.8.
|
|
72
|
+
"version": "0.8.8",
|
|
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.
|
|
80
|
-
"sha256": "
|
|
79
|
+
"version": "0.8.8",
|
|
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.8.
|
|
86
|
+
"version": "0.8.8",
|
|
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.8",
|
|
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.
|
|
101
|
-
"sha256": "
|
|
100
|
+
"version": "0.8.8",
|
|
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.8.
|
|
107
|
+
"version": "0.8.8",
|
|
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.8",
|
|
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.
|
|
122
|
-
"sha256": "
|
|
121
|
+
"version": "0.8.8",
|
|
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.8.
|
|
128
|
+
"version": "0.8.8",
|
|
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.8",
|
|
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.8",
|
|
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.8",
|
|
150
150
|
"sha256": "363449bd9e6f800a0a3168667cf78f767fb105d86e4a4adadcc649d418139303"
|
|
151
151
|
}
|
|
152
152
|
]
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ostacky",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.8",
|
|
4
4
|
"description": "Instalador interactivo de agentes y comandos para OpenCode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"ostacky": "./dist/cli.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"prebuild": "bun run scripts/sync-version.ts",
|
|
10
|
+
"prebuild": "bun run scripts/sync-version.ts && bun run scripts/sync-controller-core.ts",
|
|
11
11
|
"dev": "bun run src/cli.ts",
|
|
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",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"hash:update": "bun run scripts/update-manifest-hashes.ts",
|
|
19
19
|
"manifest:prepare": "bun run scripts/update-manifest-hashes.ts",
|
|
20
20
|
"manifest:check": "bun run scripts/update-manifest-hashes.ts --check",
|
|
21
|
-
"prepublishOnly": "bun run manifest:prepare && bun run build"
|
|
21
|
+
"prepublishOnly": "bun run scripts/sync-controller-core.ts && bun run manifest:prepare && bun run build"
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"dist/",
|