ostacky 0.10.2 → 0.10.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 +5 -3
- package/assets/agents/ostacky.md +12 -4
- package/assets/commands/install-stack.md +1 -1
- package/assets/docs/ostacky-reference.md +9 -1
- package/assets/mcp/ostacky-controller/index.js +191 -37
- package/assets/plugins/engram.ts +13 -9
- package/assets/plugins/ostacky-controller/index.ts +234 -41
- package/dist/cli.js +130 -58
- package/dist/mcp/openspec/index.js +19335 -0
- package/dist/mcp/openspec/package.json +1 -0
- package/dist/mcp/ostacky-controller/index.js +23115 -0
- package/dist/mcp/ostacky-controller/package.json +1 -0
- package/manifest.json +31 -29
- package/package.json +7 -5
package/dist/cli.js
CHANGED
|
@@ -263,17 +263,14 @@ function initGitRepo(dir) {
|
|
|
263
263
|
execFileSync("git", ["init"], { cwd: dir, stdio: "pipe" });
|
|
264
264
|
}
|
|
265
265
|
function getGlobalOpenCodeDir(opts) {
|
|
266
|
-
const platform = opts?.platform ?? process.platform;
|
|
267
266
|
const env = opts?.env ?? process.env;
|
|
268
267
|
const home = opts?.home ?? homedir();
|
|
268
|
+
const explicit = env.OPENCODE_CONFIG_DIR?.trim();
|
|
269
|
+
if (explicit)
|
|
270
|
+
return explicit;
|
|
269
271
|
const xdg = env.XDG_CONFIG_HOME?.trim();
|
|
270
272
|
if (xdg)
|
|
271
273
|
return join(xdg, "opencode");
|
|
272
|
-
if (platform === "win32") {
|
|
273
|
-
const appdata = env.APPDATA?.trim();
|
|
274
|
-
if (appdata)
|
|
275
|
-
return join(appdata, "opencode");
|
|
276
|
-
}
|
|
277
274
|
return join(home, ".config", "opencode");
|
|
278
275
|
}
|
|
279
276
|
function getOpenCodeDirForScope(scope, cwd = process.cwd()) {
|
|
@@ -641,31 +638,31 @@ var init_fs = __esm(() => {
|
|
|
641
638
|
var manifest_default;
|
|
642
639
|
var init_manifest = __esm(() => {
|
|
643
640
|
manifest_default = {
|
|
644
|
-
version: "0.10.
|
|
641
|
+
version: "0.10.3",
|
|
645
642
|
repo: "JaimeHoracio/Ostacky",
|
|
646
|
-
tag: "v0.10.
|
|
643
|
+
tag: "v0.10.3",
|
|
647
644
|
agents: [
|
|
648
645
|
{
|
|
649
646
|
name: "ostacky",
|
|
650
647
|
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.10.
|
|
652
|
-
version: "0.10.
|
|
653
|
-
sha256: "
|
|
648
|
+
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.3: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
|
|
649
|
+
version: "0.10.3",
|
|
650
|
+
sha256: "c8f18e81f3cfb2778656bd3e9b391d8521bec7797436a8539e1b7f0b7160597c"
|
|
654
651
|
}
|
|
655
652
|
],
|
|
656
653
|
commands: [
|
|
657
654
|
{
|
|
658
655
|
name: "install-stack",
|
|
659
656
|
file: "assets/commands/install-stack.md",
|
|
660
|
-
description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.10.
|
|
661
|
-
version: "0.10.
|
|
662
|
-
sha256: "
|
|
657
|
+
description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.10.3: controller plugin como alma hard-gate, Context7 removido del stack.",
|
|
658
|
+
version: "0.10.3",
|
|
659
|
+
sha256: "eefea7d0efb9e89184bf2bbdcd8912928eb168d75e7b129526010fb1a5e81d50"
|
|
663
660
|
},
|
|
664
661
|
{
|
|
665
662
|
name: "opsx-sync",
|
|
666
663
|
file: "assets/commands/opsx-sync.md",
|
|
667
664
|
description: "Sincroniza delta specs del change activo sin inicializar CodeGraph si ya existe índice",
|
|
668
|
-
version: "0.10.
|
|
665
|
+
version: "0.10.3",
|
|
669
666
|
sha256: "f883f9ad96f7d75778631d5cc13d8a1a9c3e6ec41396bbce8ce13cff2e66fca2"
|
|
670
667
|
}
|
|
671
668
|
],
|
|
@@ -673,16 +670,18 @@ var init_manifest = __esm(() => {
|
|
|
673
670
|
{
|
|
674
671
|
name: "ostacky-controller",
|
|
675
672
|
file: "assets/mcp/ostacky-controller/",
|
|
676
|
-
description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.10.
|
|
677
|
-
version: "0.10.
|
|
678
|
-
sha256: "
|
|
673
|
+
description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.10.3: 22 tools (incluye set_handoff, get_handoff, clear_handoff, get_available_transitions funcional). Bugfixes: consecutiveFailures real, lastHandoff state, defaultChoice persistido. Robustez: degraded mode automático tras 3 fallos, persistence condicional para Nivel 0, prune de skills obsoletas.",
|
|
674
|
+
version: "0.10.3",
|
|
675
|
+
sha256: "f2d20b33b02b7a452f389b603c4ae65d5e8c079fc12e38f2641689816b3024f1",
|
|
676
|
+
sourceSha256: "f12314dcce27073f6aa2a83dcb7efe2a82a83404fe43926ec2da49d2c33a17ad"
|
|
679
677
|
},
|
|
680
678
|
{
|
|
681
679
|
name: "openspec",
|
|
682
680
|
file: "assets/mcp/openspec/",
|
|
683
681
|
description: "MCP server local para OpenSpec - proposal, apply, archive, sync de cambios",
|
|
684
|
-
version: "0.10.
|
|
685
|
-
sha256: "
|
|
682
|
+
version: "0.10.3",
|
|
683
|
+
sha256: "038ef43eaa1816251626610522f874a6c932528c00237f94f5354f18ed59ef53",
|
|
684
|
+
sourceSha256: "bdb283fe8ec2dfcba2ec4f38191f4039e58cd7ae12e44e66310783b42c827638"
|
|
686
685
|
}
|
|
687
686
|
],
|
|
688
687
|
skills: [
|
|
@@ -690,105 +689,105 @@ var init_manifest = __esm(() => {
|
|
|
690
689
|
name: "brainstorming",
|
|
691
690
|
file: "assets/skills/brainstorming/SKILL.md",
|
|
692
691
|
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.10.
|
|
692
|
+
version: "0.10.3",
|
|
694
693
|
sha256: "ba76eff6fb5bea08d3b26622089ea4739b7b542b3677a46071b2576f3f2001c7"
|
|
695
694
|
},
|
|
696
695
|
{
|
|
697
696
|
name: "execution-mode-evaluation",
|
|
698
697
|
file: "assets/skills/execution-mode-evaluation/SKILL.md",
|
|
699
698
|
description: "Skill de análisis de modo de ejecución — output reconciliado con controller snapshot contract (recommendation field)",
|
|
700
|
-
version: "0.10.
|
|
699
|
+
version: "0.10.3",
|
|
701
700
|
sha256: "9090132ccfe31dcf34b6d5f399c1135dcb1044c504d4beb026e0c7d9e09e7c0d"
|
|
702
701
|
},
|
|
703
702
|
{
|
|
704
703
|
name: "tdd",
|
|
705
704
|
file: "assets/skills/tdd/SKILL.md",
|
|
706
705
|
description: "Skill de test-driven development (Superpowers)",
|
|
707
|
-
version: "0.10.
|
|
706
|
+
version: "0.10.3",
|
|
708
707
|
sha256: "cce54e81cce46ba973066f9b43e74994a7dbf21aa756146c27689241cf62704d"
|
|
709
708
|
},
|
|
710
709
|
{
|
|
711
710
|
name: "subagent-driven-development",
|
|
712
711
|
file: "assets/skills/subagent-driven-development/SKILL.md",
|
|
713
712
|
description: "Skill de ejecución con subagentes (Superpowers) — ejecuta solo después de confirmación del coordinador Ostacky",
|
|
714
|
-
version: "0.10.
|
|
713
|
+
version: "0.10.3",
|
|
715
714
|
sha256: "1a42d714a9a13faf05f0bf7b580e8d837c2e77a5633839542ccce603023419e8"
|
|
716
715
|
},
|
|
717
716
|
{
|
|
718
717
|
name: "dispatching-parallel-agents",
|
|
719
718
|
file: "assets/skills/dispatching-parallel-agents/SKILL.md",
|
|
720
719
|
description: "Skill de dispatch paralelo de agentes (Superpowers)",
|
|
721
|
-
version: "0.10.
|
|
720
|
+
version: "0.10.3",
|
|
722
721
|
sha256: "7e7b712ef742d5631e302e6a71583e2bbbd33094da9281abfb84b43505fc3ef1"
|
|
723
722
|
},
|
|
724
723
|
{
|
|
725
724
|
name: "review",
|
|
726
725
|
file: "assets/skills/review/SKILL.md",
|
|
727
726
|
description: "Skill de revisión de código (Superpowers)",
|
|
728
|
-
version: "0.10.
|
|
727
|
+
version: "0.10.3",
|
|
729
728
|
sha256: "b19650ed4d1d4d9857a4dd5b7e08e91328a1a1fc9c45bcc2fb600fa9d0213279"
|
|
730
729
|
},
|
|
731
730
|
{
|
|
732
731
|
name: "receiving-code-review",
|
|
733
732
|
file: "assets/skills/receiving-code-review/SKILL.md",
|
|
734
733
|
description: "Skill de recibir y procesar feedback de code review",
|
|
735
|
-
version: "0.10.
|
|
734
|
+
version: "0.10.3",
|
|
736
735
|
sha256: "d761e884e71d8d3476ac734d287cae403a4024506a7d12e7361a448217c0a831"
|
|
737
736
|
},
|
|
738
737
|
{
|
|
739
738
|
name: "openspec-propose",
|
|
740
739
|
file: "assets/skills/openspec-propose/SKILL.md",
|
|
741
740
|
description: "Skill de generación de proposal (OpenSpec)",
|
|
742
|
-
version: "0.10.
|
|
741
|
+
version: "0.10.3",
|
|
743
742
|
sha256: "9049b944cea88a5428fd5d77b411a0ed32d169ad68acda911b68365fac08f38f"
|
|
744
743
|
},
|
|
745
744
|
{
|
|
746
745
|
name: "openspec-apply-change",
|
|
747
746
|
file: "assets/skills/openspec-apply-change/SKILL.md",
|
|
748
747
|
description: "Skill de aplicación de change (OpenSpec)",
|
|
749
|
-
version: "0.10.
|
|
748
|
+
version: "0.10.3",
|
|
750
749
|
sha256: "dfc823bf89fc7505e91ab6dee9c1f004be38a410bd3d88fb67b211b1b6cbb1d0"
|
|
751
750
|
},
|
|
752
751
|
{
|
|
753
752
|
name: "openspec-archive-change",
|
|
754
753
|
file: "assets/skills/openspec-archive-change/SKILL.md",
|
|
755
754
|
description: "Skill de archivo de change (OpenSpec)",
|
|
756
|
-
version: "0.10.
|
|
755
|
+
version: "0.10.3",
|
|
757
756
|
sha256: "16e4b561de7747283663fed602e506abf502452c49a8d4b86d7a5539c40f0195"
|
|
758
757
|
},
|
|
759
758
|
{
|
|
760
759
|
name: "openspec-explore",
|
|
761
760
|
file: "assets/skills/openspec-explore/SKILL.md",
|
|
762
761
|
description: "Modo explore para OpenSpec — thinking partner para explorar ideas, investigar problemas y clarificar requisitos antes/durante un cambio",
|
|
763
|
-
version: "0.10.
|
|
762
|
+
version: "0.10.3",
|
|
764
763
|
sha256: "9eafc3a8c693b8d9916867ef764d49e5222da717fde501c957bb3f6c312d2415"
|
|
765
764
|
},
|
|
766
765
|
{
|
|
767
766
|
name: "using-git-worktrees",
|
|
768
767
|
file: "assets/skills/using-git-worktrees/SKILL.md",
|
|
769
768
|
description: "Skill de uso de git worktrees para aislamiento de trabajo",
|
|
770
|
-
version: "0.10.
|
|
769
|
+
version: "0.10.3",
|
|
771
770
|
sha256: "93341bc1b7c053618a8b6dc07e3615b77990d7b549a0201f5835d95fef67ce13"
|
|
772
771
|
},
|
|
773
772
|
{
|
|
774
773
|
name: "using-superpowers",
|
|
775
774
|
file: "assets/skills/using-superpowers/SKILL.md",
|
|
776
775
|
description: "Skill de orquestación de Superpowers skills",
|
|
777
|
-
version: "0.10.
|
|
776
|
+
version: "0.10.3",
|
|
778
777
|
sha256: "7e54536f96d2a379185a10bfc1e970850caa2561b6d8aca7080f0defea0381a4"
|
|
779
778
|
},
|
|
780
779
|
{
|
|
781
780
|
name: "writing-skills",
|
|
782
781
|
file: "assets/skills/writing-skills/SKILL.md",
|
|
783
782
|
description: "Skill de creación y edición de skills",
|
|
784
|
-
version: "0.10.
|
|
783
|
+
version: "0.10.3",
|
|
785
784
|
sha256: "3d76b906cee518a2b809febb70db95697a35b9f368986bb504b4120c3bfb437a"
|
|
786
785
|
},
|
|
787
786
|
{
|
|
788
787
|
name: "graceful-degradation",
|
|
789
788
|
file: "assets/skills/graceful-degradation/SKILL.md",
|
|
790
789
|
description: "Skill de degradación graceful cuando múltiples tools están indisponibles",
|
|
791
|
-
version: "0.10.
|
|
790
|
+
version: "0.10.3",
|
|
792
791
|
sha256: "363449bd9e6f800a0a3168667cf78f767fb105d86e4a4adadcc649d418139303"
|
|
793
792
|
}
|
|
794
793
|
]
|
|
@@ -840,9 +839,11 @@ function getBundledMcpPath(name) {
|
|
|
840
839
|
validateFilePath(name);
|
|
841
840
|
return join3(BUNDLED_MCP_DIR, name);
|
|
842
841
|
}
|
|
843
|
-
function getBundledExpectedHash(category, name) {
|
|
842
|
+
function getBundledExpectedHash(category, name, field = "sha256") {
|
|
844
843
|
const items = manifest_default[category] ?? [];
|
|
845
|
-
|
|
844
|
+
const found = items.find((item) => item.name === name);
|
|
845
|
+
const value = found?.[field];
|
|
846
|
+
return typeof value === "string" ? value : null;
|
|
846
847
|
}
|
|
847
848
|
function getRawUrl(repo, tag, path) {
|
|
848
849
|
return `${GITHUB_RAW}/${repo}/${tag}/${path}`;
|
|
@@ -1579,8 +1580,60 @@ var init_stack = __esm(() => {
|
|
|
1579
1580
|
// src/doctor-v2.ts
|
|
1580
1581
|
import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync3 } from "fs";
|
|
1581
1582
|
import { join as join10, delimiter, isAbsolute } from "path";
|
|
1583
|
+
function globalOstackyArtifacts(globalDir = getGlobalOpenCodeDir()) {
|
|
1584
|
+
const found = [];
|
|
1585
|
+
const candidates = [
|
|
1586
|
+
join10(globalDir, "agent", "ostacky.md"),
|
|
1587
|
+
join10(globalDir, "plugins", "ostacky-controller", "index.ts"),
|
|
1588
|
+
join10(globalDir, "plugin", "ostacky-controller", "index.ts"),
|
|
1589
|
+
join10(globalDir, "command", "ostacky.md")
|
|
1590
|
+
];
|
|
1591
|
+
for (const p of candidates) {
|
|
1592
|
+
try {
|
|
1593
|
+
if (existsSync8(p))
|
|
1594
|
+
found.push(p);
|
|
1595
|
+
} catch {}
|
|
1596
|
+
}
|
|
1597
|
+
for (const cfgName of ["opencode.json", "opencode.jsonc"]) {
|
|
1598
|
+
const cfg = join10(globalDir, cfgName);
|
|
1599
|
+
try {
|
|
1600
|
+
if (!existsSync8(cfg))
|
|
1601
|
+
continue;
|
|
1602
|
+
const raw = readFileSync6(cfg, "utf-8");
|
|
1603
|
+
const json = JSON.parse(raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, ""));
|
|
1604
|
+
const servers = json?.mcp?.servers ?? json?.mcp ?? {};
|
|
1605
|
+
if (servers && servers["ostacky-controller"])
|
|
1606
|
+
found.push(cfg);
|
|
1607
|
+
} catch {}
|
|
1608
|
+
}
|
|
1609
|
+
return found;
|
|
1610
|
+
}
|
|
1611
|
+
function globalPluginScopeAware(globalDir = getGlobalOpenCodeDir()) {
|
|
1612
|
+
const candidates = [
|
|
1613
|
+
join10(globalDir, "plugins", "ostacky-controller", "index.ts"),
|
|
1614
|
+
join10(globalDir, "plugin", "ostacky-controller", "index.ts"),
|
|
1615
|
+
join10(globalDir, "plugins", "ostacky-controller", "index.js"),
|
|
1616
|
+
join10(globalDir, "plugin", "ostacky-controller", "index.js")
|
|
1617
|
+
];
|
|
1618
|
+
for (const p of candidates) {
|
|
1619
|
+
try {
|
|
1620
|
+
if (!existsSync8(p))
|
|
1621
|
+
continue;
|
|
1622
|
+
return readFileSync6(p, "utf-8").includes("ostacky-controller-global");
|
|
1623
|
+
} catch {}
|
|
1624
|
+
}
|
|
1625
|
+
return null;
|
|
1626
|
+
}
|
|
1582
1627
|
function checkDoctorV2(projectRoot) {
|
|
1583
1628
|
const lines = [];
|
|
1629
|
+
const globalArtifacts = globalOstackyArtifacts();
|
|
1630
|
+
if (globalArtifacts.length > 0) {
|
|
1631
|
+
if (globalPluginScopeAware() === false) {
|
|
1632
|
+
lines.push(`⚠️ plugin global legacy (id compartido): OpenCode V2 conserva la copia global y deshabilita la local ("Duplicate plugin ID: ostacky-controller") — los gates los aplica el plugin global, no el local. Actualizá el global (npx ostacky install --scope global) o limpiá con: npx ostacky uninstall --scope global`);
|
|
1633
|
+
} else {
|
|
1634
|
+
lines.push(`⚠️ Instalación global convive con la local: ${globalArtifacts.join(", ")}. El plugin global cede la precedencia al local (ids distintos, sin colisión); el resto de los artefactos globales queda como residuo si no los usás. Limpiá con: npx ostacky uninstall --scope global`);
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1584
1637
|
const cwd = projectRoot;
|
|
1585
1638
|
const opencodeDir = findOpenCodeDir(cwd) || join10(cwd, ".opencode");
|
|
1586
1639
|
const pluginPaths = [
|
|
@@ -1738,7 +1791,7 @@ var init_doctor_v2 = __esm(() => {
|
|
|
1738
1791
|
// package.json
|
|
1739
1792
|
var package_default = {
|
|
1740
1793
|
name: "ostacky",
|
|
1741
|
-
version: "0.10.
|
|
1794
|
+
version: "0.10.3",
|
|
1742
1795
|
description: "Instalador interactivo de agentes y comandos para OpenCode",
|
|
1743
1796
|
type: "module",
|
|
1744
1797
|
bin: {
|
|
@@ -1747,15 +1800,17 @@ var package_default = {
|
|
|
1747
1800
|
scripts: {
|
|
1748
1801
|
prebuild: "bun run scripts/sync-version.ts && bun run scripts/sync-controller-core.ts",
|
|
1749
1802
|
dev: "bun run src/cli.ts",
|
|
1750
|
-
build: "bun build
|
|
1803
|
+
build: "bun run build:cli && bun run build:mcp",
|
|
1804
|
+
"build:cli": "bun build src/cli.ts --target=node --format=esm --outfile dist/cli.js && bun scripts/add-shebang.ts",
|
|
1805
|
+
"build:mcp": "bun run scripts/build-mcp-bundles.ts",
|
|
1751
1806
|
start: "node dist/cli.js",
|
|
1752
1807
|
test: "bun test --isolate",
|
|
1753
1808
|
"test:safe": "bun run scripts/run-tests-isolated.ts",
|
|
1754
1809
|
"check:skills": "bun run scripts/check-skill-sync.ts",
|
|
1755
1810
|
"hash:check": "bun run scripts/update-manifest-hashes.ts --check",
|
|
1756
|
-
"hash:update": "bun run scripts/update-manifest-hashes.ts",
|
|
1757
|
-
prepublishOnly: "bun run build",
|
|
1758
|
-
update: "bun run scripts/check-skill-sync.ts && bun run scripts/sync-controller-core.ts && bun run
|
|
1811
|
+
"hash:update": "bun run build:mcp && bun run scripts/update-manifest-hashes.ts",
|
|
1812
|
+
prepublishOnly: "bun run build && bun run hash:update",
|
|
1813
|
+
update: "bun run scripts/check-skill-sync.ts && bun run scripts/sync-controller-core.ts && bun run hash:update"
|
|
1759
1814
|
},
|
|
1760
1815
|
files: [
|
|
1761
1816
|
"dist/",
|
|
@@ -2918,7 +2973,7 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath, option
|
|
|
2918
2973
|
params: {
|
|
2919
2974
|
protocolVersion: "2025-03-26",
|
|
2920
2975
|
capabilities: {},
|
|
2921
|
-
clientInfo: { name: "ostacky-installer", version: "0.10.
|
|
2976
|
+
clientInfo: { name: "ostacky-installer", version: "0.10.3" }
|
|
2922
2977
|
}
|
|
2923
2978
|
});
|
|
2924
2979
|
});
|
|
@@ -2991,8 +3046,8 @@ function upsertLockfile(paths, type, item, manifest, contentHash) {
|
|
|
2991
3046
|
existing.lockedAt = new Date().toISOString();
|
|
2992
3047
|
writeLockfile(paths.root, existing);
|
|
2993
3048
|
}
|
|
2994
|
-
function assertBundledTreeHash(category, name, actualHash) {
|
|
2995
|
-
const expected = getBundledExpectedHash(category, name);
|
|
3049
|
+
function assertBundledTreeHash(category, name, actualHash, field = "sha256") {
|
|
3050
|
+
const expected = getBundledExpectedHash(category, name, field);
|
|
2996
3051
|
if (expected && actualHash !== expected) {
|
|
2997
3052
|
const labels = {
|
|
2998
3053
|
skills: "skill",
|
|
@@ -3000,7 +3055,7 @@ function assertBundledTreeHash(category, name, actualHash) {
|
|
|
3000
3055
|
agents: "agente",
|
|
3001
3056
|
commands: "command"
|
|
3002
3057
|
};
|
|
3003
|
-
throw new Error(`
|
|
3058
|
+
throw new Error(`Hash inválido para ${labels[category] ?? category} "${name}" (${field})
|
|
3004
3059
|
esperado: ${expected}
|
|
3005
3060
|
recibido: ${actualHash}`);
|
|
3006
3061
|
}
|
|
@@ -3011,6 +3066,13 @@ function readBundledAsset(relativePath) {
|
|
|
3011
3066
|
return null;
|
|
3012
3067
|
return readFileSync5(fullPath, "utf-8");
|
|
3013
3068
|
}
|
|
3069
|
+
function mcpArtifactHash(name, packageRoot = PACKAGE_ROOT) {
|
|
3070
|
+
const bundlePath = join6(packageRoot, "dist", "mcp", name, "index.js");
|
|
3071
|
+
if (existsSync5(bundlePath)) {
|
|
3072
|
+
return { field: "sha256", actual: sha256(readFileSync5(bundlePath, "utf-8")) };
|
|
3073
|
+
}
|
|
3074
|
+
return { field: "sourceSha256", actual: computeTreeHash(join6(packageRoot, "assets", "mcp", name)) };
|
|
3075
|
+
}
|
|
3014
3076
|
async function installAgent(item, manifest, paths) {
|
|
3015
3077
|
let content;
|
|
3016
3078
|
try {
|
|
@@ -3081,8 +3143,10 @@ async function installMcpServer(item, manifest, paths) {
|
|
|
3081
3143
|
if (!existsSync5(src)) {
|
|
3082
3144
|
throw new Error(`MCP server bundleado no encontrado: ${src}. ` + `¿Falta el directorio assets/mcp/${item.name}/?`);
|
|
3083
3145
|
}
|
|
3084
|
-
const
|
|
3085
|
-
|
|
3146
|
+
const bundlePath = join6(PACKAGE_ROOT, "dist", "mcp", item.name, "index.js");
|
|
3147
|
+
const hasBundle = existsSync5(bundlePath);
|
|
3148
|
+
const { field, actual: artifactHash } = mcpArtifactHash(item.name);
|
|
3149
|
+
assertBundledTreeHash("mcpServers", item.name, artifactHash, field);
|
|
3086
3150
|
const nodeExecutable = getVerifiedNodeExecutable();
|
|
3087
3151
|
await Promise.resolve().then(() => init_fs());
|
|
3088
3152
|
const projectRoot = paths.root === getGlobalOpenCodeDir() ? paths.root : dirname4(paths.root);
|
|
@@ -3091,9 +3155,8 @@ async function installMcpServer(item, manifest, paths) {
|
|
|
3091
3155
|
const statePath = item.name === "ostacky-controller" ? join6(paths.root, "ostacky-state.json") : undefined;
|
|
3092
3156
|
try {
|
|
3093
3157
|
mkdirSync3(staging, { recursive: true });
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
copyFileSync2(bundledPath, join6(staging, "index.js"));
|
|
3158
|
+
if (hasBundle) {
|
|
3159
|
+
copyFileSync2(bundlePath, join6(staging, "index.js"));
|
|
3097
3160
|
writeFileSync5(join6(staging, "package.json"), JSON.stringify({ type: "module" }) + `
|
|
3098
3161
|
`, "utf-8");
|
|
3099
3162
|
} else {
|
|
@@ -3129,7 +3192,7 @@ async function installMcpServer(item, manifest, paths) {
|
|
|
3129
3192
|
const promotion = promoteStagedDirectory(staging, dest);
|
|
3130
3193
|
try {
|
|
3131
3194
|
setMcpEntryAtProjectRoot(projectRoot, item.name, createMcpConfigEntry(item.name, nodeExecutable, join6(dest, "index.js"), statePath));
|
|
3132
|
-
upsertLockfile(paths, "mcpServers", item, manifest,
|
|
3195
|
+
upsertLockfile(paths, "mcpServers", item, manifest, artifactHash);
|
|
3133
3196
|
promotion.commit();
|
|
3134
3197
|
} catch (error) {
|
|
3135
3198
|
try {
|
|
@@ -4616,6 +4679,7 @@ import { existsSync as existsSync9, statSync as statSync3, readFileSync as readF
|
|
|
4616
4679
|
import { join as join11, dirname as dirname8 } from "node:path";
|
|
4617
4680
|
import { spawnSync } from "node:child_process";
|
|
4618
4681
|
init_fs();
|
|
4682
|
+
init_github();
|
|
4619
4683
|
|
|
4620
4684
|
// src/version-check.ts
|
|
4621
4685
|
function parseMajor(version) {
|
|
@@ -4903,16 +4967,18 @@ async function runDoctorCommand() {
|
|
|
4903
4967
|
check(`tool ${t}: ${existsSync9(p) || existsSync9(pExe) ? "found" : "missing"}`, existsSync9(p) || existsSync9(pExe), true);
|
|
4904
4968
|
}
|
|
4905
4969
|
try {
|
|
4906
|
-
const
|
|
4907
|
-
const
|
|
4970
|
+
const name = "ostacky-controller";
|
|
4971
|
+
const { field, actual } = mcpArtifactHash(name);
|
|
4972
|
+
const expected = getBundledExpectedHash("mcpServers", name, field);
|
|
4908
4973
|
if (expected) {
|
|
4909
|
-
|
|
4910
|
-
check(`manifest hash: ${expected.slice(0, 8)} vs actual ${actual.slice(0, 8)}`, expected === actual);
|
|
4974
|
+
check(`manifest ${field}: ${expected.slice(0, 8)} vs actual ${actual.slice(0, 8)}`, expected === actual);
|
|
4911
4975
|
if (expected !== actual)
|
|
4912
4976
|
console.log(" Run: bun run hash:update");
|
|
4977
|
+
} else {
|
|
4978
|
+
check(`manifest ${field}: sin entrada para ${name}`, false, true);
|
|
4913
4979
|
}
|
|
4914
4980
|
} catch {
|
|
4915
|
-
check("manifest:
|
|
4981
|
+
check("manifest: no se pudo verificar", false, true);
|
|
4916
4982
|
}
|
|
4917
4983
|
try {
|
|
4918
4984
|
await Promise.resolve().then(() => init_doctor_v2());
|
|
@@ -5103,9 +5169,15 @@ async function main() {
|
|
|
5103
5169
|
await ensureOpencodeInstalled();
|
|
5104
5170
|
}
|
|
5105
5171
|
switch (cmd) {
|
|
5106
|
-
case "install":
|
|
5172
|
+
case "install": {
|
|
5173
|
+
await Promise.resolve().then(() => init_doctor_v2());
|
|
5174
|
+
const globalArtifacts = globalOstackyArtifacts();
|
|
5175
|
+
if (scope !== "global" && globalArtifacts.length > 0) {
|
|
5176
|
+
console.error(`Aviso: hay artefactos de Ostacky en la instalación global (${globalArtifacts.join(", ")}). ` + `Podés limpiarlos con: npx ostacky uninstall --scope global`);
|
|
5177
|
+
}
|
|
5107
5178
|
await runInstallCommand(scope, { noStack });
|
|
5108
5179
|
break;
|
|
5180
|
+
}
|
|
5109
5181
|
case "install-stack":
|
|
5110
5182
|
if (scope === "global") {
|
|
5111
5183
|
console.error(`Aviso: el stack (CodeGraph/Engram) se instala siempre local por proyecto. Ignorando --scope global y usando local.`);
|