ostacky 0.7.4 → 0.8.0
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 +17 -19
- package/assets/agents/ostacky.md +45 -512
- package/assets/commands/install-stack.md +2 -2
- package/assets/docs/engram-protocol.md +79 -0
- package/assets/docs/ostacky-reference.md +79 -0
- package/assets/mcp/ostacky-controller/index.js +169 -69
- package/assets/mcp/ostacky-controller/package.json +1 -1
- package/assets/plugins/engram.ts +47 -79
- package/assets/plugins/ostacky-guard.ts +11 -205
- package/assets/plugins/ostacky-plugin.ts +646 -0
- package/assets/skills/brainstorming/SKILL.md +14 -14
- package/assets/skills/execution-mode-evaluation/SKILL.md +9 -9
- package/dist/cli.js +233 -83
- package/manifest.json +30 -30
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -293,6 +293,36 @@ var init_security = __esm(() => {
|
|
|
293
293
|
});
|
|
294
294
|
|
|
295
295
|
// src/fs.ts
|
|
296
|
+
var exports_fs = {};
|
|
297
|
+
__export(exports_fs, {
|
|
298
|
+
USER_AGENT: () => USER_AGENT,
|
|
299
|
+
checkBunAvailability: () => checkBunAvailability,
|
|
300
|
+
computeTreeHash: () => computeTreeHash,
|
|
301
|
+
copyDirRecursive: () => copyDirRecursive,
|
|
302
|
+
createOpenCodeDir: () => createOpenCodeDir,
|
|
303
|
+
detectPlatformTarget: () => detectPlatformTarget,
|
|
304
|
+
downloadAndExtract: () => downloadAndExtract,
|
|
305
|
+
downloadAndExtractWithRetry: () => downloadAndExtractWithRetry,
|
|
306
|
+
downloadToFile: () => downloadToFile,
|
|
307
|
+
downloadWithRetry: () => downloadWithRetry,
|
|
308
|
+
ensureOpenCodePaths: () => ensureOpenCodePaths,
|
|
309
|
+
ensureToolDirs: () => ensureToolDirs,
|
|
310
|
+
findBinaryInDir: () => findBinaryInDir,
|
|
311
|
+
findExecutablePath: () => findExecutablePath,
|
|
312
|
+
findOpenCodeDir: () => findOpenCodeDir,
|
|
313
|
+
findProjectRoot: () => findProjectRoot,
|
|
314
|
+
getBunInstallCommand: () => getBunInstallCommand,
|
|
315
|
+
getCommandInvocation: () => getCommandInvocation,
|
|
316
|
+
getEngramReleaseTarget: () => getEngramReleaseTarget,
|
|
317
|
+
getExecutableName: () => getExecutableName,
|
|
318
|
+
getExecutableNames: () => getExecutableNames,
|
|
319
|
+
getGlobalOpenCodeDir: () => getGlobalOpenCodeDir,
|
|
320
|
+
getOpenCodeDirForScope: () => getOpenCodeDirForScope,
|
|
321
|
+
isCommandAvailable: () => isCommandAvailable,
|
|
322
|
+
parseScopeArg: () => parseScopeArg,
|
|
323
|
+
promoteStagedDirectory: () => promoteStagedDirectory,
|
|
324
|
+
shouldRetryDownload: () => shouldRetryDownload
|
|
325
|
+
});
|
|
296
326
|
import {
|
|
297
327
|
existsSync,
|
|
298
328
|
mkdirSync,
|
|
@@ -366,6 +396,22 @@ function getOpenCodeDirForScope(scope, cwd = process.cwd()) {
|
|
|
366
396
|
}
|
|
367
397
|
return getGlobalOpenCodeDir();
|
|
368
398
|
}
|
|
399
|
+
function parseScopeArg(argv = process.argv) {
|
|
400
|
+
for (let i = 0;i < argv.length; i++) {
|
|
401
|
+
const arg = argv[i];
|
|
402
|
+
if (arg === "--scope" && i + 1 < argv.length) {
|
|
403
|
+
const v3 = argv[i + 1];
|
|
404
|
+
if (v3 === "local" || v3 === "global" || v3 === "auto")
|
|
405
|
+
return v3;
|
|
406
|
+
}
|
|
407
|
+
if (arg.startsWith("--scope=")) {
|
|
408
|
+
const v3 = arg.split("=")[1];
|
|
409
|
+
if (v3 === "local" || v3 === "global" || v3 === "auto")
|
|
410
|
+
return v3;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
369
415
|
function ensureOpenCodePaths(opencodeDir) {
|
|
370
416
|
const paths = {
|
|
371
417
|
root: opencodeDir,
|
|
@@ -389,6 +435,9 @@ function ensureToolDirs(toolsDir, toolNames) {
|
|
|
389
435
|
mkdirSync(dir, { recursive: true });
|
|
390
436
|
}
|
|
391
437
|
}
|
|
438
|
+
function createOpenCodeDir(baseDir) {
|
|
439
|
+
return ensureOpenCodePaths(join(baseDir, ".opencode"));
|
|
440
|
+
}
|
|
392
441
|
function copyDirRecursive(src, dest, skipGenerated = false) {
|
|
393
442
|
if (!existsSync(dest))
|
|
394
443
|
mkdirSync(dest, { recursive: true });
|
|
@@ -449,6 +498,44 @@ function findExecutablePath(cmd) {
|
|
|
449
498
|
return null;
|
|
450
499
|
}
|
|
451
500
|
}
|
|
501
|
+
function getBunInstallCommand() {
|
|
502
|
+
const platform = process.platform;
|
|
503
|
+
if (platform === "darwin" || platform === "linux") {
|
|
504
|
+
return {
|
|
505
|
+
command: "curl -fsSL https://bun.com/install | bash",
|
|
506
|
+
note: platform === "linux" ? "Requires 'unzip' package (sudo apt install unzip)" : undefined
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
if (platform === "win32") {
|
|
510
|
+
return {
|
|
511
|
+
command: 'powershell -c "irm bun.sh/install.ps1|iex"',
|
|
512
|
+
note: "Requires Windows 10 v1809 or later"
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
return {
|
|
516
|
+
command: "npm install -g bun",
|
|
517
|
+
note: "Cross-platform fallback"
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
function checkBunAvailability() {
|
|
521
|
+
const bunPath = findExecutablePath("bun");
|
|
522
|
+
if (bunPath) {
|
|
523
|
+
let version;
|
|
524
|
+
try {
|
|
525
|
+
version = execFileSync(bunPath, ["--version"], {
|
|
526
|
+
encoding: "utf-8",
|
|
527
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
528
|
+
}).trim();
|
|
529
|
+
} catch {}
|
|
530
|
+
return { available: true, path: bunPath, version };
|
|
531
|
+
}
|
|
532
|
+
const { command, note } = getBunInstallCommand();
|
|
533
|
+
return {
|
|
534
|
+
available: false,
|
|
535
|
+
installCommand: command,
|
|
536
|
+
installNote: note
|
|
537
|
+
};
|
|
538
|
+
}
|
|
452
539
|
function detectPlatformTarget(platform = process.platform, arch = process.arch) {
|
|
453
540
|
let os;
|
|
454
541
|
let cpu;
|
|
@@ -570,6 +657,23 @@ function downloadToFile(url, dest, timeoutMs = 180000) {
|
|
|
570
657
|
});
|
|
571
658
|
});
|
|
572
659
|
}
|
|
660
|
+
async function downloadWithRetry(url, dest, maxRetries = 2, timeoutMs = 180000) {
|
|
661
|
+
let lastError = null;
|
|
662
|
+
for (let attempt = 0;attempt <= maxRetries; attempt++) {
|
|
663
|
+
try {
|
|
664
|
+
await downloadToFile(url, dest, timeoutMs);
|
|
665
|
+
return;
|
|
666
|
+
} catch (err) {
|
|
667
|
+
lastError = err;
|
|
668
|
+
if (attempt < maxRetries && shouldRetryDownload(lastError)) {
|
|
669
|
+
const delay = 1000 * Math.pow(2, attempt);
|
|
670
|
+
console.error(`[download] Intento ${attempt + 1} falló: ${lastError.message}. Reintentando en ${delay}ms...`);
|
|
671
|
+
await new Promise((r2) => setTimeout(r2, delay));
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
throw lastError;
|
|
676
|
+
}
|
|
573
677
|
async function downloadAndExtract(url, destDir, stripComponents = 1, timeoutMs = 180000) {
|
|
574
678
|
const tmp = join(dirname(destDir), `.${basename(destDir)}.download-${Date.now()}-${process.pid}`);
|
|
575
679
|
if (!existsSync(tmp))
|
|
@@ -640,31 +744,31 @@ var init_fs = __esm(() => {
|
|
|
640
744
|
var manifest_default;
|
|
641
745
|
var init_manifest = __esm(() => {
|
|
642
746
|
manifest_default = {
|
|
643
|
-
version: "0.
|
|
747
|
+
version: "0.8.0",
|
|
644
748
|
repo: "JaimeHoracio/Ostacky",
|
|
645
|
-
tag: "v0.
|
|
749
|
+
tag: "v0.8.0",
|
|
646
750
|
agents: [
|
|
647
751
|
{
|
|
648
752
|
name: "ostacky",
|
|
649
753
|
file: "assets/agents/ostacky.md",
|
|
650
|
-
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.
|
|
651
|
-
version: "0.
|
|
652
|
-
sha256: "
|
|
754
|
+
description: "Orquestador con recuperación automática (nunca se congela), ruteo por nivel de impacto, controller MCP con SDK oficial, edición segura con fallback inline, y delegación en OpenSpec + Superpowers. v0.8.0: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
|
|
755
|
+
version: "0.8.0",
|
|
756
|
+
sha256: "d9f94bb05a33a98d6ff0ea0b56c8eb6c3c8d456d1de1ccaac3f76ee2150b3c7b"
|
|
653
757
|
}
|
|
654
758
|
],
|
|
655
759
|
commands: [
|
|
656
760
|
{
|
|
657
761
|
name: "install-stack",
|
|
658
762
|
file: "assets/commands/install-stack.md",
|
|
659
|
-
description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram,
|
|
660
|
-
version: "0.
|
|
661
|
-
sha256: "
|
|
763
|
+
description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.8.0: controller plugin como alma hard-gate, Context7 removido del stack.",
|
|
764
|
+
version: "0.8.0",
|
|
765
|
+
sha256: "1a8acef8dd59d80aa54fa0febb4bd86a31ed615dea5257ea7fa8ed4fd51836a5"
|
|
662
766
|
},
|
|
663
767
|
{
|
|
664
768
|
name: "opsx-sync",
|
|
665
769
|
file: "assets/commands/opsx-sync.md",
|
|
666
770
|
description: "Sincroniza delta specs del change activo sin inicializar CodeGraph si ya existe índice",
|
|
667
|
-
version: "0.
|
|
771
|
+
version: "0.8.0",
|
|
668
772
|
sha256: "fe0158478f2ca63b315037a85fc1632b77868532e319af6c7384285441767d64"
|
|
669
773
|
}
|
|
670
774
|
],
|
|
@@ -672,15 +776,15 @@ var init_manifest = __esm(() => {
|
|
|
672
776
|
{
|
|
673
777
|
name: "ostacky-controller",
|
|
674
778
|
file: "assets/mcp/ostacky-controller/",
|
|
675
|
-
description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.
|
|
676
|
-
version: "0.
|
|
677
|
-
sha256: "
|
|
779
|
+
description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.8.0: 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.",
|
|
780
|
+
version: "0.8.0",
|
|
781
|
+
sha256: "5c4787001143ad517714e9c44f85b20fac00ba4146631d68486a90b93aa58dcd"
|
|
678
782
|
},
|
|
679
783
|
{
|
|
680
784
|
name: "openspec",
|
|
681
785
|
file: "assets/mcp/openspec/",
|
|
682
786
|
description: "MCP server local para OpenSpec - proposal, apply, archive, sync de cambios",
|
|
683
|
-
version: "0.
|
|
787
|
+
version: "0.8.0",
|
|
684
788
|
sha256: "fa4be28bfc1e75db8f1a037e2580f04a60066c80e8e5934e90e1041020d04609"
|
|
685
789
|
}
|
|
686
790
|
],
|
|
@@ -689,105 +793,105 @@ var init_manifest = __esm(() => {
|
|
|
689
793
|
name: "brainstorming",
|
|
690
794
|
file: "assets/skills/brainstorming/SKILL.md",
|
|
691
795
|
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)",
|
|
692
|
-
version: "0.
|
|
693
|
-
sha256: "
|
|
796
|
+
version: "0.8.0",
|
|
797
|
+
sha256: "87f8d6ed28205f9272792d3865d8cd3232ab5e511a604d6d63d41e3a02a5f422"
|
|
694
798
|
},
|
|
695
799
|
{
|
|
696
800
|
name: "execution-mode-evaluation",
|
|
697
801
|
file: "assets/skills/execution-mode-evaluation/SKILL.md",
|
|
698
802
|
description: "Skill de análisis de modo de ejecución — output reconciliado con controller snapshot contract (recommendation field)",
|
|
699
|
-
version: "0.
|
|
700
|
-
sha256: "
|
|
803
|
+
version: "0.8.0",
|
|
804
|
+
sha256: "7b89dda29927c88f1eb13ffcea541a12423384c172f66c4f3d9b61efe0c7a163"
|
|
701
805
|
},
|
|
702
806
|
{
|
|
703
807
|
name: "tdd",
|
|
704
808
|
file: "assets/skills/tdd/SKILL.md",
|
|
705
809
|
description: "Skill de test-driven development (Superpowers)",
|
|
706
|
-
version: "0.
|
|
810
|
+
version: "0.8.0",
|
|
707
811
|
sha256: "aa412298980b7826165c211145c1b8e9135f68f36247bb3cb96d0a0eae274486"
|
|
708
812
|
},
|
|
709
813
|
{
|
|
710
814
|
name: "subagent-driven-development",
|
|
711
815
|
file: "assets/skills/subagent-driven-development/SKILL.md",
|
|
712
816
|
description: "Skill de ejecución con subagentes (Superpowers) — ejecuta solo después de confirmación del coordinador Ostacky",
|
|
713
|
-
version: "0.
|
|
817
|
+
version: "0.8.0",
|
|
714
818
|
sha256: "1a42d714a9a13faf05f0bf7b580e8d837c2e77a5633839542ccce603023419e8"
|
|
715
819
|
},
|
|
716
820
|
{
|
|
717
821
|
name: "dispatching-parallel-agents",
|
|
718
822
|
file: "assets/skills/dispatching-parallel-agents/SKILL.md",
|
|
719
823
|
description: "Skill de dispatch paralelo de agentes (Superpowers)",
|
|
720
|
-
version: "0.
|
|
824
|
+
version: "0.8.0",
|
|
721
825
|
sha256: "3c8a66d51ae2e719e877d02c3dac32bd804722c3bb9227c258ecae78252a20ab"
|
|
722
826
|
},
|
|
723
827
|
{
|
|
724
828
|
name: "review",
|
|
725
829
|
file: "assets/skills/review/SKILL.md",
|
|
726
830
|
description: "Skill de revisión de código (Superpowers)",
|
|
727
|
-
version: "0.
|
|
831
|
+
version: "0.8.0",
|
|
728
832
|
sha256: "b19650ed4d1d4d9857a4dd5b7e08e91328a1a1fc9c45bcc2fb600fa9d0213279"
|
|
729
833
|
},
|
|
730
834
|
{
|
|
731
835
|
name: "receiving-code-review",
|
|
732
836
|
file: "assets/skills/receiving-code-review/SKILL.md",
|
|
733
837
|
description: "Skill de recibir y procesar feedback de code review",
|
|
734
|
-
version: "0.
|
|
838
|
+
version: "0.8.0",
|
|
735
839
|
sha256: "d761e884e71d8d3476ac734d287cae403a4024506a7d12e7361a448217c0a831"
|
|
736
840
|
},
|
|
737
841
|
{
|
|
738
842
|
name: "openspec-propose",
|
|
739
843
|
file: "assets/skills/openspec-propose/SKILL.md",
|
|
740
844
|
description: "Skill de generación de proposal (OpenSpec)",
|
|
741
|
-
version: "0.
|
|
845
|
+
version: "0.8.0",
|
|
742
846
|
sha256: "bb59100b9fd3c9f9a1ec6509fa975ec55bf7fc737df4fe73bb3e9bbc217b83f7"
|
|
743
847
|
},
|
|
744
848
|
{
|
|
745
849
|
name: "openspec-apply-change",
|
|
746
850
|
file: "assets/skills/openspec-apply-change/SKILL.md",
|
|
747
851
|
description: "Skill de aplicación de change (OpenSpec)",
|
|
748
|
-
version: "0.
|
|
852
|
+
version: "0.8.0",
|
|
749
853
|
sha256: "dfc823bf89fc7505e91ab6dee9c1f004be38a410bd3d88fb67b211b1b6cbb1d0"
|
|
750
854
|
},
|
|
751
855
|
{
|
|
752
856
|
name: "openspec-archive-change",
|
|
753
857
|
file: "assets/skills/openspec-archive-change/SKILL.md",
|
|
754
858
|
description: "Skill de archivo de change (OpenSpec)",
|
|
755
|
-
version: "0.
|
|
859
|
+
version: "0.8.0",
|
|
756
860
|
sha256: "16e4b561de7747283663fed602e506abf502452c49a8d4b86d7a5539c40f0195"
|
|
757
861
|
},
|
|
758
862
|
{
|
|
759
863
|
name: "openspec-explore",
|
|
760
864
|
file: "assets/skills/openspec-explore/SKILL.md",
|
|
761
865
|
description: "Modo explore para OpenSpec — thinking partner para explorar ideas, investigar problemas y clarificar requisitos antes/durante un cambio",
|
|
762
|
-
version: "0.
|
|
866
|
+
version: "0.8.0",
|
|
763
867
|
sha256: "37ae4aaf17ea71a395bab6dc4d9d61b9a49d7910f6692535ae8553244c46880b"
|
|
764
868
|
},
|
|
765
869
|
{
|
|
766
870
|
name: "using-git-worktrees",
|
|
767
871
|
file: "assets/skills/using-git-worktrees/SKILL.md",
|
|
768
872
|
description: "Skill de uso de git worktrees para aislamiento de trabajo",
|
|
769
|
-
version: "0.
|
|
873
|
+
version: "0.8.0",
|
|
770
874
|
sha256: "93341bc1b7c053618a8b6dc07e3615b77990d7b549a0201f5835d95fef67ce13"
|
|
771
875
|
},
|
|
772
876
|
{
|
|
773
877
|
name: "using-superpowers",
|
|
774
878
|
file: "assets/skills/using-superpowers/SKILL.md",
|
|
775
879
|
description: "Skill de orquestación de Superpowers skills",
|
|
776
|
-
version: "0.
|
|
880
|
+
version: "0.8.0",
|
|
777
881
|
sha256: "7e54536f96d2a379185a10bfc1e970850caa2561b6d8aca7080f0defea0381a4"
|
|
778
882
|
},
|
|
779
883
|
{
|
|
780
884
|
name: "writing-skills",
|
|
781
885
|
file: "assets/skills/writing-skills/SKILL.md",
|
|
782
886
|
description: "Skill de creación y edición de skills",
|
|
783
|
-
version: "0.
|
|
887
|
+
version: "0.8.0",
|
|
784
888
|
sha256: "3d76b906cee518a2b809febb70db95697a35b9f368986bb504b4120c3bfb437a"
|
|
785
889
|
},
|
|
786
890
|
{
|
|
787
891
|
name: "graceful-degradation",
|
|
788
892
|
file: "assets/skills/graceful-degradation/SKILL.md",
|
|
789
893
|
description: "Skill de degradación graceful cuando múltiples tools están indisponibles",
|
|
790
|
-
version: "0.
|
|
894
|
+
version: "0.8.0",
|
|
791
895
|
sha256: "40f929e8032b70d51b3548bddcc383b931d6044fd9d4acce8a5b9f7acd014f59"
|
|
792
896
|
}
|
|
793
897
|
]
|
|
@@ -829,6 +933,19 @@ var init_cache = __esm(() => {
|
|
|
829
933
|
});
|
|
830
934
|
|
|
831
935
|
// src/github.ts
|
|
936
|
+
var exports_github = {};
|
|
937
|
+
__export(exports_github, {
|
|
938
|
+
BUNDLED_MCP_DIR: () => BUNDLED_MCP_DIR,
|
|
939
|
+
BUNDLED_SKILLS_DIR: () => BUNDLED_SKILLS_DIR,
|
|
940
|
+
PACKAGE_ROOT: () => PACKAGE_ROOT,
|
|
941
|
+
downloadFile: () => downloadFile,
|
|
942
|
+
fetchLatestManifest: () => fetchLatestManifest,
|
|
943
|
+
fetchLatestReleaseTag: () => fetchLatestReleaseTag,
|
|
944
|
+
fetchManifest: () => fetchManifest,
|
|
945
|
+
getBundledMcpPath: () => getBundledMcpPath,
|
|
946
|
+
getBundledSkillPath: () => getBundledSkillPath,
|
|
947
|
+
getRawUrl: () => getRawUrl
|
|
948
|
+
});
|
|
832
949
|
import { fileURLToPath } from "url";
|
|
833
950
|
import { dirname as dirname3, join as join3 } from "path";
|
|
834
951
|
function getBundledSkillPath(name) {
|
|
@@ -1143,6 +1260,12 @@ function patchOpenCodeConfig(projectRoot = findProjectRoot()) {
|
|
|
1143
1260
|
delete config.plugin;
|
|
1144
1261
|
changed = true;
|
|
1145
1262
|
}
|
|
1263
|
+
if (config.mcp && typeof config.mcp === "object" && "context7" in config.mcp) {
|
|
1264
|
+
delete config.mcp.context7;
|
|
1265
|
+
if (Object.keys(config.mcp).length === 0)
|
|
1266
|
+
delete config.mcp;
|
|
1267
|
+
changed = true;
|
|
1268
|
+
}
|
|
1146
1269
|
if (changed) {
|
|
1147
1270
|
writeOpenCodeConfig(configPath, config);
|
|
1148
1271
|
return { success: true, message: "Config actualizada (plugin legacy eliminado)" };
|
|
@@ -1162,7 +1285,6 @@ __export(exports_stack, {
|
|
|
1162
1285
|
installCodeGraph: () => installCodeGraph,
|
|
1163
1286
|
installEngram: () => installEngram,
|
|
1164
1287
|
installStack: () => installStack,
|
|
1165
|
-
setupContext7: () => setupContext7,
|
|
1166
1288
|
setupOpenSpec: () => setupOpenSpec,
|
|
1167
1289
|
uninstallEngramConfig: () => uninstallEngramConfig,
|
|
1168
1290
|
uninstallStackConfig: () => uninstallStackConfig,
|
|
@@ -1216,6 +1338,15 @@ function copyEngramPlugin(projectRoot) {
|
|
|
1216
1338
|
mkdirSync4(pluginsDir, { recursive: true });
|
|
1217
1339
|
copyFileSync3(pluginSource, join7(pluginsDir, "engram.ts"));
|
|
1218
1340
|
}
|
|
1341
|
+
function copyOstackyControllerPlugin(projectRoot) {
|
|
1342
|
+
const pluginSource = join7(PACKAGE_ROOT, "assets", "plugins", "ostacky-plugin.ts");
|
|
1343
|
+
const pluginsDir = join7(projectRoot, ".opencode", "plugins");
|
|
1344
|
+
if (!existsSync6(pluginSource)) {
|
|
1345
|
+
throw new Error(`Plugin bundleado de OstackyController no encontrado: ${pluginSource}`);
|
|
1346
|
+
}
|
|
1347
|
+
mkdirSync4(pluginsDir, { recursive: true });
|
|
1348
|
+
copyFileSync3(pluginSource, join7(pluginsDir, "ostacky-plugin.ts"));
|
|
1349
|
+
}
|
|
1219
1350
|
function buildEngramDownloadUrl(tag, platform = process.platform, arch = process.arch) {
|
|
1220
1351
|
const target = getEngramReleaseTarget(platform, arch);
|
|
1221
1352
|
if (!target)
|
|
@@ -1439,6 +1570,7 @@ async function installEngram(toolsDir) {
|
|
|
1439
1570
|
try {
|
|
1440
1571
|
runTool(localBin, ["--version"], projectRoot, 1e4);
|
|
1441
1572
|
copyEngramPlugin(projectRoot);
|
|
1573
|
+
copyOstackyControllerPlugin(projectRoot);
|
|
1442
1574
|
configureLocalTool(projectRoot, "engram", buildLocalMcpCommand(localBin, ["mcp"]));
|
|
1443
1575
|
} catch (error) {
|
|
1444
1576
|
return failAfterExtraction(`Engram fue instalado pero no se pudo verificar o configurar: ${error.message}`);
|
|
@@ -1446,44 +1578,15 @@ async function installEngram(toolsDir) {
|
|
|
1446
1578
|
archivePromotion?.commit();
|
|
1447
1579
|
return { success: true, message: "Engram instalado localmente y configurado para OpenCode (MCP + plugin)" };
|
|
1448
1580
|
}
|
|
1449
|
-
function setupContext7(toolsDir) {
|
|
1450
|
-
const location = resolveToolInstallLocation(toolsDir);
|
|
1451
|
-
const { projectRoot } = location;
|
|
1452
|
-
const ctx7ToolDir = join7(location.toolsDir, "context7");
|
|
1453
|
-
if (!existsSync6(ctx7ToolDir))
|
|
1454
|
-
mkdirSync4(ctx7ToolDir, { recursive: true });
|
|
1455
|
-
try {
|
|
1456
|
-
ensureMcpEntryAtProjectRoot(projectRoot, "context7", {
|
|
1457
|
-
type: "remote",
|
|
1458
|
-
url: "https://mcp.context7.com/mcp",
|
|
1459
|
-
enabled: true
|
|
1460
|
-
});
|
|
1461
|
-
} catch (error) {
|
|
1462
|
-
return { success: false, message: `No se pudo registrar Context7: ${error.message}` };
|
|
1463
|
-
}
|
|
1464
|
-
const useBun = isCommandAvailable("bun");
|
|
1465
|
-
try {
|
|
1466
|
-
const invocation = getCommandInvocation(useBun ? "bunx" : "npx", useBun ? ["ctx7", "setup", "--opencode"] : ["--yes", "ctx7", "setup", "--opencode"]);
|
|
1467
|
-
execFileSync3(invocation.command, invocation.args, {
|
|
1468
|
-
stdio: "pipe",
|
|
1469
|
-
timeout: 60000,
|
|
1470
|
-
cwd: projectRoot
|
|
1471
|
-
});
|
|
1472
|
-
return { success: true, message: "Context7 configurado (MCP + skill instalado)" };
|
|
1473
|
-
} catch {
|
|
1474
|
-
return {
|
|
1475
|
-
success: true,
|
|
1476
|
-
message: "Context7 MCP registrado (skill opcional no instalada — corrí `npx ctx7 setup --opencode` manualmente si la querés)"
|
|
1477
|
-
};
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
1581
|
async function installStack(toolsDir) {
|
|
1481
1582
|
const { projectRoot } = resolveToolInstallLocation(toolsDir);
|
|
1583
|
+
try {
|
|
1584
|
+
copyOstackyControllerPlugin(projectRoot);
|
|
1585
|
+
} catch {}
|
|
1482
1586
|
return {
|
|
1483
1587
|
codegraph: await installCodeGraph(toolsDir),
|
|
1484
1588
|
openspec: setupOpenSpec(projectRoot),
|
|
1485
1589
|
engram: await installEngram(toolsDir),
|
|
1486
|
-
context7: setupContext7(toolsDir),
|
|
1487
1590
|
config: patchOpenCodeConfig(projectRoot)
|
|
1488
1591
|
};
|
|
1489
1592
|
}
|
|
@@ -1518,7 +1621,7 @@ function uninstallStackConfig(paths) {
|
|
|
1518
1621
|
const mcp = config.mcp;
|
|
1519
1622
|
let changed = false;
|
|
1520
1623
|
if (mcp) {
|
|
1521
|
-
for (const name of ["codegraph", "
|
|
1624
|
+
for (const name of ["codegraph", "engram", "context7"]) {
|
|
1522
1625
|
if (name in mcp) {
|
|
1523
1626
|
delete mcp[name];
|
|
1524
1627
|
removed.push(`mcp.${name}`);
|
|
@@ -1588,7 +1691,7 @@ var init_stack = __esm(() => {
|
|
|
1588
1691
|
// package.json
|
|
1589
1692
|
var package_default = {
|
|
1590
1693
|
name: "ostacky",
|
|
1591
|
-
version: "0.
|
|
1694
|
+
version: "0.8.0",
|
|
1592
1695
|
description: "Instalador interactivo de agentes y comandos para OpenCode",
|
|
1593
1696
|
type: "module",
|
|
1594
1697
|
bin: {
|
|
@@ -2763,7 +2866,7 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath, option
|
|
|
2763
2866
|
params: {
|
|
2764
2867
|
protocolVersion: "2025-03-26",
|
|
2765
2868
|
capabilities: {},
|
|
2766
|
-
clientInfo: { name: "ostacky-installer", version: "0.
|
|
2869
|
+
clientInfo: { name: "ostacky-installer", version: "0.8.0" }
|
|
2767
2870
|
}
|
|
2768
2871
|
});
|
|
2769
2872
|
});
|
|
@@ -3277,11 +3380,6 @@ async function doInstallStack(toolsDir, projectRoot) {
|
|
|
3277
3380
|
spin.stop(eng.success ? `✓ ${eng.message}` : `✗ ${eng.message}`);
|
|
3278
3381
|
if (!eng.success)
|
|
3279
3382
|
allOk = false;
|
|
3280
|
-
spin.start("Configurando Context7...");
|
|
3281
|
-
const ctx = setupContext7(toolsDir);
|
|
3282
|
-
spin.stop(ctx.success ? `✓ ${ctx.message}` : `✗ ${ctx.message}`);
|
|
3283
|
-
if (!ctx.success)
|
|
3284
|
-
allOk = false;
|
|
3285
3383
|
spin.start("Verificando configuración...");
|
|
3286
3384
|
const { patchOpenCodeConfig: patchOpenCodeConfig2 } = await Promise.resolve().then(() => (init_config(), exports_config));
|
|
3287
3385
|
const cfg = patchOpenCodeConfig2(resolvedProjectRoot);
|
|
@@ -3298,9 +3396,9 @@ async function doInstallAll(manifest, paths) {
|
|
|
3298
3396
|
let errors = 0;
|
|
3299
3397
|
const isGlobal = isGlobalScope(paths);
|
|
3300
3398
|
if (!isGlobal) {
|
|
3301
|
-
ensureToolDirs(paths.tools, ["codegraph", "engram"
|
|
3399
|
+
ensureToolDirs(paths.tools, ["codegraph", "engram"]);
|
|
3302
3400
|
} else {
|
|
3303
|
-
v2.info("Scope global detectado: el stack (CodeGraph/Engram)
|
|
3401
|
+
v2.info("Scope global detectado: el stack (CodeGraph/Engram) y plugins (ostacky-controller, engram) permanecen siempre en <proyecto>/.opencode — se omite instalación de stack global.");
|
|
3304
3402
|
v2.info("Para instalar el stack, ejecutá 'npx ostacky install-stack --scope local' dentro de cada proyecto.");
|
|
3305
3403
|
}
|
|
3306
3404
|
for (const agent of manifest.agents) {
|
|
@@ -3347,6 +3445,42 @@ async function doInstallAll(manifest, paths) {
|
|
|
3347
3445
|
errors++;
|
|
3348
3446
|
}
|
|
3349
3447
|
}
|
|
3448
|
+
try {
|
|
3449
|
+
const { copyFileSync: copyFileSync4, mkdirSync: mkdirSync5, existsSync: existsSync8 } = await import("fs");
|
|
3450
|
+
const { join: join9 } = await import("path");
|
|
3451
|
+
const { PACKAGE_ROOT: PACKAGE_ROOT2 } = await Promise.resolve().then(() => (init_github(), exports_github));
|
|
3452
|
+
const { findProjectRoot: findProjectRoot3 } = await Promise.resolve().then(() => (init_fs(), exports_fs));
|
|
3453
|
+
const src = join9(PACKAGE_ROOT2, "assets", "plugins", "ostacky-plugin.ts");
|
|
3454
|
+
const dest = join9(paths.plugins, "ostacky-plugin.ts");
|
|
3455
|
+
if (existsSync8(src)) {
|
|
3456
|
+
mkdirSync5(paths.plugins, { recursive: true });
|
|
3457
|
+
copyFileSync4(src, dest);
|
|
3458
|
+
}
|
|
3459
|
+
const legacySrc = join9(PACKAGE_ROOT2, "assets", "plugins", "ostacky-controller.ts");
|
|
3460
|
+
if (!existsSync8(src) && existsSync8(legacySrc)) {
|
|
3461
|
+
mkdirSync5(paths.plugins, { recursive: true });
|
|
3462
|
+
copyFileSync4(legacySrc, join9(paths.plugins, "ostacky-controller.ts"));
|
|
3463
|
+
}
|
|
3464
|
+
const srcEng = join9(PACKAGE_ROOT2, "assets", "plugins", "engram.ts");
|
|
3465
|
+
const destEng = join9(paths.plugins, "engram.ts");
|
|
3466
|
+
if (existsSync8(srcEng)) {
|
|
3467
|
+
mkdirSync5(paths.plugins, { recursive: true });
|
|
3468
|
+
copyFileSync4(srcEng, destEng);
|
|
3469
|
+
}
|
|
3470
|
+
if (isGlobal) {
|
|
3471
|
+
try {
|
|
3472
|
+
const projRoot = findProjectRoot3();
|
|
3473
|
+
const localPlugins = join9(projRoot, ".opencode", "plugins");
|
|
3474
|
+
mkdirSync5(localPlugins, { recursive: true });
|
|
3475
|
+
if (existsSync8(src))
|
|
3476
|
+
copyFileSync4(src, join9(localPlugins, "ostacky-plugin.ts"));
|
|
3477
|
+
else if (existsSync8(legacySrc))
|
|
3478
|
+
copyFileSync4(legacySrc, join9(localPlugins, "ostacky-controller.ts"));
|
|
3479
|
+
if (existsSync8(srcEng))
|
|
3480
|
+
copyFileSync4(srcEng, join9(localPlugins, "engram.ts"));
|
|
3481
|
+
} catch {}
|
|
3482
|
+
}
|
|
3483
|
+
} catch {}
|
|
3350
3484
|
let stackOk = true;
|
|
3351
3485
|
let missingTools = [];
|
|
3352
3486
|
if (isGlobal) {
|
|
@@ -3893,7 +4027,7 @@ async function runInteractiveMenu(scope) {
|
|
|
3893
4027
|
{ value: "command", label: "Instalar command" },
|
|
3894
4028
|
{ value: "skill", label: "Instalar skill" },
|
|
3895
4029
|
{ value: "mcp", label: "Instalar MCP server" },
|
|
3896
|
-
{ value: "stack", label: "Instalar stack de herramientas (CodeGraph, Engram
|
|
4030
|
+
{ value: "stack", label: "Instalar stack de herramientas (CodeGraph, Engram)" },
|
|
3897
4031
|
{ value: "update", label: "Actualizar instalación" },
|
|
3898
4032
|
{ value: "uninstall", label: "Desinstalar" },
|
|
3899
4033
|
{ value: "exit", label: "Salir" }
|
|
@@ -3934,7 +4068,7 @@ async function runInteractiveMenu(scope) {
|
|
|
3934
4068
|
fe("Cancelado.");
|
|
3935
4069
|
break;
|
|
3936
4070
|
}
|
|
3937
|
-
ensureToolDirs(paths.tools, ["codegraph", "engram"
|
|
4071
|
+
ensureToolDirs(paths.tools, ["codegraph", "engram"]);
|
|
3938
4072
|
const stackOk = await doInstallStack(paths.tools, dirname7(paths.root));
|
|
3939
4073
|
if (!stackOk)
|
|
3940
4074
|
process.exitCode = 1;
|
|
@@ -4037,7 +4171,7 @@ async function runInstallStackCommand(scope) {
|
|
|
4037
4171
|
process.exitCode = 1;
|
|
4038
4172
|
return;
|
|
4039
4173
|
}
|
|
4040
|
-
ensureToolDirs(paths.tools, ["codegraph", "engram"
|
|
4174
|
+
ensureToolDirs(paths.tools, ["codegraph", "engram"]);
|
|
4041
4175
|
const stackOk = await doInstallStack(paths.tools, dirname7(paths.root));
|
|
4042
4176
|
if (!stackOk)
|
|
4043
4177
|
process.exitCode = 1;
|
|
@@ -4051,7 +4185,7 @@ async function runUninstallStackCommand(scope) {
|
|
|
4051
4185
|
return;
|
|
4052
4186
|
}
|
|
4053
4187
|
const confirm = await me({
|
|
4054
|
-
message: "¿Remover la configuración del stack (CodeGraph, Engram
|
|
4188
|
+
message: "¿Remover la configuración del stack (CodeGraph, Engram) del proyecto? Los binarios globales no se tocan."
|
|
4055
4189
|
});
|
|
4056
4190
|
onCancel(confirm);
|
|
4057
4191
|
if (!confirm) {
|
|
@@ -4238,12 +4372,12 @@ ostacky — Instalador de agentes, comandos, skills y MCPs para OpenCode
|
|
|
4238
4372
|
|
|
4239
4373
|
Uso:
|
|
4240
4374
|
npx ostacky [--scope local|global|auto] Menú interactivo (instalación completa, pregunta local vs global, default local)
|
|
4241
|
-
npx ostacky install [--scope local|global|auto] Instalar TODO (agente + skills + MCPs + CodeGraph + OpenSpec + Engram
|
|
4375
|
+
npx ostacky install [--scope local|global|auto] Instalar TODO (agente + skills + MCPs + CodeGraph + OpenSpec + Engram)
|
|
4242
4376
|
npx ostacky add agent [--scope local|global|auto] Agregar agente(s)
|
|
4243
4377
|
npx ostacky add command [--scope ...] Agregar command(s)
|
|
4244
4378
|
npx ostacky add skill [--scope ...] Agregar skill(s)
|
|
4245
4379
|
npx ostacky add mcp [--scope ...] Agregar MCP server(s)
|
|
4246
|
-
npx ostacky install-stack [--scope local|auto] Instalar solo el stack de herramientas (CodeGraph, OpenSpec, Engram
|
|
4380
|
+
npx ostacky install-stack [--scope local|auto] Instalar solo el stack de herramientas (CodeGraph, OpenSpec, Engram) — global bloquea con error
|
|
4247
4381
|
npx ostacky uninstall-stack [--scope local|global|auto] Remover la configuración del stack del proyecto
|
|
4248
4382
|
npx ostacky doctor Diagnostica locks, tools, state health
|
|
4249
4383
|
npx ostacky status [--json] Muestra estado del controller sin MCP
|
|
@@ -4262,7 +4396,7 @@ Scope:
|
|
|
4262
4396
|
--scope auto Elige local si existe .opencode o .git, si no global
|
|
4263
4397
|
Sin flag Pregunta interactiva local (default) vs global
|
|
4264
4398
|
`.trim();
|
|
4265
|
-
function
|
|
4399
|
+
function parseScopeArg2(argv = process.argv) {
|
|
4266
4400
|
for (let i = 0;i < argv.length; i++) {
|
|
4267
4401
|
const arg = argv[i];
|
|
4268
4402
|
if (arg === "--scope" && i + 1 < argv.length) {
|
|
@@ -4292,7 +4426,7 @@ function withoutScopeArgs(argv) {
|
|
|
4292
4426
|
}
|
|
4293
4427
|
return out;
|
|
4294
4428
|
}
|
|
4295
|
-
var scope =
|
|
4429
|
+
var scope = parseScopeArg2();
|
|
4296
4430
|
var argvNoScope = withoutScopeArgs(process.argv);
|
|
4297
4431
|
var [, , cmd, subcmd] = argvNoScope;
|
|
4298
4432
|
async function runDoctorCommand() {
|
|
@@ -4312,14 +4446,30 @@ async function runDoctorCommand() {
|
|
|
4312
4446
|
hasError = true;
|
|
4313
4447
|
}
|
|
4314
4448
|
};
|
|
4449
|
+
const pluginPaths = [
|
|
4450
|
+
join11(cwd, "assets", "plugins", "ostacky-plugin.ts"),
|
|
4451
|
+
join11(opencodeDir, "plugins", "ostacky-plugin.ts"),
|
|
4452
|
+
join11(cwd, ".opencode", "plugins", "ostacky-plugin.ts"),
|
|
4453
|
+
join11(cwd, "assets", "plugins", "ostacky-controller.ts"),
|
|
4454
|
+
join11(opencodeDir, "plugins", "ostacky-controller.ts"),
|
|
4455
|
+
join11(cwd, ".opencode", "plugins", "ostacky-controller.ts")
|
|
4456
|
+
];
|
|
4457
|
+
const pluginActive = pluginPaths.some((p2) => existsSync8(p2));
|
|
4315
4458
|
try {
|
|
4316
4459
|
if (!existsSync8(statePath)) {
|
|
4317
|
-
|
|
4460
|
+
if (pluginActive)
|
|
4461
|
+
console.log(`✅ controller: plugin active (no state yet)`);
|
|
4462
|
+
else
|
|
4463
|
+
check("controller: state file missing", false, true);
|
|
4318
4464
|
} else {
|
|
4319
4465
|
const stat = statSync3(statePath);
|
|
4320
4466
|
const raw = readFileSync6(statePath, "utf-8");
|
|
4321
4467
|
const parsed = JSON.parse(raw);
|
|
4322
|
-
|
|
4468
|
+
if (pluginActive) {
|
|
4469
|
+
console.log(`✅ controller: plugin active (rev ${parsed.revision || 0} state ${parsed.state || "unknown"})`);
|
|
4470
|
+
} else {
|
|
4471
|
+
check(`controller: OK (rev ${parsed.revision || 0} state ${parsed.state || "unknown"})`, true);
|
|
4472
|
+
}
|
|
4323
4473
|
if (parsed.degraded) {
|
|
4324
4474
|
console.log("⚠️ degraded: true (persistido)");
|
|
4325
4475
|
hasWarn = true;
|