ostacky 0.10.1 → 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 +14 -5
- package/assets/commands/install-stack.md +1 -1
- package/assets/docs/ostacky-reference.md +16 -0
- package/assets/mcp/ostacky-controller/index.js +225 -37
- package/assets/plugins/engram.ts +13 -9
- package/assets/plugins/ostacky-controller/index.ts +300 -48
- package/dist/cli.js +143 -67
- 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 +8 -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}`;
|
|
@@ -1337,13 +1338,16 @@ async function installCodeGraph(toolsDir) {
|
|
|
1337
1338
|
message: indexWarning ? `CodeGraph instalado y configurado para OpenCode. ${indexWarning}` : "CodeGraph instalado localmente y configurado para OpenCode"
|
|
1338
1339
|
};
|
|
1339
1340
|
}
|
|
1340
|
-
function setupOpenSpec(projectRoot = findProjectRoot()) {
|
|
1341
|
-
const
|
|
1341
|
+
function setupOpenSpec(projectRoot = findProjectRoot(), deps = {}) {
|
|
1342
|
+
const execFile = deps.execFileSync ?? execFileSync3;
|
|
1343
|
+
const isAvailable = deps.isCommandAvailable ?? isCommandAvailable;
|
|
1344
|
+
const invocationFor = deps.getCommandInvocation ?? getCommandInvocation;
|
|
1345
|
+
const useBun = isAvailable("bun");
|
|
1342
1346
|
const fail = (msg) => ({ success: false, message: msg });
|
|
1343
1347
|
const tryDirect = () => {
|
|
1344
1348
|
try {
|
|
1345
|
-
const invocation =
|
|
1346
|
-
|
|
1349
|
+
const invocation = invocationFor(useBun ? "bunx" : "npx", useBun ? [OPENSPEC_NPM_PACKAGE, "init", "--tools", "opencode", "--force"] : ["--yes", OPENSPEC_NPM_PACKAGE, "init", "--tools", "opencode", "--force"]);
|
|
1350
|
+
execFile(invocation.command, invocation.args, {
|
|
1347
1351
|
stdio: "pipe",
|
|
1348
1352
|
timeout: 120000,
|
|
1349
1353
|
cwd: projectRoot
|
|
@@ -1354,20 +1358,20 @@ function setupOpenSpec(projectRoot = findProjectRoot()) {
|
|
|
1354
1358
|
}
|
|
1355
1359
|
};
|
|
1356
1360
|
const tryInstallGlobal = () => {
|
|
1357
|
-
if (!useBun && !
|
|
1361
|
+
if (!useBun && !isAvailable("npm")) {
|
|
1358
1362
|
return { ok: false, error: "Ni bun ni npm están disponibles para instalar OpenSpec globalmente" };
|
|
1359
1363
|
}
|
|
1360
1364
|
const pkgManager = useBun ? "bun" : "npm";
|
|
1361
1365
|
const installArgs = useBun ? ["add", "-g", OPENSPEC_NPM_PACKAGE] : ["install", "-g", OPENSPEC_NPM_PACKAGE];
|
|
1362
1366
|
try {
|
|
1363
|
-
const invocation =
|
|
1364
|
-
|
|
1367
|
+
const invocation = invocationFor(pkgManager, installArgs);
|
|
1368
|
+
execFile(invocation.command, invocation.args, { stdio: "pipe", timeout: 120000 });
|
|
1365
1369
|
} catch (installErr) {
|
|
1366
1370
|
return { ok: false, error: `Instalación global falló: ${installErr.message}` };
|
|
1367
1371
|
}
|
|
1368
1372
|
try {
|
|
1369
|
-
const retryInvocation =
|
|
1370
|
-
|
|
1373
|
+
const retryInvocation = invocationFor("openspec", ["init", "--tools", "opencode", "--force"]);
|
|
1374
|
+
execFile(retryInvocation.command, retryInvocation.args, {
|
|
1371
1375
|
stdio: "pipe",
|
|
1372
1376
|
timeout: 120000,
|
|
1373
1377
|
cwd: projectRoot
|
|
@@ -1576,8 +1580,60 @@ var init_stack = __esm(() => {
|
|
|
1576
1580
|
// src/doctor-v2.ts
|
|
1577
1581
|
import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync3 } from "fs";
|
|
1578
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
|
+
}
|
|
1579
1627
|
function checkDoctorV2(projectRoot) {
|
|
1580
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
|
+
}
|
|
1581
1637
|
const cwd = projectRoot;
|
|
1582
1638
|
const opencodeDir = findOpenCodeDir(cwd) || join10(cwd, ".opencode");
|
|
1583
1639
|
const pluginPaths = [
|
|
@@ -1735,7 +1791,7 @@ var init_doctor_v2 = __esm(() => {
|
|
|
1735
1791
|
// package.json
|
|
1736
1792
|
var package_default = {
|
|
1737
1793
|
name: "ostacky",
|
|
1738
|
-
version: "0.10.
|
|
1794
|
+
version: "0.10.3",
|
|
1739
1795
|
description: "Instalador interactivo de agentes y comandos para OpenCode",
|
|
1740
1796
|
type: "module",
|
|
1741
1797
|
bin: {
|
|
@@ -1744,15 +1800,17 @@ var package_default = {
|
|
|
1744
1800
|
scripts: {
|
|
1745
1801
|
prebuild: "bun run scripts/sync-version.ts && bun run scripts/sync-controller-core.ts",
|
|
1746
1802
|
dev: "bun run src/cli.ts",
|
|
1747
|
-
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",
|
|
1748
1806
|
start: "node dist/cli.js",
|
|
1749
1807
|
test: "bun test --isolate",
|
|
1750
1808
|
"test:safe": "bun run scripts/run-tests-isolated.ts",
|
|
1751
1809
|
"check:skills": "bun run scripts/check-skill-sync.ts",
|
|
1752
1810
|
"hash:check": "bun run scripts/update-manifest-hashes.ts --check",
|
|
1753
|
-
"hash:update": "bun run scripts/update-manifest-hashes.ts",
|
|
1754
|
-
prepublishOnly: "bun run build",
|
|
1755
|
-
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"
|
|
1756
1814
|
},
|
|
1757
1815
|
files: [
|
|
1758
1816
|
"dist/",
|
|
@@ -1772,6 +1830,7 @@ var package_default = {
|
|
|
1772
1830
|
},
|
|
1773
1831
|
devDependencies: {
|
|
1774
1832
|
"@types/bun": "latest",
|
|
1833
|
+
openspec: "^0.0.0",
|
|
1775
1834
|
typescript: "^5.0.0"
|
|
1776
1835
|
},
|
|
1777
1836
|
publishConfig: {
|
|
@@ -2914,7 +2973,7 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath, option
|
|
|
2914
2973
|
params: {
|
|
2915
2974
|
protocolVersion: "2025-03-26",
|
|
2916
2975
|
capabilities: {},
|
|
2917
|
-
clientInfo: { name: "ostacky-installer", version: "0.10.
|
|
2976
|
+
clientInfo: { name: "ostacky-installer", version: "0.10.3" }
|
|
2918
2977
|
}
|
|
2919
2978
|
});
|
|
2920
2979
|
});
|
|
@@ -2987,8 +3046,8 @@ function upsertLockfile(paths, type, item, manifest, contentHash) {
|
|
|
2987
3046
|
existing.lockedAt = new Date().toISOString();
|
|
2988
3047
|
writeLockfile(paths.root, existing);
|
|
2989
3048
|
}
|
|
2990
|
-
function assertBundledTreeHash(category, name, actualHash) {
|
|
2991
|
-
const expected = getBundledExpectedHash(category, name);
|
|
3049
|
+
function assertBundledTreeHash(category, name, actualHash, field = "sha256") {
|
|
3050
|
+
const expected = getBundledExpectedHash(category, name, field);
|
|
2992
3051
|
if (expected && actualHash !== expected) {
|
|
2993
3052
|
const labels = {
|
|
2994
3053
|
skills: "skill",
|
|
@@ -2996,7 +3055,7 @@ function assertBundledTreeHash(category, name, actualHash) {
|
|
|
2996
3055
|
agents: "agente",
|
|
2997
3056
|
commands: "command"
|
|
2998
3057
|
};
|
|
2999
|
-
throw new Error(`
|
|
3058
|
+
throw new Error(`Hash inválido para ${labels[category] ?? category} "${name}" (${field})
|
|
3000
3059
|
esperado: ${expected}
|
|
3001
3060
|
recibido: ${actualHash}`);
|
|
3002
3061
|
}
|
|
@@ -3007,6 +3066,13 @@ function readBundledAsset(relativePath) {
|
|
|
3007
3066
|
return null;
|
|
3008
3067
|
return readFileSync5(fullPath, "utf-8");
|
|
3009
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
|
+
}
|
|
3010
3076
|
async function installAgent(item, manifest, paths) {
|
|
3011
3077
|
let content;
|
|
3012
3078
|
try {
|
|
@@ -3077,8 +3143,10 @@ async function installMcpServer(item, manifest, paths) {
|
|
|
3077
3143
|
if (!existsSync5(src)) {
|
|
3078
3144
|
throw new Error(`MCP server bundleado no encontrado: ${src}. ` + `¿Falta el directorio assets/mcp/${item.name}/?`);
|
|
3079
3145
|
}
|
|
3080
|
-
const
|
|
3081
|
-
|
|
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);
|
|
3082
3150
|
const nodeExecutable = getVerifiedNodeExecutable();
|
|
3083
3151
|
await Promise.resolve().then(() => init_fs());
|
|
3084
3152
|
const projectRoot = paths.root === getGlobalOpenCodeDir() ? paths.root : dirname4(paths.root);
|
|
@@ -3087,9 +3155,8 @@ async function installMcpServer(item, manifest, paths) {
|
|
|
3087
3155
|
const statePath = item.name === "ostacky-controller" ? join6(paths.root, "ostacky-state.json") : undefined;
|
|
3088
3156
|
try {
|
|
3089
3157
|
mkdirSync3(staging, { recursive: true });
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
copyFileSync2(bundledPath, join6(staging, "index.js"));
|
|
3158
|
+
if (hasBundle) {
|
|
3159
|
+
copyFileSync2(bundlePath, join6(staging, "index.js"));
|
|
3093
3160
|
writeFileSync5(join6(staging, "package.json"), JSON.stringify({ type: "module" }) + `
|
|
3094
3161
|
`, "utf-8");
|
|
3095
3162
|
} else {
|
|
@@ -3125,7 +3192,7 @@ async function installMcpServer(item, manifest, paths) {
|
|
|
3125
3192
|
const promotion = promoteStagedDirectory(staging, dest);
|
|
3126
3193
|
try {
|
|
3127
3194
|
setMcpEntryAtProjectRoot(projectRoot, item.name, createMcpConfigEntry(item.name, nodeExecutable, join6(dest, "index.js"), statePath));
|
|
3128
|
-
upsertLockfile(paths, "mcpServers", item, manifest,
|
|
3195
|
+
upsertLockfile(paths, "mcpServers", item, manifest, artifactHash);
|
|
3129
3196
|
promotion.commit();
|
|
3130
3197
|
} catch (error) {
|
|
3131
3198
|
try {
|
|
@@ -4612,6 +4679,7 @@ import { existsSync as existsSync9, statSync as statSync3, readFileSync as readF
|
|
|
4612
4679
|
import { join as join11, dirname as dirname8 } from "node:path";
|
|
4613
4680
|
import { spawnSync } from "node:child_process";
|
|
4614
4681
|
init_fs();
|
|
4682
|
+
init_github();
|
|
4615
4683
|
|
|
4616
4684
|
// src/version-check.ts
|
|
4617
4685
|
function parseMajor(version) {
|
|
@@ -4899,16 +4967,18 @@ async function runDoctorCommand() {
|
|
|
4899
4967
|
check(`tool ${t}: ${existsSync9(p) || existsSync9(pExe) ? "found" : "missing"}`, existsSync9(p) || existsSync9(pExe), true);
|
|
4900
4968
|
}
|
|
4901
4969
|
try {
|
|
4902
|
-
const
|
|
4903
|
-
const
|
|
4970
|
+
const name = "ostacky-controller";
|
|
4971
|
+
const { field, actual } = mcpArtifactHash(name);
|
|
4972
|
+
const expected = getBundledExpectedHash("mcpServers", name, field);
|
|
4904
4973
|
if (expected) {
|
|
4905
|
-
|
|
4906
|
-
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);
|
|
4907
4975
|
if (expected !== actual)
|
|
4908
4976
|
console.log(" Run: bun run hash:update");
|
|
4977
|
+
} else {
|
|
4978
|
+
check(`manifest ${field}: sin entrada para ${name}`, false, true);
|
|
4909
4979
|
}
|
|
4910
4980
|
} catch {
|
|
4911
|
-
check("manifest:
|
|
4981
|
+
check("manifest: no se pudo verificar", false, true);
|
|
4912
4982
|
}
|
|
4913
4983
|
try {
|
|
4914
4984
|
await Promise.resolve().then(() => init_doctor_v2());
|
|
@@ -5099,9 +5169,15 @@ async function main() {
|
|
|
5099
5169
|
await ensureOpencodeInstalled();
|
|
5100
5170
|
}
|
|
5101
5171
|
switch (cmd) {
|
|
5102
|
-
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
|
+
}
|
|
5103
5178
|
await runInstallCommand(scope, { noStack });
|
|
5104
5179
|
break;
|
|
5180
|
+
}
|
|
5105
5181
|
case "install-stack":
|
|
5106
5182
|
if (scope === "global") {
|
|
5107
5183
|
console.error(`Aviso: el stack (CodeGraph/Engram) se instala siempre local por proyecto. Ignorando --scope global y usando local.`);
|