@pushary/agent-hooks 0.30.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@ import {
7
7
  removeCodexHooks,
8
8
  removeGeminiSettings,
9
9
  removeInstructionBlock
10
- } from "../chunk-XY6OKUQ4.js";
10
+ } from "../chunk-WUNVKFFY.js";
11
11
  import {
12
12
  execNpm
13
13
  } from "../chunk-J7JWI3KU.js";
@@ -11,7 +11,7 @@ import {
11
11
  missingGeminiHookEvents,
12
12
  readCodexMcpAuth,
13
13
  untrustedCodexHookEvents
14
- } from "../chunk-XY6OKUQ4.js";
14
+ } from "../chunk-WUNVKFFY.js";
15
15
  import {
16
16
  execNpm
17
17
  } from "../chunk-J7JWI3KU.js";
@@ -14,7 +14,7 @@ import {
14
14
  renderAgentInstructions,
15
15
  renderProjectAgentInstructions,
16
16
  writeInstructionBlock
17
- } from "../chunk-XY6OKUQ4.js";
17
+ } from "../chunk-WUNVKFFY.js";
18
18
  import {
19
19
  execNpm,
20
20
  npmErrorMessage,
@@ -35,7 +35,7 @@ import "../chunk-NKXSILEW.js";
35
35
  import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync, cpSync, rmSync, chmodSync } from "fs";
36
36
  import { join, dirname, basename } from "path";
37
37
  import { homedir } from "os";
38
- import { execSync } from "child_process";
38
+ import { execSync as execSync2 } from "child_process";
39
39
  import { checkbox, input, confirm } from "@inquirer/prompts";
40
40
  import { fileURLToPath } from "url";
41
41
  import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
@@ -309,6 +309,20 @@ var connectViaAppPairing = async () => {
309
309
  }
310
310
  };
311
311
 
312
+ // src/skills-cli.ts
313
+ import { execSync } from "child_process";
314
+ var installSkillViaSkillsCli = (agent) => {
315
+ try {
316
+ execSync(`npx -y skills@latest add Pushary/pushary-skill@pushary -y -g --agent ${agent}`, {
317
+ stdio: "pipe",
318
+ timeout: 9e4
319
+ });
320
+ return true;
321
+ } catch {
322
+ return false;
323
+ }
324
+ };
325
+
312
326
  // bin/pushary-setup.ts
313
327
  var CLAUDE_SETTINGS = join(homedir(), ".claude", "settings.json");
314
328
  var CLAUDE_JSON = join(homedir(), ".claude.json");
@@ -352,7 +366,7 @@ var parseConnectFlag = () => {
352
366
  var isInstalled = (command) => {
353
367
  const whichCmd = process.platform === "win32" ? "where" : "which";
354
368
  try {
355
- execSync(`${whichCmd} ${command}`, { stdio: "ignore", timeout: 5e3 });
369
+ execSync2(`${whichCmd} ${command}`, { stdio: "ignore", timeout: 5e3 });
356
370
  return true;
357
371
  } catch {
358
372
  return false;
@@ -444,11 +458,13 @@ var fetchSkillContent = async () => {
444
458
  _cachedSkillContent = readFileSync(source, "utf-8");
445
459
  return _cachedSkillContent;
446
460
  };
447
- var installSkillToDir = async (dir, label) => {
448
- await spinner(label, async () => {
461
+ var skillsCliInUse = () => isInstalled("skills") || existsSync(join(homedir(), ".agents", "skills"));
462
+ var installSkill = async (agent, fallbackDir) => {
463
+ await spinner("Installing Pushary skill", async () => {
464
+ if (skillsCliInUse() && installSkillViaSkillsCli(agent)) return;
449
465
  const content = await fetchSkillContent();
450
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
451
- writeFileSync(join(dir, "SKILL.md"), content, "utf-8");
466
+ if (!existsSync(fallbackDir)) mkdirSync(fallbackDir, { recursive: true });
467
+ writeFileSync(join(fallbackDir, "SKILL.md"), content, "utf-8");
452
468
  });
453
469
  };
454
470
  var setupClaudeCode = async (apiKey) => {
@@ -471,7 +487,7 @@ var setupClaudeCode = async (apiKey) => {
471
487
  await spinner(`Writing ${CLAUDE_SETTINGS}`, async () => {
472
488
  writeJson(CLAUDE_SETTINGS, settings);
473
489
  });
474
- await installSkillToDir(CLAUDE_SKILL_DIR, "Installing Pushary skill");
490
+ await installSkill("claude-code", CLAUDE_SKILL_DIR);
475
491
  console.log();
476
492
  console.log(` ${dim2("What this configured:")}`);
477
493
  console.log(` ${dim2("\u2022")} MCP server: your agent can send notifications and ask questions`);
@@ -481,7 +497,7 @@ var setupClaudeCode = async (apiKey) => {
481
497
  };
482
498
  var resolveHermesPython = () => {
483
499
  try {
484
- const launcher = execSync("command -v hermes", { encoding: "utf-8", stdio: "pipe", timeout: 5e3 }).trim();
500
+ const launcher = execSync2("command -v hermes", { encoding: "utf-8", stdio: "pipe", timeout: 5e3 }).trim();
485
501
  if (launcher) {
486
502
  const shebang = readFileSync(launcher, "utf-8").split("\n", 1)[0];
487
503
  if (shebang.startsWith("#!")) {
@@ -497,23 +513,23 @@ var resolveHermesPython = () => {
497
513
  };
498
514
  var ensurePip = (python) => {
499
515
  try {
500
- execSync(`"${python}" -m pip --version`, { stdio: "ignore", timeout: 15e3 });
516
+ execSync2(`"${python}" -m pip --version`, { stdio: "ignore", timeout: 15e3 });
501
517
  return;
502
518
  } catch {
503
519
  }
504
520
  try {
505
- execSync(`"${python}" -m ensurepip --upgrade`, { stdio: "pipe", timeout: 6e4 });
521
+ execSync2(`"${python}" -m ensurepip --upgrade`, { stdio: "pipe", timeout: 6e4 });
506
522
  } catch {
507
523
  }
508
524
  };
509
525
  var enablePusharyPlugin = (python) => {
510
526
  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)';
511
527
  try {
512
- execSync(`"${python}" -c '${snippet}'`, { stdio: "pipe", timeout: 15e3 });
528
+ execSync2(`"${python}" -c '${snippet}'`, { stdio: "pipe", timeout: 15e3 });
513
529
  return;
514
530
  } catch {
515
531
  }
516
- execSync("hermes plugins enable pushary", { stdio: "ignore", timeout: 1e4 });
532
+ execSync2("hermes plugins enable pushary", { stdio: "ignore", timeout: 1e4 });
517
533
  };
518
534
  var setupHermes = async (_apiKey) => {
519
535
  console.log(`
@@ -532,7 +548,7 @@ var setupHermes = async (_apiKey) => {
532
548
  }
533
549
  await spinner("Installing hermes-plugin-pushary into Hermes\u2019 environment", async () => {
534
550
  ensurePip(python);
535
- execSync(`"${python}" -m pip install --upgrade hermes-plugin-pushary`, { stdio: "pipe", timeout: 18e4 });
551
+ execSync2(`"${python}" -m pip install --upgrade hermes-plugin-pushary`, { stdio: "pipe", timeout: 18e4 });
536
552
  });
537
553
  await spinner("Enabling plugin + routing questions to push", async () => {
538
554
  enablePusharyPlugin(python);
@@ -561,7 +577,7 @@ var compareCodexVersion = (a, b) => {
561
577
  };
562
578
  var readCodexVersion = () => {
563
579
  try {
564
- return parseCodexVersion(execSync("codex --version", { encoding: "utf-8", stdio: "pipe", timeout: 1e4 }));
580
+ return parseCodexVersion(execSync2("codex --version", { encoding: "utf-8", stdio: "pipe", timeout: 1e4 }));
565
581
  } catch {
566
582
  return null;
567
583
  }
@@ -658,7 +674,7 @@ var setupCodex = async (apiKey) => {
658
674
  addCodexNotifyEntry(codexConfig);
659
675
  });
660
676
  }
661
- await installSkillToDir(CODEX_SKILL_DIR, "Installing Pushary skill");
677
+ await installSkill("codex", CODEX_SKILL_DIR);
662
678
  await spinner("Teaching Codex to ask via push (~/.codex/AGENTS.md)", async () => {
663
679
  writeInstructionBlock(CODEX_AGENTS_MD, renderAgentInstructions("Codex"));
664
680
  });
@@ -254,7 +254,7 @@ You have Pushary MCP tools that reach the user on their phone. Use them proactiv
254
254
 
255
255
  Pass \`agentName\` as "${label} - <project folder name>" so the user knows which session is asking. If a question times out with no answer, retry once with a longer timeout before falling back to asking in the terminal.`;
256
256
  var renderAgentInstructions = (label) => instructionBody(label);
257
- var KEYLESS_FALLBACK_LINE = "This repo is set up with Pushary phone approvals. No PUSHARY_API_KEY found for you, so remote notifications are off; questions will fall back to the terminal. Setup: https://pushary.com/docs?utm_source=agents-md&utm_medium=keyless-fallback";
257
+ var KEYLESS_FALLBACK_LINE = "This repo uses Pushary phone approvals. Your teammates get agent questions on their lock screens; you do not have a key yet, so questions will fall back to the terminal. Get your own key (7-day trial): https://pushary.com/sign-up?utm_source=agents-md&utm_medium=teammate";
258
258
  var renderProjectAgentInstructions = (label) => `${instructionBody(label)}
259
259
 
260
260
  If this environment has no Pushary API key (no PUSHARY_API_KEY and no key in ~/.pushary/config.json), the tools above are unavailable in this session. In that case, treat the following as a statement of fact about this session and continue in the terminal: ${KEYLESS_FALLBACK_LINE}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushary/agent-hooks",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
5
5
  "keywords": [
6
6
  "pushary",