@pushary/agent-hooks 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/pushary-setup.js +53 -87
- package/package.json +1 -1
|
@@ -88,11 +88,15 @@ var startSpinner = (getLabel) => {
|
|
|
88
88
|
`);
|
|
89
89
|
};
|
|
90
90
|
};
|
|
91
|
-
var printQr = (url) => new Promise((resolve) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
var printQr = (url) => new Promise((resolve, reject) => {
|
|
92
|
+
try {
|
|
93
|
+
qrcodeTerminal.generate(url, { small: true }, (qr) => {
|
|
94
|
+
process.stdout.write("\n" + qr.split("\n").map((line) => " " + line).join("\n") + "\n");
|
|
95
|
+
resolve();
|
|
96
|
+
});
|
|
97
|
+
} catch (err) {
|
|
98
|
+
reject(err);
|
|
99
|
+
}
|
|
96
100
|
});
|
|
97
101
|
var waitForDevice = async (apiKey) => {
|
|
98
102
|
const deadline = Date.now() + CONNECT_TIMEOUT_MS;
|
|
@@ -200,17 +204,17 @@ var isInstalled = (command) => {
|
|
|
200
204
|
return false;
|
|
201
205
|
}
|
|
202
206
|
};
|
|
203
|
-
var readJson = (
|
|
207
|
+
var readJson = (filePath) => {
|
|
204
208
|
try {
|
|
205
|
-
return JSON.parse(readFileSync(
|
|
209
|
+
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
206
210
|
} catch {
|
|
207
211
|
return {};
|
|
208
212
|
}
|
|
209
213
|
};
|
|
210
|
-
var writeJson = (
|
|
211
|
-
const dir =
|
|
214
|
+
var writeJson = (filePath, data) => {
|
|
215
|
+
const dir = dirname(filePath);
|
|
212
216
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
213
|
-
writeFileSync(
|
|
217
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
214
218
|
};
|
|
215
219
|
var formatError = (err) => {
|
|
216
220
|
if (err instanceof Error) {
|
|
@@ -340,32 +344,42 @@ var setupClaudeCode = async (apiKey) => {
|
|
|
340
344
|
console.log(` ${dim2("\u2022")} Hooks: route permission approvals through push notifications`);
|
|
341
345
|
console.log(` ${dim2("\u2022")} Auto-allowed tools: no permission prompts for Pushary MCP calls`);
|
|
342
346
|
};
|
|
343
|
-
var
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
return
|
|
347
|
+
var resolveHermesPython = () => {
|
|
348
|
+
try {
|
|
349
|
+
const launcher = execSync("command -v hermes", { encoding: "utf-8", stdio: "pipe", timeout: 5e3 }).trim();
|
|
350
|
+
if (launcher) {
|
|
351
|
+
const shebang = readFileSync(launcher, "utf-8").split("\n", 1)[0];
|
|
352
|
+
if (shebang.startsWith("#!")) {
|
|
353
|
+
const interpreter = shebang.slice(2).trim().split(/\s+/)[0];
|
|
354
|
+
if (interpreter && /python/i.test(interpreter) && existsSync(interpreter)) return interpreter;
|
|
351
355
|
}
|
|
352
|
-
} catch {
|
|
353
356
|
}
|
|
357
|
+
} catch {
|
|
354
358
|
}
|
|
359
|
+
const venvPython = join(homedir(), ".hermes", "hermes-agent", "venv", "bin", "python3");
|
|
360
|
+
if (existsSync(venvPython)) return venvPython;
|
|
355
361
|
return null;
|
|
356
362
|
};
|
|
357
|
-
var
|
|
363
|
+
var ensurePip = (python) => {
|
|
358
364
|
try {
|
|
359
|
-
execSync(
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
);
|
|
365
|
+
execSync(`"${python}" -m pip --version`, { stdio: "ignore", timeout: 15e3 });
|
|
366
|
+
return;
|
|
367
|
+
} catch {
|
|
368
|
+
}
|
|
369
|
+
try {
|
|
370
|
+
execSync(`"${python}" -m ensurepip --upgrade`, { stdio: "pipe", timeout: 6e4 });
|
|
371
|
+
} catch {
|
|
367
372
|
}
|
|
368
373
|
};
|
|
374
|
+
var enablePusharyPlugin = (python) => {
|
|
375
|
+
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; save_config(c)';
|
|
376
|
+
try {
|
|
377
|
+
execSync(`"${python}" -c '${snippet}'`, { stdio: "pipe", timeout: 15e3 });
|
|
378
|
+
return;
|
|
379
|
+
} catch {
|
|
380
|
+
}
|
|
381
|
+
execSync("hermes plugins enable pushary", { stdio: "ignore", timeout: 1e4 });
|
|
382
|
+
};
|
|
369
383
|
var setupHermes = async (_apiKey) => {
|
|
370
384
|
console.log(`
|
|
371
385
|
${bold2("Setting up Hermes Agent")}
|
|
@@ -375,72 +389,24 @@ var setupHermes = async (_apiKey) => {
|
|
|
375
389
|
console.log(` ${dim2("Install Hermes and re-run setup to configure.")}`);
|
|
376
390
|
return;
|
|
377
391
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
return;
|
|
388
|
-
} catch {
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
let python = findPython310Plus();
|
|
392
|
-
if (!python) {
|
|
393
|
-
if (process.platform === "darwin") {
|
|
394
|
-
try {
|
|
395
|
-
execSync("which brew", { stdio: "ignore", timeout: 5e3 });
|
|
396
|
-
execSync("brew install python@3.12", { stdio: "pipe", timeout: 3e5 });
|
|
397
|
-
python = findPython310Plus();
|
|
398
|
-
} catch {
|
|
399
|
-
}
|
|
400
|
-
} else if (process.platform === "linux") {
|
|
401
|
-
for (const [check3, install] of [
|
|
402
|
-
["which apt-get", "sudo apt-get update -qq && sudo apt-get install -y -qq python3 python3-pip"],
|
|
403
|
-
["which dnf", "sudo dnf install -y -q python3 python3-pip"],
|
|
404
|
-
["which yum", "sudo yum install -y -q python3 python3-pip"],
|
|
405
|
-
["which pacman", "sudo pacman -S --noconfirm python python-pip"]
|
|
406
|
-
]) {
|
|
407
|
-
try {
|
|
408
|
-
execSync(check3, { stdio: "ignore", timeout: 5e3 });
|
|
409
|
-
execSync(install, { stdio: "pipe", timeout: 3e5 });
|
|
410
|
-
python = findPython310Plus();
|
|
411
|
-
if (python) break;
|
|
412
|
-
} catch {
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
if (python) {
|
|
418
|
-
installPythonPlugin(python);
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
for (const pip of ["pip3", "pip"]) {
|
|
422
|
-
try {
|
|
423
|
-
execSync(`${pip} install hermes-plugin-pushary`, { stdio: "pipe", timeout: 12e4 });
|
|
424
|
-
return;
|
|
425
|
-
} catch (err) {
|
|
426
|
-
if (npmErrorMessage(err).includes("externally-managed-environment")) {
|
|
427
|
-
try {
|
|
428
|
-
execSync(`${pip} install --user --break-system-packages hermes-plugin-pushary`, { stdio: "pipe", timeout: 12e4 });
|
|
429
|
-
return;
|
|
430
|
-
} catch {
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
throw new Error("Python 3.10+ not found and could not be installed");
|
|
392
|
+
const python = resolveHermesPython();
|
|
393
|
+
if (!python) {
|
|
394
|
+
console.log(` ${yellow2("!")} Could not locate the Python that Hermes runs in. Skipping.`);
|
|
395
|
+
console.log(` ${dim2("Install manually: <hermes-python> -m pip install hermes-plugin-pushary")}`);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
await spinner("Installing hermes-plugin-pushary into Hermes\u2019 environment", async () => {
|
|
399
|
+
ensurePip(python);
|
|
400
|
+
execSync(`"${python}" -m pip install --upgrade hermes-plugin-pushary`, { stdio: "pipe", timeout: 18e4 });
|
|
436
401
|
});
|
|
437
402
|
await spinner("Enabling plugin", async () => {
|
|
438
|
-
|
|
403
|
+
enablePusharyPlugin(python);
|
|
439
404
|
});
|
|
440
405
|
console.log();
|
|
441
406
|
console.log(` ${dim2("What this configured:")}`);
|
|
442
407
|
console.log(` ${dim2("\u2022")} Native tools: pushary_notify, pushary_ask, pushary_wait, pushary_cancel`);
|
|
443
408
|
console.log(` ${dim2("\u2022")} Auto-notifications: push alert when tools return errors`);
|
|
409
|
+
console.log(` ${dim2("\u2022")} Permission gating: set ${bold2("PUSHARY_GATE_TOOLS")} to require lock-screen approval for risky tools`);
|
|
444
410
|
};
|
|
445
411
|
var setupCodex = async (_apiKey) => {
|
|
446
412
|
console.log(`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pushary/agent-hooks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
|
|
5
5
|
"author": "Pushary <business@pushary.com>",
|
|
6
6
|
"homepage": "https://pushary.com",
|