ostacky 0.9.7 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +92 -315
- package/assets/agents/ostacky.md +8 -8
- package/assets/commands/install-stack.md +1 -1
- package/assets/docs/ostacky-reference.md +33 -6
- package/assets/mcp/ostacky-controller/controller-core.js +4 -0
- package/assets/mcp/ostacky-controller/index.js +374 -38
- package/assets/plugins/ostacky-controller/controller-core.ts +4 -0
- package/assets/plugins/ostacky-controller/index.ts +437 -66
- package/assets/skills/brainstorming/SKILL.md +2 -2
- package/assets/skills/execution-mode-evaluation/SKILL.md +11 -12
- package/assets/skills/openspec-propose/SKILL.md +2 -2
- package/assets/skills/tdd/SKILL.md +1 -1
- package/dist/cli.js +95 -69
- package/manifest.json +32 -32
- package/package.json +1 -1
|
@@ -25,14 +25,13 @@ Determinar el modo de ejecución óptimo entre **inline** y **subagent-driven**
|
|
|
25
25
|
|
|
26
26
|
## Procedimiento
|
|
27
27
|
|
|
28
|
-
### Paso 0:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
### Paso 0.1: Consultar Engram por decisiones previas
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
28
|
+
### Paso 0: Reusar el discovery ya obtenido en este request
|
|
29
|
+
|
|
30
|
+
Si en este mismo request ya llamaste `codegraph_codegraph_explore` para el área, **reusá ese output** (sigue en tu contexto) para construir `sharedFiles/fileClusters`; solo `codegraph_impact` para símbolos no cubiertos. Si el área difiere materialmente (overlap <30%) o todavía no hiciste discovery → `codegraph_codegraph_explore` fresco. No hay cache de archivo: no repitas la misma query sin motivo.
|
|
31
|
+
|
|
32
|
+
### Paso 0.1: Consultar Engram por decisiones previas
|
|
33
|
+
|
|
34
|
+
`engram_mem_search` con keywords del cambio, salvo que ya lo hayas hecho para el mismo tema en este request. Si existe decisión previa, usarla como referencia no vinculante.
|
|
36
35
|
### Paso 0.5: Early exit para cambios pequeños
|
|
37
36
|
|
|
38
37
|
Si el change tiene **≤2 tasks** Y **no comparten archivos entre sí** → devolver directamente:
|
|
@@ -48,10 +47,10 @@ Si el change tiene **≤2 tasks** Y **no comparten archivos entre sí** → devo
|
|
|
48
47
|
}
|
|
49
48
|
```
|
|
50
49
|
|
|
51
|
-
### Paso 1: Obtener datos de CodeGraph (solo si discovery
|
|
52
|
-
|
|
53
|
-
Si
|
|
54
|
-
Si
|
|
50
|
+
### Paso 1: Obtener datos de CodeGraph (solo si no hiciste discovery en este request)
|
|
51
|
+
|
|
52
|
+
Si ya hay discovery en contexto → **SKIP este paso**; derivar `fileClusters/sharedFiles` del output (`state.snapshots.codegraph` + `tasks.md`) con `codegraphUsed:["codegraph_explore"]` y `reuseDiscovery:true`.
|
|
53
|
+
Si no:
|
|
55
54
|
```
|
|
56
55
|
codegraph_codegraph_explore con query: "<área del cambio>"
|
|
57
56
|
```
|
|
@@ -26,9 +26,9 @@ When ready to implement, run /opsx-apply
|
|
|
26
26
|
|
|
27
27
|
**Steps**
|
|
28
28
|
|
|
29
|
-
0. **Ground with CodeGraph + Engram (SHALL — Ostacky)** — Antes de `openspec new`,
|
|
29
|
+
0. **Ground with CodeGraph + Engram (SHALL — Ostacky)** — Antes de `openspec new`, usá `codegraph_codegraph_explore` + `engram_mem_search` sobre el área (si no los hiciste ya en este request). Citá símbolos existentes en `proposal/design`; sin esto el `design.md` puede alucinar API inexistente y dispara `WARN:codegraphBypass` en `doctor`.
|
|
30
30
|
|
|
31
|
-
1. **Check Engram for similar changes** — `engram_mem_search` con keywords del *paso 0* (
|
|
31
|
+
1. **Check Engram for similar changes** — `engram_mem_search` con keywords del *paso 0* (no repetir la misma query en el mismo request). Si hay change similar previo, surfacealo. Pueden extender trabajo existente en vez de empezar de cero.
|
|
32
32
|
|
|
33
33
|
2. **If no clear input provided, ask what they want to build**
|
|
34
34
|
|
|
@@ -28,7 +28,7 @@ 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,
|
|
31
|
+
> **Ostacky ground (SHALL):** Antes de RED, verificá el área con `codegraph_codegraph_explore` + `engram_mem_search` (si no los hiciste ya en este request). Citá símbolos existentes para no testear API inexistente. Ver `execution-mode-evaluation`.
|
|
32
32
|
|
|
33
33
|
## The Iron Law
|
|
34
34
|
|
package/dist/cli.js
CHANGED
|
@@ -641,31 +641,31 @@ var init_fs = __esm(() => {
|
|
|
641
641
|
var manifest_default;
|
|
642
642
|
var init_manifest = __esm(() => {
|
|
643
643
|
manifest_default = {
|
|
644
|
-
version: "0.
|
|
644
|
+
version: "0.10.1",
|
|
645
645
|
repo: "JaimeHoracio/Ostacky",
|
|
646
|
-
tag: "v0.
|
|
646
|
+
tag: "v0.10.1",
|
|
647
647
|
agents: [
|
|
648
648
|
{
|
|
649
649
|
name: "ostacky",
|
|
650
650
|
file: "assets/agents/ostacky.md",
|
|
651
|
-
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.
|
|
652
|
-
version: "0.
|
|
653
|
-
sha256: "
|
|
651
|
+
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.10.1: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
|
|
652
|
+
version: "0.10.1",
|
|
653
|
+
sha256: "f82687e38d1ad2e88cce1e962299c9bd8b9265d53fe3c7997114efddb39898b3"
|
|
654
654
|
}
|
|
655
655
|
],
|
|
656
656
|
commands: [
|
|
657
657
|
{
|
|
658
658
|
name: "install-stack",
|
|
659
659
|
file: "assets/commands/install-stack.md",
|
|
660
|
-
description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.
|
|
661
|
-
version: "0.
|
|
662
|
-
sha256: "
|
|
660
|
+
description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.10.1: controller plugin como alma hard-gate, Context7 removido del stack.",
|
|
661
|
+
version: "0.10.1",
|
|
662
|
+
sha256: "07e70cbaec57e27b5984e4a693486e34a8f52585b1183da7dd88c5dd69c7c8d5"
|
|
663
663
|
},
|
|
664
664
|
{
|
|
665
665
|
name: "opsx-sync",
|
|
666
666
|
file: "assets/commands/opsx-sync.md",
|
|
667
667
|
description: "Sincroniza delta specs del change activo sin inicializar CodeGraph si ya existe índice",
|
|
668
|
-
version: "0.
|
|
668
|
+
version: "0.10.1",
|
|
669
669
|
sha256: "f883f9ad96f7d75778631d5cc13d8a1a9c3e6ec41396bbce8ce13cff2e66fca2"
|
|
670
670
|
}
|
|
671
671
|
],
|
|
@@ -673,15 +673,15 @@ var init_manifest = __esm(() => {
|
|
|
673
673
|
{
|
|
674
674
|
name: "ostacky-controller",
|
|
675
675
|
file: "assets/mcp/ostacky-controller/",
|
|
676
|
-
description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.
|
|
677
|
-
version: "0.
|
|
678
|
-
sha256: "
|
|
676
|
+
description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.10.1: 22 tools (incluye set_handoff, get_handoff, clear_handoff, get_available_transitions funcional). Bugfixes: consecutiveFailures real, lastHandoff state, defaultChoice persistido. Robustez: degraded mode automático tras 3 fallos, persistence condicional para Nivel 0, prune de skills obsoletas.",
|
|
677
|
+
version: "0.10.1",
|
|
678
|
+
sha256: "d10efacd03f72f5fa1cca0abb22046a9862de7e98f635308f6898c5cbd67407e"
|
|
679
679
|
},
|
|
680
680
|
{
|
|
681
681
|
name: "openspec",
|
|
682
682
|
file: "assets/mcp/openspec/",
|
|
683
683
|
description: "MCP server local para OpenSpec - proposal, apply, archive, sync de cambios",
|
|
684
|
-
version: "0.
|
|
684
|
+
version: "0.10.1",
|
|
685
685
|
sha256: "bdb283fe8ec2dfcba2ec4f38191f4039e58cd7ae12e44e66310783b42c827638"
|
|
686
686
|
}
|
|
687
687
|
],
|
|
@@ -690,105 +690,105 @@ var init_manifest = __esm(() => {
|
|
|
690
690
|
name: "brainstorming",
|
|
691
691
|
file: "assets/skills/brainstorming/SKILL.md",
|
|
692
692
|
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)",
|
|
693
|
-
version: "0.
|
|
694
|
-
sha256: "
|
|
693
|
+
version: "0.10.1",
|
|
694
|
+
sha256: "ba76eff6fb5bea08d3b26622089ea4739b7b542b3677a46071b2576f3f2001c7"
|
|
695
695
|
},
|
|
696
696
|
{
|
|
697
697
|
name: "execution-mode-evaluation",
|
|
698
698
|
file: "assets/skills/execution-mode-evaluation/SKILL.md",
|
|
699
699
|
description: "Skill de análisis de modo de ejecución — output reconciliado con controller snapshot contract (recommendation field)",
|
|
700
|
-
version: "0.
|
|
701
|
-
sha256: "
|
|
700
|
+
version: "0.10.1",
|
|
701
|
+
sha256: "9090132ccfe31dcf34b6d5f399c1135dcb1044c504d4beb026e0c7d9e09e7c0d"
|
|
702
702
|
},
|
|
703
703
|
{
|
|
704
704
|
name: "tdd",
|
|
705
705
|
file: "assets/skills/tdd/SKILL.md",
|
|
706
706
|
description: "Skill de test-driven development (Superpowers)",
|
|
707
|
-
version: "0.
|
|
708
|
-
sha256: "
|
|
707
|
+
version: "0.10.1",
|
|
708
|
+
sha256: "cce54e81cce46ba973066f9b43e74994a7dbf21aa756146c27689241cf62704d"
|
|
709
709
|
},
|
|
710
710
|
{
|
|
711
711
|
name: "subagent-driven-development",
|
|
712
712
|
file: "assets/skills/subagent-driven-development/SKILL.md",
|
|
713
713
|
description: "Skill de ejecución con subagentes (Superpowers) — ejecuta solo después de confirmación del coordinador Ostacky",
|
|
714
|
-
version: "0.
|
|
714
|
+
version: "0.10.1",
|
|
715
715
|
sha256: "1a42d714a9a13faf05f0bf7b580e8d837c2e77a5633839542ccce603023419e8"
|
|
716
716
|
},
|
|
717
717
|
{
|
|
718
718
|
name: "dispatching-parallel-agents",
|
|
719
719
|
file: "assets/skills/dispatching-parallel-agents/SKILL.md",
|
|
720
720
|
description: "Skill de dispatch paralelo de agentes (Superpowers)",
|
|
721
|
-
version: "0.
|
|
721
|
+
version: "0.10.1",
|
|
722
722
|
sha256: "7e7b712ef742d5631e302e6a71583e2bbbd33094da9281abfb84b43505fc3ef1"
|
|
723
723
|
},
|
|
724
724
|
{
|
|
725
725
|
name: "review",
|
|
726
726
|
file: "assets/skills/review/SKILL.md",
|
|
727
727
|
description: "Skill de revisión de código (Superpowers)",
|
|
728
|
-
version: "0.
|
|
728
|
+
version: "0.10.1",
|
|
729
729
|
sha256: "b19650ed4d1d4d9857a4dd5b7e08e91328a1a1fc9c45bcc2fb600fa9d0213279"
|
|
730
730
|
},
|
|
731
731
|
{
|
|
732
732
|
name: "receiving-code-review",
|
|
733
733
|
file: "assets/skills/receiving-code-review/SKILL.md",
|
|
734
734
|
description: "Skill de recibir y procesar feedback de code review",
|
|
735
|
-
version: "0.
|
|
735
|
+
version: "0.10.1",
|
|
736
736
|
sha256: "d761e884e71d8d3476ac734d287cae403a4024506a7d12e7361a448217c0a831"
|
|
737
737
|
},
|
|
738
738
|
{
|
|
739
739
|
name: "openspec-propose",
|
|
740
740
|
file: "assets/skills/openspec-propose/SKILL.md",
|
|
741
741
|
description: "Skill de generación de proposal (OpenSpec)",
|
|
742
|
-
version: "0.
|
|
743
|
-
sha256: "
|
|
742
|
+
version: "0.10.1",
|
|
743
|
+
sha256: "9049b944cea88a5428fd5d77b411a0ed32d169ad68acda911b68365fac08f38f"
|
|
744
744
|
},
|
|
745
745
|
{
|
|
746
746
|
name: "openspec-apply-change",
|
|
747
747
|
file: "assets/skills/openspec-apply-change/SKILL.md",
|
|
748
748
|
description: "Skill de aplicación de change (OpenSpec)",
|
|
749
|
-
version: "0.
|
|
749
|
+
version: "0.10.1",
|
|
750
750
|
sha256: "dfc823bf89fc7505e91ab6dee9c1f004be38a410bd3d88fb67b211b1b6cbb1d0"
|
|
751
751
|
},
|
|
752
752
|
{
|
|
753
753
|
name: "openspec-archive-change",
|
|
754
754
|
file: "assets/skills/openspec-archive-change/SKILL.md",
|
|
755
755
|
description: "Skill de archivo de change (OpenSpec)",
|
|
756
|
-
version: "0.
|
|
756
|
+
version: "0.10.1",
|
|
757
757
|
sha256: "16e4b561de7747283663fed602e506abf502452c49a8d4b86d7a5539c40f0195"
|
|
758
758
|
},
|
|
759
759
|
{
|
|
760
760
|
name: "openspec-explore",
|
|
761
761
|
file: "assets/skills/openspec-explore/SKILL.md",
|
|
762
762
|
description: "Modo explore para OpenSpec — thinking partner para explorar ideas, investigar problemas y clarificar requisitos antes/durante un cambio",
|
|
763
|
-
version: "0.
|
|
763
|
+
version: "0.10.1",
|
|
764
764
|
sha256: "9eafc3a8c693b8d9916867ef764d49e5222da717fde501c957bb3f6c312d2415"
|
|
765
765
|
},
|
|
766
766
|
{
|
|
767
767
|
name: "using-git-worktrees",
|
|
768
768
|
file: "assets/skills/using-git-worktrees/SKILL.md",
|
|
769
769
|
description: "Skill de uso de git worktrees para aislamiento de trabajo",
|
|
770
|
-
version: "0.
|
|
770
|
+
version: "0.10.1",
|
|
771
771
|
sha256: "93341bc1b7c053618a8b6dc07e3615b77990d7b549a0201f5835d95fef67ce13"
|
|
772
772
|
},
|
|
773
773
|
{
|
|
774
774
|
name: "using-superpowers",
|
|
775
775
|
file: "assets/skills/using-superpowers/SKILL.md",
|
|
776
776
|
description: "Skill de orquestación de Superpowers skills",
|
|
777
|
-
version: "0.
|
|
777
|
+
version: "0.10.1",
|
|
778
778
|
sha256: "7e54536f96d2a379185a10bfc1e970850caa2561b6d8aca7080f0defea0381a4"
|
|
779
779
|
},
|
|
780
780
|
{
|
|
781
781
|
name: "writing-skills",
|
|
782
782
|
file: "assets/skills/writing-skills/SKILL.md",
|
|
783
783
|
description: "Skill de creación y edición de skills",
|
|
784
|
-
version: "0.
|
|
784
|
+
version: "0.10.1",
|
|
785
785
|
sha256: "3d76b906cee518a2b809febb70db95697a35b9f368986bb504b4120c3bfb437a"
|
|
786
786
|
},
|
|
787
787
|
{
|
|
788
788
|
name: "graceful-degradation",
|
|
789
789
|
file: "assets/skills/graceful-degradation/SKILL.md",
|
|
790
790
|
description: "Skill de degradación graceful cuando múltiples tools están indisponibles",
|
|
791
|
-
version: "0.
|
|
791
|
+
version: "0.10.1",
|
|
792
792
|
sha256: "363449bd9e6f800a0a3168667cf78f767fb105d86e4a4adadcc649d418139303"
|
|
793
793
|
}
|
|
794
794
|
]
|
|
@@ -1046,11 +1046,19 @@ function readOpenCodeConfig(configPath) {
|
|
|
1046
1046
|
return null;
|
|
1047
1047
|
}
|
|
1048
1048
|
}
|
|
1049
|
-
function writeOpenCodeConfig(configPath, config) {
|
|
1049
|
+
function writeOpenCodeConfig(configPath, config, options = {}) {
|
|
1050
|
+
const next = JSON.stringify(config, null, 2) + `
|
|
1051
|
+
`;
|
|
1052
|
+
try {
|
|
1053
|
+
if (options.backup !== false && existsSync4(configPath)) {
|
|
1054
|
+
const prev = readFileSync4(configPath, "utf-8");
|
|
1055
|
+
if (prev !== next)
|
|
1056
|
+
writeFileSync4(`${configPath}.bak`, prev, "utf-8");
|
|
1057
|
+
}
|
|
1058
|
+
} catch {}
|
|
1050
1059
|
const tmpPath = `${configPath}.tmp.${process.pid}.${Date.now()}`;
|
|
1051
1060
|
try {
|
|
1052
|
-
writeFileSync4(tmpPath,
|
|
1053
|
-
`, "utf-8");
|
|
1061
|
+
writeFileSync4(tmpPath, next, "utf-8");
|
|
1054
1062
|
renameSync2(tmpPath, configPath);
|
|
1055
1063
|
} finally {
|
|
1056
1064
|
if (existsSync4(tmpPath))
|
|
@@ -1060,13 +1068,13 @@ function writeOpenCodeConfig(configPath, config) {
|
|
|
1060
1068
|
function ensureOpenCodeConfig(projectRoot) {
|
|
1061
1069
|
const existing = findOpenCodeConfig(projectRoot);
|
|
1062
1070
|
if (existing)
|
|
1063
|
-
return existing;
|
|
1071
|
+
return { path: existing, created: false };
|
|
1064
1072
|
const configPath = join5(projectRoot, "opencode.json");
|
|
1065
1073
|
writeOpenCodeConfig(configPath, {
|
|
1066
1074
|
$schema: "https://opencode.ai/config.json",
|
|
1067
1075
|
mcp: {}
|
|
1068
|
-
});
|
|
1069
|
-
return configPath;
|
|
1076
|
+
}, { backup: false });
|
|
1077
|
+
return { path: configPath, created: true };
|
|
1070
1078
|
}
|
|
1071
1079
|
function findOpenCodeConfig(projectRoot) {
|
|
1072
1080
|
const candidates = ["opencode.json", "opencode.jsonc"];
|
|
@@ -1078,7 +1086,7 @@ function findOpenCodeConfig(projectRoot) {
|
|
|
1078
1086
|
return null;
|
|
1079
1087
|
}
|
|
1080
1088
|
function setMcpEntryAtProjectRoot(projectRoot, name, entry) {
|
|
1081
|
-
const configPath = ensureOpenCodeConfig(projectRoot);
|
|
1089
|
+
const { path: configPath, created } = ensureOpenCodeConfig(projectRoot);
|
|
1082
1090
|
const config = readOpenCodeConfig(configPath);
|
|
1083
1091
|
if (!config)
|
|
1084
1092
|
throw new Error(`Error parseando ${configPath}`);
|
|
@@ -1090,7 +1098,7 @@ function setMcpEntryAtProjectRoot(projectRoot, name, entry) {
|
|
|
1090
1098
|
mcp.servers[name] = entry;
|
|
1091
1099
|
if (name in mcp && name !== "servers")
|
|
1092
1100
|
delete mcp[name];
|
|
1093
|
-
writeOpenCodeConfig(configPath, config);
|
|
1101
|
+
writeOpenCodeConfig(configPath, config, { backup: !created });
|
|
1094
1102
|
}
|
|
1095
1103
|
function patchOpenCodeConfig(projectRoot = findProjectRoot()) {
|
|
1096
1104
|
const configPath = findOpenCodeConfig(projectRoot);
|
|
@@ -1138,13 +1146,13 @@ var init_config = __esm(() => {
|
|
|
1138
1146
|
|
|
1139
1147
|
// src/stack.ts
|
|
1140
1148
|
import { chmodSync, copyFileSync as copyFileSync3, existsSync as existsSync6, mkdirSync as mkdirSync4, rmSync as rmSync4, unlinkSync as unlinkSync3 } from "fs";
|
|
1141
|
-
import { basename as
|
|
1149
|
+
import { basename as basename3, dirname as dirname5, join as join7, resolve as resolve3 } from "path";
|
|
1142
1150
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
1143
1151
|
function resolveToolInstallLocation(toolsDir) {
|
|
1144
1152
|
const resolvedToolsDir = resolve3(toolsDir ?? join7(findProjectRoot(), ".opencode", "tools"));
|
|
1145
1153
|
const possibleOpenCodeDir = dirname5(resolvedToolsDir);
|
|
1146
1154
|
return {
|
|
1147
|
-
projectRoot:
|
|
1155
|
+
projectRoot: basename3(possibleOpenCodeDir) === ".opencode" ? dirname5(possibleOpenCodeDir) : findProjectRoot(),
|
|
1148
1156
|
toolsDir: resolvedToolsDir
|
|
1149
1157
|
};
|
|
1150
1158
|
}
|
|
@@ -1727,7 +1735,7 @@ var init_doctor_v2 = __esm(() => {
|
|
|
1727
1735
|
// package.json
|
|
1728
1736
|
var package_default = {
|
|
1729
1737
|
name: "ostacky",
|
|
1730
|
-
version: "0.
|
|
1738
|
+
version: "0.10.1",
|
|
1731
1739
|
description: "Instalador interactivo de agentes y comandos para OpenCode",
|
|
1732
1740
|
type: "module",
|
|
1733
1741
|
bin: {
|
|
@@ -2748,7 +2756,7 @@ import {
|
|
|
2748
2756
|
rmSync as rmSync3
|
|
2749
2757
|
} from "fs";
|
|
2750
2758
|
import { execFileSync as execFileSync2, spawn } from "child_process";
|
|
2751
|
-
import { dirname as dirname4, join as join6 } from "path";
|
|
2759
|
+
import { dirname as dirname4, join as join6, basename as basename2 } from "path";
|
|
2752
2760
|
import { pathToFileURL } from "url";
|
|
2753
2761
|
function createMcpConfigEntry(name, nodeExecutable, serverPath, statePath) {
|
|
2754
2762
|
const entry = {
|
|
@@ -2906,20 +2914,25 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath, option
|
|
|
2906
2914
|
params: {
|
|
2907
2915
|
protocolVersion: "2025-03-26",
|
|
2908
2916
|
capabilities: {},
|
|
2909
|
-
clientInfo: { name: "ostacky-installer", version: "0.
|
|
2917
|
+
clientInfo: { name: "ostacky-installer", version: "0.10.1" }
|
|
2910
2918
|
}
|
|
2911
2919
|
});
|
|
2912
2920
|
});
|
|
2913
2921
|
} finally {
|
|
2914
2922
|
await new Promise((r) => setTimeout(r, 200));
|
|
2915
2923
|
if (statePath) {
|
|
2916
|
-
|
|
2924
|
+
const probeDir = dirname4(statePath);
|
|
2925
|
+
const probeBase = basename2(statePath);
|
|
2926
|
+
const probePrefix = probeBase + ".";
|
|
2927
|
+
for (const p of readdirSync2(probeDir).filter((entry) => entry === probeBase || entry.startsWith(probePrefix)).map((entry) => join6(probeDir, entry)).concat([
|
|
2917
2928
|
statePath,
|
|
2918
2929
|
statePath + ".backup",
|
|
2930
|
+
statePath + ".backup.1",
|
|
2931
|
+
statePath + ".backup.2",
|
|
2919
2932
|
statePath + ".lock.pid",
|
|
2920
2933
|
statePath + ".lock.timestamp",
|
|
2921
2934
|
statePath + ".tmp." + process.pid
|
|
2922
|
-
]) {
|
|
2935
|
+
])) {
|
|
2923
2936
|
try {
|
|
2924
2937
|
if (existsSync5(p))
|
|
2925
2938
|
rmSync3(p, { force: true });
|
|
@@ -3425,6 +3438,15 @@ async function doInstallStack(toolsDir, projectRoot) {
|
|
|
3425
3438
|
let allOk = true;
|
|
3426
3439
|
const resolvedProjectRoot = projectRoot ?? dirname6(dirname6(toolsDir ?? join8(process.cwd(), ".opencode", "tools")));
|
|
3427
3440
|
const resolvedToolsDir = toolsDir ?? join8(resolvedProjectRoot, ".opencode", "tools");
|
|
3441
|
+
try {
|
|
3442
|
+
await Promise.resolve().then(() => init_fs());
|
|
3443
|
+
const globalDir = getGlobalOpenCodeDir().replace(/\\/g, "/").toLowerCase();
|
|
3444
|
+
const toolsNorm = resolvedToolsDir.replace(/\\/g, "/").toLowerCase();
|
|
3445
|
+
if (toolsNorm === globalDir || toolsNorm.startsWith(globalDir + "/")) {
|
|
3446
|
+
v2.warn("Scope global: el stack (CodeGraph/Engram) es siempre local por proyecto — omitido aquí. Instalalo por proyecto con `npx ostacky install-stack --scope local`.");
|
|
3447
|
+
return true;
|
|
3448
|
+
}
|
|
3449
|
+
} catch {}
|
|
3428
3450
|
v2.info(`Stack → projectRoot: ${resolvedProjectRoot} | toolsDir: ${resolvedToolsDir}`);
|
|
3429
3451
|
try {
|
|
3430
3452
|
const { homedir } = await import("os");
|
|
@@ -4133,25 +4155,25 @@ function getOpencodeVersion() {
|
|
|
4133
4155
|
function getOpencodeInstallCommand(platform = process.platform, _arch = process.arch) {
|
|
4134
4156
|
if (platform === "win32") {
|
|
4135
4157
|
return {
|
|
4136
|
-
display: "npm install -g opencode
|
|
4158
|
+
display: "npm install -g @opencode/cli",
|
|
4137
4159
|
command: "npm",
|
|
4138
|
-
args: ["install", "-g", "opencode
|
|
4139
|
-
note: "Alternativas Windows:
|
|
4160
|
+
args: ["install", "-g", "@opencode/cli"],
|
|
4161
|
+
note: "Alternativas Windows: binario suelto desde https://opencode.ai/download | WSL recomendado (OpenCode no soporta package managers de Windows)."
|
|
4140
4162
|
};
|
|
4141
4163
|
}
|
|
4142
4164
|
if (platform === "darwin") {
|
|
4143
4165
|
return {
|
|
4144
|
-
display: "curl -fsSL https://opencode.ai/install | bash",
|
|
4166
|
+
display: "curl -fsSL https://opencode.ai/v2/install | bash",
|
|
4145
4167
|
command: "bash",
|
|
4146
|
-
args: ["-c", "curl -fsSL https://opencode.ai/install | bash"],
|
|
4147
|
-
note: "Alternativa macOS: brew install anomalyco/tap/opencode (tap oficial
|
|
4168
|
+
args: ["-c", "curl -fsSL https://opencode.ai/v2/install | bash"],
|
|
4169
|
+
note: "Alternativa macOS: brew install anomalyco/tap/opencode-v2 (tap oficial) | npm install -g @opencode/cli"
|
|
4148
4170
|
};
|
|
4149
4171
|
}
|
|
4150
4172
|
return {
|
|
4151
|
-
display: "curl -fsSL https://opencode.ai/install | bash",
|
|
4173
|
+
display: "curl -fsSL https://opencode.ai/v2/install | bash",
|
|
4152
4174
|
command: "bash",
|
|
4153
|
-
args: ["-c", "curl -fsSL https://opencode.ai/install | bash"],
|
|
4154
|
-
note: "Alternativas Linux: npm install -g opencode
|
|
4175
|
+
args: ["-c", "curl -fsSL https://opencode.ai/v2/install | bash"],
|
|
4176
|
+
note: "Alternativas Linux: npm install -g @opencode/cli | bun install -g --trust @opencode/cli | brew install anomalyco/tap/opencode-v2 | paru -S opencode-beta (Arch)"
|
|
4155
4177
|
};
|
|
4156
4178
|
}
|
|
4157
4179
|
async function ensureOpencodeInstalled() {
|
|
@@ -4184,14 +4206,14 @@ ${info.note}` : ""}`, `Instalación requerida (${platform})`);
|
|
|
4184
4206
|
spin.start(`Instalando OpenCode (${info.display})...`);
|
|
4185
4207
|
try {
|
|
4186
4208
|
if (platform === "win32") {
|
|
4187
|
-
execSync("npm install -g opencode
|
|
4209
|
+
execSync("npm install -g @opencode/cli", { stdio: "inherit", shell: "cmd.exe" });
|
|
4188
4210
|
} else {
|
|
4189
4211
|
if (!isCommandAvailable("curl")) {
|
|
4190
4212
|
spin.stop("curl no disponible");
|
|
4191
4213
|
v2.warn("curl no está instalado — se intentará con npm como fallback.");
|
|
4192
|
-
execSync("npm install -g opencode
|
|
4214
|
+
execSync("npm install -g @opencode/cli", { stdio: "inherit", shell: "/bin/bash" });
|
|
4193
4215
|
} else {
|
|
4194
|
-
execSync("curl -fsSL https://opencode.ai/install | bash", { stdio: "inherit", shell: "/bin/bash" });
|
|
4216
|
+
execSync("curl -fsSL https://opencode.ai/v2/install | bash", { stdio: "inherit", shell: "/bin/bash" });
|
|
4195
4217
|
}
|
|
4196
4218
|
}
|
|
4197
4219
|
spin.stop("Instalación ejecutada, verificando...");
|
|
@@ -4202,10 +4224,10 @@ ${info.note}` : ""}`, `Instalación requerida (${platform})`);
|
|
|
4202
4224
|
if (platform === "win32") {
|
|
4203
4225
|
ye([
|
|
4204
4226
|
"Intentá manualmente una de estas opciones:",
|
|
4205
|
-
" npm install -g opencode
|
|
4206
|
-
"
|
|
4207
|
-
"
|
|
4208
|
-
" (WSL) curl -fsSL https://opencode.ai/install | bash",
|
|
4227
|
+
" npm install -g @opencode/cli",
|
|
4228
|
+
" bun install -g --trust @opencode/cli",
|
|
4229
|
+
" binario suelto: https://opencode.ai/download",
|
|
4230
|
+
" (WSL) curl -fsSL https://opencode.ai/v2/install | bash",
|
|
4209
4231
|
"Luego verificá: opencode --version",
|
|
4210
4232
|
"Docs: https://opencode.ai/download"
|
|
4211
4233
|
].join(`
|
|
@@ -4214,8 +4236,8 @@ ${info.note}` : ""}`, `Instalación requerida (${platform})`);
|
|
|
4214
4236
|
ye([
|
|
4215
4237
|
"Intentá manualmente:",
|
|
4216
4238
|
` ${info.display}`,
|
|
4217
|
-
" npm install -g opencode
|
|
4218
|
-
" brew install anomalyco/tap/opencode (macOS/Linux con brew)",
|
|
4239
|
+
" npm install -g @opencode/cli (si no tenés curl)",
|
|
4240
|
+
" brew install anomalyco/tap/opencode-v2 (macOS/Linux con brew)",
|
|
4219
4241
|
"Luego verificá: opencode --version",
|
|
4220
4242
|
"Docs: https://opencode.ai/download"
|
|
4221
4243
|
].join(`
|
|
@@ -4265,7 +4287,7 @@ async function runInteractiveMenu(scope) {
|
|
|
4265
4287
|
onCancel(action);
|
|
4266
4288
|
switch (action) {
|
|
4267
4289
|
case "all":
|
|
4268
|
-
if (!await doInstallAll(manifest, paths))
|
|
4290
|
+
if (!await doInstallAll(manifest, paths, { scope: scope ?? "local" }))
|
|
4269
4291
|
process.exitCode = 1;
|
|
4270
4292
|
printPostInstallSteps();
|
|
4271
4293
|
fe(process.exitCode ? "Instalación parcial." : "Listo.");
|
|
@@ -4291,6 +4313,11 @@ async function runInteractiveMenu(scope) {
|
|
|
4291
4313
|
fe("Listo.");
|
|
4292
4314
|
break;
|
|
4293
4315
|
case "stack": {
|
|
4316
|
+
if ((scope ?? "local") === "global") {
|
|
4317
|
+
v2.warn("El stack (CodeGraph/Engram) es siempre local por proyecto. En scope global se omite; usá `npx ostacky install-stack --scope local` dentro del proyecto.");
|
|
4318
|
+
fe("Listo.");
|
|
4319
|
+
break;
|
|
4320
|
+
}
|
|
4294
4321
|
ensureToolDirs(paths.tools, ["codegraph", "engram"]);
|
|
4295
4322
|
const stackOk = await doInstallStack(paths.tools, dirname7(paths.root));
|
|
4296
4323
|
if (!stackOk)
|
|
@@ -4971,9 +4998,8 @@ async function runDoctorCommand() {
|
|
|
4971
4998
|
const pluginPath = join11(cwd, "assets", "plugins", "ostacky-controller", "index.ts");
|
|
4972
4999
|
if (existsSync9(pluginPath)) {
|
|
4973
5000
|
const plugin = readFileSync7(pluginPath, "utf-8");
|
|
4974
|
-
const
|
|
4975
|
-
|
|
4976
|
-
check("spec: no-overwrite guard", hasNoOverwrite, true);
|
|
5001
|
+
const hasNoOverwrite = plugin.includes("shouldBlockCodeRead") && plugin.includes("isCodeReadGated") && plugin.includes("isTaskTracked") && plugin.includes("isShellPathExempt");
|
|
5002
|
+
check("spec/tracked read-guard (shouldBlockCodeRead + exemptions)", hasNoOverwrite, true);
|
|
4977
5003
|
}
|
|
4978
5004
|
const hasSyncProactive = ostackyMd.includes("Noté que lo que acordamos");
|
|
4979
5005
|
check("sync: proactive WARN", hasSyncProactive, true);
|