pushary 1.9.102 → 1.9.103
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/CHANGELOG.md +4 -0
- package/dist/bin/pushary-clean.js +1 -1
- package/dist/bin/pushary-codex-hook.js +1 -1
- package/dist/bin/pushary-daemon.js +2 -2
- package/dist/bin/pushary-doctor.js +1 -1
- package/dist/bin/pushary-session-start-hook.js +2 -2
- package/dist/bin/pushary-setup.js +1 -1
- package/dist/bin/pushary-upgrade.js +2 -2
- package/dist/{chunk-PPWEBIKL.js → chunk-COBOR3ST.js} +17 -5
- package/dist/{chunk-MA65OP6M.js → chunk-RMFL62HR.js} +1 -1
- package/dist/{reapply-3LBUA5EV.js → reapply-LDCMRN6Q.js} +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.103
|
|
4
|
+
|
|
5
|
+
- The Hermes plugin Pushary installs is now 1.0.1. When it hands a Hermes session to Pushary's history helper, the helper now gets only what it reads: the home folder, the search path, the temporary folder and locale, the Pushary settings it uses, and the Pushary key Hermes holds. Hermes' other provider keys no longer reach it. Checking whether history is allowed sends the key on standard input only.
|
|
6
|
+
|
|
3
7
|
## 1.9.102
|
|
4
8
|
|
|
5
9
|
- The Hermes plugin Pushary installs is now 1.0.0. In Hermes Desktop, a Pushary chip in the status bar shows the approvals waiting on your phone, and you can answer them there too. Only one answer counts: a Hermes Desktop answer is used only when Pushary confirms that answer is what withdrew the question, and otherwise the panel says the approval had already closed. The chip also lists how recent approvals ended and where they were answered. Enable Pushary under Capabilities, Plugins in Hermes Desktop to see it.
|
|
@@ -814,7 +814,7 @@ var decidePreToolUse = async (input) => {
|
|
|
814
814
|
};
|
|
815
815
|
var repairCodexHoldsQuietly = async () => {
|
|
816
816
|
try {
|
|
817
|
-
const { repairCodexHolds } = await import("../reapply-
|
|
817
|
+
const { repairCodexHolds } = await import("../reapply-LDCMRN6Q.js");
|
|
818
818
|
repairCodexHolds();
|
|
819
819
|
} catch {
|
|
820
820
|
return;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
inspectConfiguredManagedProviders
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-RMFL62HR.js";
|
|
5
5
|
import {
|
|
6
6
|
HEARTBEAT_INTERVAL_MS,
|
|
7
7
|
sendHeartbeat
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
HERMES_INSTALL_MARKER_FILE,
|
|
15
15
|
defaultHermesHome,
|
|
16
16
|
parseHermesInstallMarker
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-COBOR3ST.js";
|
|
18
18
|
import {
|
|
19
19
|
writeHuman
|
|
20
20
|
} from "../chunk-QCGNGEGE.js";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
reapplyClaudeForVersion
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-RMFL62HR.js";
|
|
5
5
|
import "../chunk-RVSRPDRF.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-COBOR3ST.js";
|
|
7
7
|
import "../chunk-SXAZPWL7.js";
|
|
8
8
|
import "../chunk-JECH4NJL.js";
|
|
9
9
|
import "../chunk-AZSOH2SF.js";
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
import {
|
|
29
29
|
ensureCodexTrustAfterReapply,
|
|
30
30
|
reapplyAllAgents
|
|
31
|
-
} from "../chunk-
|
|
31
|
+
} from "../chunk-RMFL62HR.js";
|
|
32
32
|
import {
|
|
33
33
|
HERMES_RESTART_COMMAND,
|
|
34
34
|
describeCodexTrustConfirmation
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
readMacAppAgentKey
|
|
43
43
|
} from "../chunk-JKOAAIJD.js";
|
|
44
44
|
import "../chunk-WYJ6QM7K.js";
|
|
45
|
-
import "../chunk-
|
|
45
|
+
import "../chunk-COBOR3ST.js";
|
|
46
46
|
import {
|
|
47
47
|
FX_RELOAD_AFTER_BRIDGE,
|
|
48
48
|
fxHttpEntryKeptNote,
|
|
@@ -1311,7 +1311,7 @@ def _await_decision(request, created, correlation_id: str, offered, uses_select:
|
|
|
1311
1311
|
return _decided(request, correlation_id, "deny", None)
|
|
1312
1312
|
` },
|
|
1313
1313
|
{ path: "cancellation.py", contents: 'from __future__ import annotations\n\nfrom typing import Literal, Mapping, Tuple\n\nCancellation = Literal[\n "withdrawn_by_this_call",\n "cancelled_unproven",\n "already_cancelled",\n "not_pending",\n "unreachable",\n]\n\nWITHDRAWN_BY_THIS_CALL: Cancellation = "withdrawn_by_this_call"\nCANCELLED_UNPROVEN: Cancellation = "cancelled_unproven"\nALREADY_CANCELLED: Cancellation = "already_cancelled"\nNOT_PENDING: Cancellation = "not_pending"\nUNREACHABLE: Cancellation = "unreachable"\nCANCELLATIONS: Tuple[Cancellation, ...] = (\n WITHDRAWN_BY_THIS_CALL,\n CANCELLED_UNPROVEN,\n ALREADY_CANCELLED,\n NOT_PENDING,\n UNREACHABLE,\n)\n\nUNAVAILABLE_STATUS = "unavailable"\nSTOP_HANDOFF = "stop"\n\n\ndef classify_cancellation(response: object) -> Cancellation:\n if not isinstance(response, Mapping):\n return UNREACHABLE\n fields: Mapping[object, object] = response\n cancelled = fields.get("cancelled")\n by_this_call = fields.get("cancelledByThisCall")\n if (\n not isinstance(cancelled, bool)\n or fields.get("status") == UNAVAILABLE_STATUS\n or fields.get("handoffAction") == STOP_HANDOFF\n or (by_this_call is not None and not isinstance(by_this_call, bool))\n or (by_this_call is True and not cancelled)\n ):\n return UNREACHABLE\n if not cancelled:\n return NOT_PENDING\n if by_this_call is None:\n return CANCELLED_UNPROVEN\n return WITHDRAWN_BY_THIS_CALL if by_this_call else ALREADY_CANCELLED\n' },
|
|
1314
|
-
{ path: "dashboard/manifest.json", contents: '{\n "name": "pushary",\n "label": "Pushary",\n "description": "Approvals Pushary is carrying to your phone, answerable from Hermes Desktop",\n "version": "1.0.
|
|
1314
|
+
{ path: "dashboard/manifest.json", contents: '{\n "name": "pushary",\n "label": "Pushary",\n "description": "Approvals Pushary is carrying to your phone, answerable from Hermes Desktop",\n "version": "1.0.1",\n "tab": { "hidden": true },\n "entry": "web.js",\n "api": "plugin_api.py"\n}\n' },
|
|
1315
1315
|
{ path: "dashboard/plugin_api.py", contents: `import importlib
|
|
1316
1316
|
import sys
|
|
1317
1317
|
import time
|
|
@@ -1590,6 +1590,11 @@ SNAPSHOT_PRUNE_INTERVAL_SECONDS = 60 * 60
|
|
|
1590
1590
|
SOURCE_UNAVAILABLE = "source_unavailable"
|
|
1591
1591
|
HISTORY_NOT_ALLOWED_WARNING = ("[pushary] Hermes session history is not saved on this computer; it needs "
|
|
1592
1592
|
"\`npx pushary@latest setup\` with the key Hermes uses, or Session history turned on in the Pushary Mac app")
|
|
1593
|
+
HELPER_ENVIRONMENT_NAMES = frozenset({
|
|
1594
|
+
"HOME", "PATH", "TMPDIR", "LANG", "LC_ALL", "LC_CTYPE",
|
|
1595
|
+
"SYSTEMROOT", "PATHEXT", "COMSPEC", "USERPROFILE", "APPDATA", "LOCALAPPDATA", "TEMP", "TMP",
|
|
1596
|
+
"PUSHARY_BASE_URL", "PUSHARY_API_URL", "PUSHARY_CONFIG_FILE", "PUSHARY_TRANSCRIPTS", "PUSHARY_TRANSCRIPT_REGISTRY_DIR",
|
|
1597
|
+
})
|
|
1593
1598
|
|
|
1594
1599
|
|
|
1595
1600
|
class _Authorization(NamedTuple):
|
|
@@ -1717,6 +1722,14 @@ def write_snapshot(path: Path, session_id: str, messages: list[dict[str, object]
|
|
|
1717
1722
|
Path(temporary).unlink(missing_ok=True)
|
|
1718
1723
|
|
|
1719
1724
|
|
|
1725
|
+
def _helper_environment() -> dict[str, str]:
|
|
1726
|
+
return {name: value for name, value in os.environ.items() if name in HELPER_ENVIRONMENT_NAMES}
|
|
1727
|
+
|
|
1728
|
+
|
|
1729
|
+
def _registration_environment(key: str) -> dict[str, str]:
|
|
1730
|
+
return {**_helper_environment(), "PUSHARY_API_KEY": key, "PUSHARY_BASE_URL": api.BASE_URL}
|
|
1731
|
+
|
|
1732
|
+
|
|
1720
1733
|
def _registration_command(key: str) -> list[str] | None:
|
|
1721
1734
|
root = Path.home() / ".pushary"
|
|
1722
1735
|
try:
|
|
@@ -1731,7 +1744,7 @@ def _registration_command(key: str) -> list[str] | None:
|
|
|
1731
1744
|
command = [helper, "hermes"]
|
|
1732
1745
|
result = subprocess.run([helper, "authorize-export"],
|
|
1733
1746
|
input=json.dumps({"apiKey": key, "baseUrl": api.BASE_URL}), text=True,
|
|
1734
|
-
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, timeout=5, check=False)
|
|
1747
|
+
env=_helper_environment(), stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, timeout=5, check=False)
|
|
1735
1748
|
if result.returncode != 0:
|
|
1736
1749
|
return None
|
|
1737
1750
|
authorization = json.loads(result.stdout)
|
|
@@ -1885,8 +1898,7 @@ def _export_loop(database_path: Path, session_id: str, key: str, command: list[s
|
|
|
1885
1898
|
if ending or time.monotonic() >= next_registration:
|
|
1886
1899
|
payload = {"session_id": session_id, "cwd": str(database_path.parent), "transcript_path": str(path),
|
|
1887
1900
|
"hook_event_name": "SessionEnd" if ending else "SessionStart"}
|
|
1888
|
-
|
|
1889
|
-
result = subprocess.run(command, input=json.dumps(payload), text=True, env=environment,
|
|
1901
|
+
result = subprocess.run(command, input=json.dumps(payload), text=True, env=_registration_environment(key),
|
|
1890
1902
|
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=5, check=False)
|
|
1891
1903
|
if result.returncode != 0:
|
|
1892
1904
|
logger.warning("[pushary] Hermes history reader could not register")
|
|
@@ -2084,7 +2096,7 @@ def record_plugin_load(approval_transport_registered, home=None, pid=None, now=N
|
|
|
2084
2096
|
logger.debug("[pushary] could not record the plugin load: %s", exc)
|
|
2085
2097
|
return None
|
|
2086
2098
|
` },
|
|
2087
|
-
{ path: "plugin.yaml", contents: 'name: pushary\nversion: 1.0.
|
|
2099
|
+
{ path: "plugin.yaml", contents: 'name: pushary\nversion: 1.0.1\ndescription: Push notifications and human-in-the-loop for Hermes Agent via Pushary\nauthor: RalphNex OU\nrequires_env:\n - name: PUSHARY_API_KEY\n description: Your Pushary API key\n url: https://pushary.com/sign-up?from=hermes\n secret: true\nconfig_schema:\n api_key:\n type: secret\n env: PUSHARY_API_KEY\n label: Pushary API key\n description: "Get one at pushary.com/sign-up?from=hermes"\n required: true\nprovides_tools:\n - pushary_remind\n - pushary_notify\n - pushary_ask\n - pushary_wait\n - pushary_cancel\n - pushary_propose_scope\n - pushary_enroll\n - pushary_ask_end_user\nprovides_hooks:\n - pre_llm_call\n - pre_tool_call\n - post_tool_call\n - on_session_start\n - on_session_end\n - on_session_finalize\n - post_approval_response\nprovides_approval_transports:\n - pushary\n' },
|
|
2088
2100
|
{ path: "schemas.py", contents: `PUSHARY_REMIND = {
|
|
2089
2101
|
"name": "pushary_remind",
|
|
2090
2102
|
"description": "Schedule a one-time personal reminder on Pushary, even after Hermes exits. Use body plus in_minutes or at (ISO timestamp with explicit UTC offset, within 30 days). Never guess the user's timezone. Confirm the returned time. No arguments lists pending reminders; cancel_reminder_id cancels a scheduled one. Use Hermes cron for agent work; use this for reminding the operator.",
|
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
reapplyOpenCodePlugin,
|
|
13
13
|
reapplyVsCodePlugin,
|
|
14
14
|
repairCodexHolds
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-RMFL62HR.js";
|
|
16
16
|
import "./chunk-RVSRPDRF.js";
|
|
17
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-COBOR3ST.js";
|
|
18
18
|
import "./chunk-SXAZPWL7.js";
|
|
19
19
|
import "./chunk-JECH4NJL.js";
|
|
20
20
|
import "./chunk-AZSOH2SF.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pushary",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.103",
|
|
4
4
|
"description": "Human-in-the-loop (HITL) for AI agents: ask a person for approvals or answers by push notification. One command connects Claude Code, Codex, Cursor, Gemini CLI and more.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pushary",
|