ostacky 0.8.2 → 0.8.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/dist/cli.js CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { createRequire } from "node:module";
3
2
  var __create = Object.create;
4
3
  var __getProtoOf = Object.getPrototypeOf;
5
4
  var __defProp = Object.defineProperty;
@@ -19,7 +18,7 @@ var __toESM = (mod, isNodeMode, target) => {
19
18
  return cached;
20
19
  }
21
20
  target = mod != null ? __create(__getProtoOf(mod)) : {};
22
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
21
+ const to = isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
23
22
  if (mod && typeof mod === "object" || typeof mod === "function") {
24
23
  for (let key of __getOwnPropNames(mod))
25
24
  if (!__hasOwnProp.call(to, key))
@@ -46,8 +45,17 @@ var __export = (target, all) => {
46
45
  set: __exportSetter.bind(all, name)
47
46
  });
48
47
  };
49
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
50
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
48
+ var __esm = (fn, res, err) => () => {
49
+ if (fn)
50
+ try {
51
+ res = fn(fn = 0);
52
+ } catch (e) {
53
+ err = [e];
54
+ }
55
+ if (err)
56
+ throw err[0];
57
+ return res;
58
+ };
51
59
 
52
60
  // node_modules/sisteransi/src/index.js
53
61
  var require_src = __commonJS(function(exports, module) {
@@ -178,17 +186,6 @@ var require_picocolors = __commonJS(function(exports, module) {
178
186
  });
179
187
 
180
188
  // src/security.ts
181
- var exports_security = {};
182
- __export(exports_security, {
183
- BASH_SENSITIVE_RE: () => BASH_SENSITIVE_RE,
184
- SENSITIVE_DEFAULT: () => SENSITIVE_DEFAULT,
185
- extractPathsFromBash: () => extractPathsFromBash,
186
- getSensitivePatterns: () => getSensitivePatterns,
187
- isSensitive: () => isSensitive,
188
- sha256: () => sha256,
189
- validateFilePath: () => validateFilePath,
190
- verifyChecksum: () => verifyChecksum
191
- });
192
189
  import { createHash } from "crypto";
193
190
  function validateFilePath(filePath) {
194
191
  if (filePath.includes("..") || filePath.startsWith("/") || filePath.startsWith("\\") || /^[a-zA-Z]:/.test(filePath)) {
@@ -208,124 +205,13 @@ function verifyChecksum(content, expectedHash, label) {
208
205
  recibido: ${actual}`);
209
206
  }
210
207
  }
211
- function isSensitive(filePath, patterns = SENSITIVE_DEFAULT) {
212
- if (!filePath)
213
- return false;
214
- const normalized = filePath.replace(/\\/g, "/");
215
- const lower = normalized.toLowerCase();
216
- if (lower.endsWith(".env.example") || lower.endsWith(".env.template") || lower.endsWith(".env.sample"))
217
- return false;
218
- const base = lower.split("/").pop() || "";
219
- for (const pat of patterns) {
220
- if (pat.includes(".env") && base.startsWith(".env"))
221
- return true;
222
- if (pat.includes(".secrets") && lower.includes(".secrets"))
223
- return true;
224
- if (pat.includes("*.pem") && lower.endsWith(".pem"))
225
- return true;
226
- if (pat.includes("*.key") && lower.endsWith(".key"))
227
- return true;
228
- if (pat.includes(".aws") && lower.includes(".aws"))
229
- return true;
230
- if (pat.includes(".ssh") && lower.includes(".ssh"))
231
- return true;
232
- if (pat.includes("credentials.json") && lower.endsWith("credentials.json"))
233
- return true;
234
- if (pat.includes(".npmrc") && lower.endsWith(".npmrc"))
235
- return true;
236
- }
237
- if (/\.(pem|key)$/i.test(normalized))
238
- return true;
239
- if (base.startsWith(".env"))
240
- return true;
241
- return false;
242
- }
243
- function extractPathsFromBash(cmd) {
244
- if (!cmd)
245
- return [];
246
- const normalized = cmd.replace(/&&/g, ";").replace(/\|\|/g, ";");
247
- const segments = normalized.split(/[|;><\n]+/);
248
- const paths = [];
249
- for (const seg of segments) {
250
- const trimmed = seg.trim();
251
- if (!trimmed)
252
- continue;
253
- const tokens = trimmed.match(/(?:[^\s"'`\\]+|"[^"]*"|'[^']*'|`[^`]*`)+/g) || [];
254
- for (let token of tokens) {
255
- const stripped = token.replace(/["'`]/g, "").replace(/\\/g, "");
256
- if (!stripped)
257
- continue;
258
- if (["cat", "grep", "ls", "echo", "awk", "sed", "cut", "head", "tail", "wc", "find", "xargs", "bash", "sh", "zsh", "env", "printenv", "node", "bun", "npm", "npx", "ls"].includes(stripped))
259
- continue;
260
- if (stripped.startsWith("-"))
261
- continue;
262
- const lower = stripped.toLowerCase();
263
- if (stripped.includes("/") || stripped.includes(".") || lower.startsWith(".env") || lower.includes(".secrets") || lower.endsWith(".pem") || lower.endsWith(".key") || lower.includes(".aws") || lower.includes(".ssh") || lower.endsWith("credentials.json") || lower.endsWith(".npmrc")) {
264
- const cleaned = stripped.replace(/[,:;)\]]+$/, "");
265
- if (cleaned)
266
- paths.push(cleaned);
267
- } else if (stripped === ".env") {
268
- paths.push(stripped);
269
- }
270
- }
271
- }
272
- return [...new Set(paths)];
273
- }
274
- function getSensitivePatterns() {
275
- const raw = process.env.OSTACKY_SENSITIVE_PATTERNS;
276
- if (!raw)
277
- return SENSITIVE_DEFAULT;
278
- return raw.split(",").map((s) => s.trim()).filter(Boolean);
279
- }
280
- var SENSITIVE_DEFAULT, BASH_SENSITIVE_RE;
281
- var init_security = __esm(() => {
282
- SENSITIVE_DEFAULT = [
283
- "**/.env*",
284
- "**/.secrets/**",
285
- "**/*.pem",
286
- "**/*.key",
287
- "**/.aws/**",
288
- "**/.ssh/**",
289
- "**/credentials.json",
290
- "**/.npmrc"
291
- ];
292
- BASH_SENSITIVE_RE = /(?:^|[^a-zA-Z0-9_.-])(\.env(\b|[_.-])|\.secrets\b|\.pem\b|\.key\b|credentials\.json|\.aws\b|\.ssh\b|\.npmrc\b)/i;
293
- });
208
+ var init_security = () => {};
294
209
 
295
210
  // 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
- });
326
211
  import {
327
212
  existsSync,
328
213
  mkdirSync,
214
+ writeFileSync,
329
215
  unlinkSync,
330
216
  readdirSync,
331
217
  statSync,
@@ -336,9 +222,8 @@ import {
336
222
  renameSync
337
223
  } from "fs";
338
224
  import { createHash as createHash2 } from "crypto";
339
- import { join, resolve, dirname, relative, basename, win32 } from "path";
225
+ import { join, resolve, dirname, relative, basename } from "path";
340
226
  import { execFileSync } from "child_process";
341
- import { homedir } from "os";
342
227
  function findOpenCodeDir(startDir = process.cwd()) {
343
228
  let current = resolve(startDir);
344
229
  while (true) {
@@ -370,47 +255,11 @@ function findProjectRoot(startDir = process.cwd()) {
370
255
  current = parent;
371
256
  }
372
257
  }
373
- function getGlobalOpenCodeDir(platform = process.platform, home = homedir()) {
374
- if (platform === "win32") {
375
- const appData = process.env.APPDATA ?? win32.join(home, "AppData", "Roaming");
376
- return win32.join(appData, "opencode");
377
- }
378
- const xdg = process.env.XDG_CONFIG_HOME ?? join(home, ".config");
379
- return join(xdg, "opencode");
380
- }
381
258
  function getOpenCodeDirForScope(scope, cwd = process.cwd()) {
382
- if (scope === "global")
383
- return getGlobalOpenCodeDir();
384
- if (scope === "local") {
385
- const existing2 = findOpenCodeDir(cwd);
386
- if (existing2)
387
- return existing2;
388
- return join(findProjectRoot(cwd), ".opencode");
389
- }
390
259
  const existing = findOpenCodeDir(cwd);
391
260
  if (existing)
392
261
  return existing;
393
- const root = findProjectRoot(cwd);
394
- if (existsSync(join(root, ".opencode")) || existsSync(join(root, ".git"))) {
395
- return join(root, ".opencode");
396
- }
397
- return getGlobalOpenCodeDir();
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;
262
+ return join(findProjectRoot(cwd), ".opencode");
414
263
  }
415
264
  function ensureOpenCodePaths(opencodeDir) {
416
265
  const paths = {
@@ -435,9 +284,6 @@ function ensureToolDirs(toolsDir, toolNames) {
435
284
  mkdirSync(dir, { recursive: true });
436
285
  }
437
286
  }
438
- function createOpenCodeDir(baseDir) {
439
- return ensureOpenCodePaths(join(baseDir, ".opencode"));
440
- }
441
287
  function copyDirRecursive(src, dest, skipGenerated = false) {
442
288
  if (!existsSync(dest))
443
289
  mkdirSync(dest, { recursive: true });
@@ -498,44 +344,6 @@ function findExecutablePath(cmd) {
498
344
  return null;
499
345
  }
500
346
  }
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
- }
539
347
  function detectPlatformTarget(platform = process.platform, arch = process.arch) {
540
348
  let os;
541
349
  let cpu;
@@ -620,7 +428,7 @@ function promoteStagedDirectory(stagedDir, destinationDir) {
620
428
  };
621
429
  }
622
430
  function downloadToFile(url, dest, timeoutMs = 180000) {
623
- return new Promise((resolve2, reject) => {
431
+ return new Promise((resolve, reject) => {
624
432
  const controller = new AbortController;
625
433
  const timer = setTimeout(() => controller.abort(), timeoutMs);
626
434
  fetch(url, { signal: controller.signal, headers: { "User-Agent": USER_AGENT } }).then((res) => {
@@ -636,7 +444,7 @@ function downloadToFile(url, dest, timeoutMs = 180000) {
636
444
  reject(error);
637
445
  };
638
446
  file.once("error", fail);
639
- file.once("finish", resolve2);
447
+ file.once("finish", resolve);
640
448
  const writable = new WritableStream({
641
449
  write(chunk) {
642
450
  return new Promise((ok, failWrite) => file.write(Buffer.from(chunk), (err) => err ? failWrite(err) : ok()));
@@ -657,23 +465,6 @@ function downloadToFile(url, dest, timeoutMs = 180000) {
657
465
  });
658
466
  });
659
467
  }
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
- }
677
468
  async function downloadAndExtract(url, destDir, stripComponents = 1, timeoutMs = 180000) {
678
469
  const tmp = join(dirname(destDir), `.${basename(destDir)}.download-${Date.now()}-${process.pid}`);
679
470
  if (!existsSync(tmp))
@@ -714,7 +505,7 @@ async function downloadAndExtractWithRetry(url, destDir, stripComponents = 1, ti
714
505
  if (attempt < maxRetries && shouldRetryDownload(lastError)) {
715
506
  const delay = 1000 * Math.pow(2, attempt);
716
507
  console.error(`[download] Intento ${attempt + 1} falló: ${lastError.message}. Reintentando en ${delay}ms...`);
717
- await new Promise((r2) => setTimeout(r2, delay));
508
+ await new Promise((r) => setTimeout(r, delay));
718
509
  }
719
510
  }
720
511
  }
@@ -735,40 +526,126 @@ function findBinaryInDir(dir, name) {
735
526
  }
736
527
  return null;
737
528
  }
738
- var USER_AGENT = "ostacky-installer";
529
+ function ensureGitignore(projectRoot = findProjectRoot()) {
530
+ const gitignorePath = join(projectRoot, ".gitignore");
531
+ const patternsAdded = [];
532
+ let created = false;
533
+ let updated = false;
534
+ let raw = "";
535
+ if (existsSync(gitignorePath)) {
536
+ raw = readFileSync(gitignorePath, "utf-8");
537
+ } else {
538
+ created = true;
539
+ }
540
+ const hasHeader = raw.includes(OSTACKY_GITIGNORE_HEADER);
541
+ const missingPatterns = OSTACKY_GITIGNORE_PATTERNS.filter((p) => !raw.includes(p));
542
+ if (missingPatterns.length === 0 && hasHeader) {
543
+ if (raw.length > 0 && !raw.endsWith(`
544
+ `)) {
545
+ writeFileSync(gitignorePath, raw + `
546
+ `, "utf-8");
547
+ updated = true;
548
+ }
549
+ return { created, updated, patternsAdded };
550
+ }
551
+ if (!hasHeader) {
552
+ const needsNewline = raw.length > 0 && !raw.endsWith(`
553
+ `);
554
+ const block = [OSTACKY_GITIGNORE_HEADER, ...OSTACKY_GITIGNORE_PATTERNS].join(`
555
+ `) + `
556
+ `;
557
+ const newContent = raw + (needsNewline ? `
558
+ ` : raw.length > 0 ? "" : "") + block;
559
+ let final = "";
560
+ if (raw.length === 0) {
561
+ final = block;
562
+ } else if (raw.endsWith(`
563
+ `)) {
564
+ final = raw + block;
565
+ } else {
566
+ final = raw + `
567
+ ` + block;
568
+ }
569
+ writeFileSync(gitignorePath, final, "utf-8");
570
+ patternsAdded.push(...missingPatterns.length ? missingPatterns : [...OSTACKY_GITIGNORE_PATTERNS]);
571
+ updated = true;
572
+ return { created, updated, patternsAdded };
573
+ }
574
+ const lines = raw.split(`
575
+ `);
576
+ const headerIdx = lines.findIndex((l) => l.trim() === OSTACKY_GITIGNORE_HEADER);
577
+ if (headerIdx !== -1) {
578
+ let insertIdx = headerIdx + 1;
579
+ while (insertIdx < lines.length && (OSTACKY_GITIGNORE_PATTERNS.some((p) => lines[insertIdx].trim() === p) || lines[insertIdx].trim() === "")) {
580
+ insertIdx++;
581
+ }
582
+ lines.splice(insertIdx, 0, ...missingPatterns);
583
+ const newContent = lines.join(`
584
+ `);
585
+ const finalContent = newContent.endsWith(`
586
+ `) ? newContent : newContent + `
587
+ `;
588
+ writeFileSync(gitignorePath, finalContent, "utf-8");
589
+ patternsAdded.push(...missingPatterns);
590
+ updated = true;
591
+ } else {
592
+ const newContent = raw.endsWith(`
593
+ `) ? raw + missingPatterns.join(`
594
+ `) + `
595
+ ` : raw + `
596
+ ` + missingPatterns.join(`
597
+ `) + `
598
+ `;
599
+ writeFileSync(gitignorePath, newContent, "utf-8");
600
+ patternsAdded.push(...missingPatterns);
601
+ updated = true;
602
+ }
603
+ return { created, updated, patternsAdded };
604
+ }
605
+ var USER_AGENT = "ostacky-installer", OSTACKY_GITIGNORE_PATTERNS, OSTACKY_GITIGNORE_HEADER = "# Ostacky";
739
606
  var init_fs = __esm(() => {
740
607
  init_security();
608
+ OSTACKY_GITIGNORE_PATTERNS = [
609
+ ".opencode/tools/",
610
+ ".opencode/cache/",
611
+ ".opencode/ostacky-state.json",
612
+ ".opencode/ostacky-state.json.backup*",
613
+ ".opencode/ostacky-state.json.lock.*",
614
+ ".opencode/ostacky-audit.jsonl",
615
+ ".codegraph/",
616
+ "openspec/"
617
+ ];
741
618
  });
742
619
 
743
620
  // manifest.json
744
621
  var manifest_default;
745
622
  var init_manifest = __esm(() => {
746
623
  manifest_default = {
747
- version: "0.8.2",
624
+ version: "0.8.3",
748
625
  repo: "JaimeHoracio/Ostacky",
749
- tag: "v0.8.2",
626
+ tag: "v0.8.3",
750
627
  agents: [
751
628
  {
752
629
  name: "ostacky",
753
630
  file: "assets/agents/ostacky.md",
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.2: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
755
- version: "0.8.2",
756
- sha256: "7b2be94d05cd371fab5be5844ef7d82e542e84c2869d8171ccd63dc14e922dc3"
631
+ 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.3: prune de skills obsoletas, lastHandoff, getAvailableTransitions, consecutiveFailures real, mem_session_summary automático al cierre.",
632
+ version: "0.8.3",
633
+ sha256: "b32ec792c01d1f2c4dac58c4de752e4d30f5df8315b33512f4a7efc15a7380eb"
757
634
  }
758
635
  ],
759
636
  commands: [
760
637
  {
761
638
  name: "install-stack",
762
639
  file: "assets/commands/install-stack.md",
763
- description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.8.2: controller plugin como alma hard-gate, Context7 removido del stack.",
764
- version: "0.8.2",
640
+ description: "Instala el stack tecnológico del proyecto (CodeGraph, skills, OpenSpec, Engram, controller plugin). v0.8.3: controller plugin como alma hard-gate, Context7 removido del stack.",
641
+ version: "0.8.3",
765
642
  sha256: "24802dc29675a584dacf4d0ac8a944dd935ee0f96a4e804a9b1c5bdb3709438c"
766
643
  },
767
644
  {
768
645
  name: "opsx-sync",
769
646
  file: "assets/commands/opsx-sync.md",
770
647
  description: "Sincroniza delta specs del change activo sin inicializar CodeGraph si ya existe índice",
771
- version: "0.8.2",
648
+ version: "0.8.3",
772
649
  sha256: "fe0158478f2ca63b315037a85fc1632b77868532e319af6c7384285441767d64"
773
650
  }
774
651
  ],
@@ -776,15 +653,15 @@ var init_manifest = __esm(() => {
776
653
  {
777
654
  name: "ostacky-controller",
778
655
  file: "assets/mcp/ostacky-controller/",
779
- description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.8.2: 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.2",
781
- sha256: "a9d45b027a88e8037a4e29704b84f78a1d03d41654ba7445a3091a0c6767d094"
656
+ description: "Máquina de estados persistida con @modelcontextprotocol/server SDK. v0.8.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.",
657
+ version: "0.8.3",
658
+ sha256: "da929dae61b9caa0b818ee1c69c5573075d84cb8d31da6910888fc5b6163a0d1"
782
659
  },
783
660
  {
784
661
  name: "openspec",
785
662
  file: "assets/mcp/openspec/",
786
663
  description: "MCP server local para OpenSpec - proposal, apply, archive, sync de cambios",
787
- version: "0.8.2",
664
+ version: "0.8.3",
788
665
  sha256: "fa4be28bfc1e75db8f1a037e2580f04a60066c80e8e5934e90e1041020d04609"
789
666
  }
790
667
  ],
@@ -793,105 +670,105 @@ var init_manifest = __esm(() => {
793
670
  name: "brainstorming",
794
671
  file: "assets/skills/brainstorming/SKILL.md",
795
672
  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)",
796
- version: "0.8.2",
797
- sha256: "4c54604d4680bc695b7049c70cf8680296d8d2602e5790ddfc1cce7ba7c6f1fc"
673
+ version: "0.8.3",
674
+ sha256: "f1013a86a8f27914d85a716e23c7fd32db1786d93615e8b0834b13d184308549"
798
675
  },
799
676
  {
800
677
  name: "execution-mode-evaluation",
801
678
  file: "assets/skills/execution-mode-evaluation/SKILL.md",
802
679
  description: "Skill de análisis de modo de ejecución — output reconciliado con controller snapshot contract (recommendation field)",
803
- version: "0.8.2",
680
+ version: "0.8.3",
804
681
  sha256: "7b89dda29927c88f1eb13ffcea541a12423384c172f66c4f3d9b61efe0c7a163"
805
682
  },
806
683
  {
807
684
  name: "tdd",
808
685
  file: "assets/skills/tdd/SKILL.md",
809
686
  description: "Skill de test-driven development (Superpowers)",
810
- version: "0.8.2",
687
+ version: "0.8.3",
811
688
  sha256: "aa412298980b7826165c211145c1b8e9135f68f36247bb3cb96d0a0eae274486"
812
689
  },
813
690
  {
814
691
  name: "subagent-driven-development",
815
692
  file: "assets/skills/subagent-driven-development/SKILL.md",
816
693
  description: "Skill de ejecución con subagentes (Superpowers) — ejecuta solo después de confirmación del coordinador Ostacky",
817
- version: "0.8.2",
694
+ version: "0.8.3",
818
695
  sha256: "1a42d714a9a13faf05f0bf7b580e8d837c2e77a5633839542ccce603023419e8"
819
696
  },
820
697
  {
821
698
  name: "dispatching-parallel-agents",
822
699
  file: "assets/skills/dispatching-parallel-agents/SKILL.md",
823
700
  description: "Skill de dispatch paralelo de agentes (Superpowers)",
824
- version: "0.8.2",
701
+ version: "0.8.3",
825
702
  sha256: "3c8a66d51ae2e719e877d02c3dac32bd804722c3bb9227c258ecae78252a20ab"
826
703
  },
827
704
  {
828
705
  name: "review",
829
706
  file: "assets/skills/review/SKILL.md",
830
707
  description: "Skill de revisión de código (Superpowers)",
831
- version: "0.8.2",
708
+ version: "0.8.3",
832
709
  sha256: "b19650ed4d1d4d9857a4dd5b7e08e91328a1a1fc9c45bcc2fb600fa9d0213279"
833
710
  },
834
711
  {
835
712
  name: "receiving-code-review",
836
713
  file: "assets/skills/receiving-code-review/SKILL.md",
837
714
  description: "Skill de recibir y procesar feedback de code review",
838
- version: "0.8.2",
715
+ version: "0.8.3",
839
716
  sha256: "d761e884e71d8d3476ac734d287cae403a4024506a7d12e7361a448217c0a831"
840
717
  },
841
718
  {
842
719
  name: "openspec-propose",
843
720
  file: "assets/skills/openspec-propose/SKILL.md",
844
721
  description: "Skill de generación de proposal (OpenSpec)",
845
- version: "0.8.2",
722
+ version: "0.8.3",
846
723
  sha256: "bb59100b9fd3c9f9a1ec6509fa975ec55bf7fc737df4fe73bb3e9bbc217b83f7"
847
724
  },
848
725
  {
849
726
  name: "openspec-apply-change",
850
727
  file: "assets/skills/openspec-apply-change/SKILL.md",
851
728
  description: "Skill de aplicación de change (OpenSpec)",
852
- version: "0.8.2",
729
+ version: "0.8.3",
853
730
  sha256: "dfc823bf89fc7505e91ab6dee9c1f004be38a410bd3d88fb67b211b1b6cbb1d0"
854
731
  },
855
732
  {
856
733
  name: "openspec-archive-change",
857
734
  file: "assets/skills/openspec-archive-change/SKILL.md",
858
735
  description: "Skill de archivo de change (OpenSpec)",
859
- version: "0.8.2",
736
+ version: "0.8.3",
860
737
  sha256: "16e4b561de7747283663fed602e506abf502452c49a8d4b86d7a5539c40f0195"
861
738
  },
862
739
  {
863
740
  name: "openspec-explore",
864
741
  file: "assets/skills/openspec-explore/SKILL.md",
865
742
  description: "Modo explore para OpenSpec — thinking partner para explorar ideas, investigar problemas y clarificar requisitos antes/durante un cambio",
866
- version: "0.8.2",
743
+ version: "0.8.3",
867
744
  sha256: "37ae4aaf17ea71a395bab6dc4d9d61b9a49d7910f6692535ae8553244c46880b"
868
745
  },
869
746
  {
870
747
  name: "using-git-worktrees",
871
748
  file: "assets/skills/using-git-worktrees/SKILL.md",
872
749
  description: "Skill de uso de git worktrees para aislamiento de trabajo",
873
- version: "0.8.2",
750
+ version: "0.8.3",
874
751
  sha256: "93341bc1b7c053618a8b6dc07e3615b77990d7b549a0201f5835d95fef67ce13"
875
752
  },
876
753
  {
877
754
  name: "using-superpowers",
878
755
  file: "assets/skills/using-superpowers/SKILL.md",
879
756
  description: "Skill de orquestación de Superpowers skills",
880
- version: "0.8.2",
757
+ version: "0.8.3",
881
758
  sha256: "7e54536f96d2a379185a10bfc1e970850caa2561b6d8aca7080f0defea0381a4"
882
759
  },
883
760
  {
884
761
  name: "writing-skills",
885
762
  file: "assets/skills/writing-skills/SKILL.md",
886
763
  description: "Skill de creación y edición de skills",
887
- version: "0.8.2",
764
+ version: "0.8.3",
888
765
  sha256: "3d76b906cee518a2b809febb70db95697a35b9f368986bb504b4120c3bfb437a"
889
766
  },
890
767
  {
891
768
  name: "graceful-degradation",
892
769
  file: "assets/skills/graceful-degradation/SKILL.md",
893
770
  description: "Skill de degradación graceful cuando múltiples tools están indisponibles",
894
- version: "0.8.2",
771
+ version: "0.8.3",
895
772
  sha256: "79d0eeb2116382cb5db5b753277a333b7ca5682f4a541170b4a6158125c2cb50"
896
773
  }
897
774
  ]
@@ -933,19 +810,6 @@ var init_cache = __esm(() => {
933
810
  });
934
811
 
935
812
  // 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
- });
949
813
  import { fileURLToPath } from "url";
950
814
  import { dirname as dirname3, join as join3 } from "path";
951
815
  function getBundledSkillPath(name) {
@@ -977,9 +841,9 @@ async function fetchLatestReleaseTag(repo) {
977
841
  headers: { "User-Agent": USER_AGENT }
978
842
  });
979
843
  const loc = res.headers.get("location") ?? "";
980
- const m3 = loc.match(/releases\/tag\/(v[^/]+)$/);
981
- if (m3)
982
- return m3[1];
844
+ const m = loc.match(/releases\/tag\/(v[^/]+)$/);
845
+ if (m)
846
+ return m[1];
983
847
  } catch {}
984
848
  return null;
985
849
  }
@@ -1044,15 +908,6 @@ var init_github = __esm(() => {
1044
908
  });
1045
909
 
1046
910
  // src/lockfile.ts
1047
- var exports_lockfile = {};
1048
- __export(exports_lockfile, {
1049
- clearLockfile: () => clearLockfile,
1050
- getInstalledVersion: () => getInstalledVersion,
1051
- getLockfilePath: () => getLockfilePath,
1052
- readLockfile: () => readLockfile,
1053
- removeFromLockfile: () => removeFromLockfile,
1054
- writeLockfile: () => writeLockfile
1055
- });
1056
911
  import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
1057
912
  import { join as join4 } from "path";
1058
913
  function getLockfilePath(opencodeRoot) {
@@ -1114,19 +969,6 @@ var init_lockfile = __esm(() => {
1114
969
  });
1115
970
 
1116
971
  // src/config.ts
1117
- var exports_config = {};
1118
- __export(exports_config, {
1119
- ensureMcpEntry: () => ensureMcpEntry,
1120
- ensureMcpEntryAtProjectRoot: () => ensureMcpEntryAtProjectRoot,
1121
- ensureOpenCodeConfig: () => ensureOpenCodeConfig,
1122
- findOpenCodeConfig: () => findOpenCodeConfig,
1123
- patchOpenCodeConfig: () => patchOpenCodeConfig,
1124
- readOpenCodeConfig: () => readOpenCodeConfig,
1125
- setMcpEntry: () => setMcpEntry,
1126
- setMcpEntryAtProjectRoot: () => setMcpEntryAtProjectRoot,
1127
- stripJsoncComments: () => stripJsoncComments,
1128
- writeOpenCodeConfig: () => writeOpenCodeConfig
1129
- });
1130
972
  import { existsSync as existsSync4, readFileSync as readFileSync4, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
1131
973
  import { join as join5 } from "path";
1132
974
  function stripJsoncComments(text) {
@@ -1211,9 +1053,6 @@ function findOpenCodeConfig(projectRoot) {
1211
1053
  }
1212
1054
  return null;
1213
1055
  }
1214
- function setMcpEntry(name, entry) {
1215
- setMcpEntryAtProjectRoot(findProjectRoot(), name, entry);
1216
- }
1217
1056
  function setMcpEntryAtProjectRoot(projectRoot, name, entry) {
1218
1057
  const configPath = ensureOpenCodeConfig(projectRoot);
1219
1058
  const config = readOpenCodeConfig(configPath);
@@ -1224,22 +1063,6 @@ function setMcpEntryAtProjectRoot(projectRoot, name, entry) {
1224
1063
  config.mcp[name] = entry;
1225
1064
  writeOpenCodeConfig(configPath, config);
1226
1065
  }
1227
- function ensureMcpEntry(name, entry) {
1228
- ensureMcpEntryAtProjectRoot(findProjectRoot(), name, entry);
1229
- }
1230
- function ensureMcpEntryAtProjectRoot(projectRoot, name, entry) {
1231
- const configPath = ensureOpenCodeConfig(projectRoot);
1232
- const config = readOpenCodeConfig(configPath);
1233
- if (!config)
1234
- throw new Error(`Error parseando ${configPath}`);
1235
- if (!config.mcp)
1236
- config.mcp = {};
1237
- const mcp = config.mcp;
1238
- if (!mcp[name]) {
1239
- mcp[name] = entry;
1240
- writeOpenCodeConfig(configPath, config);
1241
- }
1242
- }
1243
1066
  function patchOpenCodeConfig(projectRoot = findProjectRoot()) {
1244
1067
  const configPath = findOpenCodeConfig(projectRoot);
1245
1068
  if (!configPath) {
@@ -1271,19 +1094,6 @@ var init_config = __esm(() => {
1271
1094
  });
1272
1095
 
1273
1096
  // src/stack.ts
1274
- var exports_stack = {};
1275
- __export(exports_stack, {
1276
- OPENSPEC_NPM_PACKAGE: () => OPENSPEC_NPM_PACKAGE,
1277
- buildEngramDownloadUrl: () => buildEngramDownloadUrl,
1278
- buildLocalMcpCommand: () => buildLocalMcpCommand,
1279
- installCodeGraph: () => installCodeGraph,
1280
- installEngram: () => installEngram,
1281
- installStack: () => installStack,
1282
- setupOpenSpec: () => setupOpenSpec,
1283
- uninstallEngramConfig: () => uninstallEngramConfig,
1284
- uninstallStackConfig: () => uninstallStackConfig,
1285
- verifyMcpServers: () => verifyMcpServers
1286
- });
1287
1097
  import { chmodSync, copyFileSync as copyFileSync3, existsSync as existsSync6, mkdirSync as mkdirSync4, rmSync as rmSync4, unlinkSync as unlinkSync3 } from "fs";
1288
1098
  import { basename as basename2, dirname as dirname5, join as join7, resolve as resolve2 } from "path";
1289
1099
  import { execFileSync as execFileSync3 } from "child_process";
@@ -1344,12 +1154,15 @@ function copyEngramPlugin(projectRoot) {
1344
1154
  }
1345
1155
  function copyOstackyControllerPlugin(projectRoot) {
1346
1156
  const pluginSource = join7(PACKAGE_ROOT, "assets", "plugins", "ostacky-plugin.ts");
1157
+ const coreSource = join7(PACKAGE_ROOT, "assets", "plugins", "controller-core.ts");
1347
1158
  const pluginsDir = join7(projectRoot, ".opencode", "plugins");
1348
1159
  if (!existsSync6(pluginSource)) {
1349
1160
  throw new Error(`Plugin bundleado de OstackyController no encontrado: ${pluginSource}`);
1350
1161
  }
1351
1162
  mkdirSync4(pluginsDir, { recursive: true });
1352
1163
  copyFileSync3(pluginSource, join7(pluginsDir, "ostacky-plugin.ts"));
1164
+ if (existsSync6(coreSource))
1165
+ copyFileSync3(coreSource, join7(pluginsDir, "controller-core.ts"));
1353
1166
  }
1354
1167
  function buildEngramDownloadUrl(tag, platform = process.platform, arch = process.arch) {
1355
1168
  const target = getEngramReleaseTarget(platform, arch);
@@ -1401,10 +1214,10 @@ async function installCodeGraph(toolsDir) {
1401
1214
  const url = `https://github.com/colbymchenry/codegraph/releases/download/${tag}/codegraph-${target}.${ext}`;
1402
1215
  try {
1403
1216
  archivePromotion = await downloadAndExtractWithRetry(url, cgToolDir, 0, 180000, 2);
1404
- } catch (e2) {
1217
+ } catch (e) {
1405
1218
  return {
1406
1219
  success: false,
1407
- message: `Error descargando CodeGraph ${tag}: ${e2.message}`
1220
+ message: `Error descargando CodeGraph ${tag}: ${e.message}`
1408
1221
  };
1409
1222
  }
1410
1223
  const expectedBin = join7(cgToolDir, "bin", getExecutableName("codegraph"));
@@ -1567,10 +1380,10 @@ async function installEngram(toolsDir) {
1567
1380
  }
1568
1381
  try {
1569
1382
  archivePromotion = await downloadAndExtractWithRetry(url, engramToolDir, 0, 120000, 2);
1570
- } catch (e2) {
1383
+ } catch (e) {
1571
1384
  return {
1572
1385
  success: false,
1573
- message: `Error descargando Engram ${tag}: ${e2.message}`
1386
+ message: `Error descargando Engram ${tag}: ${e.message}`
1574
1387
  };
1575
1388
  }
1576
1389
  mkdirSync4(engramBinDir, { recursive: true });
@@ -1601,18 +1414,6 @@ async function installEngram(toolsDir) {
1601
1414
  archivePromotion?.commit();
1602
1415
  return { success: true, message: "Engram instalado localmente y configurado para OpenCode (MCP + plugin)" };
1603
1416
  }
1604
- async function installStack(toolsDir) {
1605
- const { projectRoot } = resolveToolInstallLocation(toolsDir);
1606
- try {
1607
- copyOstackyControllerPlugin(projectRoot);
1608
- } catch {}
1609
- return {
1610
- codegraph: await installCodeGraph(toolsDir),
1611
- openspec: setupOpenSpec(projectRoot),
1612
- engram: await installEngram(toolsDir),
1613
- config: patchOpenCodeConfig(projectRoot)
1614
- };
1615
- }
1616
1417
  function uninstallEngramConfig() {
1617
1418
  const projectRoot = findProjectRoot();
1618
1419
  const configPath = findOpenCodeConfig(projectRoot);
@@ -1682,29 +1483,6 @@ function uninstallStackConfig(paths) {
1682
1483
  message: `Removido: ${removed.join(", ")}. Los binarios globales (codegraph, engram) no se tocaron.`
1683
1484
  };
1684
1485
  }
1685
- function verifyMcpServers(projectRoot) {
1686
- const opencodeDir = findOpenCodeDir(projectRoot);
1687
- const mcpBase = opencodeDir ? join7(opencodeDir, "mcp") : join7(projectRoot, ".opencode", "mcp");
1688
- const controllerPath = join7(mcpBase, "ostacky-controller", "index.js");
1689
- const openspecPath = join7(mcpBase, "openspec", "index.js");
1690
- const result = {
1691
- ostackyController: {
1692
- exists: existsSync6(controllerPath),
1693
- path: controllerPath
1694
- },
1695
- openspec: {
1696
- exists: existsSync6(openspecPath),
1697
- path: openspecPath
1698
- }
1699
- };
1700
- if (!result.ostackyController.exists) {
1701
- result.ostackyController.error = "ostacky-controller MCP server not found";
1702
- }
1703
- if (!result.openspec.exists) {
1704
- result.openspec.error = "openspec MCP server not found";
1705
- }
1706
- return result;
1707
- }
1708
1486
  var OPENSPEC_NPM_PACKAGE = "@fission-ai/openspec";
1709
1487
  var init_stack = __esm(() => {
1710
1488
  init_fs();
@@ -1714,7 +1492,7 @@ var init_stack = __esm(() => {
1714
1492
  // package.json
1715
1493
  var package_default = {
1716
1494
  name: "ostacky",
1717
- version: "0.8.2",
1495
+ version: "0.8.3",
1718
1496
  description: "Instalador interactivo de agentes y comandos para OpenCode",
1719
1497
  type: "module",
1720
1498
  bin: {
@@ -2379,13 +2157,13 @@ var y2 = (s) => {
2379
2157
  }
2380
2158
  };
2381
2159
  var k2 = (s) => {
2382
- const { cursor: n, options: t, style: i } = s, r2 = s.maxItems ?? Number.POSITIVE_INFINITY, c2 = Math.max(process.stdout.rows - 4, 0), o = Math.min(c2, Math.max(r2, 5));
2383
- let l2 = 0;
2384
- n >= l2 + o - 3 ? l2 = Math.max(Math.min(n - o + 3, t.length - o), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
2385
- const $2 = o < t.length && l2 > 0, d2 = o < t.length && l2 + o < t.length;
2386
- return t.slice(l2, l2 + o).map((w2, b2, C) => {
2387
- const I2 = b2 === 0 && $2, x2 = b2 === C.length - 1 && d2;
2388
- return I2 || x2 ? import_picocolors2.default.dim("...") : i(w2, b2 + l2 === n);
2160
+ const { cursor: n, options: t, style: i } = s, r = s.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), o = Math.min(c, Math.max(r, 5));
2161
+ let l = 0;
2162
+ n >= l + o - 3 ? l = Math.max(Math.min(n - o + 3, t.length - o), 0) : n < l + 2 && (l = Math.max(n - 2, 0));
2163
+ const $ = o < t.length && l > 0, d = o < t.length && l + o < t.length;
2164
+ return t.slice(l, l + o).map((w, b, C) => {
2165
+ const I = b === 0 && $, x = b === C.length - 1 && d;
2166
+ return I || x ? import_picocolors2.default.dim("...") : i(w, b + l === n);
2389
2167
  });
2390
2168
  };
2391
2169
  var ue = (s) => new PD({ validate: s.validate, placeholder: s.placeholder, defaultValue: s.defaultValue, initialValue: s.initialValue, render() {
@@ -2435,12 +2213,12 @@ var me = (s) => {
2435
2213
  return new fD({ active: n, inactive: t, initialValue: s.initialValue ?? true, render() {
2436
2214
  const i = `${import_picocolors2.default.gray(a)}
2437
2215
  ${y2(this.state)} ${s.message}
2438
- `, r2 = this.value ? n : t;
2216
+ `, r = this.value ? n : t;
2439
2217
  switch (this.state) {
2440
2218
  case "submit":
2441
- return `${i}${import_picocolors2.default.gray(a)} ${import_picocolors2.default.dim(r2)}`;
2219
+ return `${i}${import_picocolors2.default.gray(a)} ${import_picocolors2.default.dim(r)}`;
2442
2220
  case "cancel":
2443
- return `${i}${import_picocolors2.default.gray(a)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(r2))}
2221
+ return `${i}${import_picocolors2.default.gray(a)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(r))}
2444
2222
  ${import_picocolors2.default.gray(a)}`;
2445
2223
  default:
2446
2224
  return `${i}${import_picocolors2.default.cyan(a)} ${this.value ? `${import_picocolors2.default.green(j2)} ${n}` : `${import_picocolors2.default.dim(R2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(R2)} ${import_picocolors2.default.dim(t)}` : `${import_picocolors2.default.green(j2)} ${t}`}
@@ -2451,16 +2229,16 @@ ${import_picocolors2.default.cyan(m2)}
2451
2229
  };
2452
2230
  var de = (s) => {
2453
2231
  const n = (t, i) => {
2454
- const r2 = t.label ?? String(t.value);
2232
+ const r = t.label ?? String(t.value);
2455
2233
  switch (i) {
2456
2234
  case "selected":
2457
- return `${import_picocolors2.default.dim(r2)}`;
2235
+ return `${import_picocolors2.default.dim(r)}`;
2458
2236
  case "active":
2459
- return `${import_picocolors2.default.green(j2)} ${r2} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}`;
2237
+ return `${import_picocolors2.default.green(j2)} ${r} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}`;
2460
2238
  case "cancelled":
2461
- return `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(r2))}`;
2239
+ return `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(r))}`;
2462
2240
  default:
2463
- return `${import_picocolors2.default.dim(R2)} ${import_picocolors2.default.dim(r2)}`;
2241
+ return `${import_picocolors2.default.dim(R2)} ${import_picocolors2.default.dim(r)}`;
2464
2242
  }
2465
2243
  };
2466
2244
  return new jD({ options: s.options, initialValue: s.initialValue, render() {
@@ -2474,7 +2252,7 @@ ${y2(this.state)} ${s.message}
2474
2252
  return `${t}${import_picocolors2.default.gray(a)} ${n(this.options[this.cursor], "cancelled")}
2475
2253
  ${import_picocolors2.default.gray(a)}`;
2476
2254
  default:
2477
- return `${t}${import_picocolors2.default.cyan(a)} ${k2({ cursor: this.cursor, options: this.options, maxItems: s.maxItems, style: (i, r2) => n(i, r2 ? "active" : "inactive") }).join(`
2255
+ return `${t}${import_picocolors2.default.cyan(a)} ${k2({ cursor: this.cursor, options: this.options, maxItems: s.maxItems, style: (i, r) => n(i, r ? "active" : "inactive") }).join(`
2478
2256
  ${import_picocolors2.default.cyan(a)} `)}
2479
2257
  ${import_picocolors2.default.cyan(m2)}
2480
2258
  `;
@@ -2483,8 +2261,8 @@ ${import_picocolors2.default.cyan(m2)}
2483
2261
  };
2484
2262
  var he = (s) => {
2485
2263
  const n = (t, i = "inactive") => {
2486
- const r2 = t.label ?? String(t.value);
2487
- return i === "selected" ? `${import_picocolors2.default.dim(r2)}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(r2))}` : i === "active" ? `${import_picocolors2.default.bgCyan(import_picocolors2.default.gray(` ${t.value} `))} ${r2} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}` : `${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(` ${t.value} `)))} ${r2} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}`;
2264
+ const r = t.label ?? String(t.value);
2265
+ return i === "selected" ? `${import_picocolors2.default.dim(r)}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(r))}` : i === "active" ? `${import_picocolors2.default.bgCyan(import_picocolors2.default.gray(` ${t.value} `))} ${r} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}` : `${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(` ${t.value} `)))} ${r} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}`;
2488
2266
  };
2489
2267
  return new OD({ options: s.options, initialValue: s.initialValue, render() {
2490
2268
  const t = `${import_picocolors2.default.gray(a)}
@@ -2497,7 +2275,7 @@ ${y2(this.state)} ${s.message}
2497
2275
  return `${t}${import_picocolors2.default.gray(a)} ${n(this.options[0], "cancelled")}
2498
2276
  ${import_picocolors2.default.gray(a)}`;
2499
2277
  default:
2500
- return `${t}${import_picocolors2.default.cyan(a)} ${this.options.map((i, r2) => n(i, r2 === this.cursor ? "active" : "inactive")).join(`
2278
+ return `${t}${import_picocolors2.default.cyan(a)} ${this.options.map((i, r) => n(i, r === this.cursor ? "active" : "inactive")).join(`
2501
2279
  ${import_picocolors2.default.cyan(a)} `)}
2502
2280
  ${import_picocolors2.default.cyan(m2)}
2503
2281
  `;
@@ -2506,8 +2284,8 @@ ${import_picocolors2.default.cyan(m2)}
2506
2284
  };
2507
2285
  var pe = (s) => {
2508
2286
  const n = (t, i) => {
2509
- const r2 = t.label ?? String(t.value);
2510
- return i === "active" ? `${import_picocolors2.default.cyan(V2)} ${r2} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(M2)} ${import_picocolors2.default.dim(r2)}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(r2))}` : i === "active-selected" ? `${import_picocolors2.default.green(M2)} ${r2} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(r2)}` : `${import_picocolors2.default.dim(G2)} ${import_picocolors2.default.dim(r2)}`;
2287
+ const r = t.label ?? String(t.value);
2288
+ return i === "active" ? `${import_picocolors2.default.cyan(V2)} ${r} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(M2)} ${import_picocolors2.default.dim(r)}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(r))}` : i === "active-selected" ? `${import_picocolors2.default.green(M2)} ${r} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(r)}` : `${import_picocolors2.default.dim(G2)} ${import_picocolors2.default.dim(r)}`;
2511
2289
  };
2512
2290
  return new wD({ options: s.options, initialValues: s.initialValues, required: s.required ?? true, cursorAt: s.cursorAt, validate(t) {
2513
2291
  if (this.required && t.length === 0)
@@ -2516,25 +2294,25 @@ ${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${impor
2516
2294
  }, render() {
2517
2295
  const t = `${import_picocolors2.default.gray(a)}
2518
2296
  ${y2(this.state)} ${s.message}
2519
- `, i = (r2, c2) => {
2520
- const o = this.value.includes(r2.value);
2521
- return c2 && o ? n(r2, "active-selected") : o ? n(r2, "selected") : n(r2, c2 ? "active" : "inactive");
2297
+ `, i = (r, c) => {
2298
+ const o = this.value.includes(r.value);
2299
+ return c && o ? n(r, "active-selected") : o ? n(r, "selected") : n(r, c ? "active" : "inactive");
2522
2300
  };
2523
2301
  switch (this.state) {
2524
2302
  case "submit":
2525
- return `${t}${import_picocolors2.default.gray(a)} ${this.options.filter(({ value: r2 }) => this.value.includes(r2)).map((r2) => n(r2, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
2303
+ return `${t}${import_picocolors2.default.gray(a)} ${this.options.filter(({ value: r }) => this.value.includes(r)).map((r) => n(r, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
2526
2304
  case "cancel": {
2527
- const r2 = this.options.filter(({ value: c2 }) => this.value.includes(c2)).map((c2) => n(c2, "cancelled")).join(import_picocolors2.default.dim(", "));
2528
- return `${t}${import_picocolors2.default.gray(a)} ${r2.trim() ? `${r2}
2305
+ const r = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
2306
+ return `${t}${import_picocolors2.default.gray(a)} ${r.trim() ? `${r}
2529
2307
  ${import_picocolors2.default.gray(a)}` : ""}`;
2530
2308
  }
2531
2309
  case "error": {
2532
- const r2 = this.error.split(`
2533
- `).map((c2, o) => o === 0 ? `${import_picocolors2.default.yellow(m2)} ${import_picocolors2.default.yellow(c2)}` : ` ${c2}`).join(`
2310
+ const r = this.error.split(`
2311
+ `).map((c, o) => o === 0 ? `${import_picocolors2.default.yellow(m2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
2534
2312
  `);
2535
2313
  return `${t + import_picocolors2.default.yellow(a)} ${k2({ options: this.options, cursor: this.cursor, maxItems: s.maxItems, style: i }).join(`
2536
2314
  ${import_picocolors2.default.yellow(a)} `)}
2537
- ${r2}
2315
+ ${r}
2538
2316
  `;
2539
2317
  }
2540
2318
  default:
@@ -2546,9 +2324,9 @@ ${import_picocolors2.default.cyan(m2)}
2546
2324
  } }).prompt();
2547
2325
  };
2548
2326
  var ge = (s) => {
2549
- const n = (t, i, r2 = []) => {
2550
- const c2 = t.label ?? String(t.value), o = typeof t.group == "string", l2 = o && (r2[r2.indexOf(t) + 1] ?? { group: true }), $2 = o && l2.group === true, d2 = o ? `${$2 ? m2 : a} ` : "";
2551
- return i === "active" ? `${import_picocolors2.default.dim(d2)}${import_picocolors2.default.cyan(V2)} ${c2} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}` : i === "group-active" ? `${d2}${import_picocolors2.default.cyan(V2)} ${import_picocolors2.default.dim(c2)}` : i === "group-active-selected" ? `${d2}${import_picocolors2.default.green(M2)} ${import_picocolors2.default.dim(c2)}` : i === "selected" ? `${import_picocolors2.default.dim(d2)}${import_picocolors2.default.green(M2)} ${import_picocolors2.default.dim(c2)}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(c2))}` : i === "active-selected" ? `${import_picocolors2.default.dim(d2)}${import_picocolors2.default.green(M2)} ${c2} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(c2)}` : `${import_picocolors2.default.dim(d2)}${import_picocolors2.default.dim(G2)} ${import_picocolors2.default.dim(c2)}`;
2327
+ const n = (t, i, r = []) => {
2328
+ const c = t.label ?? String(t.value), o = typeof t.group == "string", l = o && (r[r.indexOf(t) + 1] ?? { group: true }), $ = o && l.group === true, d = o ? `${$ ? m2 : a} ` : "";
2329
+ return i === "active" ? `${import_picocolors2.default.dim(d)}${import_picocolors2.default.cyan(V2)} ${c} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}` : i === "group-active" ? `${d}${import_picocolors2.default.cyan(V2)} ${import_picocolors2.default.dim(c)}` : i === "group-active-selected" ? `${d}${import_picocolors2.default.green(M2)} ${import_picocolors2.default.dim(c)}` : i === "selected" ? `${import_picocolors2.default.dim(d)}${import_picocolors2.default.green(M2)} ${import_picocolors2.default.dim(c)}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(c))}` : i === "active-selected" ? `${import_picocolors2.default.dim(d)}${import_picocolors2.default.green(M2)} ${c} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(c)}` : `${import_picocolors2.default.dim(d)}${import_picocolors2.default.dim(G2)} ${import_picocolors2.default.dim(c)}`;
2552
2330
  };
2553
2331
  return new dD({ options: s.options, initialValues: s.initialValues, required: s.required ?? true, cursorAt: s.cursorAt, validate(t) {
2554
2332
  if (this.required && t.length === 0)
@@ -2562,26 +2340,26 @@ ${y2(this.state)} ${s.message}
2562
2340
  case "submit":
2563
2341
  return `${t}${import_picocolors2.default.gray(a)} ${this.options.filter(({ value: i }) => this.value.includes(i)).map((i) => n(i, "submitted")).join(import_picocolors2.default.dim(", "))}`;
2564
2342
  case "cancel": {
2565
- const i = this.options.filter(({ value: r2 }) => this.value.includes(r2)).map((r2) => n(r2, "cancelled")).join(import_picocolors2.default.dim(", "));
2343
+ const i = this.options.filter(({ value: r }) => this.value.includes(r)).map((r) => n(r, "cancelled")).join(import_picocolors2.default.dim(", "));
2566
2344
  return `${t}${import_picocolors2.default.gray(a)} ${i.trim() ? `${i}
2567
2345
  ${import_picocolors2.default.gray(a)}` : ""}`;
2568
2346
  }
2569
2347
  case "error": {
2570
2348
  const i = this.error.split(`
2571
- `).map((r2, c2) => c2 === 0 ? `${import_picocolors2.default.yellow(m2)} ${import_picocolors2.default.yellow(r2)}` : ` ${r2}`).join(`
2349
+ `).map((r, c) => c === 0 ? `${import_picocolors2.default.yellow(m2)} ${import_picocolors2.default.yellow(r)}` : ` ${r}`).join(`
2572
2350
  `);
2573
- return `${t}${import_picocolors2.default.yellow(a)} ${this.options.map((r2, c2, o) => {
2574
- const l2 = this.value.includes(r2.value) || r2.group === true && this.isGroupSelected(`${r2.value}`), $2 = c2 === this.cursor;
2575
- return !$2 && typeof r2.group == "string" && this.options[this.cursor].value === r2.group ? n(r2, l2 ? "group-active-selected" : "group-active", o) : $2 && l2 ? n(r2, "active-selected", o) : l2 ? n(r2, "selected", o) : n(r2, $2 ? "active" : "inactive", o);
2351
+ return `${t}${import_picocolors2.default.yellow(a)} ${this.options.map((r, c, o) => {
2352
+ const l = this.value.includes(r.value) || r.group === true && this.isGroupSelected(`${r.value}`), $ = c === this.cursor;
2353
+ return !$ && typeof r.group == "string" && this.options[this.cursor].value === r.group ? n(r, l ? "group-active-selected" : "group-active", o) : $ && l ? n(r, "active-selected", o) : l ? n(r, "selected", o) : n(r, $ ? "active" : "inactive", o);
2576
2354
  }).join(`
2577
2355
  ${import_picocolors2.default.yellow(a)} `)}
2578
2356
  ${i}
2579
2357
  `;
2580
2358
  }
2581
2359
  default:
2582
- return `${t}${import_picocolors2.default.cyan(a)} ${this.options.map((i, r2, c2) => {
2583
- const o = this.value.includes(i.value) || i.group === true && this.isGroupSelected(`${i.value}`), l2 = r2 === this.cursor;
2584
- return !l2 && typeof i.group == "string" && this.options[this.cursor].value === i.group ? n(i, o ? "group-active-selected" : "group-active", c2) : l2 && o ? n(i, "active-selected", c2) : o ? n(i, "selected", c2) : n(i, l2 ? "active" : "inactive", c2);
2360
+ return `${t}${import_picocolors2.default.cyan(a)} ${this.options.map((i, r, c) => {
2361
+ const o = this.value.includes(i.value) || i.group === true && this.isGroupSelected(`${i.value}`), l = r === this.cursor;
2362
+ return !l && typeof i.group == "string" && this.options[this.cursor].value === i.group ? n(i, o ? "group-active-selected" : "group-active", c) : l && o ? n(i, "active-selected", c) : o ? n(i, "selected", c) : n(i, l ? "active" : "inactive", c);
2585
2363
  }).join(`
2586
2364
  ${import_picocolors2.default.cyan(a)} `)}
2587
2365
  ${import_picocolors2.default.cyan(m2)}
@@ -2593,15 +2371,15 @@ var ye = (s = "", n = "") => {
2593
2371
  const t = `
2594
2372
  ${s}
2595
2373
  `.split(`
2596
- `), i = T2(n).length, r2 = Math.max(t.reduce((o, l2) => {
2597
- const $2 = T2(l2);
2598
- return $2.length > o ? $2.length : o;
2599
- }, 0), i) + 2, c2 = t.map((o) => `${import_picocolors2.default.gray(a)} ${import_picocolors2.default.dim(o)}${" ".repeat(r2 - T2(o).length)}${import_picocolors2.default.gray(a)}`).join(`
2374
+ `), i = T2(n).length, r = Math.max(t.reduce((o, l) => {
2375
+ const $ = T2(l);
2376
+ return $.length > o ? $.length : o;
2377
+ }, 0), i) + 2, c = t.map((o) => `${import_picocolors2.default.gray(a)} ${import_picocolors2.default.dim(o)}${" ".repeat(r - T2(o).length)}${import_picocolors2.default.gray(a)}`).join(`
2600
2378
  `);
2601
2379
  process.stdout.write(`${import_picocolors2.default.gray(a)}
2602
- ${import_picocolors2.default.green(S2)} ${import_picocolors2.default.reset(n)} ${import_picocolors2.default.gray(N2.repeat(Math.max(r2 - i - 1, 1)) + re)}
2603
- ${c2}
2604
- ${import_picocolors2.default.gray(ie + N2.repeat(r2 + 2) + ne)}
2380
+ ${import_picocolors2.default.green(S2)} ${import_picocolors2.default.reset(n)} ${import_picocolors2.default.gray(N2.repeat(Math.max(r - i - 1, 1)) + re)}
2381
+ ${c}
2382
+ ${import_picocolors2.default.gray(ie + N2.repeat(r + 2) + ne)}
2605
2383
  `);
2606
2384
  };
2607
2385
  var ve = (s = "") => {
@@ -2622,9 +2400,9 @@ ${import_picocolors2.default.gray(m2)} ${s}
2622
2400
  var v2 = { message: (s = "", { symbol: n = import_picocolors2.default.gray(a) } = {}) => {
2623
2401
  const t = [`${import_picocolors2.default.gray(a)}`];
2624
2402
  if (s) {
2625
- const [i, ...r2] = s.split(`
2403
+ const [i, ...r] = s.split(`
2626
2404
  `);
2627
- t.push(`${n} ${i}`, ...r2.map((c2) => `${import_picocolors2.default.gray(a)} ${c2}`));
2405
+ t.push(`${n} ${i}`, ...r.map((c) => `${import_picocolors2.default.gray(a)} ${c}`));
2628
2406
  }
2629
2407
  process.stdout.write(`${t.join(`
2630
2408
  `)}
@@ -2644,54 +2422,54 @@ var v2 = { message: (s = "", { symbol: n = import_picocolors2.default.gray(a) }
2644
2422
  } };
2645
2423
  var L2 = () => {
2646
2424
  const s = E ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], n = E ? 80 : 120, t = process.env.CI === "true";
2647
- let i, r2, c2 = false, o = "", l2;
2648
- const $2 = (h2) => {
2649
- const g2 = h2 > 1 ? "Something went wrong" : "Canceled";
2650
- c2 && P2(g2, h2);
2651
- }, d2 = () => $2(2), w2 = () => $2(1), b2 = () => {
2652
- process.on("uncaughtExceptionMonitor", d2), process.on("unhandledRejection", d2), process.on("SIGINT", w2), process.on("SIGTERM", w2), process.on("exit", $2);
2425
+ let i, r, c = false, o = "", l;
2426
+ const $ = (h) => {
2427
+ const g = h > 1 ? "Something went wrong" : "Canceled";
2428
+ c && P(g, h);
2429
+ }, d = () => $(2), w = () => $(1), b = () => {
2430
+ process.on("uncaughtExceptionMonitor", d), process.on("unhandledRejection", d), process.on("SIGINT", w), process.on("SIGTERM", w), process.on("exit", $);
2653
2431
  }, C = () => {
2654
- process.removeListener("uncaughtExceptionMonitor", d2), process.removeListener("unhandledRejection", d2), process.removeListener("SIGINT", w2), process.removeListener("SIGTERM", w2), process.removeListener("exit", $2);
2655
- }, I2 = () => {
2656
- if (l2 === undefined)
2432
+ process.removeListener("uncaughtExceptionMonitor", d), process.removeListener("unhandledRejection", d), process.removeListener("SIGINT", w), process.removeListener("SIGTERM", w), process.removeListener("exit", $);
2433
+ }, I = () => {
2434
+ if (l === undefined)
2657
2435
  return;
2658
2436
  t && process.stdout.write(`
2659
2437
  `);
2660
- const h2 = l2.split(`
2438
+ const h = l.split(`
2661
2439
  `);
2662
- process.stdout.write(import_sisteransi2.cursor.move(-999, h2.length - 1)), process.stdout.write(import_sisteransi2.erase.down(h2.length));
2663
- }, x2 = (h2) => h2.replace(/\.+$/, ""), O2 = (h2 = "") => {
2664
- c2 = true, i = cD(), o = x2(h2), process.stdout.write(`${import_picocolors2.default.gray(a)}
2440
+ process.stdout.write(import_sisteransi2.cursor.move(-999, h.length - 1)), process.stdout.write(import_sisteransi2.erase.down(h.length));
2441
+ }, x = (h) => h.replace(/\.+$/, ""), O = (h = "") => {
2442
+ c = true, i = cD(), o = x(h), process.stdout.write(`${import_picocolors2.default.gray(a)}
2665
2443
  `);
2666
- let g2 = 0, f2 = 0;
2667
- b2(), r2 = setInterval(() => {
2668
- if (t && o === l2)
2444
+ let g = 0, f = 0;
2445
+ b(), r = setInterval(() => {
2446
+ if (t && o === l)
2669
2447
  return;
2670
- I2(), l2 = o;
2671
- const W2 = import_picocolors2.default.magenta(s[g2]), _2 = t ? "..." : ".".repeat(Math.floor(f2)).slice(0, 3);
2672
- process.stdout.write(`${W2} ${o}${_2}`), g2 = g2 + 1 < s.length ? g2 + 1 : 0, f2 = f2 < s.length ? f2 + 0.125 : 0;
2448
+ I(), l = o;
2449
+ const W = import_picocolors2.default.magenta(s[g]), _ = t ? "..." : ".".repeat(Math.floor(f)).slice(0, 3);
2450
+ process.stdout.write(`${W} ${o}${_}`), g = g + 1 < s.length ? g + 1 : 0, f = f < s.length ? f + 0.125 : 0;
2673
2451
  }, n);
2674
- }, P2 = (h2 = "", g2 = 0) => {
2675
- c2 = false, clearInterval(r2), I2();
2676
- const f2 = g2 === 0 ? import_picocolors2.default.green(S2) : g2 === 1 ? import_picocolors2.default.red(A2) : import_picocolors2.default.red(B);
2677
- o = x2(h2 ?? o), process.stdout.write(`${f2} ${o}
2452
+ }, P = (h = "", g = 0) => {
2453
+ c = false, clearInterval(r), I();
2454
+ const f = g === 0 ? import_picocolors2.default.green(S2) : g === 1 ? import_picocolors2.default.red(A2) : import_picocolors2.default.red(B);
2455
+ o = x(h ?? o), process.stdout.write(`${f} ${o}
2678
2456
  `), C(), i();
2679
2457
  };
2680
- return { start: O2, stop: P2, message: (h2 = "") => {
2681
- o = x2(h2 ?? o);
2458
+ return { start: O, stop: P, message: (h = "") => {
2459
+ o = x(h ?? o);
2682
2460
  } };
2683
2461
  };
2684
2462
  var be = async (s, n) => {
2685
2463
  const t = {}, i = Object.keys(s);
2686
- for (const r2 of i) {
2687
- const c2 = s[r2], o = await c2({ results: t })?.catch((l2) => {
2688
- throw l2;
2464
+ for (const r of i) {
2465
+ const c = s[r], o = await c({ results: t })?.catch((l) => {
2466
+ throw l;
2689
2467
  });
2690
2468
  if (typeof n?.onCancel == "function" && BD(o)) {
2691
- t[r2] = "canceled", n.onCancel({ results: t });
2469
+ t[r] = "canceled", n.onCancel({ results: t });
2692
2470
  continue;
2693
2471
  }
2694
- t[r2] = o;
2472
+ t[r] = o;
2695
2473
  }
2696
2474
  return t;
2697
2475
  };
@@ -2778,7 +2556,7 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath, option
2778
2556
  const requiredTools = options.requiredTools ?? DEFAULT_PROBE_OPTIONS.requiredTools;
2779
2557
  const exerciseWrite = options.exerciseWrite ?? requiredTools.includes("start_request");
2780
2558
  try {
2781
- await new Promise((resolve2, reject) => {
2559
+ await new Promise((resolve, reject) => {
2782
2560
  const child = spawn(nodeExecutable, [serverPath], {
2783
2561
  cwd,
2784
2562
  env: {
@@ -2805,13 +2583,13 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath, option
2805
2583
  const onExit = () => {
2806
2584
  if (exitTimeout)
2807
2585
  clearTimeout(exitTimeout);
2808
- error ? reject(error) : resolve2();
2586
+ error ? reject(error) : resolve();
2809
2587
  };
2810
2588
  child.once("exit", onExit);
2811
2589
  child.kill();
2812
2590
  exitTimeout = setTimeout(onExit, 500);
2813
2591
  } else {
2814
- error ? reject(error) : resolve2();
2592
+ error ? reject(error) : resolve();
2815
2593
  }
2816
2594
  };
2817
2595
  const fail = (message) => finish(new Error(`${message}${stderr ? `: ${stderr.trim()}` : ""}`));
@@ -2889,14 +2667,14 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath, option
2889
2667
  params: {
2890
2668
  protocolVersion: "2025-03-26",
2891
2669
  capabilities: {},
2892
- clientInfo: { name: "ostacky-installer", version: "0.8.2" }
2670
+ clientInfo: { name: "ostacky-installer", version: "0.8.3" }
2893
2671
  }
2894
2672
  });
2895
2673
  });
2896
2674
  } finally {
2897
- await new Promise((r2) => setTimeout(r2, 200));
2675
+ await new Promise((r) => setTimeout(r, 200));
2898
2676
  if (statePath) {
2899
- for (const p2 of [
2677
+ for (const p of [
2900
2678
  statePath,
2901
2679
  statePath + ".backup",
2902
2680
  statePath + ".lock.pid",
@@ -2904,13 +2682,13 @@ async function probeMcpServer(nodeExecutable, serverPath, cwd, statePath, option
2904
2682
  statePath + ".tmp." + process.pid
2905
2683
  ]) {
2906
2684
  try {
2907
- if (existsSync5(p2))
2908
- rmSync3(p2, { force: true });
2685
+ if (existsSync5(p))
2686
+ rmSync3(p, { force: true });
2909
2687
  } catch {}
2910
2688
  }
2911
2689
  try {
2912
- const { dirname: dirname5, join: join7 } = await import("path");
2913
- const handoff = join7(dirname5(statePath), ".ostacky-handoff-compaction.json");
2690
+ const { dirname, join } = await import("path");
2691
+ const handoff = join(dirname(statePath), ".ostacky-handoff-compaction.json");
2914
2692
  if (existsSync5(handoff)) {
2915
2693
  try {
2916
2694
  rmSync3(handoff, { force: true });
@@ -3247,75 +3025,28 @@ function printPostInstallSteps() {
3247
3025
  `), "Próximos pasos");
3248
3026
  }
3249
3027
  async function resolveOpenCodePaths(scope) {
3250
- if (scope === "local" || scope === "global" || scope === "auto") {
3251
- const dir2 = getOpenCodeDirForScope(scope);
3252
- const isGlobalDir = dir2.replace(/\\/g, "/") === getGlobalOpenCodeDir().replace(/\\/g, "/");
3253
- try {
3254
- const paths = ensureOpenCodePaths(dir2);
3255
- if (scope === "global")
3256
- ye(dir2, "Instalación global");
3257
- else if (scope === "auto")
3258
- ye(dir2, `Scope auto → ${isGlobalDir ? "global" : "local"}`);
3259
- else
3260
- ye(dir2, "Instalación local");
3261
- return paths;
3262
- } catch (e2) {
3263
- const msg = e2.message ?? "";
3264
- if ((scope === "global" || scope === "auto" && isGlobalDir) && (msg.includes("EACCES") || msg.toLowerCase().includes("permission"))) {
3265
- v2.warn(`No se pudo escribir en global (${dir2}): ${msg}. ¿Instalar local?`);
3266
- const retry = await me({ message: "¿Reintentar como instalación local?" });
3267
- onCancel(retry);
3268
- if (retry) {
3269
- const localDir2 = getOpenCodeDirForScope("local");
3270
- return ensureOpenCodePaths(localDir2);
3271
- }
3272
- }
3273
- throw e2;
3274
- }
3275
- }
3276
3028
  const cwd = process.cwd();
3277
- const localDir = getOpenCodeDirForScope("local", cwd);
3278
- const globalDir = getGlobalOpenCodeDir();
3279
- const hasLocal = !!findOpenCodeDir(cwd);
3280
- const scopeChoice = await de({
3281
- message: `¿Instalar en proyecto local (${localDir}) o global (${globalDir})?`,
3282
- options: [
3283
- { value: "local", label: "Local", hint: `${localDir} (recomendado)` },
3284
- { value: "global", label: "Global", hint: globalDir }
3285
- ],
3286
- initialValue: "local"
3287
- });
3288
- onCancel(scopeChoice);
3289
- const chosen = scopeChoice;
3290
- const dir = getOpenCodeDirForScope(chosen, cwd);
3029
+ const dir = scope === "local" || !scope ? getOpenCodeDirForScope("local", cwd) : getOpenCodeDirForScope("local", cwd);
3030
+ if (scope && scope !== "local") {
3031
+ v2.warn(`Scope ${scope} removido; usando local en ${dir}`);
3032
+ }
3291
3033
  try {
3292
- return ensureOpenCodePaths(dir);
3293
- } catch (e2) {
3294
- const msg = e2.message ?? "";
3295
- if (chosen === "global" && (msg.includes("EACCES") || msg.includes("permission"))) {
3296
- v2.warn(`No se pudo escribir en global (${dir}): ${msg}.`);
3297
- const retry = await me({ message: "¿Instalar local en su lugar?" });
3298
- onCancel(retry);
3299
- if (retry)
3300
- return ensureOpenCodePaths(getOpenCodeDirForScope("local", cwd));
3301
- }
3302
- throw e2;
3034
+ const paths = ensureOpenCodePaths(dir);
3035
+ ye(dir, "Instalación local");
3036
+ return paths;
3037
+ } catch (e) {
3038
+ throw e;
3303
3039
  }
3304
3040
  }
3305
- function isGlobalScope(paths) {
3306
- const globalDir = getGlobalOpenCodeDir().replace(/\\/g, "/");
3307
- const root = paths.root.replace(/\\/g, "/");
3308
- return root === globalDir || root.startsWith(globalDir + "/");
3309
- }
3310
3041
  function getOrphanedItems(manifest, paths) {
3311
3042
  const lockfile = readLockfile(paths.root);
3312
3043
  if (!lockfile)
3313
3044
  return [];
3314
3045
  const manifestNames = {
3315
- agents: new Set(manifest.agents.map((a2) => a2.name)),
3316
- commands: new Set(manifest.commands.map((c2) => c2.name)),
3046
+ agents: new Set(manifest.agents.map((a) => a.name)),
3047
+ commands: new Set(manifest.commands.map((c) => c.name)),
3317
3048
  skills: new Set((manifest.skills ?? []).map((s) => s.name)),
3318
- mcpServers: new Set((manifest.mcpServers ?? []).map((m3) => m3.name))
3049
+ mcpServers: new Set((manifest.mcpServers ?? []).map((m) => m.name))
3319
3050
  };
3320
3051
  const orphans = [];
3321
3052
  for (const type of ["agents", "commands", "skills", "mcpServers"]) {
@@ -3392,8 +3123,8 @@ async function doInstallStack(toolsDir, projectRoot) {
3392
3123
  const resolvedToolsDir = toolsDir ?? join8(resolvedProjectRoot, ".opencode", "tools");
3393
3124
  v2.info(`Stack → projectRoot: ${resolvedProjectRoot} | toolsDir: ${resolvedToolsDir}`);
3394
3125
  try {
3395
- const { homedir: homedir2 } = await import("os");
3396
- const home = homedir2();
3126
+ const { homedir } = await import("os");
3127
+ const home = homedir();
3397
3128
  const inHome = resolvedProjectRoot.replace(/\\/g, "/") === home.replace(/\\/g, "/");
3398
3129
  if (inHome && !existsSync7(join8(home, ".git"))) {
3399
3130
  v2.warn(`Estás instalando el stack en tu home (${home}). Si esperabas instalar en un proyecto, hacé cd al proyecto y usá --scope local.`);
@@ -3415,34 +3146,35 @@ async function doInstallStack(toolsDir, projectRoot) {
3415
3146
  if (!eng.success)
3416
3147
  allOk = false;
3417
3148
  spin.start("Verificando configuración...");
3418
- const { patchOpenCodeConfig: patchOpenCodeConfig2 } = await Promise.resolve().then(() => (init_config(), exports_config));
3419
- const cfg = patchOpenCodeConfig2(resolvedProjectRoot);
3149
+ await Promise.resolve().then(() => init_config());
3150
+ const cfg = patchOpenCodeConfig(resolvedProjectRoot);
3420
3151
  spin.stop(cfg.success ? `✓ ${cfg.message}` : `✗ ${cfg.message}`);
3421
3152
  if (!cfg.success)
3422
3153
  allOk = false;
3423
3154
  if (!allOk) {
3424
3155
  v2.warn("Algunos componentes requieren atención. Revisá los mensajes de error arriba.");
3425
3156
  }
3157
+ try {
3158
+ const gi = ensureGitignore(resolvedProjectRoot);
3159
+ if (gi.created)
3160
+ v2.info(`.gitignore creado con patrones Ostacky`);
3161
+ else if (gi.updated)
3162
+ v2.info(`.gitignore actualizado: ${gi.patternsAdded.join(", ")}`);
3163
+ } catch {}
3426
3164
  return allOk;
3427
3165
  }
3428
3166
  async function doInstallAll(manifest, paths) {
3429
3167
  const spin = L2();
3430
3168
  let errors = 0;
3431
- const isGlobal = isGlobalScope(paths);
3432
- v2.info(`Scope → ${isGlobal ? "global" : "local"} | opencodeDir: ${paths.root} | tools: ${paths.tools}`);
3433
- if (!isGlobal) {
3434
- ensureToolDirs(paths.tools, ["codegraph", "engram"]);
3435
- } else {
3436
- 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.");
3437
- v2.info("Para instalar el stack, ejecutá 'npx ostacky install-stack --scope local' dentro de cada proyecto.");
3438
- }
3169
+ v2.info(`Scope local | opencodeDir: ${paths.root} | tools: ${paths.tools}`);
3170
+ ensureToolDirs(paths.tools, ["codegraph", "engram"]);
3439
3171
  for (const agent of manifest.agents) {
3440
3172
  spin.start(`Descargando agente: ${agent.name} (${agent.version})`);
3441
3173
  try {
3442
3174
  await installAgent(agent, manifest, paths);
3443
3175
  spin.stop(`Agente instalado: ${agent.name} (${agent.version})`);
3444
- } catch (e2) {
3445
- spin.stop(`Error en ${agent.name}: ${e2.message}`);
3176
+ } catch (e) {
3177
+ spin.stop(`Error en ${agent.name}: ${e.message}`);
3446
3178
  errors++;
3447
3179
  }
3448
3180
  }
@@ -3451,8 +3183,8 @@ async function doInstallAll(manifest, paths) {
3451
3183
  try {
3452
3184
  await installCommand(cmd, manifest, paths);
3453
3185
  spin.stop(`Command instalado: ${cmd.name} (${cmd.version})`);
3454
- } catch (e2) {
3455
- spin.stop(`Error en ${cmd.name}: ${e2.message}`);
3186
+ } catch (e) {
3187
+ spin.stop(`Error en ${cmd.name}: ${e.message}`);
3456
3188
  errors++;
3457
3189
  }
3458
3190
  }
@@ -3461,8 +3193,8 @@ async function doInstallAll(manifest, paths) {
3461
3193
  try {
3462
3194
  await installSkill(skill, manifest, paths);
3463
3195
  spin.stop(`Skill instalada: ${skill.name} (${skill.version})`);
3464
- } catch (e2) {
3465
- spin.stop(`Error en ${skill.name}: ${e2.message}`);
3196
+ } catch (e) {
3197
+ spin.stop(`Error en ${skill.name}: ${e.message}`);
3466
3198
  errors++;
3467
3199
  }
3468
3200
  }
@@ -3475,70 +3207,48 @@ async function doInstallAll(manifest, paths) {
3475
3207
  try {
3476
3208
  await installMcpServer(mcp, manifest, paths);
3477
3209
  spin.stop(`MCP server instalado: ${mcp.name} (${mcp.version})`);
3478
- } catch (e2) {
3479
- spin.stop(`Error en ${mcp.name}: ${e2.message}`);
3210
+ } catch (e) {
3211
+ spin.stop(`Error en ${mcp.name}: ${e.message}`);
3480
3212
  errors++;
3481
3213
  }
3482
3214
  }
3483
3215
  try {
3484
- const { copyFileSync: copyFileSync4, mkdirSync: mkdirSync5, existsSync: existsSync8, rmSync: rmSync5 } = await import("fs");
3485
- const { join: join9 } = await import("path");
3486
- const { PACKAGE_ROOT: PACKAGE_ROOT2 } = await Promise.resolve().then(() => (init_github(), exports_github));
3487
- const { findProjectRoot: findProjectRoot3 } = await Promise.resolve().then(() => (init_fs(), exports_fs));
3488
- const src = join9(PACKAGE_ROOT2, "assets", "plugins", "ostacky-plugin.ts");
3489
- const dest = join9(paths.plugins, "ostacky-plugin.ts");
3490
- if (existsSync8(src)) {
3491
- mkdirSync5(paths.plugins, { recursive: true });
3492
- copyFileSync4(src, dest);
3216
+ const { copyFileSync, mkdirSync, existsSync, rmSync } = await import("fs");
3217
+ const { join } = await import("path");
3218
+ await Promise.resolve().then(() => init_github());
3219
+ const { findProjectRoot } = await Promise.resolve().then(() => (init_fs(), {}));
3220
+ const src = join(PACKAGE_ROOT, "assets", "plugins", "ostacky-plugin.ts");
3221
+ const dest = join(paths.plugins, "ostacky-plugin.ts");
3222
+ if (existsSync(src)) {
3223
+ mkdirSync(paths.plugins, { recursive: true });
3224
+ copyFileSync(src, dest);
3493
3225
  }
3494
3226
  for (const legacy of ["ostacky-guard.ts", "ostacky-controller.ts"]) {
3495
- const lp = join9(paths.plugins, legacy);
3496
- if (existsSync8(lp))
3227
+ const lp = join(paths.plugins, legacy);
3228
+ if (existsSync(lp))
3497
3229
  try {
3498
- rmSync5(lp, { force: true });
3230
+ rmSync(lp, { force: true });
3499
3231
  } catch {}
3500
3232
  }
3501
- const srcEng = join9(PACKAGE_ROOT2, "assets", "plugins", "engram.ts");
3502
- const destEng = join9(paths.plugins, "engram.ts");
3503
- if (existsSync8(srcEng)) {
3504
- mkdirSync5(paths.plugins, { recursive: true });
3505
- copyFileSync4(srcEng, destEng);
3506
- }
3507
- if (isGlobal) {
3508
- try {
3509
- const projRoot = findProjectRoot3();
3510
- const localPlugins = join9(projRoot, ".opencode", "plugins");
3511
- mkdirSync5(localPlugins, { recursive: true });
3512
- if (existsSync8(src))
3513
- copyFileSync4(src, join9(localPlugins, "ostacky-plugin.ts"));
3514
- if (existsSync8(srcEng))
3515
- copyFileSync4(srcEng, join9(localPlugins, "engram.ts"));
3516
- for (const legacy of ["ostacky-guard.ts", "ostacky-controller.ts"]) {
3517
- const lp = join9(localPlugins, legacy);
3518
- if (existsSync8(lp))
3519
- try {
3520
- rmSync5(lp, { force: true });
3521
- } catch {}
3522
- }
3523
- } catch {}
3233
+ const srcEng = join(PACKAGE_ROOT, "assets", "plugins", "engram.ts");
3234
+ const destEng = join(paths.plugins, "engram.ts");
3235
+ if (existsSync(srcEng)) {
3236
+ mkdirSync(paths.plugins, { recursive: true });
3237
+ copyFileSync(srcEng, destEng);
3524
3238
  }
3525
3239
  } catch {}
3526
3240
  let stackOk = true;
3527
3241
  let missingTools = [];
3528
- if (isGlobal) {
3529
- stackOk = true;
3530
- } else {
3531
- v2.info("Instalando stack de herramientas...");
3532
- stackOk = await doInstallStack(paths.tools, dirname6(paths.root));
3533
- if (!stackOk)
3534
- errors++;
3535
- const codegraphDir = join8(paths.tools, "codegraph");
3536
- const engramDir = join8(paths.tools, "engram");
3537
- if (!existsSync7(codegraphDir) || !findBinaryInDir(codegraphDir, "codegraph"))
3538
- missingTools.push("CodeGraph");
3539
- if (!existsSync7(engramDir) || !findBinaryInDir(engramDir, "engram"))
3540
- missingTools.push("Engram");
3541
- }
3242
+ v2.info("Instalando stack de herramientas...");
3243
+ stackOk = await doInstallStack(paths.tools, dirname6(paths.root));
3244
+ if (!stackOk)
3245
+ errors++;
3246
+ const codegraphDir = join8(paths.tools, "codegraph");
3247
+ const engramDir = join8(paths.tools, "engram");
3248
+ if (!existsSync7(codegraphDir) || !findBinaryInDir(codegraphDir, "codegraph"))
3249
+ missingTools.push("CodeGraph");
3250
+ if (!existsSync7(engramDir) || !findBinaryInDir(engramDir, "engram"))
3251
+ missingTools.push("Engram");
3542
3252
  if (missingTools.length > 0) {
3543
3253
  v2.warn(`Faltan herramientas del stack: ${missingTools.join(", ")}.
3544
3254
  ` + "Ejecutá `/install-stack` desde el agente para instalarlas manualmente.");
@@ -3548,6 +3258,14 @@ async function doInstallAll(manifest, paths) {
3548
3258
  } else {
3549
3259
  v2.warn(`Instalación parcial: ${errors} componente(s) requieren atención.`);
3550
3260
  }
3261
+ try {
3262
+ const projectRoot = dirname6(paths.root);
3263
+ const gi = ensureGitignore(projectRoot);
3264
+ if (gi.created)
3265
+ v2.info(`.gitignore creado con patrones Ostacky`);
3266
+ else if (gi.updated)
3267
+ v2.info(`.gitignore actualizado: ${gi.patternsAdded.join(", ")}`);
3268
+ } catch {}
3551
3269
  return errors === 0 && stackOk && missingTools.length === 0;
3552
3270
  }
3553
3271
 
@@ -3555,10 +3273,10 @@ async function doInstallAll(manifest, paths) {
3555
3273
  init_lockfile();
3556
3274
  async function doAddAgent(manifest, paths) {
3557
3275
  const lockfile = readLockfile(paths.root);
3558
- const options = manifest.agents.map((a2) => {
3559
- const installed = getInstalledVersion(lockfile, "agents", a2.name);
3560
- const hint = installed ? `v${installed} instalado — ${a2.description}` : a2.description;
3561
- return { value: a2.name, label: `${a2.name} (v${a2.version})`, hint };
3276
+ const options = manifest.agents.map((a) => {
3277
+ const installed = getInstalledVersion(lockfile, "agents", a.name);
3278
+ const hint = installed ? `v${installed} instalado — ${a.description}` : a.description;
3279
+ return { value: a.name, label: `${a.name} (v${a.version})`, hint };
3562
3280
  });
3563
3281
  const selected = await pe({
3564
3282
  message: "¿Qué agentes deseas instalar?",
@@ -3568,22 +3286,22 @@ async function doAddAgent(manifest, paths) {
3568
3286
  onCancel(selected);
3569
3287
  const spin = L2();
3570
3288
  for (const name of selected) {
3571
- const item = manifest.agents.find((a2) => a2.name === name);
3289
+ const item = manifest.agents.find((a) => a.name === name);
3572
3290
  spin.start(`Descargando agente: ${name} (${item.version})`);
3573
3291
  try {
3574
3292
  await installAgent(item, manifest, paths);
3575
3293
  spin.stop(`Agente instalado: ${name} (${item.version})`);
3576
- } catch (e2) {
3577
- spin.stop(`Error: ${e2.message}`);
3294
+ } catch (e) {
3295
+ spin.stop(`Error: ${e.message}`);
3578
3296
  }
3579
3297
  }
3580
3298
  }
3581
3299
  async function doAddCommand(manifest, paths) {
3582
3300
  const lockfile = readLockfile(paths.root);
3583
- const options = manifest.commands.map((c2) => {
3584
- const installed = getInstalledVersion(lockfile, "commands", c2.name);
3585
- const hint = installed ? `v${installed} instalado — ${c2.description}` : c2.description;
3586
- return { value: c2.name, label: `${c2.name} (v${c2.version})`, hint };
3301
+ const options = manifest.commands.map((c) => {
3302
+ const installed = getInstalledVersion(lockfile, "commands", c.name);
3303
+ const hint = installed ? `v${installed} instalado — ${c.description}` : c.description;
3304
+ return { value: c.name, label: `${c.name} (v${c.version})`, hint };
3587
3305
  });
3588
3306
  const selected = await pe({
3589
3307
  message: "¿Qué commands deseas instalar?",
@@ -3593,13 +3311,13 @@ async function doAddCommand(manifest, paths) {
3593
3311
  onCancel(selected);
3594
3312
  const spin = L2();
3595
3313
  for (const name of selected) {
3596
- const item = manifest.commands.find((c2) => c2.name === name);
3314
+ const item = manifest.commands.find((c) => c.name === name);
3597
3315
  spin.start(`Descargando command: ${name} (${item.version})`);
3598
3316
  try {
3599
3317
  await installCommand(item, manifest, paths);
3600
3318
  spin.stop(`Command instalado: ${name} (${item.version})`);
3601
- } catch (e2) {
3602
- spin.stop(`Error: ${e2.message}`);
3319
+ } catch (e) {
3320
+ spin.stop(`Error: ${e.message}`);
3603
3321
  }
3604
3322
  }
3605
3323
  }
@@ -3627,17 +3345,17 @@ async function doAddSkill(manifest, paths) {
3627
3345
  try {
3628
3346
  await installSkill(item, manifest, paths);
3629
3347
  spin.stop(`Skill instalada: ${name} (${item.version})`);
3630
- } catch (e2) {
3631
- spin.stop(`Error: ${e2.message}`);
3348
+ } catch (e) {
3349
+ spin.stop(`Error: ${e.message}`);
3632
3350
  }
3633
3351
  }
3634
3352
  }
3635
3353
  async function doAddMcp(manifest, paths) {
3636
3354
  const lockfile = readLockfile(paths.root);
3637
- const options = (manifest.mcpServers ?? []).map((m3) => {
3638
- const installed = getInstalledVersion(lockfile, "mcpServers", m3.name);
3639
- const hint = installed ? `v${installed} instalado — ${m3.description}` : m3.description;
3640
- return { value: m3.name, label: `${m3.name} (v${m3.version})`, hint };
3355
+ const options = (manifest.mcpServers ?? []).map((m) => {
3356
+ const installed = getInstalledVersion(lockfile, "mcpServers", m.name);
3357
+ const hint = installed ? `v${installed} instalado — ${m.description}` : m.description;
3358
+ return { value: m.name, label: `${m.name} (v${m.version})`, hint };
3641
3359
  });
3642
3360
  if (options.length === 0) {
3643
3361
  v2.info("No hay MCP servers disponibles en el manifest.");
@@ -3651,15 +3369,15 @@ async function doAddMcp(manifest, paths) {
3651
3369
  onCancel(selected);
3652
3370
  const spin = L2();
3653
3371
  for (const name of selected) {
3654
- const item = manifest.mcpServers?.find((m3) => m3.name === name);
3372
+ const item = manifest.mcpServers?.find((m) => m.name === name);
3655
3373
  if (!item)
3656
3374
  continue;
3657
3375
  spin.start(`Instalando MCP server: ${name} (${item.version})`);
3658
3376
  try {
3659
3377
  await installMcpServer(item, manifest, paths);
3660
3378
  spin.stop(`MCP server instalado: ${name} (${item.version})`);
3661
- } catch (e2) {
3662
- spin.stop(`Error: ${e2.message}`);
3379
+ } catch (e) {
3380
+ spin.stop(`Error: ${e.message}`);
3663
3381
  }
3664
3382
  }
3665
3383
  }
@@ -3726,8 +3444,8 @@ async function doUpdate(manifest, paths) {
3726
3444
  }
3727
3445
  spin.stop(`Actualizado: ${item.name} (${item.version})`);
3728
3446
  updated++;
3729
- } catch (e2) {
3730
- spin.stop(`Error en ${item.name}: ${e2.message}`);
3447
+ } catch (e) {
3448
+ spin.stop(`Error en ${item.name}: ${e.message}`);
3731
3449
  }
3732
3450
  }
3733
3451
  v2.success(`${updated} recurso(s) actualizado(s).`);
@@ -3941,10 +3659,10 @@ async function doUninstall(paths) {
3941
3659
  }
3942
3660
  async function doUninstallAgentByName(name, paths) {
3943
3661
  try {
3944
- const { validateFilePath: validateFilePath2 } = await Promise.resolve().then(() => (init_security(), exports_security));
3945
- validateFilePath2(`${name}.md`);
3946
- } catch (e2) {
3947
- v2.warn(`Nombre inválido: ${e2.message}`);
3662
+ await Promise.resolve().then(() => init_security());
3663
+ validateFilePath(`${name}.md`);
3664
+ } catch (e) {
3665
+ v2.warn(`Nombre inválido: ${e.message}`);
3948
3666
  return;
3949
3667
  }
3950
3668
  const lockfile = readLockfile(paths.root);
@@ -3969,10 +3687,10 @@ async function doUninstallAgentByName(name, paths) {
3969
3687
  }
3970
3688
  async function doUninstallCommandByName(name, paths) {
3971
3689
  try {
3972
- const { validateFilePath: validateFilePath2 } = await Promise.resolve().then(() => (init_security(), exports_security));
3973
- validateFilePath2(`${name}.md`);
3974
- } catch (e2) {
3975
- v2.warn(`Nombre inválido: ${e2.message}`);
3690
+ await Promise.resolve().then(() => init_security());
3691
+ validateFilePath(`${name}.md`);
3692
+ } catch (e) {
3693
+ v2.warn(`Nombre inválido: ${e.message}`);
3976
3694
  return;
3977
3695
  }
3978
3696
  const lockfile = readLockfile(paths.root);
@@ -3997,10 +3715,10 @@ async function doUninstallCommandByName(name, paths) {
3997
3715
  }
3998
3716
  async function doUninstallSkillByName(name, paths) {
3999
3717
  try {
4000
- const { validateFilePath: validateFilePath2 } = await Promise.resolve().then(() => (init_security(), exports_security));
4001
- validateFilePath2(name);
4002
- } catch (e2) {
4003
- v2.warn(`Nombre inválido: ${e2.message}`);
3718
+ await Promise.resolve().then(() => init_security());
3719
+ validateFilePath(name);
3720
+ } catch (e) {
3721
+ v2.warn(`Nombre inválido: ${e.message}`);
4004
3722
  return;
4005
3723
  }
4006
3724
  const lockfile = readLockfile(paths.root);
@@ -4025,10 +3743,10 @@ async function doUninstallSkillByName(name, paths) {
4025
3743
  }
4026
3744
  async function doUninstallMcpByName(name, paths) {
4027
3745
  try {
4028
- const { validateFilePath: validateFilePath2 } = await Promise.resolve().then(() => (init_security(), exports_security));
4029
- validateFilePath2(name);
4030
- } catch (e2) {
4031
- v2.warn(`Nombre inválido: ${e2.message}`);
3746
+ await Promise.resolve().then(() => init_security());
3747
+ validateFilePath(name);
3748
+ } catch (e) {
3749
+ v2.warn(`Nombre inválido: ${e.message}`);
4032
3750
  return;
4033
3751
  }
4034
3752
  const lockfile = readLockfile(paths.root);
@@ -4121,9 +3839,9 @@ ${info.note}` : ""}`, `Instalación requerida (${platform})`);
4121
3839
  }
4122
3840
  }
4123
3841
  spin.stop("Instalación ejecutada, verificando...");
4124
- } catch (e2) {
3842
+ } catch (e) {
4125
3843
  spin.stop("Fallo la instalación automática.");
4126
- const msg = e2.message ?? String(e2);
3844
+ const msg = e.message ?? String(e);
4127
3845
  v2.error(`No se pudo instalar OpenCode automáticamente: ${msg}`);
4128
3846
  if (platform === "win32") {
4129
3847
  ye([
@@ -4217,12 +3935,6 @@ async function runInteractiveMenu(scope) {
4217
3935
  fe("Listo.");
4218
3936
  break;
4219
3937
  case "stack": {
4220
- if (isGlobalScope(paths)) {
4221
- v2.error("install-stack requiere scope local; el stack vive en <proyecto>/.opencode/tools");
4222
- v2.info(`Elegiste global (${paths.root}) — el stack debe instalarse por proyecto local.`);
4223
- fe("Cancelado.");
4224
- break;
4225
- }
4226
3938
  ensureToolDirs(paths.tools, ["codegraph", "engram"]);
4227
3939
  const stackOk = await doInstallStack(paths.tools, dirname7(paths.root));
4228
3940
  if (!stackOk)
@@ -4313,25 +4025,12 @@ async function runAddMcpCommand(scope) {
4313
4025
  }
4314
4026
  async function runInstallStackCommand(scope) {
4315
4027
  await ensureOpencodeInstalled();
4316
- if (scope === "global") {
4317
- v2.error("install-stack requiere scope local; el stack vive en <proyecto>/.opencode/tools");
4318
- fe("Usá: npx ostacky install-stack --scope local");
4319
- process.exitCode = 1;
4320
- return;
4321
- }
4322
4028
  we(" OpenCode Installer — Stack ");
4323
4029
  const paths = await resolveOpenCodePaths(scope ?? null);
4324
4030
  if (!paths) {
4325
4031
  fe("Cancelado.");
4326
4032
  return;
4327
4033
  }
4328
- if (isGlobalScope(paths)) {
4329
- v2.error("install-stack requiere scope local; el stack vive en <proyecto>/.opencode/tools");
4330
- v2.info(`Scope resuelto a global (${paths.root}) — el stack debe instalarse por proyecto local.`);
4331
- fe("Cancelado.");
4332
- process.exitCode = 1;
4333
- return;
4334
- }
4335
4034
  ensureToolDirs(paths.tools, ["codegraph", "engram"]);
4336
4035
  const stackOk = await doInstallStack(paths.tools, dirname7(paths.root));
4337
4036
  if (!stackOk)
@@ -4353,8 +4052,8 @@ async function runUninstallStackCommand(scope) {
4353
4052
  fe("Cancelado.");
4354
4053
  return;
4355
4054
  }
4356
- const { uninstallStackConfig: uninstallStackConfig2 } = await Promise.resolve().then(() => (init_stack(), exports_stack));
4357
- const result = uninstallStackConfig2(paths);
4055
+ await Promise.resolve().then(() => init_stack());
4056
+ const result = uninstallStackConfig(paths);
4358
4057
  if (result.success) {
4359
4058
  v2.success(result.message);
4360
4059
  } else {
@@ -4394,8 +4093,8 @@ async function runUninstallAgentCommand(name, scope) {
4394
4093
  if (name) {
4395
4094
  await doUninstallAgentByName(name, paths);
4396
4095
  } else {
4397
- const { readLockfile: readLockfile2 } = await Promise.resolve().then(() => (init_lockfile(), exports_lockfile));
4398
- const lockfile = readLockfile2(paths.root);
4096
+ await Promise.resolve().then(() => init_lockfile());
4097
+ const lockfile = readLockfile(paths.root);
4399
4098
  if (lockfile && Object.keys(lockfile.agents).length > 0) {
4400
4099
  const prompts = exports_dist;
4401
4100
  const installed = Object.keys(lockfile.agents);
@@ -4429,8 +4128,8 @@ async function runUninstallCommandCommand(name, scope) {
4429
4128
  if (name) {
4430
4129
  await doUninstallCommandByName(name, paths);
4431
4130
  } else {
4432
- const { readLockfile: readLockfile2 } = await Promise.resolve().then(() => (init_lockfile(), exports_lockfile));
4433
- const lockfile = readLockfile2(paths.root);
4131
+ await Promise.resolve().then(() => init_lockfile());
4132
+ const lockfile = readLockfile(paths.root);
4434
4133
  if (lockfile && Object.keys(lockfile.commands).length > 0) {
4435
4134
  const prompts = exports_dist;
4436
4135
  const installed = Object.keys(lockfile.commands);
@@ -4464,8 +4163,8 @@ async function runUninstallSkillCommand(name, scope) {
4464
4163
  if (name) {
4465
4164
  await doUninstallSkillByName(name, paths);
4466
4165
  } else {
4467
- const { readLockfile: readLockfile2 } = await Promise.resolve().then(() => (init_lockfile(), exports_lockfile));
4468
- const lockfile = readLockfile2(paths.root);
4166
+ await Promise.resolve().then(() => init_lockfile());
4167
+ const lockfile = readLockfile(paths.root);
4469
4168
  if (lockfile && lockfile.skills && Object.keys(lockfile.skills).length > 0) {
4470
4169
  const prompts = exports_dist;
4471
4170
  const installed = Object.keys(lockfile.skills);
@@ -4499,8 +4198,8 @@ async function runUninstallMcpCommand(name, scope) {
4499
4198
  if (name) {
4500
4199
  await doUninstallMcpByName(name, paths);
4501
4200
  } else {
4502
- const { readLockfile: readLockfile2 } = await Promise.resolve().then(() => (init_lockfile(), exports_lockfile));
4503
- const lockfile = readLockfile2(paths.root);
4201
+ await Promise.resolve().then(() => init_lockfile());
4202
+ const lockfile = readLockfile(paths.root);
4504
4203
  if (lockfile && lockfile.mcpServers && Object.keys(lockfile.mcpServers).length > 0) {
4505
4204
  const prompts = exports_dist;
4506
4205
  const installed = Object.keys(lockfile.mcpServers);
@@ -4533,43 +4232,49 @@ var HELP = `
4533
4232
  ostacky — Instalador de agentes, comandos, skills y MCPs para OpenCode
4534
4233
 
4535
4234
  Uso:
4536
- npx ostacky [--scope local|global|auto] Menú interactivo (instalación completa, pregunta local vs global, default local)
4537
- npx ostacky install [--scope local|global|auto] Instalar TODO (agente + skills + MCPs + CodeGraph + OpenSpec + Engram)
4538
- npx ostacky add agent [--scope local|global|auto] Agregar agente(s)
4539
- npx ostacky add command [--scope ...] Agregar command(s)
4540
- npx ostacky add skill [--scope ...] Agregar skill(s)
4541
- npx ostacky add mcp [--scope ...] Agregar MCP server(s)
4542
- npx ostacky install-stack [--scope local|auto] Instalar solo el stack de herramientas (CodeGraph, OpenSpec, Engram) — global bloquea con error
4543
- npx ostacky uninstall-stack [--scope local|global|auto] Remover la configuración del stack del proyecto
4235
+ npx ostacky [--scope local] Menú interactivo (instalación completa, siempre local)
4236
+ npx ostacky install [--scope local] Instalar TODO (agente + skills + MCPs + CodeGraph + OpenSpec + Engram)
4237
+ npx ostacky add agent [--scope local] Agregar agente(s)
4238
+ npx ostacky add command [--scope local] Agregar command(s)
4239
+ npx ostacky add skill [--scope local] Agregar skill(s)
4240
+ npx ostacky add mcp [--scope local] Agregar MCP server(s)
4241
+ npx ostacky install-stack [--scope local] Instalar solo el stack de herramientas (CodeGraph, OpenSpec, Engram)
4242
+ npx ostacky uninstall-stack [--scope local] Remover la configuración del stack del proyecto
4544
4243
  npx ostacky doctor Diagnostica locks, tools, state health
4545
4244
  npx ostacky status [--json] Muestra estado del controller sin MCP
4546
- npx ostacky update [--scope ...] Actualizar instalación
4547
- npx ostacky uninstall [--scope ...] Desinstalar todo
4548
- npx ostacky uninstall agent [--scope ...] Desinstalar agente(s)
4549
- npx ostacky uninstall command [--scope ...] Desinstalar command(s)
4550
- npx ostacky uninstall skill [--scope ...] Desinstalar skill(s)
4551
- npx ostacky uninstall mcp [--scope ...] Desinstalar MCP server(s)
4245
+ npx ostacky update [--scope local] Actualizar instalación
4246
+ npx ostacky uninstall [--scope local] Desinstalar todo
4247
+ npx ostacky uninstall agent [--scope local] Desinstalar agente(s)
4248
+ npx ostacky uninstall command [--scope local] Desinstalar command(s)
4249
+ npx ostacky uninstall skill [--scope local] Desinstalar skill(s)
4250
+ npx ostacky uninstall mcp [--scope local] Desinstalar MCP server(s)
4552
4251
  npx ostacky --help Mostrar esta ayuda
4553
4252
  npx ostacky --version Mostrar versión
4554
4253
 
4555
4254
  Scope:
4556
- --scope local Escribe en <proyecto>/.opencode (recomendado, default al preguntar)
4557
- --scope global Escribe en ~/.config/opencode (o %APPDATA%\\opencode en Windows)
4558
- --scope auto Elige local si existe .opencode o .git, si no global
4559
- Sin flag Pregunta interactiva local (default) vs global
4255
+ --scope local Escribe en <proyecto>/.opencode (siempre local, instalador único)
4256
+ Sin flag Asume local implícito (no pregunta global)
4560
4257
  `.trim();
4561
- function parseScopeArg2(argv = process.argv) {
4258
+ function parseScopeArg(argv = process.argv) {
4562
4259
  for (let i = 0;i < argv.length; i++) {
4563
4260
  const arg = argv[i];
4564
4261
  if (arg === "--scope" && i + 1 < argv.length) {
4565
- const v3 = argv[i + 1];
4566
- if (v3 === "local" || v3 === "global" || v3 === "auto")
4567
- return v3;
4262
+ const v = argv[i + 1];
4263
+ if (v === "local")
4264
+ return v;
4265
+ if (v === "global" || v === "auto") {
4266
+ console.error(`Error: --scope ${v} removido; Ostacky instala siempre local en <proyecto>/.opencode. Hacé cd al proyecto y re-ejecutá con --scope local.`);
4267
+ process.exit(1);
4268
+ }
4568
4269
  }
4569
4270
  if (arg.startsWith("--scope=")) {
4570
- const v3 = arg.split("=")[1];
4571
- if (v3 === "local" || v3 === "global" || v3 === "auto")
4572
- return v3;
4271
+ const v = arg.split("=")[1];
4272
+ if (v === "local")
4273
+ return v;
4274
+ if (v === "global" || v === "auto") {
4275
+ console.error(`Error: --scope ${v} removido; Ostacky instala siempre local en <proyecto>/.opencode. Hacé cd al proyecto y re-ejecutá con --scope local.`);
4276
+ process.exit(1);
4277
+ }
4573
4278
  }
4574
4279
  }
4575
4280
  return null;
@@ -4588,7 +4293,7 @@ function withoutScopeArgs(argv) {
4588
4293
  }
4589
4294
  return out;
4590
4295
  }
4591
- var scope = parseScopeArg2();
4296
+ var scope = parseScopeArg();
4592
4297
  var argvNoScope = withoutScopeArgs(process.argv);
4593
4298
  var [, , cmd, subcmd] = argvNoScope;
4594
4299
  async function runDoctorCommand() {
@@ -4616,7 +4321,7 @@ async function runDoctorCommand() {
4616
4321
  join10(opencodeDir, "plugins", "ostacky-controller.ts"),
4617
4322
  join10(cwd, ".opencode", "plugins", "ostacky-controller.ts")
4618
4323
  ];
4619
- const pluginActive = pluginPaths.some((p2) => existsSync8(p2));
4324
+ const pluginActive = pluginPaths.some((p) => existsSync8(p));
4620
4325
  try {
4621
4326
  if (!existsSync8(statePath)) {
4622
4327
  if (pluginActive)
@@ -4683,8 +4388,8 @@ async function runDoctorCommand() {
4683
4388
  }
4684
4389
  }
4685
4390
  }
4686
- } catch (e2) {
4687
- check(`controller: ${e2.message}`, false);
4391
+ } catch (e) {
4392
+ check(`controller: ${e.message}`, false);
4688
4393
  }
4689
4394
  try {
4690
4395
  const lockPid = join10(opencodeDir, "ostacky-state.json.lock.pid");
@@ -4713,13 +4418,13 @@ async function runDoctorCommand() {
4713
4418
  }
4714
4419
  const tools = ["codegraph", "engram"];
4715
4420
  for (const t of tools) {
4716
- const p2 = join10(opencodeDir, "tools", t, "bin", t);
4717
- const pExe = p2 + ".exe";
4718
- check(`tool ${t}: ${existsSync8(p2) || existsSync8(pExe) ? "found" : "missing"}`, existsSync8(p2) || existsSync8(pExe), true);
4421
+ const p = join10(opencodeDir, "tools", t, "bin", t);
4422
+ const pExe = p + ".exe";
4423
+ check(`tool ${t}: ${existsSync8(p) || existsSync8(pExe) ? "found" : "missing"}`, existsSync8(p) || existsSync8(pExe), true);
4719
4424
  }
4720
4425
  try {
4721
4426
  const manifest = JSON.parse(readFileSync6(join10(cwd, "manifest.json"), "utf-8"));
4722
- const expected = manifest.mcpServers?.find((x2) => x2.name === "ostacky-controller")?.sha256;
4427
+ const expected = manifest.mcpServers?.find((x) => x.name === "ostacky-controller")?.sha256;
4723
4428
  if (expected) {
4724
4429
  const actual = computeTreeHash(join10(cwd, "assets", "mcp", "ostacky-controller"));
4725
4430
  check(`manifest hash: ${expected.slice(0, 8)} vs actual ${actual.slice(0, 8)}`, expected === actual);
@@ -4742,9 +4447,9 @@ async function runDoctorCommand() {
4742
4447
  } else {
4743
4448
  const files = readdirSync3(cacheDir);
4744
4449
  let total = 0;
4745
- for (const f2 of files) {
4450
+ for (const f of files) {
4746
4451
  try {
4747
- total += statSync3(join10(cacheDir, f2)).size;
4452
+ total += statSync3(join10(cacheDir, f)).size;
4748
4453
  } catch {}
4749
4454
  }
4750
4455
  const totalMB = (total / 1048576).toFixed(2);
@@ -4761,9 +4466,86 @@ async function runDoctorCommand() {
4761
4466
  }
4762
4467
  } catch {}
4763
4468
  }
4764
- } catch (e2) {
4765
- console.log(`⚠️ cache: check failed ${e2.message}`);
4469
+ } catch (e) {
4470
+ console.log(`⚠️ cache: check failed ${e.message}`);
4471
+ }
4472
+ try {
4473
+ const coreSrc = join10(cwd, "src", "controller-core.ts");
4474
+ const coreMcp = join10(cwd, "assets", "mcp", "ostacky-controller", "controller-core.js");
4475
+ const corePlugin = join10(cwd, "assets", "plugins", "controller-core.ts");
4476
+ const coreSync = existsSync8(coreSrc) && existsSync8(coreMcp) && existsSync8(corePlugin);
4477
+ if (coreSync) {
4478
+ const srcHash = readFileSync6(coreSrc, "utf-8").slice(0, 100);
4479
+ const mcpHash = readFileSync6(coreMcp, "utf-8").slice(0, 100);
4480
+ const ok = readFileSync6(coreMcp, "utf-8").includes("STATES") && readFileSync6(corePlugin, "utf-8").includes("STATES");
4481
+ check(`controller-core: synced (${ok ? "STATES present" : "mismatch"})`, ok);
4482
+ if (!ok)
4483
+ console.log(" Run: bun run scripts/sync-controller-core.ts (if exists) or copy src/controller-core.ts");
4484
+ } else {
4485
+ check("controller-core: synced", false, true);
4486
+ }
4487
+ const auditPath = join10(opencodeDir, "ostacky-audit.jsonl");
4488
+ if (existsSync8(auditPath)) {
4489
+ const sz = statSync3(auditPath).size;
4490
+ const lines = readFileSync6(auditPath, "utf-8").split(`
4491
+ `).filter(Boolean).length;
4492
+ check(`audit: jsonl ${lines} entries, ${(sz / 1024).toFixed(1)}KB`, sz < 512000);
4493
+ if (existsSync8(statePath)) {
4494
+ const s = JSON.parse(readFileSync6(statePath, "utf-8"));
4495
+ const stateSize = statSync3(statePath).size;
4496
+ check(`state size <50KB (${(stateSize / 1024).toFixed(1)}KB)`, stateSize < 51200);
4497
+ if (s.audit && s.audit.length > 20)
4498
+ console.log(`⚠️ state.audit large: ${s.audit.length} (should be tail only, full in jsonl)`);
4499
+ else if (s.auditTail)
4500
+ console.log(`✅ state.auditTail: ${s.auditTail.length} (jsonl primary)`);
4501
+ }
4502
+ } else {
4503
+ console.log("ℹ️ audit: jsonl not yet created (will be created on next audit)");
4504
+ }
4505
+ const ostackyMd = readFileSync6(join10(cwd, "assets", "agents", "ostacky.md"), "utf-8");
4506
+ const hasLevels = ostackyMd.includes("LEVEL_THRESHOLDS") || ostackyMd.includes("classifyLevel");
4507
+ check("levels: unified via tiered.ts", hasLevels, true);
4508
+ const hasHonesty = ostackyMd.includes("Principios de honestidad");
4509
+ check("honesty: 7 SHALL", hasHonesty);
4510
+ if (!hasHonesty)
4511
+ console.log(" Expected: ## Principios de honestidad (SHALL) in ostacky.md");
4512
+ const pluginPath = join10(cwd, "assets", "plugins", "ostacky-plugin.ts");
4513
+ if (existsSync8(pluginPath)) {
4514
+ const plugin = readFileSync6(pluginPath, "utf-8");
4515
+ const hasSpecGuard = plugin.includes("getDiscoverySnapshot") && plugin.includes("specSnapshot");
4516
+ const hasNoOverwrite = plugin.includes("No edites sin Read fresco") || plugin.includes("specSnapshot");
4517
+ check("spec: no-overwrite guard", hasNoOverwrite, true);
4518
+ }
4519
+ const hasSyncProactive = ostackyMd.includes("Noté que lo que acordamos");
4520
+ check("sync: proactive WARN", hasSyncProactive, true);
4521
+ } catch (e) {
4522
+ console.log(`⚠️ honesty/spec checks failed: ${e.message}`);
4766
4523
  }
4524
+ try {
4525
+ const giPath = join10(cwd, ".gitignore");
4526
+ if (!existsSync8(giPath)) {
4527
+ console.log("⚠️ .gitignore: missing (run npx ostacky install --scope local to create)");
4528
+ hasWarn = true;
4529
+ } else {
4530
+ const gi = readFileSync6(giPath, "utf-8");
4531
+ const needed = [
4532
+ ".opencode/tools/",
4533
+ ".opencode/cache/",
4534
+ ".opencode/ostacky-state.json",
4535
+ ".codegraph/",
4536
+ "openspec/"
4537
+ ];
4538
+ const missing = needed.filter((p) => !gi.includes(p));
4539
+ if (missing.length > 0) {
4540
+ console.log(`⚠️ .gitignore: missing ${missing.join(", ")} — run npx ostacky install to regenerate`);
4541
+ hasWarn = true;
4542
+ } else {
4543
+ console.log("✅ .gitignore: OK (covers .opencode/tools/, cache, state, .codegraph/, openspec/)");
4544
+ }
4545
+ if (!gi.includes("# Ostacky"))
4546
+ console.log("ℹ️ .gitignore: missing # Ostacky header");
4547
+ }
4548
+ } catch {}
4767
4549
  try {
4768
4550
  const secPath = join10(cwd, "src", "security.ts");
4769
4551
  if (!existsSync8(secPath)) {
@@ -4810,14 +4592,20 @@ async function runStatusCommand(args) {
4810
4592
  const degraded = parsed.degraded ? " degraded" : "";
4811
4593
  const lastHandoff = parsed.lastHandoff ? ` lastHandoff: ${parsed.lastHandoff.summary?.slice(0, 60)}` : "";
4812
4594
  if (isJson) {
4813
- console.log(JSON.stringify({ state: parsed.state, revision: parsed.revision, degraded: !!parsed.degraded, tasks: `${completed}/${expected}`, lastHandoff: parsed.lastHandoff }, null, 2));
4595
+ console.log(JSON.stringify({
4596
+ state: parsed.state,
4597
+ revision: parsed.revision,
4598
+ degraded: !!parsed.degraded,
4599
+ tasks: `${completed}/${expected}`,
4600
+ lastHandoff: parsed.lastHandoff
4601
+ }, null, 2));
4814
4602
  } else {
4815
4603
  console.log(`${parsed.state} rev ${parsed.revision}${degraded} tasks ${completed}/${expected}${lastHandoff}`);
4816
4604
  if (parsed.lastProposal)
4817
4605
  console.log(`lastProposal: ${parsed.lastProposal.summary} shownToUser=${parsed.lastProposal.shownToUser}`);
4818
4606
  }
4819
- } catch (e2) {
4820
- console.log(`Error reading state: ${e2.message}`);
4607
+ } catch (e) {
4608
+ console.log(`Error reading state: ${e.message}`);
4821
4609
  }
4822
4610
  }
4823
4611
  async function main() {
@@ -4830,11 +4618,6 @@ async function main() {
4830
4618
  await runInstallCommand(scope);
4831
4619
  break;
4832
4620
  case "install-stack":
4833
- if (scope === "global") {
4834
- console.error("Error: install-stack requiere scope local; el stack vive en <proyecto>/.opencode/tools");
4835
- console.error("Sugerencia: ejecutá 'npx ostacky install-stack --scope local' dentro de cada proyecto.");
4836
- process.exit(1);
4837
- }
4838
4621
  await runInstallStackCommand(scope);
4839
4622
  break;
4840
4623
  case "uninstall-stack":
@@ -4899,7 +4682,7 @@ async function main() {
4899
4682
  await runInteractiveMenu(scope);
4900
4683
  }
4901
4684
  }
4902
- main().catch((e2) => {
4903
- console.error("Error:", e2.message);
4685
+ main().catch((e) => {
4686
+ console.error("Error:", e.message);
4904
4687
  process.exit(1);
4905
4688
  });