pushary 1.8.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.
Files changed (186) hide show
  1. package/CHANGELOG.md +1943 -0
  2. package/LICENSE +21 -0
  3. package/README.md +330 -0
  4. package/data/SKILL.md +591 -0
  5. package/data/cowork/SKILL.md +77 -0
  6. package/data/cursor-plugin/.cursor-plugin/plugin.json +25 -0
  7. package/data/cursor-plugin/CHANGELOG.md +70 -0
  8. package/data/cursor-plugin/CONTRIBUTING.md +40 -0
  9. package/data/cursor-plugin/LICENSE +21 -0
  10. package/data/cursor-plugin/README.md +113 -0
  11. package/data/cursor-plugin/SECURITY.md +33 -0
  12. package/data/cursor-plugin/assets/logo.png +0 -0
  13. package/data/cursor-plugin/commands/notify-when-done.md +14 -0
  14. package/data/cursor-plugin/commands/pushary-test.md +13 -0
  15. package/data/cursor-plugin/hooks/hooks.json +75 -0
  16. package/data/cursor-plugin/mcp.json +11 -0
  17. package/data/cursor-plugin/rules/pushary.mdc +40 -0
  18. package/data/cursor-plugin/scripts/pushary-gate.mjs +724 -0
  19. package/data/cursor-plugin/scripts/pushary-gate.test.mjs +137 -0
  20. package/data/cursor-plugin/scripts/redaction.mjs +51 -0
  21. package/data/cursor-plugin/skills/pushary/SKILL.md +584 -0
  22. package/data/vscode-plugin/.claude-plugin/plugin.json +28 -0
  23. package/data/vscode-plugin/.mcp.json +11 -0
  24. package/data/vscode-plugin/CHANGELOG.md +49 -0
  25. package/data/vscode-plugin/CONTRIBUTING.md +40 -0
  26. package/data/vscode-plugin/LICENSE +21 -0
  27. package/data/vscode-plugin/README.md +128 -0
  28. package/data/vscode-plugin/SECURITY.md +56 -0
  29. package/data/vscode-plugin/assets/logo.png +0 -0
  30. package/data/vscode-plugin/commands/notify-when-done.md +14 -0
  31. package/data/vscode-plugin/commands/pushary-test.md +13 -0
  32. package/data/vscode-plugin/hooks/hooks.json +60 -0
  33. package/data/vscode-plugin/scripts/pushary-gate.mjs +762 -0
  34. package/data/vscode-plugin/scripts/redaction.mjs +51 -0
  35. package/data/vscode-plugin/skills/pushary/SKILL.md +584 -0
  36. package/dist/bin/pushary-bell-hook.d.ts +1 -0
  37. package/dist/bin/pushary-bell-hook.js +46 -0
  38. package/dist/bin/pushary-bell.d.ts +1 -0
  39. package/dist/bin/pushary-bell.js +146 -0
  40. package/dist/bin/pushary-claude.d.ts +1 -0
  41. package/dist/bin/pushary-claude.js +1916 -0
  42. package/dist/bin/pushary-clean.d.ts +1 -0
  43. package/dist/bin/pushary-clean.js +1300 -0
  44. package/dist/bin/pushary-codex-bridge.d.ts +1 -0
  45. package/dist/bin/pushary-codex-bridge.js +599 -0
  46. package/dist/bin/pushary-codex-hook.d.ts +1 -0
  47. package/dist/bin/pushary-codex-hook.js +886 -0
  48. package/dist/bin/pushary-codex.d.ts +1 -0
  49. package/dist/bin/pushary-codex.js +125 -0
  50. package/dist/bin/pushary-connect.d.ts +1 -0
  51. package/dist/bin/pushary-connect.js +100 -0
  52. package/dist/bin/pushary-cowork.d.ts +1 -0
  53. package/dist/bin/pushary-cowork.js +36 -0
  54. package/dist/bin/pushary-daemon-supervisor.d.ts +1 -0
  55. package/dist/bin/pushary-daemon-supervisor.js +27 -0
  56. package/dist/bin/pushary-daemon.d.ts +1 -0
  57. package/dist/bin/pushary-daemon.js +878 -0
  58. package/dist/bin/pushary-disconnect.d.ts +1 -0
  59. package/dist/bin/pushary-disconnect.js +264 -0
  60. package/dist/bin/pushary-doctor.d.ts +1 -0
  61. package/dist/bin/pushary-doctor.js +1433 -0
  62. package/dist/bin/pushary-elicitation-hook.d.ts +1 -0
  63. package/dist/bin/pushary-elicitation-hook.js +149 -0
  64. package/dist/bin/pushary-gemini-bridge.d.ts +1 -0
  65. package/dist/bin/pushary-gemini-bridge.js +339 -0
  66. package/dist/bin/pushary-gemini-hook.d.ts +1 -0
  67. package/dist/bin/pushary-gemini-hook.js +381 -0
  68. package/dist/bin/pushary-hook.d.ts +1 -0
  69. package/dist/bin/pushary-hook.js +95 -0
  70. package/dist/bin/pushary-login.d.ts +1 -0
  71. package/dist/bin/pushary-login.js +198 -0
  72. package/dist/bin/pushary-logout.d.ts +1 -0
  73. package/dist/bin/pushary-logout.js +147 -0
  74. package/dist/bin/pushary-mcp.d.ts +1 -0
  75. package/dist/bin/pushary-mcp.js +114 -0
  76. package/dist/bin/pushary-mode.d.ts +1 -0
  77. package/dist/bin/pushary-mode.js +130 -0
  78. package/dist/bin/pushary-notification-hook.d.ts +1 -0
  79. package/dist/bin/pushary-notification-hook.js +56 -0
  80. package/dist/bin/pushary-opencode-hook.d.ts +1 -0
  81. package/dist/bin/pushary-opencode-hook.js +338 -0
  82. package/dist/bin/pushary-permission-denied-hook.d.ts +1 -0
  83. package/dist/bin/pushary-permission-denied-hook.js +60 -0
  84. package/dist/bin/pushary-permission-hook.d.ts +1 -0
  85. package/dist/bin/pushary-permission-hook.js +65 -0
  86. package/dist/bin/pushary-post-hook.d.ts +1 -0
  87. package/dist/bin/pushary-post-hook.js +70 -0
  88. package/dist/bin/pushary-prompt-hook.d.ts +1 -0
  89. package/dist/bin/pushary-prompt-hook.js +61 -0
  90. package/dist/bin/pushary-session-end-hook.d.ts +1 -0
  91. package/dist/bin/pushary-session-end-hook.js +59 -0
  92. package/dist/bin/pushary-session-start-hook.d.ts +1 -0
  93. package/dist/bin/pushary-session-start-hook.js +72 -0
  94. package/dist/bin/pushary-setup.d.ts +1 -0
  95. package/dist/bin/pushary-setup.js +2660 -0
  96. package/dist/bin/pushary-stats.d.ts +1 -0
  97. package/dist/bin/pushary-stats.js +44 -0
  98. package/dist/bin/pushary-status.d.ts +1 -0
  99. package/dist/bin/pushary-status.js +262 -0
  100. package/dist/bin/pushary-stop-hook.d.ts +1 -0
  101. package/dist/bin/pushary-stop-hook.js +63 -0
  102. package/dist/bin/pushary-stopfailure-hook.d.ts +1 -0
  103. package/dist/bin/pushary-stopfailure-hook.js +56 -0
  104. package/dist/bin/pushary-suggestions.d.ts +1 -0
  105. package/dist/bin/pushary-suggestions.js +100 -0
  106. package/dist/bin/pushary-transcript-register.d.ts +1 -0
  107. package/dist/bin/pushary-transcript-register.js +40 -0
  108. package/dist/bin/pushary-transcripts.d.ts +1 -0
  109. package/dist/bin/pushary-transcripts.js +77 -0
  110. package/dist/bin/pushary-upgrade.d.ts +1 -0
  111. package/dist/bin/pushary-upgrade.js +599 -0
  112. package/dist/bin/pushary-wait.d.ts +1 -0
  113. package/dist/bin/pushary-wait.js +122 -0
  114. package/dist/bin/pushary.d.ts +1 -0
  115. package/dist/bin/pushary.js +74 -0
  116. package/dist/chunk-2ABTSGFT.js +173 -0
  117. package/dist/chunk-2OY3ZZ5N.js +124 -0
  118. package/dist/chunk-3EGEA4KH.js +44 -0
  119. package/dist/chunk-3EVPNIBE.js +185 -0
  120. package/dist/chunk-5OP5MQI7.js +45 -0
  121. package/dist/chunk-6J2JC2RT.js +149 -0
  122. package/dist/chunk-7QLSKOSU.js +19 -0
  123. package/dist/chunk-7Z7Q4GGS.js +88 -0
  124. package/dist/chunk-A2A2YTMG.js +835 -0
  125. package/dist/chunk-AHV4LNB5.js +377 -0
  126. package/dist/chunk-AXPCESYO.js +197 -0
  127. package/dist/chunk-C2WCPBF7.js +86 -0
  128. package/dist/chunk-CJVVKOSR.js +73 -0
  129. package/dist/chunk-CULUZTWQ.js +2117 -0
  130. package/dist/chunk-CVQYGMSR.js +142 -0
  131. package/dist/chunk-CVWG2N3Y.js +16 -0
  132. package/dist/chunk-D2FX3EPW.js +15 -0
  133. package/dist/chunk-DB3ONZB4.js +44 -0
  134. package/dist/chunk-DE4Y6TCC.js +160 -0
  135. package/dist/chunk-E4FJTUH4.js +249 -0
  136. package/dist/chunk-EPCXUP3P.js +41 -0
  137. package/dist/chunk-EX3GAPA4.js +44 -0
  138. package/dist/chunk-EYK3GSRH.js +143 -0
  139. package/dist/chunk-GMXKITVA.js +70 -0
  140. package/dist/chunk-GPEGOGRJ.js +49 -0
  141. package/dist/chunk-GU3EJCVV.js +43 -0
  142. package/dist/chunk-HQ6G3B5R.js +59 -0
  143. package/dist/chunk-HZVVNGEW.js +22 -0
  144. package/dist/chunk-IPVKH2ST.js +231 -0
  145. package/dist/chunk-J5TIV3J6.js +238 -0
  146. package/dist/chunk-JU6W3XAU.js +64 -0
  147. package/dist/chunk-JYG4B33G.js +227 -0
  148. package/dist/chunk-JZTHGAPA.js +503 -0
  149. package/dist/chunk-KGDWDSNL.js +102 -0
  150. package/dist/chunk-KVQBWI5T.js +99 -0
  151. package/dist/chunk-KZERVKTD.js +16 -0
  152. package/dist/chunk-LXQ5FBBD.js +47 -0
  153. package/dist/chunk-M5ICYGHT.js +138 -0
  154. package/dist/chunk-M5JDZ45W.js +943 -0
  155. package/dist/chunk-MDEPU45E.js +1226 -0
  156. package/dist/chunk-MPWXGONV.js +157 -0
  157. package/dist/chunk-N6IOSZOE.js +185 -0
  158. package/dist/chunk-NGDD6TXY.js +192 -0
  159. package/dist/chunk-NQTHFF4W.js +2830 -0
  160. package/dist/chunk-OKXS7WDZ.js +68 -0
  161. package/dist/chunk-OLQRRFBX.js +21 -0
  162. package/dist/chunk-P7WQEVWA.js +307 -0
  163. package/dist/chunk-POFBE6ZY.js +12 -0
  164. package/dist/chunk-PQ4K74WL.js +30 -0
  165. package/dist/chunk-PUZZELE6.js +37 -0
  166. package/dist/chunk-Q7E4I6UA.js +767 -0
  167. package/dist/chunk-QCGNGEGE.js +15 -0
  168. package/dist/chunk-R7437YI3.js +151 -0
  169. package/dist/chunk-RHR6NARM.js +305 -0
  170. package/dist/chunk-SAXBC4AZ.js +60 -0
  171. package/dist/chunk-SGZJ5LYH.js +76 -0
  172. package/dist/chunk-SIFVFP6T.js +70 -0
  173. package/dist/chunk-SLFABHW3.js +150 -0
  174. package/dist/chunk-T7E75EKA.js +67 -0
  175. package/dist/chunk-TY4JT7W3.js +38 -0
  176. package/dist/chunk-U4TMAANR.js +111 -0
  177. package/dist/chunk-UI36QSBI.js +177 -0
  178. package/dist/chunk-VQKRG3AC.js +339 -0
  179. package/dist/chunk-WE2J62NC.js +1131 -0
  180. package/dist/chunk-XHKBHWLX.js +14 -0
  181. package/dist/chunk-ZSZSSJCV.js +275 -0
  182. package/dist/chunk-ZVSKMPBZ.js +135 -0
  183. package/dist/reapply-CW3MA66V.js +34 -0
  184. package/dist/src/index.d.ts +204 -0
  185. package/dist/src/index.js +64 -0
  186. package/package.json +108 -0
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: pushary-cowork
3
+ version: 0.4.2
4
+ description: Phone notifications and human-in-the-loop for Claude Cowork through the Pushary connector. Use inside a Cowork session whenever you need a human and nobody is watching the session, such as before an irreversible or destructive action, before spending money, deploying, force-pushing or deleting, when blocked on a decision outside your authority, when running unattended and you hit a genuine ambiguity, when another skill's workflow says to confirm with the user, and when a task finishes or fails with nobody watching. Also use it when the user says things like ping me on my phone when this is done, ask me before doing anything risky, keep me in the loop while I am away, or notify me if you get stuck. Sends completion alerts, asks questions (yes/no, multiple choice, or free text) via push, and gets answers from connected devices. This Pushary connector is cooperative; it does not install native Cowork permission hooks. Pushary is a hosted service, $9.99/mo after a 3-day card-first trial.
5
+ metadata:
6
+ tags: notifications, push, mcp, human-in-the-loop, cowork, claude, alerts, approvals
7
+ ---
8
+
9
+ # Pushary for Claude Cowork
10
+
11
+ Pushary is connected as a custom connector. It reaches the user on their phone, where confirm notifications can offer lock-screen actions; choices and text open the app. Use it proactively. Do not wait for the user to ask.
12
+
13
+ ## Ask in as few interruptions as possible
14
+
15
+ Honor authorization already granted in this session. Ask only for a missing decision or an action outside that authorization, or when an enforced host policy requires it. A multi-step task alone does not require plan approval. Never ask again merely because the next authorized step deletes, deploys or publishes something. These skills guide the agent; supported hooks and runtime approval gates enforce policy. Do not bypass an enforced gate.
16
+
17
+ Every question costs the user their attention wherever they are. Before a run of more than a step or two, work out where you will need a human and fold those points together: one `select` carrying the real options beats three `confirm`s in a row, ask once at a boundary rather than once per instance, and never ask what you can determine yourself from the task or from a tool call you can make.
18
+
19
+ ## When to reach out
20
+
21
+ - **You need a decision or a clarifying answer.** Call `ask_user` instead of guessing or stalling. Use type `confirm` for yes or no, `select` for a fixed set of options, and `input` for free text.
22
+ - **An action outside your existing authorization is risky or irreversible.** Deleting or overwriting files, spending money, sending anything external, bulk changes: call `ask_user` with type `confirm` first and wait for approval.
23
+ - **Meaningful work finishes while the user is away, or they requested an alert.** Call `send_notification` with a short summary of what changed, and pass `context.type` as `task_complete`. That is what marks it a task update, and the user's setting for where task updates land can only route one that says so. Keep a reply channel open only for a specific unresolved decision needed to finish, as described below.
24
+ - **You are blocked or hit an error you cannot resolve.** Call `send_notification` with `context.type` as `error` so the user knows, and `ask_user` if you need a decision to continue.
25
+ - **Another skill's workflow says to confirm with the user.** That instruction assumes someone is watching the session. Often nobody is. Route the confirmation through `ask_user` so the run continues when they answer, instead of stalling on a prompt they never see.
26
+
27
+ ## Hand back with a way to reply
28
+
29
+ The connector is the only channel between this session and the user's phone, and it carries only what you ask it to. A plain completion notice is one way traffic: once your turn ends nothing here is listening, so anything the user types back on their phone has nowhere to land. Pushary also cannot start a new Cowork task on its own, so a reply that says "now do X" reaches nobody unless you asked for it before you stopped.
30
+
31
+ When a specific unresolved decision is needed before you can finish, keep the channel open:
32
+
33
+ 1. Call `send_notification` with `context.type` set to `task_complete` and `context.askQuestion` set to an `input` question, such as "Which of these two drafts should I publish?".
34
+ 2. Poll the returned `linkedCorrelationId` once with `wait_for_answer`, then follow its handoff.
35
+ 3. Act on the answer in this same session, then hand back the same way again if more work follows.
36
+
37
+ Do not create a question just to keep the turn alive or ask for optional feedback after every result. Once this turn ends, tell the user to reopen Cowork for follow-up work.
38
+
39
+ ## How to wait for answers
40
+
41
+ Read `answered`, `status` and `handoffAction` (falling back to `nextAction`) on every response. Only `pending` is live; expired, cancelled, missing and unavailable are not new timeouts. Follow the returned handoff rather than inventing a retry loop. Before moving a live question to the current chat, cancel it. If cancellation says `stop`, stop; if it loses a race, poll once for one second and honor the winning answer. Silence is never consent. A select or input value containing “yes” is answer data, not approval of a separate action.
42
+
43
+ Delivery is controlled by the user's policy: `push_first` uses presence, `push_only` requests push every time, `notify_only` leaves the decision in the current client, and `terminal_only` avoids push. Do not override the mode or duplicate a question on every surface. The runtime owns delivery, expiry and settlement; do not claim that a reply can restart an ended agent turn.
44
+
45
+ - If `ask_user` times out, call `wait_for_answer` once with the same question id. If it is still pending, cancel it before asking in the current client. If cancellation returns `handoffAction: "stop"`, stop. Otherwise, if cancellation returns false, poll once for 1 second and honor the answer that won the race.
46
+ - On long tasks where the user might be away, prefer `send_notification` with `context.askQuestion` over a blocking `ask_user`. The user can answer from the notification page while the question remains live. Poll the returned `linkedCorrelationId` once when you need the result, then follow the returned handoff; do not promise an overnight wait or a reply after the turn ends.
47
+ - Use `cancel_question` to retract a question that is no longer needed.
48
+
49
+ ## Answer surfaces and account boundaries
50
+
51
+ | Surface | What the user can do |
52
+ | --- | --- |
53
+ | Mobile app | Answer confirm, select and input questions. Supported confirm notifications offer approve/deny actions on the lock screen; arbitrary choices and text open the app. |
54
+ | Mac notch | Answer personal account questions with confirm, select, input and question-set controls, including keyboard controls. Presence and delivery policy determine when the phone is also reached. |
55
+ | Slack | Answer through buttons, menus or text modals when the integration and intended recipient are configured. |
56
+ | Browser | Open the decision page as a fallback; browser notification delivery requires permission. |
57
+
58
+ Personal setup connects the operator's devices. For a Mac, install from https://pushary.com/download, sign in to the same personal account and connect your agents in the app. Run `npx @pushary/agent-hooks@latest cowork` for connector setup, then ask one harmless test question inside Cowork, answer it from Pushary, and verify Cowork receives the answer. CLI doctor checks do not verify a hosted connector. Test phone fallback while away from the Mac; do not infer delivery from a successful API call alone.
59
+
60
+ Partner customers use scoped enrollment links issued by their application. Do not enroll them into the operator's account or send their decisions through personal tools. The Mac notch currently uses the personal account/session API; do not promise a Partner customer inbox on Mac. See https://pushary.com/docs/agents/embed for Partner setup.
61
+
62
+ ## Conventions
63
+
64
+ - Reuse one opaque `sessionId` per Cowork task. Do not reuse it across parallel tasks or put credentials in it.
65
+ - Pass `agentName` as `Claude Cowork - <task name>` on every call, so the user knows which session is asking and their dashboard groups the session correctly.
66
+ - Keep questions short and decision-shaped. One sentence of context, then the ask. The user is reading a lock screen, not a report.
67
+ - Do not ask through Pushary for things you can safely decide yourself. Reserve it for real decisions, risky steps, completions, and errors, so a ping always means something.
68
+
69
+ ## Setup and capability boundary
70
+
71
+ Install the Pushary Cowork plugin to supply this skill and its remote MCP connector, or add `https://pushary.com/api/mcp/mcp` under Customize > Connectors. Sign in with the same Pushary account used by your phone and Mac. Enable the connector in the task and approve its tool access when Claude asks. For proactive behavior, use this skill or standing instructions under Settings > Cowork; do not rely on a repository memory file.
72
+
73
+ Anthropic documents plugin hooks in supported Cowork versions. This plugin currently uses the cooperative connector and does not install or verify native permission hooks. Local and cloud Cowork tasks may have different capabilities; do not infer them from the product name. Native Claude permission prompts still need Claude’s own approval surface.
74
+
75
+ ## If the connector is missing
76
+
77
+ If no Pushary tools are available in this session, the connector is not enabled. Tell the user once: Pushary is not connected in this session. Enable it under Customize, Connectors, or set it up at https://pushary.com/docs/agents/guides/claude-desktop. Then continue the task without it.
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "pushary",
3
+ "displayName": "Pushary — Control Panel for AI Agents",
4
+ "description": "Push notifications, human-in-the-loop questions, and permission gating for your AI coding agent. Get a push when a task finishes, answer the agent from your phone, and approve risky commands before they run.",
5
+ "version": "0.2.3",
6
+ "author": { "name": "Pushary", "email": "business@pushary.com" },
7
+ "homepage": "https://pushary.com",
8
+ "repository": "https://github.com/Pushary/cursor-plugin",
9
+ "license": "MIT",
10
+ "keywords": [
11
+ "notifications",
12
+ "push",
13
+ "human-in-the-loop",
14
+ "permissions",
15
+ "approvals",
16
+ "mcp",
17
+ "agent",
18
+ "control-panel",
19
+ "ask",
20
+ "alerts"
21
+ ],
22
+ "category": "developer-tools",
23
+ "tags": ["notifications", "approvals", "human-in-the-loop", "mcp", "workflow"],
24
+ "logo": "assets/logo.png"
25
+ }
@@ -0,0 +1,70 @@
1
+ # Changelog
2
+
3
+ ## 0.2.3
4
+
5
+ - Approval text never hides part of a command. The value after a credential name is hidden only up to the first space, quote or piece of shell syntax, so `echo "password=" && rm -rf ~` and `eval TOKEN="x; rm -rf ~"` both show the `rm`. A private key block is hidden only when it holds nothing but the key.
6
+ - Updates and Terminal hand an approval back to Cursor promptly. The gate no longer waits for a phone answer that Updates never asks for, and it withdraws the phone question before Cursor decides. An answer that arrives in that moment still counts.
7
+ - A file change that goes back to the agent's own permissions is refused with the reason, because Cursor file hooks cannot show a local approval. Choose Every time for file changes you want to approve from your phone.
8
+ - With no phone or other notification channel connected, a file change is refused with a message that says so. Shell commands and MCP calls still open Cursor's own prompt with "No device connected, approve here."
9
+ - Approval questions carry the repository and the tool name the gate judged, so routing and repository rules apply to the question as they did to the gate. A file change is asked about with its full path, so path rules and routing match it. A path longer than 80 characters falls back to the file type instead of making the question fail.
10
+
11
+ ## 0.2.2
12
+
13
+ - Allow file edits when the server explicitly says the action is not gated.
14
+ - Keep unresolved file checks denied with an accurate retry message, while shell/MCP hooks retain the native prompt.
15
+
16
+ ## 0.2.0
17
+
18
+ The gate stopped carrying its own copy of the policy engine.
19
+
20
+ Pattern matching, glob compilation, the destructive-command list and policy
21
+ resolution all lived in this file, roughly two hundred and fifty lines of it,
22
+ kept in step with the real engine by hand. That is how 0.1.1 happened: the copy
23
+ matched on tool name alone, so every argument rule was invisible here. It also
24
+ never gained the safe read-only allowlist, so `git status` reached your phone
25
+ from Cursor and from nowhere else.
26
+
27
+ The gate now asks the server, which runs the same engine as every other client
28
+ over the same policy and mode state. There is nothing left to keep in step.
29
+
30
+ - The safe read-only allowlist applies here now: ordinary read-only commands
31
+ stop reaching your phone.
32
+ - A policy change takes effect immediately. The five-minute on-disk policy cache
33
+ is gone, along with the stale-cache fallback.
34
+ - An unreachable Pushary hands the command to Cursor's own prompt, as before.
35
+ Nothing is ever denied because we could not reach the server.
36
+
37
+ ## 0.1.1
38
+
39
+ Policy parity with the other agents. The gate matched rules on tool NAME alone, so
40
+ every argument rule was invisible here: a `Bash(rm:*)` deny you had written did
41
+ nothing, and `rm -rf` was auto-approved by a broad `Bash` allow. Cursor was
42
+ strictly less safe than Claude Code for the same dashboard policy.
43
+
44
+ - Argument rules now match: `Bash(git status)` exact, `Bash(npm test:*)` prefix,
45
+ and path-style globs, with the same precedence the hook uses.
46
+ - The destructive ceiling applies: a command the classifier flags can no longer
47
+ auto-approve through a general bare-tool or wildcard rule. An explicit rule you
48
+ wrote still wins.
49
+ - Repo-scoped rules are honoured. Identity is the normalized git remote, read from
50
+ `.git/config` as a file; credentials are stripped. `PUSHARY_REPO_KEY` pins it,
51
+ `PUSHARY_REPO_KEY=off` disables scoping.
52
+ - Approvals now carry the command target and body, so the server can drop the
53
+ one-tap Approve on a dangerous call and the audit trail records Cursor
54
+ decisions at the same grain as every other agent.
55
+ - `scripts/pushary-gate.test.mjs` mirrors the monorepo's policy tests, since the
56
+ matcher is vendored and cannot be imported.
57
+
58
+ Verified against the canonical matcher over 1512 resolutions: zero cases where
59
+ the gate is less safe. The remaining differences are all the safe-read-only
60
+ allowlist, which is deliberately not vendored because it only ever loosens a
61
+ decision.
62
+
63
+ ## 0.1.0
64
+
65
+ Initial release.
66
+
67
+ - MCP server (`send_notification`, `ask_user`, `wait_for_answer`, `cancel_question`, `list_sessions`) wired via `mcp.json`, key supplied at runtime through `PUSHARY_API_KEY`.
68
+ - Always-on rule and full tool-reference skill so the agent uses Pushary proactively.
69
+ - `beforeShellExecution` gate (`scripts/pushary-gate.mjs`, zero-dependency) that evaluates risky commands against your Pushary dashboard policy — auto-approve, the four approval modes, timeout actions, live mode override, and kill switch, scoped to the Cursor conversation. Falls back to Cursor's own prompt when Pushary is unreachable, and is fail-closed: a broken gate blocks rather than allows.
70
+ - Commands: `/pushary-test`, `/notify-when-done`.
@@ -0,0 +1,40 @@
1
+ # Contributing
2
+
3
+ Bug reports, documentation fixes, runnable examples, and patches are welcome.
4
+ Open an issue in this public repository, or fork it and open a pull request here.
5
+ You do not need access to Pushary's private repository to contribute.
6
+
7
+ ## Start small
8
+
9
+ Pick an unassigned `good first issue`, explain the change you plan, and include
10
+ steps that another developer can use to verify it. For a bug, include the package
11
+ and framework versions, your OS, expected behavior, and a minimal reproduction.
12
+ Never include API keys, enrollment links, customer data, or private transcripts.
13
+
14
+ For a JavaScript adapter, run `npm install`, `npm run typecheck`, `npm test`, and
15
+ `npm run build` in your clone. Follow the README for Python or plugin-specific
16
+ setup. Documentation changes should have working links and commands you tried.
17
+
18
+ ## How your patch ships
19
+
20
+ This repository is a public mirror of a directory in Pushary's private monorepo.
21
+ We review your PR here, then apply accepted changes upstream before publishing
22
+ this mirror. A direct merge into the mirror could be overwritten by the next sync.
23
+
24
+ The maintainer handling your PR will:
25
+
26
+ 1. Review the patch and discuss requested changes in the public PR.
27
+ 2. Apply accepted changes upstream, retaining author attribution in that commit.
28
+ 3. Run the relevant checks, release a package if needed, and sync this repository.
29
+ 4. Link the public sync commit and released version (when applicable) back to your
30
+ PR, credit your contribution publicly, then close it as shipped.
31
+
32
+ Public sync commits squash private history, so upstream author attribution does
33
+ not automatically appear in this mirror's GitHub contributor graph. The public
34
+ PR and shipping comment preserve visible credit. An upstream-only patch is not
35
+ considered shipped. If we cannot accept a change, we explain why on the PR.
36
+
37
+ ## Security
38
+
39
+ Report vulnerabilities privately to aadil@pushary.com instead of opening a public
40
+ issue. If this repository has a SECURITY.md, follow its disclosure guidance.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pushary
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,113 @@
1
+ <p align="center">
2
+ <img src="assets/logo.png" alt="Pushary" width="72" height="72" />
3
+ </p>
4
+
5
+ <h1 align="center">Pushary for Cursor</h1>
6
+
7
+ <p align="center">A control panel for your AI coding agent. Get a push when work finishes, answer the agent from your phone, and approve risky commands before they run.</p>
8
+
9
+ ---
10
+
11
+ ## What it is
12
+
13
+ Pushary connects Cursor to your phone. When the agent finishes a task, needs a decision, or is about to run something risky, it reaches you with a push notification. You answer from the lock screen and the agent keeps going. It works even when you have stepped away from your computer.
14
+
15
+ ## What it does
16
+
17
+ There are three things.
18
+
19
+ 1. Notify. The agent sends a push when a long task finishes, or when a build, test, or deploy fails. The push can include what changed, the error, and suggested next steps.
20
+
21
+ 2. Ask. The agent asks you questions through push: yes or no, multiple choice, or free text. It waits for your answer. The bundled instructions guide the agent to use Pushary for questions. Native editor question dialogs are not automatically intercepted.
22
+
23
+ 3. Gate. Shell commands, file writes/edits/deletes, and third-party MCP calls reach your Pushary policy before execution. The policy can approve, deny, or wait for your answer. Cancelled or unverifiable decisions stop the action. Cursor’s generic file-tool hook does not enforce `ask`, so an unresolved file action is denied. File actions explicitly marked `not_gated` by the server proceed; shell/MCP hooks can hand off to Cursor’s prompt.
24
+
25
+ ## Install
26
+
27
+ You need two things: the plugin, and an API key.
28
+
29
+ ### Option 1: Cursor Marketplace (recommended)
30
+
31
+ Open the Marketplace panel in Cursor, search for Pushary, and click install. Then set your API key (see below).
32
+
33
+ ### Option 2: CLI
34
+
35
+ This also sets up Claude Code, Codex, and Hermes if you use them.
36
+
37
+ ```bash
38
+ npx @pushary/agent-hooks@latest setup
39
+ ```
40
+
41
+ ### Option 3: Manual MCP
42
+
43
+ Add this to `.cursor/mcp.json` in your project, or `~/.cursor/mcp.json` for every project:
44
+
45
+ ```json
46
+ {
47
+ "mcpServers": {
48
+ "pushary": {
49
+ "type": "http",
50
+ "url": "https://pushary.com/api/mcp/mcp",
51
+ "headers": { "Authorization": "Bearer ${env:PUSHARY_API_KEY}" }
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ The plugin and CLI installer use the same decision service. Manual MCP-only configuration provides questions and notifications, but does not install approval or activity hooks.
58
+
59
+ ## Set your API key
60
+
61
+ The plugin reads your key from the `PUSHARY_API_KEY` environment variable. Get a key at https://pushary.com, then add it to your shell profile:
62
+
63
+ ```bash
64
+ echo 'export PUSHARY_API_KEY="pk_xxx.sk_xxx"' >> ~/.zshrc
65
+ source ~/.zshrc
66
+ ```
67
+
68
+ Install the Pushary app on your phone (or turn on web push) so the agent can reach you.
69
+
70
+ ## Troubleshooting
71
+
72
+ macOS GUI apps do not read `.zshrc`. If Settings > MCP shows pushary in red after you set the env var, launch Cursor from a terminal where `PUSHARY_API_KEY` is exported, or set the variable system-wide so GUI apps see it.
73
+
74
+ ## What is in the plugin
75
+
76
+ | Part | File | What it does |
77
+ |------|------|--------------|
78
+ | MCP server | `mcp.json` | Connects Cursor to the Pushary tools: `send_notification`, `ask_user`, `wait_for_answer`, `cancel_question`, `list_sessions` |
79
+ | Rule | `rules/pushary.mdc` | Always on guidance so the agent uses Pushary on its own |
80
+ | Skill | `skills/pushary/SKILL.md` | Full tool reference: parameters, examples, return values |
81
+ | Hook | `hooks/hooks.json` and `scripts/pushary-gate.mjs` | Evaluates tool approvals and reports session/tool activity |
82
+ | Commands | `commands/` | `/pushary-test` and `/notify-when-done` |
83
+
84
+ ## How the gate decides
85
+
86
+ The hooks register the supported execution boundaries; your dashboard policy decides which actions need approval. No shell-command regex hides a tool from policy evaluation. Lifecycle hooks report session starts, turn completion, tool results, compaction, and subagent activity.
87
+
88
+ Timeout approvals apply only after the configured wait actually elapsed. Short editor hook budgets can end a wait earlier; cancellation is attempted before handoff. An uncertain cancellation denies the action. Local plugin installation does not install hooks into remote or cloud agent environments.
89
+
90
+ ## Commands
91
+
92
+ - `/pushary-test` sends a test push so you can confirm delivery.
93
+ - `/notify-when-done` tells the agent to push a summary when the current task finishes.
94
+
95
+ ## Development
96
+
97
+ `skills/pushary/SKILL.md` mirrors the Pushary skill that ships with `@pushary/agent-hooks`. Keep the two the same.
98
+
99
+ Test the plugin locally before publishing:
100
+
101
+ ```bash
102
+ ln -s "$(pwd)" ~/.cursor/plugins/local/pushary
103
+ ```
104
+
105
+ Then reload Cursor with Developer: Reload Window.
106
+
107
+ ## Security
108
+
109
+ This repository has no secrets. Your key is read at runtime from `PUSHARY_API_KEY`. The gate script has no dependencies and only talks to pushary.com. Read `scripts/pushary-gate.mjs` to see exactly what it sends. See `SECURITY.md` for details.
110
+
111
+ ## License
112
+
113
+ MIT. See `LICENSE`.
@@ -0,0 +1,33 @@
1
+ # Security
2
+
3
+ ## Reporting a vulnerability
4
+
5
+ Email **security@pushary.com** with details and reproduction steps. Please do not open a public
6
+ issue for security reports. We aim to acknowledge within 72 hours.
7
+
8
+ ## What this plugin sends
9
+
10
+ The plugin connects Cursor to the Pushary MCP server at `https://pushary.com/api/mcp/mcp` using
11
+ the API key you provide via the `PUSHARY_API_KEY` environment variable. No key is committed to
12
+ this repository.
13
+
14
+ The permission gate (`scripts/pushary-gate.mjs`) runs only on shell commands matching the regex
15
+ in `hooks/hooks.json`. For a matched command it sends, over HTTPS to Pushary:
16
+
17
+ - the command text,
18
+ - the basename of the working directory (e.g. `my-repo`, not the full path),
19
+ - an agent label (`Cursor - <project>`),
20
+ - the Cursor conversation id, so the dashboard kill switch and per-session mode can target this session,
21
+ - a machine id — the first 8 hex characters of a SHA-256 of your hostname (never the hostname itself).
22
+
23
+ It also fetches your permission policy and mode from `pushary.com` (the policy is cached in the
24
+ system temp directory for 5 minutes). It contacts no host other than `pushary.com`, has no
25
+ third-party dependencies, and writes only that policy cache to disk. The full source is in this
26
+ repository — read it before installing.
27
+
28
+ ## Fail-closed by design
29
+
30
+ The gate is configured `failClosed: true`. If the gate cannot produce a decision (crash,
31
+ timeout, invalid output), Cursor **blocks** the matched command rather than letting it run
32
+ unapproved. When Pushary is reachable but you don't answer in time, it falls back to Cursor's
33
+ own in-editor approval prompt.
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: notify-when-done
3
+ description: Send a Pushary push summarizing what changed when the current task finishes.
4
+ ---
5
+
6
+ When you finish the current task, send a Pushary push notification so the user knows it's done — even if they have stepped away from the editor.
7
+
8
+ Call `send_notification` with:
9
+ - `title`: a short summary (under 60 chars) of what was completed
10
+ - `body`: one line on the outcome (under 200 chars)
11
+ - `agentName`: `"Cursor - {project}"`
12
+ - `context`: `{ type: "task_complete", summary, filesChanged, nextSteps }`
13
+
14
+ Send a single notification for the task. If the task fails instead, send `context.type: "error"` with `errorMessage` and the file where it failed.
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: pushary-test
3
+ description: Send a test Pushary push notification to confirm notifications are working.
4
+ ---
5
+
6
+ Send a test push notification with the Pushary `send_notification` tool so the user can confirm delivery on their phone.
7
+
8
+ Call `send_notification` with:
9
+ - `title`: "Pushary test"
10
+ - `body`: "If you can read this on your phone, Pushary is working."
11
+ - `agentName`: `"Cursor - {project}"` (use the current project folder name)
12
+
13
+ Then tell the user it was sent and to check their device. If the call fails, report the error and remind them to set the `PUSHARY_API_KEY` environment variable and sign in at https://pushary.com.
@@ -0,0 +1,75 @@
1
+ {
2
+ "version": 1,
3
+ "hooks": {
4
+ "beforeShellExecution": [
5
+ {
6
+ "command": "node ./scripts/pushary-gate.mjs",
7
+ "timeout": 60,
8
+ "failClosed": true
9
+ }
10
+ ],
11
+ "beforeMCPExecution": [
12
+ {
13
+ "command": "node ./scripts/pushary-gate.mjs",
14
+ "timeout": 60,
15
+ "failClosed": true
16
+ }
17
+ ],
18
+ "preToolUse": [
19
+ {
20
+ "command": "node ./scripts/pushary-gate.mjs",
21
+ "matcher": "Write|Delete|Edit",
22
+ "timeout": 60,
23
+ "failClosed": true
24
+ }
25
+ ],
26
+ "postToolUse": [
27
+ {
28
+ "command": "node ./scripts/pushary-gate.mjs",
29
+ "timeout": 10
30
+ }
31
+ ],
32
+ "stop": [
33
+ {
34
+ "command": "node ./scripts/pushary-gate.mjs",
35
+ "timeout": 10
36
+ }
37
+ ],
38
+ "sessionStart": [
39
+ {
40
+ "command": "node ./scripts/pushary-gate.mjs",
41
+ "timeout": 10
42
+ }
43
+ ],
44
+ "sessionEnd": [
45
+ {
46
+ "command": "node ./scripts/pushary-gate.mjs",
47
+ "timeout": 10
48
+ }
49
+ ],
50
+ "beforeSubmitPrompt": [
51
+ {
52
+ "command": "node ./scripts/pushary-gate.mjs",
53
+ "timeout": 10
54
+ }
55
+ ],
56
+ "preCompact": [
57
+ {
58
+ "command": "node ./scripts/pushary-gate.mjs",
59
+ "timeout": 10
60
+ }
61
+ ],
62
+ "subagentStart": [
63
+ {
64
+ "command": "node ./scripts/pushary-gate.mjs",
65
+ "timeout": 10
66
+ }
67
+ ],
68
+ "subagentStop": [
69
+ {
70
+ "command": "node ./scripts/pushary-gate.mjs",
71
+ "timeout": 10
72
+ }
73
+ ]
74
+ }
75
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "pushary": {
4
+ "type": "http",
5
+ "url": "https://pushary.com/api/mcp/mcp",
6
+ "headers": {
7
+ "Authorization": "Bearer ${env:PUSHARY_API_KEY}"
8
+ }
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,40 @@
1
+ ---
2
+ description: Pushary is connected. Use it to ask the user questions, notify them, and gate risky commands through push.
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Pushary
7
+
8
+ Pushary is connected as an MCP server. It reaches the user on their phone, so use it on your own without being asked. Assume the user may be away from the editor.
9
+
10
+ ## Ask the user through Pushary
11
+
12
+ When Pushary is connected, it is your channel for reaching the user. Any time you would stop and ask the user something, ask it through the `ask_user` tool and wait for the answer, instead of only asking in the chat. This covers all of your questions:
13
+
14
+ - Yes or no. Use type "confirm".
15
+ - Multiple choice. Use type "select" with 2 to 6 options.
16
+ - A name, a path, a value, or other free text. Use type "input".
17
+ - Approval of a plan or an approach before you start. Use type "select" with the options the user is choosing between, or "confirm" to approve a single plan.
18
+
19
+ `ask_user` blocks and returns `{ answered, value, nextAction, handoffAction }`. Always set `context` to one line on what you are doing, and set `agentName` to "Cursor - {project}". If `answered` is false, follow `handoffAction` when present, otherwise `nextAction`: poll once when instructed, then cancel a live phone question before asking in the current chat. Never assume approval.
20
+
21
+ If the user answers in the chat before the push comes back, call `cancel_question` with the correlationId before acting. If cancellation returns `handoffAction: "stop"`, stop. Otherwise, if cancellation returns false, poll once for 1 second and honor any phone answer that won the race.
22
+
23
+ ## Notify the user
24
+
25
+ Use `send_notification` when something is worth the user's attention:
26
+
27
+ - A task of 3 or more steps finishes. Use `context.type` "task_complete" with a short summary and the files changed.
28
+ - A build, test, or deploy fails. Use `context.type` "error" with the error message.
29
+ - A long job finishes, such as a migration, refactor, or generation.
30
+
31
+ ## Risky commands are gated for you
32
+
33
+ Risky shell commands (rm, force push, history rewrites, database drops, deploys, systemctl, and similar) are sent to the user for phone approval automatically by the plugin's hook, following the user's Pushary policy. You do not need to ask separately for those. For anything else destructive that the hook might not catch, ask first with `ask_user`.
34
+
35
+ ## Keep it tidy
36
+
37
+ - Keep titles under 60 characters and bodies under 200. Put detail in the `context` object, not the title.
38
+ - Send at most 3 notifications per task unless the user asks for more.
39
+
40
+ For the full tool reference, with every parameter, examples, and return values, see the pushary skill.