@pushary/agent-hooks 0.61.0 → 0.62.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/dist/bin/pushary-claude.js +4 -4
  3. package/dist/bin/pushary-clean.js +82 -35
  4. package/dist/bin/pushary-codex-hook.js +4 -4
  5. package/dist/bin/pushary-codex.js +3 -3
  6. package/dist/bin/pushary-connect.js +7 -6
  7. package/dist/bin/pushary-daemon.js +37 -5
  8. package/dist/bin/pushary-doctor.js +114 -34
  9. package/dist/bin/pushary-gemini-hook.js +4 -4
  10. package/dist/bin/pushary-hook.js +5 -5
  11. package/dist/bin/pushary-login.js +5 -4
  12. package/dist/bin/pushary-logout.js +52 -9
  13. package/dist/bin/pushary-mode.js +4 -4
  14. package/dist/bin/pushary-notification-hook.js +2 -2
  15. package/dist/bin/pushary-permission-denied-hook.js +3 -3
  16. package/dist/bin/pushary-permission-hook.js +3 -3
  17. package/dist/bin/pushary-post-hook.js +2 -2
  18. package/dist/bin/pushary-prompt-hook.js +2 -2
  19. package/dist/bin/pushary-session-end-hook.js +2 -2
  20. package/dist/bin/pushary-session-start-hook.js +2 -2
  21. package/dist/bin/pushary-setup.js +97 -155
  22. package/dist/bin/pushary-stats.js +2 -2
  23. package/dist/bin/pushary-status.js +6 -5
  24. package/dist/bin/pushary-stop-hook.js +2 -2
  25. package/dist/bin/pushary-stopfailure-hook.js +2 -2
  26. package/dist/bin/pushary-suggestions.js +2 -2
  27. package/dist/bin/pushary-upgrade.js +189 -18
  28. package/dist/bin/pushary-wait.js +4 -4
  29. package/dist/bin/pushary.js +1 -1
  30. package/dist/{chunk-GX64YGU3.js → chunk-3O27ZSRE.js} +25 -0
  31. package/dist/{chunk-HI4AGGE6.js → chunk-5SO3CEGJ.js} +4 -4
  32. package/dist/chunk-6MTNS63X.js +55 -0
  33. package/dist/{chunk-B26DNXCA.js → chunk-COC6NPWG.js} +13 -59
  34. package/dist/chunk-E2U35RLD.js +108 -0
  35. package/dist/chunk-ER657KRJ.js +168 -0
  36. package/dist/{chunk-HUJQSP4F.js → chunk-IIZZYUWK.js} +1 -1
  37. package/dist/chunk-N7XJ4L2W.js +79 -0
  38. package/dist/{chunk-R6C4USIV.js → chunk-ONVEYEVR.js} +2 -2
  39. package/dist/{chunk-SML23YOT.js → chunk-SP7OZXCQ.js} +10 -2
  40. package/dist/chunk-UXXRRXUS.js +93 -0
  41. package/dist/{chunk-UKNAAVEE.js → chunk-YJ7YZRVV.js} +1 -1
  42. package/dist/src/index.js +3 -3
  43. package/package.json +1 -1
  44. package/dist/chunk-S4TFBJ5O.js +0 -339
  45. package/dist/{chunk-VFBYRR2N.js → chunk-HIIBSYFJ.js} +3 -3
@@ -7,41 +7,54 @@ import {
7
7
  addPusharyHooks,
8
8
  addPusharyToolPermissions
9
9
  } from "../chunk-CAJZAFVS.js";
10
+ import {
11
+ describeDetection,
12
+ detectAllAgents,
13
+ isDetected
14
+ } from "../chunk-UXXRRXUS.js";
15
+ import {
16
+ renderAgentInstructions,
17
+ renderProjectAgentInstructions,
18
+ writeInstructionBlock
19
+ } from "../chunk-N7XJ4L2W.js";
10
20
  import {
11
21
  GEMINI_HOOK_BINARY,
22
+ addGeminiHooks,
23
+ addGeminiMcpServer
24
+ } from "../chunk-E2U35RLD.js";
25
+ import {
12
26
  addCodexHookTrust,
13
27
  addCodexHooks,
14
28
  addCodexMcpServer,
15
- addGeminiHooks,
16
- addGeminiMcpServer,
17
- renderAgentInstructions,
18
- renderProjectAgentInstructions,
19
- writeInstructionBlock
20
- } from "../chunk-S4TFBJ5O.js";
29
+ codexConfigToml,
30
+ codexHome
31
+ } from "../chunk-ER657KRJ.js";
21
32
  import {
22
33
  confirmAppConnection,
23
34
  connectDevice,
24
35
  connectViaAppPairing,
25
36
  printConnectInstructions,
26
37
  setHumanStream
27
- } from "../chunk-GX64YGU3.js";
38
+ } from "../chunk-3O27ZSRE.js";
28
39
  import "../chunk-3EGEA4KH.js";
29
40
  import {
30
41
  parseFlags
31
42
  } from "../chunk-N4DA4CJB.js";
32
43
  import {
33
44
  KEY_FILE_MODE,
34
- backupFile,
35
45
  exportLine,
46
+ writeKey
47
+ } from "../chunk-COC6NPWG.js";
48
+ import {
49
+ backupFile,
36
50
  readJsonSafe,
37
51
  writeFileAtomic,
38
- writeJsonAtomic,
39
- writeKey
40
- } from "../chunk-B26DNXCA.js";
52
+ writeJsonAtomic
53
+ } from "../chunk-6MTNS63X.js";
41
54
  import {
42
55
  checkApiKey,
43
56
  describeKeyCheck
44
- } from "../chunk-UKNAAVEE.js";
57
+ } from "../chunk-YJ7YZRVV.js";
45
58
  import {
46
59
  UsageError
47
60
  } from "../chunk-7QLSKOSU.js";
@@ -60,28 +73,38 @@ import {
60
73
  EXIT,
61
74
  getPackageVersion,
62
75
  renderCommandHelp
63
- } from "../chunk-SML23YOT.js";
76
+ } from "../chunk-SP7OZXCQ.js";
64
77
  import {
65
78
  reportEvent
66
- } from "../chunk-VFBYRR2N.js";
67
- import "../chunk-RN3NOEJF.js";
79
+ } from "../chunk-HIIBSYFJ.js";
68
80
  import "../chunk-HNTKTK5B.js";
69
81
  import {
70
82
  isValidApiKey
71
83
  } from "../chunk-DQAN3JQP.js";
84
+ import "../chunk-RN3NOEJF.js";
72
85
  import "../chunk-2UMNXADU.js";
73
86
 
74
87
  // bin/pushary-setup.ts
75
- import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync, cpSync, rmSync, renameSync } from "fs";
76
- import { join as join2, dirname, basename } from "path";
77
- import { homedir as homedir2, tmpdir } from "os";
78
- import { execSync as execSync3 } from "child_process";
88
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync, rmSync, renameSync } from "fs";
89
+ import { join, dirname, basename } from "path";
90
+ import { homedir, tmpdir } from "os";
91
+ import { execSync as execSync2 } from "child_process";
79
92
  import { checkbox, input, confirm } from "@inquirer/prompts";
80
93
  import { fileURLToPath } from "url";
81
94
  import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
82
95
 
83
96
  // src/setup/closing.ts
84
97
  var ACTIVITY_URL = "pushary.com/dashboard/agent/activity";
98
+ var COMMAND_SURFACE = [
99
+ { command: "pushary status", summary: "what this machine is connected to" },
100
+ { command: "pushary mode", summary: "switch between ask, auto and notify-only" },
101
+ { command: "pushary wait", summary: "block until a pending question is answered" },
102
+ { command: "pushary stats", summary: "what your agents have been asking" },
103
+ { command: "pushary claude", summary: "run Claude Code with the Pushary wrapper" },
104
+ { command: "pushary doctor", summary: "check the install" }
105
+ ];
106
+ var SURFACE_COLUMN = Math.max(...COMMAND_SURFACE.map((entry) => entry.command.length)) + 2;
107
+ var renderCommandSurface = () => COMMAND_SURFACE.map((entry) => `${entry.command.padEnd(SURFACE_COLUMN)}${entry.summary}`);
85
108
  var nextSteps = (facts, reachable) => {
86
109
  const lines = [];
87
110
  if (facts.completed.includes("claude_code")) {
@@ -229,102 +252,18 @@ var parseSetupOptions = (input2) => {
229
252
  };
230
253
  };
231
254
 
232
- // src/setup/detect.ts
233
- import { execSync as execSync2 } from "child_process";
234
- import { existsSync } from "fs";
235
- import { homedir } from "os";
236
- import { join } from "path";
237
- var whichCommand = () => process.platform === "win32" ? "where" : "which";
238
- var binaryOnPath = (binary) => {
239
- try {
240
- execSync2(`${whichCommand()} ${binary}`, { stdio: "ignore", timeout: 5e3 });
241
- return true;
242
- } catch {
243
- return false;
244
- }
245
- };
246
- var defaultDeps = { onPath: binaryOnPath, exists: existsSync };
247
- var detectAgent = (probe, deps = defaultDeps) => {
248
- const checked = [];
249
- if (probe.binary) {
250
- checked.push(`${whichCommand()} ${probe.binary}`);
251
- if (deps.onPath(probe.binary)) {
252
- return { kind: "installed", evidence: `${probe.binary} on PATH`, strong: true };
253
- }
254
- }
255
- for (const path of probe.paths) {
256
- checked.push(path);
257
- if (deps.exists(path)) return { kind: "installed", evidence: path, strong: true };
258
- }
259
- for (const marker of probe.configMarkers) {
260
- checked.push(marker);
261
- if (deps.exists(marker)) return { kind: "installed", evidence: marker, strong: false };
262
- }
263
- if (probe.binary === null && probe.paths.length === 0 && probe.configMarkers.length === 0) {
264
- return { kind: "unknown" };
265
- }
266
- return { kind: "not-found", checked };
267
- };
268
- var agentProbes = (home = homedir()) => ({
269
- claude_code: {
270
- binary: "claude",
271
- // The native installer puts it here, outside a default non-login PATH.
272
- paths: [join(home, ".local", "bin", "claude")],
273
- configMarkers: [join(home, ".claude")]
274
- },
275
- codex: {
276
- binary: "codex",
277
- paths: [],
278
- configMarkers: [process.env.CODEX_HOME?.trim() || join(home, ".codex")]
279
- },
280
- gemini_cli: {
281
- binary: "gemini",
282
- paths: [],
283
- configMarkers: [join(home, ".gemini")]
284
- },
285
- hermes: {
286
- binary: "hermes",
287
- paths: [],
288
- configMarkers: [join(home, ".hermes")]
289
- },
290
- cursor: {
291
- // GUI editor. `cursor` on PATH only exists if the user ran "Install 'cursor'
292
- // command in PATH" from the command palette, which most never do.
293
- binary: "cursor",
294
- paths: process.platform === "darwin" ? ["/Applications/Cursor.app"] : process.platform === "win32" ? [join(process.env.LOCALAPPDATA ?? join(home, "AppData", "Local"), "Programs", "cursor")] : ["/usr/share/cursor", join(home, ".local", "share", "cursor")],
295
- configMarkers: [join(home, ".cursor")]
296
- },
297
- // "Other" is a set of printed instructions for any MCP or HTTP client. There is
298
- // nothing to detect, and it must never be auto-selected.
299
- custom: { binary: null, paths: [], configMarkers: [] }
300
- });
301
- var detectAllAgents = (deps = defaultDeps, home) => {
302
- const probes = agentProbes(home);
303
- return Object.keys(probes).map((agent) => ({
304
- agent,
305
- result: detectAgent(probes[agent], deps)
306
- }));
307
- };
308
- var isDetected = (result) => result.kind === "installed";
309
- var shortenHome = (path, home = homedir()) => home && path.startsWith(home) ? `~${path.slice(home.length)}` : path;
310
- var describeDetection = (result, home) => {
311
- if (result.kind !== "installed") return null;
312
- const evidence = shortenHome(result.evidence, home);
313
- return result.strong ? evidence : `${evidence}, config only`;
314
- };
315
-
316
255
  // bin/pushary-setup.ts
317
- var CLAUDE_SETTINGS = join2(homedir2(), ".claude", "settings.json");
318
- var CLAUDE_JSON = join2(homedir2(), ".claude.json");
319
- var CURSOR_PLUGIN_DIR = join2(homedir2(), ".cursor", "plugins", "local", "pushary");
320
- var CURSOR_USER_HOOKS = join2(homedir2(), ".cursor", "hooks.json");
321
- var CLAUDE_SKILL_DIR = join2(homedir2(), ".claude", "skills", "pushary");
322
- var CODEX_HOME = process.env.CODEX_HOME?.trim() || join2(homedir2(), ".codex");
323
- var CODEX_SKILL_DIR = join2(CODEX_HOME, "skills", "pushary");
324
- var CODEX_AGENTS_MD = join2(CODEX_HOME, "AGENTS.md");
325
- var GEMINI_SETTINGS = join2(homedir2(), ".gemini", "settings.json");
326
- var GEMINI_MD = join2(homedir2(), ".gemini", "GEMINI.md");
327
- var PUSHARY_CONFIG_FILE = join2(homedir2(), ".pushary", "config.json");
256
+ var CLAUDE_SETTINGS = join(homedir(), ".claude", "settings.json");
257
+ var CLAUDE_JSON = join(homedir(), ".claude.json");
258
+ var CURSOR_PLUGIN_DIR = join(homedir(), ".cursor", "plugins", "local", "pushary");
259
+ var CURSOR_USER_HOOKS = join(homedir(), ".cursor", "hooks.json");
260
+ var CLAUDE_SKILL_DIR = join(homedir(), ".claude", "skills", "pushary");
261
+ var CODEX_HOME = codexHome();
262
+ var CODEX_SKILL_DIR = join(CODEX_HOME, "skills", "pushary");
263
+ var CODEX_AGENTS_MD = join(CODEX_HOME, "AGENTS.md");
264
+ var GEMINI_SETTINGS = join(homedir(), ".gemini", "settings.json");
265
+ var GEMINI_MD = join(homedir(), ".gemini", "GEMINI.md");
266
+ var PUSHARY_CONFIG_FILE = join(homedir(), ".pushary", "config.json");
328
267
  var manualSteps = [];
329
268
  var noteManual = (step) => {
330
269
  manualSteps.push(step);
@@ -361,7 +300,7 @@ var readKeyFromStdin = async (options) => {
361
300
  var isInstalled = (command) => {
362
301
  const whichCmd = process.platform === "win32" ? "where" : "which";
363
302
  try {
364
- execSync3(`${whichCmd} ${command}`, { stdio: "ignore", timeout: 5e3 });
303
+ execSync2(`${whichCmd} ${command}`, { stdio: "ignore", timeout: 5e3 });
365
304
  return true;
366
305
  } catch {
367
306
  return false;
@@ -386,7 +325,7 @@ var readAgentJson = (filePath) => {
386
325
  };
387
326
  var writeJson = (filePath, data) => {
388
327
  const dir = dirname(filePath);
389
- if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
328
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
390
329
  writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
391
330
  };
392
331
  var readAgentToml = (filePath) => {
@@ -466,21 +405,21 @@ var fetchSkillContent = async () => {
466
405
  if (_cachedSkillContent) return _cachedSkillContent;
467
406
  const __dirname = dirname(fileURLToPath(import.meta.url));
468
407
  const candidates = [
469
- join2(__dirname, "..", "..", "data", "SKILL.md"),
470
- join2(__dirname, "..", "data", "SKILL.md")
408
+ join(__dirname, "..", "..", "data", "SKILL.md"),
409
+ join(__dirname, "..", "data", "SKILL.md")
471
410
  ];
472
- const source = candidates.find((path) => existsSync2(path));
411
+ const source = candidates.find((path) => existsSync(path));
473
412
  if (!source) throw new Error("packaged skill not found");
474
413
  _cachedSkillContent = readFileSync(source, "utf-8");
475
414
  return _cachedSkillContent;
476
415
  };
477
- var skillsCliInUse = () => isInstalled("skills") || existsSync2(join2(homedir2(), ".agents", "skills"));
416
+ var skillsCliInUse = () => isInstalled("skills") || existsSync(join(homedir(), ".agents", "skills"));
478
417
  var installSkill = async (agent, fallbackDir) => {
479
418
  await spinner("Installing Pushary skill", async () => {
480
419
  if (skillsCliInUse() && installSkillViaSkillsCli(agent)) return;
481
420
  const content = await fetchSkillContent();
482
- if (!existsSync2(fallbackDir)) mkdirSync(fallbackDir, { recursive: true });
483
- writeFileSync(join2(fallbackDir, "SKILL.md"), content, "utf-8");
421
+ if (!existsSync(fallbackDir)) mkdirSync(fallbackDir, { recursive: true });
422
+ writeFileSync(join(fallbackDir, "SKILL.md"), content, "utf-8");
484
423
  });
485
424
  };
486
425
  var setupClaudeCode = async (apiKey) => {
@@ -517,40 +456,40 @@ var IS_WINDOWS = process.platform === "win32";
517
456
  var resolveHermesPython = () => {
518
457
  try {
519
458
  const probe = IS_WINDOWS ? "where hermes" : "command -v hermes";
520
- const launcher = execSync3(probe, { encoding: "utf-8", stdio: "pipe", timeout: 5e3 }).split("\n")[0].trim();
459
+ const launcher = execSync2(probe, { encoding: "utf-8", stdio: "pipe", timeout: 5e3 }).split("\n")[0].trim();
521
460
  if (launcher && !IS_WINDOWS) {
522
461
  const shebang = readFileSync(launcher, "utf-8").split("\n", 1)[0];
523
462
  if (shebang.startsWith("#!")) {
524
463
  const interpreter = shebang.slice(2).trim().split(/\s+/)[0];
525
- if (interpreter && /python/i.test(interpreter) && existsSync2(interpreter)) return interpreter;
464
+ if (interpreter && /python/i.test(interpreter) && existsSync(interpreter)) return interpreter;
526
465
  }
527
466
  }
528
467
  } catch {
529
468
  }
530
- const venvRoot = join2(homedir2(), ".hermes", "hermes-agent", "venv");
531
- const candidates = IS_WINDOWS ? [join2(venvRoot, "Scripts", "python.exe"), join2(venvRoot, "Scripts", "python3.exe")] : [join2(venvRoot, "bin", "python3"), join2(venvRoot, "bin", "python")];
532
- return candidates.find(existsSync2) ?? null;
469
+ const venvRoot = join(homedir(), ".hermes", "hermes-agent", "venv");
470
+ const candidates = IS_WINDOWS ? [join(venvRoot, "Scripts", "python.exe"), join(venvRoot, "Scripts", "python3.exe")] : [join(venvRoot, "bin", "python3"), join(venvRoot, "bin", "python")];
471
+ return candidates.find(existsSync) ?? null;
533
472
  };
534
473
  var ensurePip = (python) => {
535
474
  try {
536
- execSync3(`"${python}" -m pip --version`, { stdio: "ignore", timeout: 15e3 });
475
+ execSync2(`"${python}" -m pip --version`, { stdio: "ignore", timeout: 15e3 });
537
476
  return;
538
477
  } catch {
539
478
  }
540
479
  try {
541
- execSync3(`"${python}" -m ensurepip --upgrade`, { stdio: "pipe", timeout: 6e4 });
480
+ execSync2(`"${python}" -m ensurepip --upgrade`, { stdio: "pipe", timeout: 6e4 });
542
481
  } catch {
543
482
  }
544
483
  };
545
484
  var enablePusharyPlugin = (python) => {
546
485
  const snippet = 'from hermes_cli.config import load_config, save_config; c = load_config(); p = c.get("plugins") if isinstance(c.get("plugins"), dict) else {}; e = p.get("enabled") if isinstance(p.get("enabled"), list) else []; p["enabled"] = (e + ["pushary"]) if "pushary" not in e else e; c["plugins"] = p; a = c.get("agent") if isinstance(c.get("agent"), dict) else {}; d = a.get("disabled_toolsets") if isinstance(a.get("disabled_toolsets"), list) else []; a["disabled_toolsets"] = (d + ["clarify"]) if "clarify" not in d else d; c["agent"] = a; save_config(c)';
547
- const scriptPath = join2(tmpdir(), `pushary-hermes-${process.pid}.py`);
486
+ const scriptPath = join(tmpdir(), `pushary-hermes-${process.pid}.py`);
548
487
  try {
549
488
  writeFileSync(scriptPath, snippet.split("; ").join("\n"), "utf-8");
550
- execSync3(`"${python}" "${scriptPath}"`, { stdio: "pipe", timeout: 15e3 });
489
+ execSync2(`"${python}" "${scriptPath}"`, { stdio: "pipe", timeout: 15e3 });
551
490
  return;
552
491
  } catch {
553
- execSync3("hermes plugins enable pushary", { stdio: "ignore", timeout: 1e4 });
492
+ execSync2("hermes plugins enable pushary", { stdio: "ignore", timeout: 1e4 });
554
493
  } finally {
555
494
  try {
556
495
  rmSync(scriptPath, { force: true });
@@ -575,7 +514,7 @@ var setupHermes = async (_apiKey) => {
575
514
  }
576
515
  await spinner("Installing hermes-plugin-pushary into Hermes\u2019 environment", async () => {
577
516
  ensurePip(python);
578
- execSync3(`"${python}" -m pip install --upgrade hermes-plugin-pushary`, { stdio: "pipe", timeout: 18e4 });
517
+ execSync2(`"${python}" -m pip install --upgrade hermes-plugin-pushary`, { stdio: "pipe", timeout: 18e4 });
579
518
  });
580
519
  await spinner("Enabling plugin + routing questions to push", async () => {
581
520
  enablePusharyPlugin(python);
@@ -588,7 +527,7 @@ var setupHermes = async (_apiKey) => {
588
527
  console.log(` ${dim("\u2022")} Permission gating: set ${bold("PUSHARY_GATE_TOOLS")} to require lock-screen approval for risky tools`);
589
528
  console.log(` ${dim("To re-enable terminal prompts:")} remove ${bold("clarify")} from ${dim("agent.disabled_toolsets")} in ~/.hermes/config.yaml`);
590
529
  };
591
- var CODEX_HOOKS_JSON = join2(CODEX_HOME, "hooks.json");
530
+ var CODEX_HOOKS_JSON = join(CODEX_HOME, "hooks.json");
592
531
  var CODEX_HOOKS_MIN_VERSION = [0, 122, 0];
593
532
  var CODEX_TRUST_VERIFIED_MAX = [0, 142, 2];
594
533
  var parseCodexVersion = (raw) => {
@@ -604,7 +543,7 @@ var compareCodexVersion = (a, b) => {
604
543
  };
605
544
  var readCodexVersion = () => {
606
545
  try {
607
- return parseCodexVersion(execSync3("codex --version", { encoding: "utf-8", stdio: "pipe", timeout: 1e4 }));
546
+ return parseCodexVersion(execSync2("codex --version", { encoding: "utf-8", stdio: "pipe", timeout: 1e4 }));
608
547
  } catch {
609
548
  return null;
610
549
  }
@@ -655,7 +594,7 @@ var setupCodex = async (apiKey) => {
655
594
  return "skipped";
656
595
  }
657
596
  await installGlobally2();
658
- const codexConfig = join2(homedir2(), ".codex", "config.toml");
597
+ const codexConfig = codexConfigToml();
659
598
  await spinner("Adding Pushary MCP server (key embedded, auto-allowed)", async () => {
660
599
  const config = readAgentToml(codexConfig);
661
600
  addCodexMcpServer(config, apiKey);
@@ -731,19 +670,19 @@ var setupCodex = async (apiKey) => {
731
670
  var resolveBundledPlugin = () => {
732
671
  const dir = dirname(fileURLToPath(import.meta.url));
733
672
  const candidates = [
734
- join2(dir, "..", "..", "data", "cursor-plugin"),
735
- join2(dir, "..", "data", "cursor-plugin"),
736
- join2(dir, "..", "..", "..", "cursor-plugin"),
737
- join2(dir, "..", "..", "cursor-plugin")
673
+ join(dir, "..", "..", "data", "cursor-plugin"),
674
+ join(dir, "..", "data", "cursor-plugin"),
675
+ join(dir, "..", "..", "..", "cursor-plugin"),
676
+ join(dir, "..", "..", "cursor-plugin")
738
677
  ];
739
- return candidates.find((p) => existsSync2(join2(p, ".cursor-plugin", "plugin.json"))) ?? null;
678
+ return candidates.find((p) => existsSync(join(p, ".cursor-plugin", "plugin.json"))) ?? null;
740
679
  };
741
680
  var installCursorUserHooks = (gateScript) => {
742
- const template = readJson(join2(CURSOR_PLUGIN_DIR, "hooks", "hooks.json")).hooks?.beforeShellExecution?.[0];
681
+ const template = readJson(join(CURSOR_PLUGIN_DIR, "hooks", "hooks.json")).hooks?.beforeShellExecution?.[0];
743
682
  if (!template) throw new Error("bundled Cursor hooks.json missing a beforeShellExecution entry");
744
683
  const entry = { ...template, command: `node "${gateScript}"` };
745
684
  let userHooks = {};
746
- if (existsSync2(CURSOR_USER_HOOKS)) {
685
+ if (existsSync(CURSOR_USER_HOOKS)) {
747
686
  try {
748
687
  userHooks = JSON.parse(readFileSync(CURSOR_USER_HOOKS, "utf-8"));
749
688
  } catch {
@@ -761,8 +700,8 @@ var installCursorUserHooks = (gateScript) => {
761
700
  writeJson(CURSOR_USER_HOOKS, { ...userHooks, version: userHooks.version ?? 1, hooks });
762
701
  };
763
702
  var neutralizePluginGate = () => {
764
- const path = join2(CURSOR_PLUGIN_DIR, "hooks", "hooks.json");
765
- if (!existsSync2(path)) return;
703
+ const path = join(CURSOR_PLUGIN_DIR, "hooks", "hooks.json");
704
+ if (!existsSync(path)) return;
766
705
  const data = readJson(path);
767
706
  if (data.hooks && "beforeShellExecution" in data.hooks) {
768
707
  delete data.hooks.beforeShellExecution;
@@ -776,7 +715,7 @@ var setupCursor = async (apiKey) => {
776
715
  const source = resolveBundledPlugin();
777
716
  if (!source) throw new Error("bundled Cursor plugin not found in this package");
778
717
  await spinner("Installing Pushary plugin", async () => {
779
- const staging = join2(dirname(CURSOR_PLUGIN_DIR), `.pushary-staging-${process.pid}`);
718
+ const staging = join(dirname(CURSOR_PLUGIN_DIR), `.pushary-staging-${process.pid}`);
780
719
  const backup = `${CURSOR_PLUGIN_DIR}.pushary-backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
781
720
  rmSync(staging, { recursive: true, force: true });
782
721
  try {
@@ -784,11 +723,11 @@ var setupCursor = async (apiKey) => {
784
723
  recursive: true,
785
724
  filter: (p) => !["tools", "node_modules", ".git", ".DS_Store"].includes(basename(p))
786
725
  });
787
- const staged = readJsonSafe(join2(staging, ".cursor-plugin", "plugin.json"));
726
+ const staged = readJsonSafe(join(staging, ".cursor-plugin", "plugin.json"));
788
727
  if (staged.kind !== "ok") {
789
728
  throw new Error("staged Cursor plugin is missing or has an unreadable plugin.json");
790
729
  }
791
- const hadExisting = existsSync2(CURSOR_PLUGIN_DIR);
730
+ const hadExisting = existsSync(CURSOR_PLUGIN_DIR);
792
731
  if (hadExisting) renameSync(CURSOR_PLUGIN_DIR, backup);
793
732
  try {
794
733
  renameSync(staging, CURSOR_PLUGIN_DIR);
@@ -802,7 +741,7 @@ var setupCursor = async (apiKey) => {
802
741
  }
803
742
  });
804
743
  await spinner("Linking your API key", async () => {
805
- const mcpPath = join2(CURSOR_PLUGIN_DIR, "mcp.json");
744
+ const mcpPath = join(CURSOR_PLUGIN_DIR, "mcp.json");
806
745
  const mcp = readAgentJson(mcpPath);
807
746
  const servers = mcp.mcpServers ?? {};
808
747
  if (servers.pushary) {
@@ -812,7 +751,7 @@ var setupCursor = async (apiKey) => {
812
751
  }
813
752
  });
814
753
  await spinner("Registering permission gate (~/.cursor/hooks.json)", async () => {
815
- installCursorUserHooks(join2(CURSOR_PLUGIN_DIR, "scripts", "pushary-gate.mjs"));
754
+ installCursorUserHooks(join(CURSOR_PLUGIN_DIR, "scripts", "pushary-gate.mjs"));
816
755
  neutralizePluginGate();
817
756
  });
818
757
  console.log();
@@ -931,8 +870,8 @@ var offerProjectInstructions = async (agents, options) => {
931
870
  });
932
871
  if (!wanted) return;
933
872
  for (const target of targets) {
934
- await spinner(`Writing managed block to ${join2(process.cwd(), target.file)}`, async () => {
935
- writeInstructionBlock(join2(process.cwd(), target.file), renderProjectAgentInstructions(target.label));
873
+ await spinner(`Writing managed block to ${join(process.cwd(), target.file)}`, async () => {
874
+ writeInstructionBlock(join(process.cwd(), target.file), renderProjectAgentInstructions(target.label));
936
875
  }, { optional: true });
937
876
  }
938
877
  console.log(` ${dim("Commit the file to share it. Teammates without a key fall back to the terminal.")}`);
@@ -1054,11 +993,11 @@ var resolveAgents = async (options) => {
1054
993
  });
1055
994
  };
1056
995
  var AGENT_TARGETS = {
1057
- claude_code: [CLAUDE_JSON, CLAUDE_SETTINGS, join2(CLAUDE_SKILL_DIR, "SKILL.md")],
1058
- codex: [join2(CODEX_HOME, "config.toml"), CODEX_HOOKS_JSON, join2(CODEX_SKILL_DIR, "SKILL.md"), CODEX_AGENTS_MD],
996
+ claude_code: [CLAUDE_JSON, CLAUDE_SETTINGS, join(CLAUDE_SKILL_DIR, "SKILL.md")],
997
+ codex: [join(CODEX_HOME, "config.toml"), CODEX_HOOKS_JSON, join(CODEX_SKILL_DIR, "SKILL.md"), CODEX_AGENTS_MD],
1059
998
  gemini_cli: [GEMINI_SETTINGS, GEMINI_MD],
1060
999
  hermes: ["the Hermes virtualenv (pip install pushary-hermes)"],
1061
- cursor: [join2(CURSOR_PLUGIN_DIR, "mcp.json"), CURSOR_USER_HOOKS],
1000
+ cursor: [join(CURSOR_PLUGIN_DIR, "mcp.json"), CURSOR_USER_HOOKS],
1062
1001
  custom: ["nothing (prints connection details only)"]
1063
1002
  };
1064
1003
  var reportDryRun = (apiKey, agents, keyCheck) => {
@@ -1305,6 +1244,9 @@ var main = async () => {
1305
1244
  console.log();
1306
1245
  for (const line of closing.next) console.log(` ${line}`);
1307
1246
  console.log();
1247
+ console.log(` ${dim("Useful:")}`);
1248
+ for (const line of renderCommandSurface()) console.log(` ${dim(line)}`);
1249
+ console.log();
1308
1250
  const exitCode = closing.exitCode;
1309
1251
  emitJson(options, {
1310
1252
  ok: closing.ok,
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  exitOnHelpFlag
4
- } from "../chunk-HUJQSP4F.js";
5
- import "../chunk-SML23YOT.js";
4
+ } from "../chunk-IIZZYUWK.js";
5
+ import "../chunk-SP7OZXCQ.js";
6
6
  import {
7
7
  readLedgerSummary
8
8
  } from "../chunk-WLGEY4UX.js";
@@ -3,15 +3,16 @@ import {
3
3
  describeReach,
4
4
  fetchChannels,
5
5
  reachVerdict
6
- } from "../chunk-GX64YGU3.js";
6
+ } from "../chunk-3O27ZSRE.js";
7
7
  import "../chunk-3EGEA4KH.js";
8
8
  import {
9
9
  readKeySource
10
- } from "../chunk-B26DNXCA.js";
10
+ } from "../chunk-COC6NPWG.js";
11
+ import "../chunk-6MTNS63X.js";
11
12
  import {
12
13
  checkApiKey,
13
14
  describeKeyCheck
14
- } from "../chunk-UKNAAVEE.js";
15
+ } from "../chunk-YJ7YZRVV.js";
15
16
  import {
16
17
  createIo
17
18
  } from "../chunk-TX7KBKT7.js";
@@ -19,10 +20,10 @@ import "../chunk-7QLSKOSU.js";
19
20
  import "../chunk-BC3VCZ3E.js";
20
21
  import {
21
22
  exitOnHelpFlag
22
- } from "../chunk-HUJQSP4F.js";
23
+ } from "../chunk-IIZZYUWK.js";
23
24
  import {
24
25
  EXIT
25
- } from "../chunk-SML23YOT.js";
26
+ } from "../chunk-SP7OZXCQ.js";
26
27
  import "../chunk-HNTKTK5B.js";
27
28
  import "../chunk-DQAN3JQP.js";
28
29
  import "../chunk-2UMNXADU.js";
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleStop
4
- } from "../chunk-VFBYRR2N.js";
5
- import "../chunk-RN3NOEJF.js";
4
+ } from "../chunk-HIIBSYFJ.js";
6
5
  import "../chunk-HNTKTK5B.js";
7
6
  import "../chunk-DQAN3JQP.js";
7
+ import "../chunk-RN3NOEJF.js";
8
8
  import "../chunk-2UMNXADU.js";
9
9
 
10
10
  // bin/pushary-stop-hook.ts
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleStopFailure
4
- } from "../chunk-VFBYRR2N.js";
5
- import "../chunk-RN3NOEJF.js";
4
+ } from "../chunk-HIIBSYFJ.js";
6
5
  import "../chunk-HNTKTK5B.js";
7
6
  import "../chunk-DQAN3JQP.js";
7
+ import "../chunk-RN3NOEJF.js";
8
8
  import "../chunk-2UMNXADU.js";
9
9
 
10
10
  // bin/pushary-stopfailure-hook.ts
@@ -4,8 +4,8 @@ import {
4
4
  } from "../chunk-TX7KBKT7.js";
5
5
  import {
6
6
  exitOnHelpFlag
7
- } from "../chunk-HUJQSP4F.js";
8
- import "../chunk-SML23YOT.js";
7
+ } from "../chunk-IIZZYUWK.js";
8
+ import "../chunk-SP7OZXCQ.js";
9
9
  import {
10
10
  getApiKey,
11
11
  getBaseUrl