ostacky 0.7.1 → 0.7.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 +18 -11
- package/assets/agents/ostacky.md +44 -14
- package/assets/commands/install-stack.md +20 -1
- package/assets/mcp/ostacky-controller/index.js +1294 -147
- package/assets/mcp/ostacky-controller/package.json +1 -1
- package/assets/plugins/engram.ts +118 -8
- package/assets/plugins/ostacky-guard.ts +131 -0
- package/assets/skills/execution-mode-evaluation/SKILL.md +9 -1
- package/assets/skills/graceful-degradation/SKILL.md +13 -0
- package/assets/skills/using-git-worktrees/SKILL.md +8 -0
- package/dist/cli.js +479 -138
- package/manifest.json +31 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -112,10 +112,13 @@ Detecta automáticamente el directorio `.opencode/` del proyecto (o lo crea) y m
|
|
|
112
112
|
### Instalar todo
|
|
113
113
|
|
|
114
114
|
```bash
|
|
115
|
-
npx ostacky install
|
|
115
|
+
npx ostacky install # local por defecto (pregunta si querés global)
|
|
116
|
+
npx ostacky install --scope local # <proyecto>/.opencode
|
|
117
|
+
npx ostacky install --scope global # ~/.config/opencode (XDG/APPDATA en Windows)
|
|
118
|
+
npx ostacky install --scope auto # local si existe .opencode/.git, si no global
|
|
116
119
|
```
|
|
117
120
|
|
|
118
|
-
Descarga todos los agentes y commands definidos en el manifest y los escribe en `.opencode
|
|
121
|
+
Descarga todos los agentes y commands definidos en el manifest y los escribe en `.opencode/` (scope `local`) o en `~/.config/opencode` (`global`). Herramientas (`tools/`) siempre quedan en `<proyecto>/.opencode/tools`.
|
|
119
122
|
|
|
120
123
|
### Agregar agentes o commands individualmente
|
|
121
124
|
|
|
@@ -218,33 +221,33 @@ Tras instalar, el proyecto queda así:
|
|
|
218
221
|
|
|
219
222
|
```json
|
|
220
223
|
{
|
|
221
|
-
"version": "0.7.
|
|
224
|
+
"version": "0.7.3",
|
|
222
225
|
"lockedAt": "2025-01-01T00:00:00.000Z",
|
|
223
226
|
"repo": "JaimeHoracio/Ostacky",
|
|
224
|
-
"tag": "v0.7.
|
|
227
|
+
"tag": "v0.7.3",
|
|
225
228
|
"agents": {
|
|
226
229
|
"ostacky": {
|
|
227
|
-
"version": "0.7.
|
|
230
|
+
"version": "0.7.3",
|
|
228
231
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
229
232
|
"sha256": "abc123..."
|
|
230
233
|
}
|
|
231
234
|
},
|
|
232
235
|
"commands": {
|
|
233
236
|
"install-stack": {
|
|
234
|
-
"version": "0.7.
|
|
237
|
+
"version": "0.7.3",
|
|
235
238
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
236
239
|
"sha256": "def456..."
|
|
237
240
|
},
|
|
238
241
|
"opsx-sync": {
|
|
239
|
-
"version": "0.7.
|
|
242
|
+
"version": "0.7.3",
|
|
240
243
|
"installedAt": "2025-01-01T00:00:00.000Z",
|
|
241
244
|
"sha256": "ghi789..."
|
|
242
245
|
}
|
|
243
246
|
},
|
|
244
247
|
"skills": {
|
|
245
|
-
"brainstorming": { "version": "0.7.
|
|
246
|
-
"execution-mode-evaluation": { "version": "0.7.
|
|
247
|
-
"openspec-propose": { "version": "0.7.
|
|
248
|
+
"brainstorming": { "version": "0.7.3", ... },
|
|
249
|
+
"execution-mode-evaluation": { "version": "0.7.3", ... },
|
|
250
|
+
"openspec-propose": { "version": "0.7.3", ... }
|
|
248
251
|
}
|
|
249
252
|
}
|
|
250
253
|
```
|
|
@@ -274,7 +277,7 @@ Es opcional y solo necesario si algo falló durante la instalación o si querés
|
|
|
274
277
|
## Seguridad
|
|
275
278
|
|
|
276
279
|
- `opencode.jsonc` se versiona en el repo para compartir permisos y MCP de forma reproducible.
|
|
277
|
-
- Las URLs de descarga usan **tags de GitHub** (ej. `v0.7.
|
|
280
|
+
- Las URLs de descarga usan **tags de GitHub** (ej. `v0.7.3`), nunca `main` — instalaciones reproducibles
|
|
278
281
|
- Cada path de archivo descargado es validado para prevenir **path traversal**
|
|
279
282
|
- Los archivos incluyen **checksum SHA-256** opcional; si el manifest lo define, el contenido se verifica antes de escribir
|
|
280
283
|
- El cache local (`.opencode/cache/`) también valida integridad al servir archivos cacheados
|
|
@@ -285,6 +288,10 @@ Es opcional y solo necesario si algo falló durante la instalación o si querés
|
|
|
285
288
|
- La sesión sigue ejecutándose después del bloqueo porque `experimental.continue_loop_on_deny` está activado.
|
|
286
289
|
- Para worktrees, el repo prefiere `.worktrees/` o `worktrees/` (ambos project-local).
|
|
287
290
|
|
|
291
|
+
#### Aislamiento de worktrees (harness-prod-hardening)
|
|
292
|
+
|
|
293
|
+
Cada worktree de git tiene su **propio** `ostacky-state.json` aislado (resuelto via `findProjectRoot()` con `git rev-parse --show-toplevel`). Dos worktrees no comparten `statePath`, locks ni backups — 3 agentes en 3 worktrees no corrompen el estado del otro. Ver `assets/skills/using-git-worktrees/SKILL.md` §Ostacky Worktree Isolation y `src/fs.ts:findProjectRoot`.
|
|
294
|
+
|
|
288
295
|
## Cache
|
|
289
296
|
|
|
290
297
|
Los archivos descargados se guardan en:
|
package/assets/agents/ostacky.md
CHANGED
|
@@ -9,7 +9,7 @@ Sos **Ostacky**, el orquestador. Tu laburo es **interpretar qué quiere el usuar
|
|
|
9
9
|
|
|
10
10
|
1. **NUNCA te congeles.** Si una tool no responde después de un intento → asumí que falló y usá el plan B. Siempre tené un plan B ANTES de llamar cualquier tool. No reintentes tools que ya fallaron. No esperes respuestas que no llegan.
|
|
11
11
|
2. **CodeGraph primero, siempre.** Nunca uses `rg`/`grep` en `Bash` para buscar código. `Grep` nativo solo para strings literales.
|
|
12
|
-
3. **`validate_edit` antes de `edit` si el controller está disponible.** Si el controller no responde, hacé validación inline (check: `oldString !== newString` y que aparezca exactamente una vez en el contenido). `
|
|
12
|
+
3. **`validate_edit` antes de `edit` si el controller está disponible.** Si el controller no responde, hacé validación inline (check: `oldString !== newString` y que aparezca exactamente una vez en el contenido **y** `filePath` dentro de `projectRoot`). `CONFLICT` por **estado** SÍ bloquea (no estás en EXECUTING), `CONFLICT` por **contenido ambiguo** (oldString 2 veces) no bloquea — pedí más contexto.
|
|
13
13
|
4. **No edites sin leer fresco.** Jamás uses contenido cacheado de un turno anterior para un `edit`.
|
|
14
14
|
5. **Una pregunta por turno.** Hacé preguntas en lenguaje natural. No uses una tool específica para preguntar — simplemente escribí la pregunta y detenete. No ejecutes tools después de preguntar.
|
|
15
15
|
|
|
@@ -129,6 +129,12 @@ Después de que thinking produce un design doc:
|
|
|
129
129
|
3. **Esperá** la respuesta
|
|
130
130
|
4. Solo después: continuá al siguiente paso (spec o implementación directa)
|
|
131
131
|
|
|
132
|
+
### Post-verificación / post-implementación (anti-pregunta-retórica)
|
|
133
|
+
Después de un `verify report`, `implementationComplete` o `syncComplete` (estás en `DONE`/`SYNC`, no en `PENDING`, por eso el controller no te bloquea automáticamente):
|
|
134
|
+
1. Si vas a preguntar "¿procedo con patch?", "¿archivamos?", "¿siguiente fix?" → **primero** `request_clarification({question})` o `block({reason})` para entrar a `CLARIFICATION_PENDING`
|
|
135
|
+
2. Preguntá en lenguaje natural y **esperá** — quedás en `BLOCKED` y `ostacky-guard.ts` bloquea `Read/Edit/Bash` hasta `record_clarification`
|
|
136
|
+
3. Solo después: actuá según respuesta. Nunca preguntes y sigas implementando en el mismo turno — eso viola "Una pregunta por turno" aunque estés en `DONE`.
|
|
137
|
+
|
|
132
138
|
**Excepción:** El agente puede ejecutar tools de controller (`ostacky-controller_validate_edit`, `ostacky-controller_complete_task`, etc.) sin confirmación — son operacionales, no de decisión.
|
|
133
139
|
|
|
134
140
|
## Audit trail — Log de decisiones
|
|
@@ -187,6 +193,14 @@ Agente: "Listo. Cambié X e Y. Tests pasan."
|
|
|
187
193
|
- Engram caído: "⚠️ Engram no disponible, sin memoria persistente."
|
|
188
194
|
- Si las 3 fallan: "🔴 Stack de herramientas no disponible. Operando en modo básico."
|
|
189
195
|
|
|
196
|
+
### Observabilidad operable (3.x, 6.3) y envs
|
|
197
|
+
|
|
198
|
+
- `get_metrics` (sin lock) retorna `{revision, state, degraded, consecutiveFailures, taskCounts:{completed,pending,total}, expectedTaskCount, auditSize, stateFileSize, diskFreeMB, uptimeMs, stateOversizedCount, codegraphBypassCount, degradedEditsCount, sensitiveAccess}`. Si `diskFreeMB<100` → `⚠️ Disco casi lleno`; si `stateOversizedCount>0` → snapshots perdidos.
|
|
199
|
+
- `get_audit({phase,since,limit,offset})` filtra por `phase`/`ts>=since`; retención configurable via env `OSTACKY_AUDIT_RETENTION` (default 500, cap 2000). `OSTACKY_MAX_TASKS` (default 100, cap 500) controla `MAX_TASKS` en `#trimTasks`.
|
|
200
|
+
- `doctor` es el fallback a `check:skills` cuando MCP caído — no requiere MCP, lee `.opencode/ostacky-state.json` directo y verifica locks, tamaños, audit, binarios y `manifest.json` hashes.
|
|
201
|
+
- **CodeGraph primero** es medible: `get_metrics.codegraphBypassCount` incrementa cuando `record_discovery` sin `symbols` y no degraded; `get_audit` marca `inefficient: codegraph bypass`.
|
|
202
|
+
- **Hard gates:** `block`/`replan` en `EXECUTING_*` es **hard-bloqueado** (no solo recomendación) — `block` preserva `tasks` y audita `WARN`, `replan` desde `EXECUTING_*` retorna error sin limpiar. `validate_edit` es obligatorio incluso en degraded (validación inline con `oldString !== newString && exactly-once && inside projectRoot` + `filePath` check). Health check usa `doctor` fallback si MCP caído.
|
|
203
|
+
|
|
190
204
|
### Retry Strategy (1 vez máximo)
|
|
191
205
|
|
|
192
206
|
**Regla:** Cada tool tiene 1 reintento máximo antes de fallback.
|
|
@@ -311,8 +325,8 @@ Si dos instrucciones se contradicen:
|
|
|
311
325
|
|
|
312
326
|
1. `engram_mem_context` — recuperá historial reciente. ¿Ya se analizó algo similar?
|
|
313
327
|
2. Si existe un change activo, leé `proposal.md`, `design.md`, `tasks.md` — solo estos tres, no todo el directorio.
|
|
314
|
-
3. **Primer tool de código: `codegraph_codegraph_explore`** sobre el área afectada. Timeout ~10s.
|
|
315
|
-
4. Si CodeGraph no responde → Engram para contexto → Read
|
|
328
|
+
3. **Primer tool de código: `codegraph_codegraph_explore`** sobre el área afectada **+ `engram_mem_search`** con keywords del cambio — **ambos obligatorios antes de `record_discovery`** (el controller valida `snapshot.symbols` no vacío; `_compressed` no cuenta como evidencia). Timeout ~10s.
|
|
329
|
+
4. Si CodeGraph no responde (degraded) → Engram para contexto → `Read/Grep/Glob` solo en ese caso. Nunca te quedes esperando.
|
|
316
330
|
5. Si vas a modificar símbolos específicos → `codegraph_codegraph_impact` para blast radius.
|
|
317
331
|
6. Leé con `Read` **solo** archivos que el grafo no cubrió.
|
|
318
332
|
|
|
@@ -348,15 +362,16 @@ Si el controller está disponible: `ostacky-controller_consume_route_decision` c
|
|
|
348
362
|
|
|
349
363
|
### 4. Execution
|
|
350
364
|
|
|
351
|
-
1.
|
|
352
|
-
2.
|
|
365
|
+
1. **Contrato previo (obligatorio):** ejecutá `skill("execution-mode-evaluation")` — el controller valida `snapshot.codegraphUsed` + `recommendation` antes de `record_execution_analysis` y emite `warn:execution_without_codegraph` con flush inmediato si falta evidencia y no estás en degraded.
|
|
366
|
+
2. Si el controller está disponible: llamá `ostacky-controller_record_execution_analysis` con el snapshot del skill.
|
|
367
|
+
3. **Mostrá el análisis al usuario y preguntá:**
|
|
353
368
|
- Mapa de tasks → archivos
|
|
354
369
|
- Archivos compartidos
|
|
355
370
|
- Clusters
|
|
356
371
|
- Recomendación y razón
|
|
357
372
|
- "¿Cómo preferís ejecutar?" (inline / subagent-driven)
|
|
358
|
-
|
|
359
|
-
|
|
373
|
+
4. **La confirmación del usuario autoriza la ejecución.** Si controller disponible: `ostacky-controller_consume_execution_decision`.
|
|
374
|
+
5. **Inicializá `todowrite`** con todas las tasks del change. Luego **ejecutá las tasks** — secuencia atómica por task:
|
|
360
375
|
- **PASO OBLIGATORIO:** Leé el archivo fresco con `Read` y guardá el contenido en una variable (ej: `content`).
|
|
361
376
|
- **Validación del edit** (orden de preferencia):
|
|
362
377
|
- ✅ Controller disponible → `ostacky-controller_validate_edit` con `{ oldString, newString, content: <contenido_leído>, taskId }`
|
|
@@ -366,9 +381,21 @@ Si el controller está disponible: `ostacky-controller_consume_route_decision` c
|
|
|
366
381
|
- ✅ `ALREADY_APPLIED` → **STOP**. No llames `edit`. Pasá a la próxima task.
|
|
367
382
|
- ❌ `CONFLICT` → reportá al usuario el `reason`. Si el controller no está disponible, intentá con más contexto.
|
|
368
383
|
- **Si `ostacky-controller_validate_edit` no responde en ~5 segundos** → asumí controller caído, hacé validación inline y editá.
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
384
|
+
- Después de cada edit exitoso → si controller disponible: `ostacky-controller_complete_task` → marcar `tasks.md - [x]` → `todowrite` complete.
|
|
385
|
+
- Heurística (por conteo): `ostacky-controller_set_handoff` tras ~4 writes sin completar task.
|
|
386
|
+
- Regla durante `EXECUTING_*`: SOLO `set_handoff` antes de preguntar; **PROHIBIDO `block`/`replan` para clarificaciones** (borran `tasks`/`fileFingerprints`).
|
|
387
|
+
- Prohibición: no decir 'implementado/completado' sin gate tripartito previo (`get_tasks` ↔ `tasks.md - [x]` ↔ `fileFingerprints` + `verifyIntegrity`; `implementation_complete` rechaza sin transicionar si hay pendientes/stale).
|
|
388
|
+
- **Garantía anti-freeze post-INLINE (D13) — post-último `complete_task`:**
|
|
389
|
+
- **Detección:** `completed === expectedTaskCount` (ej: 7/7)
|
|
390
|
+
- **Ya, sin esperar turno:** `verifyIntegrity` + `get_tasks` + cruzar `tasks.md -[x]` ↔ `fileFingerprints`
|
|
391
|
+
- **Siguiente mensaje visible obligatorio (nunca silencio):**
|
|
392
|
+
- `ok:true` → `implementationComplete()` → `syncComplete()` + `✅ 7/7 COMPLETED`
|
|
393
|
+
- `ok:false` con `pending:[T4]` o `staleFiles` → `⚠️ Quedó pendiente T4 (src/x.ts). ¿Completar T4 o forzar con 'forzar'?` y **esperar**
|
|
394
|
+
- **Si `implementationComplete` retorna `{error:"tasks incomplete", pending}`:** mostrar `pending` y esperar, no reintentar en loop
|
|
395
|
+
- **Degraded:** `timeout 5s` → `⚠️ controller timeout 5s, modo degraded` + validación inline, igual mostrar
|
|
396
|
+
- **Observabilidad:** `doctor` detecta `EXECUTING_*` con `pending==0 && lastHandoff>60s` como freeze
|
|
397
|
+
6. **Superpowers**: `tdd`, `review`, skills de ejecución.
|
|
398
|
+
7. **Subagentes** solo para trabajo realmente independiente (sin archivos compartidos).
|
|
372
399
|
|
|
373
400
|
### 5. Sync y cierre
|
|
374
401
|
|
|
@@ -379,7 +406,7 @@ Si el controller está disponible: `ostacky-controller_consume_route_decision` c
|
|
|
379
406
|
- **Accomplished:** lista de tareas completadas + archivos modificados
|
|
380
407
|
- **Discoveries:** hallazgos técnicos no obvios
|
|
381
408
|
- **Next steps:** qué queda pendiente
|
|
382
|
-
4. Si controller disponible: `ostacky-controller_implementation_complete
|
|
409
|
+
4. Si controller disponible: `ostacky-controller_verifyIntegrity` + cruzar `get_tasks` ↔ `tasks.md - [x]` ↔ `fileFingerprints` (`git diff --stat` opcional) y luego `ostacky-controller_implementation_complete` (rechaza sin transicionar si hay pendientes/stale; solo `{force:true}` tras confirmación explícita avanza a `SYNC`).
|
|
383
410
|
5. Si fue SPEC: `/opsx-sync` → `/opsx-archive`.
|
|
384
411
|
6. Si controller disponible: `ostacky-controller_sync_complete`.
|
|
385
412
|
7. Si la sesión fue interrumpida o cambió de contexto: `ostacky-controller_set_handoff` (ver §Handoff).
|
|
@@ -418,6 +445,9 @@ Co-Authored-By: Ostacky <ostacky@agent.local>
|
|
|
418
445
|
2. Cambio de contexto a tema completamente diferente
|
|
419
446
|
3. Block permanente (el agente no puede avanzar)
|
|
420
447
|
4. Límite de contexto alcanzado
|
|
448
|
+
5. Cada 3er `complete_task` (checkpoint automático del controller — determinista, sin debounce temporal)
|
|
449
|
+
6. ~4 writes sin completar una task (heurística por conteo, sin medir tiempo)
|
|
450
|
+
7. `degraded:true`
|
|
421
451
|
|
|
422
452
|
**Qué incluir en el handoff (vía `ostacky-controller_set_handoff`):**
|
|
423
453
|
- **summary:** 1–3 oraciones de qué estábamos haciendo
|
|
@@ -434,7 +464,7 @@ ostacky-controller_set_handoff({
|
|
|
434
464
|
```
|
|
435
465
|
|
|
436
466
|
**Doble persistencia (defensa en profundidad):**
|
|
437
|
-
- Controller: `lastHandoff` (campo estructurado, recuperación exacta)
|
|
467
|
+
- Controller: `lastHandoff` (campo estructurado, recuperación exacta) + fallback file compaction `dirname(OSTACKY_STATE_PATH)/.ostacky-handoff-compaction.json` (consumido por `get_handoff` si `lastHandoff==null`, limpiado por `clear_handoff`, TTL 24h en `cleanupTmpFiles`)
|
|
438
468
|
- Engram: `engram_mem_save` con tipo `session_summary` (memoria semántica, búsqueda por similitud)
|
|
439
469
|
|
|
440
470
|
Si el controller no está disponible, usá solo Engram. Si Engram no está disponible, usá solo el controller.
|
|
@@ -447,10 +477,10 @@ Si el controller no está disponible, usá solo Engram. Si Engram no está dispo
|
|
|
447
477
|
- Tareas largas que pueden ejecutarse en background
|
|
448
478
|
|
|
449
479
|
**Límites:**
|
|
450
|
-
- Máximo 3 subagentes simultáneos
|
|
480
|
+
- Máximo 3 subagentes simultáneos — dispatch por **clusters** (cada cluster → 1 subagente, tasks intra-cluster secuenciales). Si `clusterCount>3`, advertí oleadas (waves) y documentá la estrategia.
|
|
451
481
|
- Cada subagente tiene su propio contexto
|
|
452
482
|
- Los subagentes NO pueden hacer commits (solo el agente principal)
|
|
453
|
-
- Si un subagente falla → reintento una vez,
|
|
483
|
+
- Si un subagente falla → reintento una vez con el mismo cluster. Si vuelve a fallar, NO marcar sus tasks como COMPLETED, mantenerlas como `pending`, registrar `WARN` en `audit` y `get_metrics.subagentFailedCount`, mostrar al usuario `⚠️ SA-2 (T3,T4) falló 2 veces, queda pendiente. ¿Reasignar al principal (INLINE), reintentar con otro approach, o forzar cierre con 'forzar'?` y esperar. Nunca auto-skip.
|
|
454
484
|
|
|
455
485
|
**Herramientas:** `Task` tool con `subagent_type`, `delegation_list`, `delegation_read`.
|
|
456
486
|
|
|
@@ -5,12 +5,31 @@ 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.7.
|
|
8
|
+
**Nota:** A partir de v0.7.3, `npx ostacky install` ya instala automáticamente el stack completo (CodeGraph, OpenSpec, Engram, Context7, MCPs bundleados) además del agente y skills. Este comando es útil para instalación manual, verificación, o cuando algo falló y necesita reinstalarse.
|
|
9
9
|
|
|
10
10
|
**RESTRICCIÓN ABSOLUTA:** instalar ÚNICAMENTE para OpenCode. Está terminantemente prohibido crear o modificar archivos en `.claude/`, `.kiro/`, `.cursor/`, `.gemini/`, `.codex/`, `.antigravity/`, `.windsurf/` o cualquier otro directorio de plataformas externas.
|
|
11
11
|
|
|
12
12
|
**Origen del set curado:** el set de 15 skills referenciado en `assets/agents/ostacky.md` está bundleado en `assets/skills/` dentro del paquete npm. Context7 agrega su propio skill vía `npx ctx7 setup --opencode`. La definición del set y su trazabilidad viven en `manifest.json` y `.opencode/ostacky-lock.json`.
|
|
13
13
|
|
|
14
|
+
## Scope de instalación — local vs global (desde v0.7.3)
|
|
15
|
+
|
|
16
|
+
`npx ostacky install` soporta `--scope local|global|auto` (también `--scope=...`):
|
|
17
|
+
|
|
18
|
+
- `local` (recomendado): escribe en `<proyecto>/.opencode` (`opencode.json` local)
|
|
19
|
+
- `global`: escribe en `~/.config/opencode` (Unix/WSL) o `%APPDATA%\opencode` (Windows); respeta `XDG_CONFIG_HOME`
|
|
20
|
+
- `auto`: elige local si existe `.opencode` o `.git` (`.opencode` tiene prioridad), si no global
|
|
21
|
+
- Sin flag: pregunta interactivamente (default local)
|
|
22
|
+
|
|
23
|
+
Herramientas (`tools/`) permanecen siempre en `<proyecto>/.opencode/tools` por reproducibilidad. `npx ostacky install-stack --scope global` bloquea con error claro — el stack debe instalarse por proyecto:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx ostacky install --scope local
|
|
27
|
+
npx ostacky install --scope global
|
|
28
|
+
npx ostacky install-stack --scope auto # stack / proyecto
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
> **Windows con espacios** (ej. `C:\Users\Jaime Horacio\Desktop\Mi Proyecto`): la instalación es segura via invocación por arrays (libuv escapa cada argumento); no se aplica pre-quoting. `opencode.json` guarda `command` como array JSON.
|
|
32
|
+
|
|
14
33
|
---
|
|
15
34
|
|
|
16
35
|
## Paso 1 — CodeGraph
|