ostacky 0.7.0 → 0.7.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 CHANGED
@@ -218,33 +218,33 @@ Tras instalar, el proyecto queda así:
218
218
 
219
219
  ```json
220
220
  {
221
- "version": "0.7.0",
221
+ "version": "0.7.1",
222
222
  "lockedAt": "2025-01-01T00:00:00.000Z",
223
223
  "repo": "JaimeHoracio/Ostacky",
224
- "tag": "v0.7.0",
224
+ "tag": "v0.7.1",
225
225
  "agents": {
226
226
  "ostacky": {
227
- "version": "0.7.0",
227
+ "version": "0.7.1",
228
228
  "installedAt": "2025-01-01T00:00:00.000Z",
229
229
  "sha256": "abc123..."
230
230
  }
231
231
  },
232
232
  "commands": {
233
233
  "install-stack": {
234
- "version": "0.7.0",
234
+ "version": "0.7.1",
235
235
  "installedAt": "2025-01-01T00:00:00.000Z",
236
236
  "sha256": "def456..."
237
237
  },
238
238
  "opsx-sync": {
239
- "version": "0.7.0",
239
+ "version": "0.7.1",
240
240
  "installedAt": "2025-01-01T00:00:00.000Z",
241
241
  "sha256": "ghi789..."
242
242
  }
243
243
  },
244
244
  "skills": {
245
- "brainstorming": { "version": "0.7.0", ... },
246
- "execution-mode-evaluation": { "version": "0.7.0", ... },
247
- "openspec-propose": { "version": "0.7.0", ... }
245
+ "brainstorming": { "version": "0.7.1", ... },
246
+ "execution-mode-evaluation": { "version": "0.7.1", ... },
247
+ "openspec-propose": { "version": "0.7.1", ... }
248
248
  }
249
249
  }
250
250
  ```
@@ -274,7 +274,7 @@ Es opcional y solo necesario si algo falló durante la instalación o si querés
274
274
  ## Seguridad
275
275
 
276
276
  - `opencode.jsonc` se versiona en el repo para compartir permisos y MCP de forma reproducible.
277
- - Las URLs de descarga usan **tags de GitHub** (ej. `v0.7.0`), nunca `main` — instalaciones reproducibles
277
+ - Las URLs de descarga usan **tags de GitHub** (ej. `v0.7.1`), nunca `main` — instalaciones reproducibles
278
278
  - Cada path de archivo descargado es validado para prevenir **path traversal**
279
279
  - Los archivos incluyen **checksum SHA-256** opcional; si el manifest lo define, el contenido se verifica antes de escribir
280
280
  - El cache local (`.opencode/cache/`) también valida integridad al servir archivos cacheados
@@ -5,7 +5,7 @@ agent: build
5
5
 
6
6
  Instala el stack tecnológico de desarrollo para OpenCode. **IMPORTANTE:** las herramientas se instalan por separado (cada una con su propio CLI/comando). `npx ostacky install` solo instala el agente y commands de Ostacky en `.opencode/`. Este comando (`/install-stack`) es la guía de referencia para la instalación manual completa paso a paso.
7
7
 
8
- **Nota:** A partir de v0.7.0, `npx ostacky install` ya instala automáticamente el stack completo (CodeGraph, OpenSpec, Engram, Context7, MCPs bundleados) además del agente y skills. Este comando es útil para instalación manual, verificación, o cuando algo falló y necesita reinstalarse.
8
+ **Nota:** A partir de v0.7.1, `npx ostacky install` ya instala automáticamente el stack completo (CodeGraph, OpenSpec, Engram, Context7, MCPs bundleados) además del agente y skills. Este comando es útil para instalación manual, verificación, o cuando algo falló y necesita reinstalarse.
9
9
 
10
10
  **RESTRICCIÓN ABSOLUTA:** instalar ÚNICAMENTE para OpenCode. Está terminantemente prohibido crear o modificar archivos en `.claude/`, `.kiro/`, `.cursor/`, `.gemini/`, `.codex/`, `.antigravity/`, `.windsurf/` o cualquier otro directorio de plataformas externas.
11
11
 
@@ -415,7 +415,9 @@ class OstackyController {
415
415
  this.#consecutiveFailures++;
416
416
  log('error:persist_failed', { consecutive: this.#consecutiveFailures, error: err.message });
417
417
  if (this.#consecutiveFailures >= DEGRADED_THRESHOLD && !this.#degraded) {
418
- this.#enterDegradedMode(`persistence_failures: ${this.#consecutiveFailures} consecutive persists: ${err.message}`);
418
+ this.#enterDegradedMode(
419
+ `persistence_failures: ${this.#consecutiveFailures} consecutive persists: ${err.message}`
420
+ );
419
421
  }
420
422
  throw err;
421
423
  } finally {
@@ -559,7 +561,11 @@ class OstackyController {
559
561
  async requestClarification({ question } = {}) {
560
562
  this.#load();
561
563
  const to = this.#isAllowedTransition(this.#state.state, 'request_clarification');
562
- if (!to) return this.#makeError(`Cannot request clarification from state ${this.#state.state}`, 'request_clarification');
564
+ if (!to)
565
+ return this.#makeError(
566
+ `Cannot request clarification from state ${this.#state.state}`,
567
+ 'request_clarification'
568
+ );
563
569
  this.#transition(to, { error: question ? `Clarification: ${question}` : null });
564
570
  this.#audit('CLARIFICATION_PENDING', 'request_clarification', question || 'no question');
565
571
  return { state: this.#state.state, revision: this.#state.revision };
@@ -568,7 +574,11 @@ class OstackyController {
568
574
  async recordClarification() {
569
575
  this.#load();
570
576
  const to = this.#isAllowedTransition(this.#state.state, 'record_clarification');
571
- if (!to) return this.#makeError(`Cannot record clarification from state ${this.#state.state}`, 'record_clarification');
577
+ if (!to)
578
+ return this.#makeError(
579
+ `Cannot record clarification from state ${this.#state.state}`,
580
+ 'record_clarification'
581
+ );
572
582
  this.#transition(to, { error: null });
573
583
  this.#audit('DISCOVERY', 'record_clarification');
574
584
  return { state: this.#state.state, revision: this.#state.revision };
@@ -600,7 +610,9 @@ class OstackyController {
600
610
  if (!to) return this.#makeError(`Cannot record discovery from state ${this.#state.state}`, 'record_discovery');
601
611
 
602
612
  // O3: Compress snapshot before persisting
603
- const compressedSnapshot = snapshot ? this.#compressCodegraphSnapshot(snapshot) : this.#state.snapshots.codegraph;
613
+ const compressedSnapshot = snapshot
614
+ ? this.#compressCodegraphSnapshot(snapshot)
615
+ : this.#state.snapshots.codegraph;
604
616
  const snapshotJson = compressedSnapshot ? safeJsonStringify(compressedSnapshot) : '';
605
617
  if (snapshotJson.length > MAX_SNAPSHOT_JSON_LENGTH) {
606
618
  return this.#makeError(
@@ -647,11 +659,16 @@ class OstackyController {
647
659
  async consumeRouteDecision({ decisionId, choice } = {}) {
648
660
  this.#load();
649
661
  if (this.#state.state !== 'ROUTE_DECISION_PENDING') {
650
- return this.#makeError(`Cannot consume route decision from state ${this.#state.state}`, 'consume_route_decision');
662
+ return this.#makeError(
663
+ `Cannot consume route decision from state ${this.#state.state}`,
664
+ 'consume_route_decision'
665
+ );
651
666
  }
652
- if (this.#state.routeDecisionId !== decisionId) return this.#makeError('Decision ID mismatch', 'consume_route_decision');
667
+ if (this.#state.routeDecisionId !== decisionId)
668
+ return this.#makeError('Decision ID mismatch', 'consume_route_decision');
653
669
  const to = this.#isAllowedTransition(this.#state.state, 'consume_route_decision', choice);
654
- if (!to) return this.#makeError(`Route ${choice} not allowed from ${this.#state.state}`, 'consume_route_decision');
670
+ if (!to)
671
+ return this.#makeError(`Route ${choice} not allowed from ${this.#state.state}`, 'consume_route_decision');
655
672
  this.#transition(to, { routeChoice: choice });
656
673
  this.#audit(to, 'consume_route_decision', `choice=${choice}`);
657
674
  return { state: this.#state.state, revision: this.#state.revision, routeChoice: choice };
@@ -669,7 +686,11 @@ class OstackyController {
669
686
  async recordExecutionAnalysis({ executionDecisionId, snapshot } = {}) {
670
687
  this.#load();
671
688
  const to = this.#isAllowedTransition(this.#state.state, 'record_execution_analysis');
672
- if (!to) return this.#makeError(`Cannot record execution analysis from state ${this.#state.state}`, 'record_execution_analysis');
689
+ if (!to)
690
+ return this.#makeError(
691
+ `Cannot record execution analysis from state ${this.#state.state}`,
692
+ 'record_execution_analysis'
693
+ );
673
694
  if (snapshot && safeJsonStringify(snapshot).length > MAX_SNAPSHOT_JSON_LENGTH) {
674
695
  return this.#makeError(
675
696
  `Snapshot exceeds maximum size of ${MAX_SNAPSHOT_JSON_LENGTH} bytes`,
@@ -692,11 +713,16 @@ class OstackyController {
692
713
  async consumeExecutionDecision({ decisionId, mode } = {}) {
693
714
  this.#load();
694
715
  if (this.#state.state !== 'EXECUTION_DECISION_PENDING') {
695
- return this.#makeError(`Cannot consume execution decision from state ${this.#state.state}`, 'consume_execution_decision');
716
+ return this.#makeError(
717
+ `Cannot consume execution decision from state ${this.#state.state}`,
718
+ 'consume_execution_decision'
719
+ );
696
720
  }
697
- if (this.#state.executionDecisionId !== decisionId) return this.#makeError('Decision ID mismatch', 'consume_execution_decision');
721
+ if (this.#state.executionDecisionId !== decisionId)
722
+ return this.#makeError('Decision ID mismatch', 'consume_execution_decision');
698
723
  const to = this.#isAllowedTransition(this.#state.state, 'consume_execution_decision', mode);
699
- if (!to) return this.#makeError(`Mode ${mode} not allowed from ${this.#state.state}`, 'consume_execution_decision');
724
+ if (!to)
725
+ return this.#makeError(`Mode ${mode} not allowed from ${this.#state.state}`, 'consume_execution_decision');
700
726
  this.#transition(to, { executionMode: mode });
701
727
  this.#audit(to, 'consume_execution_decision', `mode=${mode}`);
702
728
  return { state: this.#state.state, revision: this.#state.revision, executionMode: mode };
@@ -705,7 +731,11 @@ class OstackyController {
705
731
  async implementationComplete() {
706
732
  this.#load();
707
733
  const to = this.#isAllowedTransition(this.#state.state, 'implementation_complete');
708
- if (!to) return this.#makeError(`Cannot complete implementation from state ${this.#state.state}`, 'implementation_complete');
734
+ if (!to)
735
+ return this.#makeError(
736
+ `Cannot complete implementation from state ${this.#state.state}`,
737
+ 'implementation_complete'
738
+ );
709
739
  this.#transition(to);
710
740
  this.#audit('SYNC', 'implementation_complete');
711
741
  return { state: this.#state.state, revision: this.#state.revision };
@@ -917,7 +947,7 @@ function safeHandler(fn) {
917
947
 
918
948
  const server = new McpServer({
919
949
  name: 'ostacky-controller',
920
- version: '0.7.0',
950
+ version: '0.7.1',
921
951
  });
922
952
 
923
953
  server.registerTool(
@@ -939,7 +969,8 @@ server.registerTool(
939
969
  server.registerTool(
940
970
  'request_clarification',
941
971
  {
942
- description: 'Pause execution to ask the user for clarification. Use when the request is too vague to classify. Transitions to CLARIFICATION_PENDING — you MUST stop and wait for user response.',
972
+ description:
973
+ 'Pause execution to ask the user for clarification. Use when the request is too vague to classify. Transitions to CLARIFICATION_PENDING — you MUST stop and wait for user response.',
943
974
  inputSchema: z.object({
944
975
  question: z.string().optional().describe('The clarification question'),
945
976
  }),
@@ -1091,7 +1122,8 @@ server.registerTool(
1091
1122
  server.registerTool(
1092
1123
  'proceed_to_route',
1093
1124
  {
1094
- description: 'Proceed from LEVEL_RESOLVED to ROUTE_DECISION_PENDING after discovery is confirmed. Only valid from LEVEL_RESOLVED — call this after asking the user about the route decision.',
1125
+ description:
1126
+ 'Proceed from LEVEL_RESOLVED to ROUTE_DECISION_PENDING after discovery is confirmed. Only valid from LEVEL_RESOLVED — call this after asking the user about the route decision.',
1095
1127
  inputSchema: z.object({}),
1096
1128
  },
1097
1129
  safeHandler(async () => {
@@ -1170,7 +1202,8 @@ server.registerTool(
1170
1202
  server.registerTool(
1171
1203
  'set_handoff',
1172
1204
  {
1173
- description: 'Save handoff context for the next session. Call at session end if interrupted or before a context switch. Persists to controller state.',
1205
+ description:
1206
+ 'Save handoff context for the next session. Call at session end if interrupted or before a context switch. Persists to controller state.',
1174
1207
  inputSchema: z.object({
1175
1208
  summary: z.string().describe('What we were working on (1-3 sentences)'),
1176
1209
  nextSteps: z.array(z.string()).optional().describe('Concrete next actions'),
@@ -1278,7 +1311,10 @@ server.registerTool(
1278
1311
  inputSchema: z.object({
1279
1312
  taskId: z.string().describe('The task ID to mark as completed.'),
1280
1313
  filePath: z.string().optional().describe('Optional file path that was modified.'),
1281
- fileHash: z.string().optional().describe('Optional SHA-256 or fast fingerprint of the file after modification.'),
1314
+ fileHash: z
1315
+ .string()
1316
+ .optional()
1317
+ .describe('Optional SHA-256 or fast fingerprint of the file after modification.'),
1282
1318
  }),
1283
1319
  },
1284
1320
  safeHandler(async ({ taskId, filePath, fileHash }) => {
@@ -1318,7 +1354,7 @@ function setupGracefulShutdown(ctrl) {
1318
1354
  }
1319
1355
 
1320
1356
  async function main() {
1321
- log('Starting ostacky-controller MCP v0.7.0...');
1357
+ log('Starting ostacky-controller MCP v0.7.1...');
1322
1358
  log('State path:', { path: statePath });
1323
1359
  // Clean up stale tmp/lock files from previous runs
1324
1360
  cleanupTmpFiles(statePath);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ostacky-controller",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "dependencies": {
package/dist/cli.js CHANGED
@@ -520,15 +520,15 @@ var init_fs = __esm(() => {
520
520
  var manifest_default;
521
521
  var init_manifest = __esm(() => {
522
522
  manifest_default = {
523
- version: "0.7.0",
523
+ version: "0.7.1",
524
524
  repo: "JaimeHoracio/Ostacky",
525
- tag: "v0.7.0",
525
+ tag: "v0.7.1",
526
526
  agents: [
527
527
  {
528
528
  name: "ostacky",
529
529
  file: "assets/agents/ostacky.md",
530
- 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.7.0: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
531
- version: "0.7.0",
530
+ 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.7.1: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
531
+ version: "0.7.1",
532
532
  sha256: "f833e69b6eaa3dfe24de9addf6455b3da55f829b51cba3c7c90c65c69cda34c2"
533
533
  }
534
534
  ],
@@ -536,15 +536,15 @@ var init_manifest = __esm(() => {
536
536
  {
537
537
  name: "install-stack",
538
538
  file: "assets/commands/install-stack.md",
539
- description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, Context7, controller MCP con SDK oficial). v0.7.0: Paso 1.5 controller expandido con verificación post-instalación y troubleshooting.",
540
- version: "0.7.0",
541
- sha256: "c957627dfafabfdb9da2717546b996d1d8856f08a6e4c48caf72c562363b566b"
539
+ description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, Context7, controller MCP con SDK oficial). v0.7.1: Paso 1.5 controller expandido con verificación post-instalación y troubleshooting.",
540
+ version: "0.7.1",
541
+ sha256: "ef4244855cf733dfe50a2a8e7c436c5741f92574cc50f0fca49faed60480e013"
542
542
  },
543
543
  {
544
544
  name: "opsx-sync",
545
545
  file: "assets/commands/opsx-sync.md",
546
546
  description: "Sincroniza delta specs del change activo sin inicializar CodeGraph si ya existe índice",
547
- version: "0.7.0",
547
+ version: "0.7.1",
548
548
  sha256: "fe0158478f2ca63b315037a85fc1632b77868532e319af6c7384285441767d64"
549
549
  }
550
550
  ],
@@ -552,15 +552,15 @@ var init_manifest = __esm(() => {
552
552
  {
553
553
  name: "ostacky-controller",
554
554
  file: "assets/mcp/ostacky-controller/",
555
- description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.7.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.",
556
- version: "0.7.0",
557
- sha256: "0ec6fa0fc2900c78b884258168309653dea4b77ded3596bb56866f689ec2404c"
555
+ description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.7.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.",
556
+ version: "0.7.1",
557
+ sha256: "0e639fb1d5bedf8b93b4e259782b9b7de68cd4bb89875e2c546279d17131b7b7"
558
558
  },
559
559
  {
560
560
  name: "openspec",
561
561
  file: "assets/mcp/openspec/",
562
562
  description: "MCP server local para OpenSpec - proposal, apply, archive, sync de cambios",
563
- version: "0.7.0",
563
+ version: "0.7.1",
564
564
  sha256: "fa4be28bfc1e75db8f1a037e2580f04a60066c80e8e5934e90e1041020d04609"
565
565
  }
566
566
  ],
@@ -569,105 +569,105 @@ var init_manifest = __esm(() => {
569
569
  name: "brainstorming",
570
570
  file: "assets/skills/brainstorming/SKILL.md",
571
571
  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)",
572
- version: "0.7.0",
572
+ version: "0.7.1",
573
573
  sha256: "333810ca63450e8ab795e8c5a58e645101e788d79210ca8ac36e10d11be39585"
574
574
  },
575
575
  {
576
576
  name: "execution-mode-evaluation",
577
577
  file: "assets/skills/execution-mode-evaluation/SKILL.md",
578
578
  description: "Skill de análisis de modo de ejecución — output reconciliado con controller snapshot contract (recommendation field)",
579
- version: "0.7.0",
579
+ version: "0.7.1",
580
580
  sha256: "edf6fca0af52cce83f8fd08e7db9b3d79cc130b53fca505e90d3fbaf4909338b"
581
581
  },
582
582
  {
583
583
  name: "tdd",
584
584
  file: "assets/skills/tdd/SKILL.md",
585
585
  description: "Skill de test-driven development (Superpowers)",
586
- version: "0.7.0",
586
+ version: "0.7.1",
587
587
  sha256: "aa412298980b7826165c211145c1b8e9135f68f36247bb3cb96d0a0eae274486"
588
588
  },
589
589
  {
590
590
  name: "subagent-driven-development",
591
591
  file: "assets/skills/subagent-driven-development/SKILL.md",
592
592
  description: "Skill de ejecución con subagentes (Superpowers) — ejecuta solo después de confirmación del coordinador Ostacky",
593
- version: "0.7.0",
593
+ version: "0.7.1",
594
594
  sha256: "1a42d714a9a13faf05f0bf7b580e8d837c2e77a5633839542ccce603023419e8"
595
595
  },
596
596
  {
597
597
  name: "dispatching-parallel-agents",
598
598
  file: "assets/skills/dispatching-parallel-agents/SKILL.md",
599
599
  description: "Skill de dispatch paralelo de agentes (Superpowers)",
600
- version: "0.7.0",
600
+ version: "0.7.1",
601
601
  sha256: "3c8a66d51ae2e719e877d02c3dac32bd804722c3bb9227c258ecae78252a20ab"
602
602
  },
603
603
  {
604
604
  name: "review",
605
605
  file: "assets/skills/review/SKILL.md",
606
606
  description: "Skill de revisión de código (Superpowers)",
607
- version: "0.7.0",
607
+ version: "0.7.1",
608
608
  sha256: "b19650ed4d1d4d9857a4dd5b7e08e91328a1a1fc9c45bcc2fb600fa9d0213279"
609
609
  },
610
610
  {
611
611
  name: "receiving-code-review",
612
612
  file: "assets/skills/receiving-code-review/SKILL.md",
613
613
  description: "Skill de recibir y procesar feedback de code review",
614
- version: "0.7.0",
614
+ version: "0.7.1",
615
615
  sha256: "d761e884e71d8d3476ac734d287cae403a4024506a7d12e7361a448217c0a831"
616
616
  },
617
617
  {
618
618
  name: "openspec-propose",
619
619
  file: "assets/skills/openspec-propose/SKILL.md",
620
620
  description: "Skill de generación de proposal (OpenSpec)",
621
- version: "0.7.0",
621
+ version: "0.7.1",
622
622
  sha256: "bb59100b9fd3c9f9a1ec6509fa975ec55bf7fc737df4fe73bb3e9bbc217b83f7"
623
623
  },
624
624
  {
625
625
  name: "openspec-apply-change",
626
626
  file: "assets/skills/openspec-apply-change/SKILL.md",
627
627
  description: "Skill de aplicación de change (OpenSpec)",
628
- version: "0.7.0",
628
+ version: "0.7.1",
629
629
  sha256: "dfc823bf89fc7505e91ab6dee9c1f004be38a410bd3d88fb67b211b1b6cbb1d0"
630
630
  },
631
631
  {
632
632
  name: "openspec-archive-change",
633
633
  file: "assets/skills/openspec-archive-change/SKILL.md",
634
634
  description: "Skill de archivo de change (OpenSpec)",
635
- version: "0.7.0",
635
+ version: "0.7.1",
636
636
  sha256: "16e4b561de7747283663fed602e506abf502452c49a8d4b86d7a5539c40f0195"
637
637
  },
638
638
  {
639
639
  name: "openspec-explore",
640
640
  file: "assets/skills/openspec-explore/SKILL.md",
641
641
  description: "Modo explore para OpenSpec — thinking partner para explorar ideas, investigar problemas y clarificar requisitos antes/durante un cambio",
642
- version: "0.7.0",
642
+ version: "0.7.1",
643
643
  sha256: "37ae4aaf17ea71a395bab6dc4d9d61b9a49d7910f6692535ae8553244c46880b"
644
644
  },
645
645
  {
646
646
  name: "using-git-worktrees",
647
647
  file: "assets/skills/using-git-worktrees/SKILL.md",
648
648
  description: "Skill de uso de git worktrees para aislamiento de trabajo",
649
- version: "0.7.0",
649
+ version: "0.7.1",
650
650
  sha256: "11afa9123828fc5caa22137aff907cd99c751e99027fbd4c020751110a949281"
651
651
  },
652
652
  {
653
653
  name: "using-superpowers",
654
654
  file: "assets/skills/using-superpowers/SKILL.md",
655
655
  description: "Skill de orquestación de Superpowers skills",
656
- version: "0.7.0",
656
+ version: "0.7.1",
657
657
  sha256: "7e54536f96d2a379185a10bfc1e970850caa2561b6d8aca7080f0defea0381a4"
658
658
  },
659
659
  {
660
660
  name: "writing-skills",
661
661
  file: "assets/skills/writing-skills/SKILL.md",
662
662
  description: "Skill de creación y edición de skills",
663
- version: "0.7.0",
663
+ version: "0.7.1",
664
664
  sha256: "3d76b906cee518a2b809febb70db95697a35b9f368986bb504b4120c3bfb437a"
665
665
  },
666
666
  {
667
667
  name: "graceful-degradation",
668
668
  file: "assets/skills/graceful-degradation/SKILL.md",
669
669
  description: "Skill de degradación graceful cuando múltiples tools están indisponibles",
670
- version: "0.7.0",
670
+ version: "0.7.1",
671
671
  sha256: "e5090e475729f21871bb25bce738000f3616955ed3edb3ba926dd740d3298948"
672
672
  }
673
673
  ]
@@ -1045,7 +1045,8 @@ __export(exports_stack, {
1045
1045
  installEngram: () => installEngram,
1046
1046
  installCodeGraph: () => installCodeGraph,
1047
1047
  buildLocalMcpCommand: () => buildLocalMcpCommand,
1048
- buildEngramDownloadUrl: () => buildEngramDownloadUrl
1048
+ buildEngramDownloadUrl: () => buildEngramDownloadUrl,
1049
+ OPENSPEC_NPM_PACKAGE: () => OPENSPEC_NPM_PACKAGE
1049
1050
  });
1050
1051
  import { chmodSync, copyFileSync as copyFileSync3, existsSync as existsSync6, mkdirSync as mkdirSync4, rmSync as rmSync4, unlinkSync as unlinkSync3 } from "fs";
1051
1052
  import { basename as basename2, dirname as dirname5, join as join7, resolve as resolve2 } from "path";
@@ -1185,20 +1186,56 @@ async function installCodeGraph(toolsDir) {
1185
1186
  }
1186
1187
  function setupOpenSpec(projectRoot = findProjectRoot()) {
1187
1188
  const useBun = isCommandAvailable("bun");
1188
- try {
1189
- const invocation = getCommandInvocation(useBun ? "bunx" : "npx", useBun ? ["openspec", "init", "--tools", "opencode", "--force"] : ["--yes", "openspec", "init", "--tools", "opencode", "--force"]);
1190
- execFileSync3(invocation.command, invocation.args, {
1191
- stdio: "pipe",
1192
- timeout: 120000,
1193
- cwd: projectRoot
1194
- });
1189
+ const fail = (msg) => ({ success: false, message: msg });
1190
+ const tryDirect = () => {
1191
+ try {
1192
+ const invocation = getCommandInvocation(useBun ? "bunx" : "npx", useBun ? [OPENSPEC_NPM_PACKAGE, "init", "--tools", "opencode", "--force"] : ["--yes", OPENSPEC_NPM_PACKAGE, "init", "--tools", "opencode", "--force"]);
1193
+ execFileSync3(invocation.command, invocation.args, {
1194
+ stdio: "pipe",
1195
+ timeout: 120000,
1196
+ cwd: projectRoot
1197
+ });
1198
+ return true;
1199
+ } catch {
1200
+ return false;
1201
+ }
1202
+ };
1203
+ const tryInstallGlobal = () => {
1204
+ if (!useBun && !isCommandAvailable("npm")) {
1205
+ return { ok: false, error: "Ni bun ni npm están disponibles para instalar OpenSpec globalmente" };
1206
+ }
1207
+ const pkgManager = useBun ? "bun" : "npm";
1208
+ const installArgs = useBun ? ["add", "-g", OPENSPEC_NPM_PACKAGE] : ["install", "-g", OPENSPEC_NPM_PACKAGE];
1209
+ try {
1210
+ const invocation = getCommandInvocation(pkgManager, installArgs);
1211
+ execFileSync3(invocation.command, invocation.args, { stdio: "pipe", timeout: 120000 });
1212
+ } catch (installErr) {
1213
+ return { ok: false, error: `Instalación global falló: ${installErr.message}` };
1214
+ }
1215
+ try {
1216
+ const retryInvocation = getCommandInvocation("openspec", ["init", "--tools", "opencode", "--force"]);
1217
+ execFileSync3(retryInvocation.command, retryInvocation.args, {
1218
+ stdio: "pipe",
1219
+ timeout: 120000,
1220
+ cwd: projectRoot
1221
+ });
1222
+ return { ok: true };
1223
+ } catch (retryErr) {
1224
+ return { ok: false, error: `Reintento con binario global falló: ${retryErr.message}` };
1225
+ }
1226
+ };
1227
+ if (tryDirect()) {
1195
1228
  return { success: true, message: "OpenSpec configurado para OpenCode" };
1196
- } catch (e2) {
1229
+ }
1230
+ const fallback = tryInstallGlobal();
1231
+ if (fallback.ok) {
1197
1232
  return {
1198
- success: false,
1199
- message: `Error configurando OpenSpec: ${e2.message}`
1233
+ success: true,
1234
+ message: `OpenSpec configurado para OpenCode (binario instalado globalmente con ${useBun ? "bun" : "npm"})`
1200
1235
  };
1201
1236
  }
1237
+ const manualCmd = useBun ? `bun add -g ${OPENSPEC_NPM_PACKAGE}` : `npm install -g ${OPENSPEC_NPM_PACKAGE}`;
1238
+ return fail(`Error configurando OpenSpec: ni bunx/npx ni la instalación global resolvieron el binario. ` + `Solución manual: ejecuta \`${manualCmd}\` y luego corré /install-stack de nuevo. ` + `Detalle: ${fallback.error}`);
1202
1239
  }
1203
1240
  async function installEngram(toolsDir) {
1204
1241
  const location = resolveToolInstallLocation(toolsDir);
@@ -1422,6 +1459,7 @@ function verifyMcpServers(projectRoot) {
1422
1459
  }
1423
1460
  return result;
1424
1461
  }
1462
+ var OPENSPEC_NPM_PACKAGE = "@fission-ai/openspec";
1425
1463
  var init_stack = __esm(() => {
1426
1464
  init_fs();
1427
1465
  init_config();
@@ -1430,7 +1468,7 @@ var init_stack = __esm(() => {
1430
1468
  // package.json
1431
1469
  var package_default = {
1432
1470
  name: "ostacky",
1433
- version: "0.7.0",
1471
+ version: "0.7.1",
1434
1472
  description: "Instalador interactivo de agentes y comandos para OpenCode",
1435
1473
  type: "module",
1436
1474
  bin: {
@@ -2486,7 +2524,13 @@ function validateMcpModule(nodeExecutable, serverPath, cwd) {
2486
2524
  throw new Error(`El MCP no pasó la validación de carga: ${error.message}`);
2487
2525
  }
2488
2526
  }
2489
- async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath) {
2527
+ var DEFAULT_PROBE_OPTIONS = {
2528
+ requiredTools: ["ping", "start_request"],
2529
+ exerciseWrite: true
2530
+ };
2531
+ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath, options = {}) {
2532
+ const requiredTools = options.requiredTools ?? DEFAULT_PROBE_OPTIONS.requiredTools;
2533
+ const exerciseWrite = options.exerciseWrite ?? requiredTools.includes("start_request");
2490
2534
  try {
2491
2535
  await new Promise((resolve2, reject) => {
2492
2536
  const child = spawn(nodeExecutable, [serverPath], {
@@ -2555,17 +2599,22 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath) {
2555
2599
  }
2556
2600
  if (message.id === 2) {
2557
2601
  const tools = message.result?.tools ?? [];
2558
- if (!tools.some((tool) => tool.name === "ping") || !tools.some((tool) => tool.name === "start_request")) {
2559
- fail("El MCP inició pero no expuso las tools requeridas");
2602
+ const missing = requiredTools.filter((name) => !tools.some((tool) => tool.name === name));
2603
+ if (missing.length > 0) {
2604
+ fail(`El MCP inició pero no expuso las tools requeridas: ${missing.join(", ")}`);
2560
2605
  return;
2561
2606
  }
2562
- send({
2563
- jsonrpc: "2.0",
2564
- id: 3,
2565
- method: "tools/call",
2566
- params: { name: "start_request", arguments: { requestId: "installer-probe" } }
2567
- });
2568
- continue;
2607
+ if (exerciseWrite) {
2608
+ send({
2609
+ jsonrpc: "2.0",
2610
+ id: 3,
2611
+ method: "tools/call",
2612
+ params: { name: "start_request", arguments: { requestId: "installer-probe" } }
2613
+ });
2614
+ continue;
2615
+ }
2616
+ finish();
2617
+ return;
2569
2618
  }
2570
2619
  if (message.id === 3) {
2571
2620
  const result = message.result;
@@ -2584,7 +2633,7 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath) {
2584
2633
  params: {
2585
2634
  protocolVersion: "2025-03-26",
2586
2635
  capabilities: {},
2587
- clientInfo: { name: "ostacky-installer", version: "0.7.0" }
2636
+ clientInfo: { name: "ostacky-installer", version: "0.7.1" }
2588
2637
  }
2589
2638
  });
2590
2639
  });
@@ -2754,7 +2803,9 @@ async function installMcpServer(item, manifest, paths) {
2754
2803
  throw new Error(`El MCP ${item.name} no contiene index.js después de instalarse.`);
2755
2804
  }
2756
2805
  validateMcpModule(nodeExecutable, stagedServerPath, staging);
2757
- await probeMcpServer(nodeExecutable, stagedServerPath, staging, item.name === "ostacky-controller" ? join6(staging, ".probe-state.json") : undefined);
2806
+ const isController = item.name === "ostacky-controller";
2807
+ const probeOptions = isController ? { requiredTools: ["ping", "start_request"], exerciseWrite: true } : { requiredTools: [], exerciseWrite: false };
2808
+ await probeMcpServer(nodeExecutable, stagedServerPath, staging, isController ? join6(staging, ".probe-state.json") : undefined, probeOptions);
2758
2809
  const configPath = findOpenCodeConfig(projectRoot) ?? join6(projectRoot, "opencode.json");
2759
2810
  const configSnapshot = takeFileSnapshot(configPath);
2760
2811
  const lockfileSnapshot = takeFileSnapshot(getLockfilePath(paths.root));
package/manifest.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
- "version": "0.7.0",
2
+ "version": "0.7.1",
3
3
  "repo": "JaimeHoracio/Ostacky",
4
- "tag": "v0.7.0",
4
+ "tag": "v0.7.1",
5
5
  "agents": [
6
6
  {
7
7
  "name": "ostacky",
8
8
  "file": "assets/agents/ostacky.md",
9
- "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.7.0: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
10
- "version": "0.7.0",
9
+ "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.7.1: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
10
+ "version": "0.7.1",
11
11
  "sha256": "f833e69b6eaa3dfe24de9addf6455b3da55f829b51cba3c7c90c65c69cda34c2"
12
12
  }
13
13
  ],
@@ -15,15 +15,15 @@
15
15
  {
16
16
  "name": "install-stack",
17
17
  "file": "assets/commands/install-stack.md",
18
- "description": "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, Context7, controller MCP con SDK oficial). v0.7.0: Paso 1.5 controller expandido con verificación post-instalación y troubleshooting.",
19
- "version": "0.7.0",
20
- "sha256": "c957627dfafabfdb9da2717546b996d1d8856f08a6e4c48caf72c562363b566b"
18
+ "description": "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, Context7, controller MCP con SDK oficial). v0.7.1: Paso 1.5 controller expandido con verificación post-instalación y troubleshooting.",
19
+ "version": "0.7.1",
20
+ "sha256": "ef4244855cf733dfe50a2a8e7c436c5741f92574cc50f0fca49faed60480e013"
21
21
  },
22
22
  {
23
23
  "name": "opsx-sync",
24
24
  "file": "assets/commands/opsx-sync.md",
25
25
  "description": "Sincroniza delta specs del change activo sin inicializar CodeGraph si ya existe índice",
26
- "version": "0.7.0",
26
+ "version": "0.7.1",
27
27
  "sha256": "fe0158478f2ca63b315037a85fc1632b77868532e319af6c7384285441767d64"
28
28
  }
29
29
  ],
@@ -31,15 +31,15 @@
31
31
  {
32
32
  "name": "ostacky-controller",
33
33
  "file": "assets/mcp/ostacky-controller/",
34
- "description": "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.7.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.",
35
- "version": "0.7.0",
36
- "sha256": "0ec6fa0fc2900c78b884258168309653dea4b77ded3596bb56866f689ec2404c"
34
+ "description": "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.7.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.",
35
+ "version": "0.7.1",
36
+ "sha256": "0e639fb1d5bedf8b93b4e259782b9b7de68cd4bb89875e2c546279d17131b7b7"
37
37
  },
38
38
  {
39
39
  "name": "openspec",
40
40
  "file": "assets/mcp/openspec/",
41
41
  "description": "MCP server local para OpenSpec - proposal, apply, archive, sync de cambios",
42
- "version": "0.7.0",
42
+ "version": "0.7.1",
43
43
  "sha256": "fa4be28bfc1e75db8f1a037e2580f04a60066c80e8e5934e90e1041020d04609"
44
44
  }
45
45
  ],
@@ -48,105 +48,105 @@
48
48
  "name": "brainstorming",
49
49
  "file": "assets/skills/brainstorming/SKILL.md",
50
50
  "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)",
51
- "version": "0.7.0",
51
+ "version": "0.7.1",
52
52
  "sha256": "333810ca63450e8ab795e8c5a58e645101e788d79210ca8ac36e10d11be39585"
53
53
  },
54
54
  {
55
55
  "name": "execution-mode-evaluation",
56
56
  "file": "assets/skills/execution-mode-evaluation/SKILL.md",
57
57
  "description": "Skill de análisis de modo de ejecución — output reconciliado con controller snapshot contract (recommendation field)",
58
- "version": "0.7.0",
58
+ "version": "0.7.1",
59
59
  "sha256": "edf6fca0af52cce83f8fd08e7db9b3d79cc130b53fca505e90d3fbaf4909338b"
60
60
  },
61
61
  {
62
62
  "name": "tdd",
63
63
  "file": "assets/skills/tdd/SKILL.md",
64
64
  "description": "Skill de test-driven development (Superpowers)",
65
- "version": "0.7.0",
65
+ "version": "0.7.1",
66
66
  "sha256": "aa412298980b7826165c211145c1b8e9135f68f36247bb3cb96d0a0eae274486"
67
67
  },
68
68
  {
69
69
  "name": "subagent-driven-development",
70
70
  "file": "assets/skills/subagent-driven-development/SKILL.md",
71
71
  "description": "Skill de ejecución con subagentes (Superpowers) — ejecuta solo después de confirmación del coordinador Ostacky",
72
- "version": "0.7.0",
72
+ "version": "0.7.1",
73
73
  "sha256": "1a42d714a9a13faf05f0bf7b580e8d837c2e77a5633839542ccce603023419e8"
74
74
  },
75
75
  {
76
76
  "name": "dispatching-parallel-agents",
77
77
  "file": "assets/skills/dispatching-parallel-agents/SKILL.md",
78
78
  "description": "Skill de dispatch paralelo de agentes (Superpowers)",
79
- "version": "0.7.0",
79
+ "version": "0.7.1",
80
80
  "sha256": "3c8a66d51ae2e719e877d02c3dac32bd804722c3bb9227c258ecae78252a20ab"
81
81
  },
82
82
  {
83
83
  "name": "review",
84
84
  "file": "assets/skills/review/SKILL.md",
85
85
  "description": "Skill de revisión de código (Superpowers)",
86
- "version": "0.7.0",
86
+ "version": "0.7.1",
87
87
  "sha256": "b19650ed4d1d4d9857a4dd5b7e08e91328a1a1fc9c45bcc2fb600fa9d0213279"
88
88
  },
89
89
  {
90
90
  "name": "receiving-code-review",
91
91
  "file": "assets/skills/receiving-code-review/SKILL.md",
92
92
  "description": "Skill de recibir y procesar feedback de code review",
93
- "version": "0.7.0",
93
+ "version": "0.7.1",
94
94
  "sha256": "d761e884e71d8d3476ac734d287cae403a4024506a7d12e7361a448217c0a831"
95
95
  },
96
96
  {
97
97
  "name": "openspec-propose",
98
98
  "file": "assets/skills/openspec-propose/SKILL.md",
99
99
  "description": "Skill de generación de proposal (OpenSpec)",
100
- "version": "0.7.0",
100
+ "version": "0.7.1",
101
101
  "sha256": "bb59100b9fd3c9f9a1ec6509fa975ec55bf7fc737df4fe73bb3e9bbc217b83f7"
102
102
  },
103
103
  {
104
104
  "name": "openspec-apply-change",
105
105
  "file": "assets/skills/openspec-apply-change/SKILL.md",
106
106
  "description": "Skill de aplicación de change (OpenSpec)",
107
- "version": "0.7.0",
107
+ "version": "0.7.1",
108
108
  "sha256": "dfc823bf89fc7505e91ab6dee9c1f004be38a410bd3d88fb67b211b1b6cbb1d0"
109
109
  },
110
110
  {
111
111
  "name": "openspec-archive-change",
112
112
  "file": "assets/skills/openspec-archive-change/SKILL.md",
113
113
  "description": "Skill de archivo de change (OpenSpec)",
114
- "version": "0.7.0",
114
+ "version": "0.7.1",
115
115
  "sha256": "16e4b561de7747283663fed602e506abf502452c49a8d4b86d7a5539c40f0195"
116
116
  },
117
117
  {
118
118
  "name": "openspec-explore",
119
119
  "file": "assets/skills/openspec-explore/SKILL.md",
120
120
  "description": "Modo explore para OpenSpec — thinking partner para explorar ideas, investigar problemas y clarificar requisitos antes/durante un cambio",
121
- "version": "0.7.0",
121
+ "version": "0.7.1",
122
122
  "sha256": "37ae4aaf17ea71a395bab6dc4d9d61b9a49d7910f6692535ae8553244c46880b"
123
123
  },
124
124
  {
125
125
  "name": "using-git-worktrees",
126
126
  "file": "assets/skills/using-git-worktrees/SKILL.md",
127
127
  "description": "Skill de uso de git worktrees para aislamiento de trabajo",
128
- "version": "0.7.0",
128
+ "version": "0.7.1",
129
129
  "sha256": "11afa9123828fc5caa22137aff907cd99c751e99027fbd4c020751110a949281"
130
130
  },
131
131
  {
132
132
  "name": "using-superpowers",
133
133
  "file": "assets/skills/using-superpowers/SKILL.md",
134
134
  "description": "Skill de orquestación de Superpowers skills",
135
- "version": "0.7.0",
135
+ "version": "0.7.1",
136
136
  "sha256": "7e54536f96d2a379185a10bfc1e970850caa2561b6d8aca7080f0defea0381a4"
137
137
  },
138
138
  {
139
139
  "name": "writing-skills",
140
140
  "file": "assets/skills/writing-skills/SKILL.md",
141
141
  "description": "Skill de creación y edición de skills",
142
- "version": "0.7.0",
142
+ "version": "0.7.1",
143
143
  "sha256": "3d76b906cee518a2b809febb70db95697a35b9f368986bb504b4120c3bfb437a"
144
144
  },
145
145
  {
146
146
  "name": "graceful-degradation",
147
147
  "file": "assets/skills/graceful-degradation/SKILL.md",
148
148
  "description": "Skill de degradación graceful cuando múltiples tools están indisponibles",
149
- "version": "0.7.0",
149
+ "version": "0.7.1",
150
150
  "sha256": "e5090e475729f21871bb25bce738000f3616955ed3edb3ba926dd740d3298948"
151
151
  }
152
152
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ostacky",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Instalador interactivo de agentes y comandos para OpenCode",
5
5
  "type": "module",
6
6
  "bin": {