@pushary/agent-hooks 0.84.1 → 0.85.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 (54) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +24 -0
  3. package/dist/bin/pushary-bell-hook.js +5 -3
  4. package/dist/bin/pushary-bell.js +8 -7
  5. package/dist/bin/pushary-claude.js +5 -5
  6. package/dist/bin/pushary-clean.js +6 -5
  7. package/dist/bin/pushary-codex-bridge.js +2 -2
  8. package/dist/bin/pushary-codex-hook.js +7 -13
  9. package/dist/bin/pushary-codex.js +1 -1
  10. package/dist/bin/pushary-connect.js +5 -5
  11. package/dist/bin/pushary-daemon.js +5 -5
  12. package/dist/bin/pushary-disconnect.d.ts +1 -0
  13. package/dist/bin/pushary-disconnect.js +125 -0
  14. package/dist/bin/pushary-doctor.js +9 -9
  15. package/dist/bin/pushary-gemini-bridge.js +2 -2
  16. package/dist/bin/pushary-gemini-hook.js +7 -13
  17. package/dist/bin/pushary-hook.js +13 -20
  18. package/dist/bin/pushary-login.js +2 -2
  19. package/dist/bin/pushary-logout.js +3 -3
  20. package/dist/bin/pushary-mode.js +2 -2
  21. package/dist/bin/pushary-notification-hook.js +6 -9
  22. package/dist/bin/pushary-permission-denied-hook.js +11 -9
  23. package/dist/bin/pushary-permission-hook.js +11 -9
  24. package/dist/bin/pushary-post-hook.js +6 -9
  25. package/dist/bin/pushary-prompt-hook.js +6 -9
  26. package/dist/bin/pushary-session-end-hook.js +6 -6
  27. package/dist/bin/pushary-session-start-hook.js +6 -6
  28. package/dist/bin/pushary-setup.js +23 -24
  29. package/dist/bin/pushary-stats.js +2 -2
  30. package/dist/bin/pushary-status.js +2 -2
  31. package/dist/bin/pushary-stop-hook.js +6 -6
  32. package/dist/bin/pushary-stopfailure-hook.js +6 -6
  33. package/dist/bin/pushary-suggestions.js +2 -2
  34. package/dist/bin/pushary-upgrade.js +13 -8
  35. package/dist/bin/pushary-wait.js +2 -2
  36. package/dist/bin/pushary.js +2 -1
  37. package/dist/{chunk-HZNOAJGB.js → chunk-4QPOMJUB.js} +1 -1
  38. package/dist/chunk-64PXDATC.js +187 -0
  39. package/dist/chunk-6CUUA7HO.js +59 -0
  40. package/dist/{chunk-UXWEE3QI.js → chunk-ADISVXZL.js} +1 -1
  41. package/dist/chunk-AXRATIS6.js +70 -0
  42. package/dist/{chunk-CCCJ6BPW.js → chunk-EXMUM226.js} +19 -7
  43. package/dist/{chunk-YR5TSPXB.js → chunk-GFM3STWO.js} +3 -3
  44. package/dist/{chunk-MGJBC6DD.js → chunk-GOEXZ5QJ.js} +1 -0
  45. package/dist/{chunk-BLDDXHHA.js → chunk-GXIFADGD.js} +1 -1
  46. package/dist/{chunk-SEAHGHCE.js → chunk-HVZIHTOO.js} +33 -0
  47. package/dist/chunk-PWTKKQQI.js +27 -0
  48. package/dist/{chunk-J4KFVOCQ.js → chunk-SQOFGPNX.js} +1 -1
  49. package/dist/{chunk-CCH775Y6.js → chunk-WEAQQSHQ.js} +1 -1
  50. package/dist/{chunk-ILB6UOAF.js → chunk-YKW6JCWI.js} +1 -1
  51. package/dist/src/index.d.ts +1 -1
  52. package/dist/src/index.js +6 -4
  53. package/package.json +3 -2
  54. package/dist/chunk-UKSQWTBH.js +0 -208
package/CHANGELOG.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.85.0
4
+
5
+ ### A hook command that cannot outlive what it points at
6
+
7
+ Every hook command written into `~/.claude/settings.json`, `~/.codex/hooks.json`
8
+ and `~/.gemini/settings.json`, the free bell included, is now wrapped so that a missing binary, a removed
9
+ `node`, a changed npm prefix or a moved home directory exits 0 and the agent reads
10
+ "no opinion". Before, any of those turned every tool call into a failing hook.
11
+ The guard is tested on every shell that can be `/bin/sh`, including dash, and with
12
+ `node` off PATH, which used to exit 127 and print on every tool call.
13
+
14
+ Codex hashes the exact command string to trust a hook, so `pushary upgrade` rewrites
15
+ the trust entry when it re-applies the hooks.
16
+
17
+ ### Hooks registered for the CLI you have
18
+
19
+ Claude Code events are registered from a table with a version floor per event.
20
+ `SubagentStart`, `SubagentStop`, `PreCompact`, `PostCompact` and `TeammateIdle`
21
+ are added on a CLI that understands them, and `pushary upgrade` re-registers
22
+ against the CLI you have now. Disconnect removes every event in the table; a
23
+ hand-typed list used to leave the five observability events behind.
24
+
25
+ ### `pushary disconnect <agent>`
26
+
27
+ Removes the MCP server, the hooks, the skill and, for Codex, the trust entries and
28
+ the API key from `config.toml`, for one agent, leaving the others alone. The bin
29
+ map entry was written in a shape the build silently dropped, and the command read
30
+ the dispatcher's own token as the agent name; both are fixed before this, its
31
+ first release, and a test now holds every bin entry to the one shape tsup builds.
32
+
33
+ ### A kill switch per hook path
34
+
35
+ `~/.pushary/admission-rules.json` (`{"version":1,"disabled":["claude:PostToolUse"]}`)
36
+ silences one event on one agent, or one agent entirely, without a release. Every
37
+ hook binary reads its input through this check, from the same file the macOS
38
+ helper reads, so one file governs both transports. Deny-only: nothing in the file
39
+ can enable a hook.
40
+
41
+ ### `PostToolUse` no longer pays two round trips per tool call
42
+
43
+ The telemetry hooks reuse the mode state the gate fetched for the same session
44
+ within the last 60 seconds. The gate itself still reads it live, so a remote stop
45
+ and a scope contract are never served stale where they decide anything.
46
+
3
47
  ## 0.84.1
4
48
 
5
49
  ### Remote starts survive lost acknowledgements without double-launching
package/README.md CHANGED
@@ -108,6 +108,29 @@ npx @pushary/agent-hooks@latest doctor
108
108
 
109
109
  Any other MCP client can use notify and ask by pointing at the Pushary MCP endpoint directly.
110
110
 
111
+ ## Hook events, gated by version
112
+
113
+ Claude Code 2.1.239 names thirty-one hook events and the set grows release by release,
114
+ so the ones we register are gated on the version actually installed. The version is
115
+ read from disk and never by running the binary: `codex --version` once submitted the
116
+ Codex CLI to XProtect, which killed it and moved the 181 MB binary to the Trash, so
117
+ setup deleted the user's installation as a side effect of asking its version.
118
+
119
+ An unreadable version registers only the events that predate gating. Each registration
120
+ records `registered|<version>`, which is what lets an upgrade pick up newer events
121
+ without anyone re-running setup.
122
+
123
+ ## Admission rules
124
+
125
+ Publishing this package is a version bump merged to main, and a hook change is not
126
+ live until that happens, so a hook that floods on one event would otherwise need a
127
+ release to stop. `~/.pushary/admission-rules.json` can disable an `(agent, event)`
128
+ pair as data.
129
+
130
+ Deny-only by construction: a rule can silence a hook we ship, and no shape of the file
131
+ can enable one we do not. A file that cannot be read admits everything, because
132
+ failing closed would let one malformed download silence every hook on the machine.
133
+
111
134
  ## Commands
112
135
 
113
136
  <!-- Managed: every command below is declared in src/cli/commands.ts, and a test
@@ -123,6 +146,7 @@ logout Remove the key this machine stores, and say what it does not remove
123
146
  connect Connect a phone without re-running setup (--app for the Pushary app)
124
147
  bell Free local bell when an agent finishes or needs you. No account, no key, no network
125
148
  doctor Verify your Pushary installation is working
149
+ disconnect Turn off one agent (claude|codex|gemini|cursor)
126
150
  clean Remove all Pushary configuration (--yes for non-interactive)
127
151
  mode Switch approval mode (push_only, push_first, terminal_only)
128
152
  wait Show or set the "wait for your phone" ladder (pushary wait 45)
@@ -2,6 +2,9 @@
2
2
  import {
3
3
  handleBell
4
4
  } from "../chunk-7PZPJSWI.js";
5
+ import {
6
+ readHookInput
7
+ } from "../chunk-6CUUA7HO.js";
5
8
  import "../chunk-K7CSRGKZ.js";
6
9
  import "../chunk-BC3VCZ3E.js";
7
10
  import "../chunk-6MTNS63X.js";
@@ -11,10 +14,9 @@ import "../chunk-MQMPG5X4.js";
11
14
 
12
15
  // bin/pushary-bell-hook.ts
13
16
  var main = async () => {
14
- let rawInput = "";
15
17
  try {
16
- for await (const chunk of process.stdin) rawInput += chunk;
17
- handleBell(rawInput.trim() ? JSON.parse(rawInput) : {});
18
+ const input = await readHookInput("claude");
19
+ if (input) handleBell(input);
18
20
  } catch {
19
21
  }
20
22
  process.stdout.write("{}");
@@ -6,9 +6,13 @@ import {
6
6
  ring,
7
7
  upgradeThreshold
8
8
  } from "../chunk-7PZPJSWI.js";
9
+ import {
10
+ guardBinary
11
+ } from "../chunk-PWTKKQQI.js";
12
+ import "../chunk-VT4IVERX.js";
9
13
  import {
10
14
  claudeSettings
11
- } from "../chunk-SEAHGHCE.js";
15
+ } from "../chunk-HVZIHTOO.js";
12
16
  import {
13
17
  createIo
14
18
  } from "../chunk-5RUIFDTP.js";
@@ -18,8 +22,8 @@ import {
18
22
  } from "../chunk-GMXKITVA.js";
19
23
  import {
20
24
  exitOnHelpFlag
21
- } from "../chunk-J4KFVOCQ.js";
22
- import "../chunk-MGJBC6DD.js";
25
+ } from "../chunk-SQOFGPNX.js";
26
+ import "../chunk-GOEXZ5QJ.js";
23
27
  import "../chunk-BC3VCZ3E.js";
24
28
  import "../chunk-DINDL2CF.js";
25
29
  import {
@@ -53,10 +57,7 @@ var isBellHook = (entry) => {
53
57
  var BELL_TIMEOUT_SECONDS = 5;
54
58
  var BELL_NOTIFICATION_MATCHER = "idle_prompt|agent_needs_input|agent_completed";
55
59
  var addBellHooks = (settings, binDir) => {
56
- const resolve = (name) => {
57
- const path = binDir ? join(binDir, name) : name;
58
- return /\s/.test(path) ? `"${path}"` : path;
59
- };
60
+ const resolve = (name) => guardBinary(binDir ? join(binDir, name) : name);
60
61
  const hooks = ensureRecord(settings, "hooks");
61
62
  const notification = (Array.isArray(hooks.Notification) ? hooks.Notification : []).filter((entry) => !isBellHook(entry));
62
63
  notification.push({
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ensureDaemonRunning
4
- } from "../chunk-CCH775Y6.js";
4
+ } from "../chunk-WEAQQSHQ.js";
5
5
  import {
6
6
  buildTranscriptRecords,
7
7
  decodePublicKey,
@@ -13,18 +13,18 @@ import {
13
13
  import {
14
14
  startProcessOwnership,
15
15
  withSpawnProcessOwnership
16
- } from "../chunk-ILB6UOAF.js";
16
+ } from "../chunk-YKW6JCWI.js";
17
17
  import {
18
18
  needsShell,
19
19
  spawnClaude
20
20
  } from "../chunk-XHKBHWLX.js";
21
21
  import "../chunk-VT4IVERX.js";
22
- import "../chunk-SEAHGHCE.js";
22
+ import "../chunk-HVZIHTOO.js";
23
23
  import {
24
24
  KILL_REASON,
25
25
  isDeferAnswer,
26
26
  resolveGate
27
- } from "../chunk-BLDDXHHA.js";
27
+ } from "../chunk-GXIFADGD.js";
28
28
  import {
29
29
  askUser,
30
30
  cancelQuestion,
@@ -36,7 +36,7 @@ import {
36
36
  reportEvent,
37
37
  scopePathFor,
38
38
  waitForAnswer
39
- } from "../chunk-CCCJ6BPW.js";
39
+ } from "../chunk-EXMUM226.js";
40
40
  import {
41
41
  getMachineId
42
42
  } from "../chunk-RN3NOEJF.js";
@@ -4,14 +4,15 @@ import {
4
4
  shortenHome,
5
5
  unregisterPluginLocation,
6
6
  vscodeSettingsTargets
7
- } from "../chunk-UXWEE3QI.js";
7
+ } from "../chunk-ADISVXZL.js";
8
8
  import {
9
9
  removeGeminiSettings
10
10
  } from "../chunk-DOXSWT4Q.js";
11
11
  import {
12
12
  removeClaudeMcpServers,
13
13
  removePusharySettings
14
- } from "../chunk-UKSQWTBH.js";
14
+ } from "../chunk-64PXDATC.js";
15
+ import "../chunk-PWTKKQQI.js";
15
16
  import {
16
17
  execNpm
17
18
  } from "../chunk-VT4IVERX.js";
@@ -32,14 +33,14 @@ import {
32
33
  pusharyDir,
33
34
  removeCodexHooks,
34
35
  vscodePluginDir
35
- } from "../chunk-SEAHGHCE.js";
36
+ } from "../chunk-HVZIHTOO.js";
36
37
  import {
37
38
  rejectUnknownFlags
38
39
  } from "../chunk-GMXKITVA.js";
39
40
  import {
40
41
  exitOnHelpFlag
41
- } from "../chunk-J4KFVOCQ.js";
42
- import "../chunk-MGJBC6DD.js";
42
+ } from "../chunk-SQOFGPNX.js";
43
+ import "../chunk-GOEXZ5QJ.js";
43
44
  import {
44
45
  removeClaudeAlias
45
46
  } from "../chunk-BC3VCZ3E.js";
@@ -11,14 +11,14 @@ import "../chunk-GCKAWHFP.js";
11
11
  import {
12
12
  startProcessOwnership,
13
13
  withSpawnProcessOwnership
14
- } from "../chunk-ILB6UOAF.js";
14
+ } from "../chunk-YKW6JCWI.js";
15
15
  import {
16
16
  spawnClaude
17
17
  } from "../chunk-XHKBHWLX.js";
18
18
  import {
19
19
  resolveBinary
20
20
  } from "../chunk-VT4IVERX.js";
21
- import "../chunk-SEAHGHCE.js";
21
+ import "../chunk-HVZIHTOO.js";
22
22
  import {
23
23
  getMachineId
24
24
  } from "../chunk-RN3NOEJF.js";
@@ -3,12 +3,15 @@ import {
3
3
  isGatingMoment,
4
4
  recordKeylessMoment
5
5
  } from "../chunk-NJ7JT26G.js";
6
+ import {
7
+ readHookInput
8
+ } from "../chunk-6CUUA7HO.js";
6
9
  import {
7
10
  KILL_REASON,
8
11
  denyReasonFrom,
9
12
  isDeferAnswer,
10
13
  resolveGate
11
- } from "../chunk-BLDDXHHA.js";
14
+ } from "../chunk-GXIFADGD.js";
12
15
  import {
13
16
  CODEX_AGENT,
14
17
  DEFAULT_SESSION,
@@ -40,7 +43,7 @@ import {
40
43
  toPolicyLookup,
41
44
  toPolicyLookups,
42
45
  waitForAnswer
43
- } from "../chunk-CCCJ6BPW.js";
46
+ } from "../chunk-EXMUM226.js";
44
47
  import {
45
48
  getMachineId
46
49
  } from "../chunk-RN3NOEJF.js";
@@ -310,17 +313,8 @@ var emit = (wire) => {
310
313
  if (wire) process.stdout.write(JSON.stringify(wire));
311
314
  };
312
315
  var main = async () => {
313
- let rawInput = "";
314
- for await (const chunk of process.stdin) {
315
- rawInput += chunk;
316
- }
317
- if (!rawInput.trim()) {
318
- process.exit(0);
319
- }
320
- let input;
321
- try {
322
- input = JSON.parse(rawInput);
323
- } catch {
316
+ const input = await readHookInput("codex");
317
+ if (!input) {
324
318
  process.exit(0);
325
319
  }
326
320
  try {
@@ -3,7 +3,7 @@ import {
3
3
  askUser,
4
4
  reportEvent,
5
5
  waitForAnswer
6
- } from "../chunk-CCCJ6BPW.js";
6
+ } from "../chunk-EXMUM226.js";
7
7
  import {
8
8
  getMachineId
9
9
  } from "../chunk-RN3NOEJF.js";
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ printKeyCheck
4
+ } from "../chunk-FBGBJXVC.js";
2
5
  import {
3
6
  confirmAppConnection,
4
7
  connectDevice,
5
8
  printConnectInstructions
6
9
  } from "../chunk-6LC4WSCL.js";
7
10
  import "../chunk-3EGEA4KH.js";
8
- import {
9
- printKeyCheck
10
- } from "../chunk-FBGBJXVC.js";
11
11
  import {
12
12
  checkApiKey
13
13
  } from "../chunk-F52SIIDG.js";
@@ -22,8 +22,8 @@ import {
22
22
  } from "../chunk-GMXKITVA.js";
23
23
  import {
24
24
  exitOnHelpFlag
25
- } from "../chunk-J4KFVOCQ.js";
26
- import "../chunk-MGJBC6DD.js";
25
+ } from "../chunk-SQOFGPNX.js";
26
+ import "../chunk-GOEXZ5QJ.js";
27
27
  import "../chunk-BC3VCZ3E.js";
28
28
  import "../chunk-DINDL2CF.js";
29
29
  import "../chunk-6MTNS63X.js";
@@ -8,7 +8,7 @@ import {
8
8
  acquireDaemonLease,
9
9
  readDaemonStatus,
10
10
  requestDaemonHandoff
11
- } from "../chunk-CCH775Y6.js";
11
+ } from "../chunk-WEAQQSHQ.js";
12
12
  import {
13
13
  CODEX_BRIDGE_CAPABILITY,
14
14
  CODEX_RESUME_CAPABILITY,
@@ -17,7 +17,7 @@ import {
17
17
  import {
18
18
  findLiveProcessBySpawnId,
19
19
  ownsLiveProcess
20
- } from "../chunk-ILB6UOAF.js";
20
+ } from "../chunk-YKW6JCWI.js";
21
21
  import {
22
22
  spawnClaude
23
23
  } from "../chunk-XHKBHWLX.js";
@@ -26,14 +26,14 @@ import {
26
26
  resolveGlobalPackageVersion,
27
27
  resolvePackageVersionFromBinary
28
28
  } from "../chunk-VT4IVERX.js";
29
- import "../chunk-SEAHGHCE.js";
29
+ import "../chunk-HVZIHTOO.js";
30
30
  import {
31
31
  getMachineId
32
32
  } from "../chunk-RN3NOEJF.js";
33
33
  import {
34
34
  exitOnHelpFlag
35
- } from "../chunk-J4KFVOCQ.js";
36
- import "../chunk-MGJBC6DD.js";
35
+ } from "../chunk-SQOFGPNX.js";
36
+ import "../chunk-GOEXZ5QJ.js";
37
37
  import "../chunk-DINDL2CF.js";
38
38
  import "../chunk-6MTNS63X.js";
39
39
  import {
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ removeGeminiSettings
4
+ } from "../chunk-DOXSWT4Q.js";
5
+ import {
6
+ removeClaudeMcpServers,
7
+ removePusharySettings
8
+ } from "../chunk-64PXDATC.js";
9
+ import "../chunk-PWTKKQQI.js";
10
+ import "../chunk-VT4IVERX.js";
11
+ import {
12
+ claudeJson,
13
+ claudeSettings,
14
+ claudeSettingsLocal,
15
+ codexConfigToml,
16
+ codexHooksJson,
17
+ cursorUserHooks,
18
+ cursorUserMcp,
19
+ geminiSettings,
20
+ removeCodexHooks,
21
+ removeCodexSettings
22
+ } from "../chunk-HVZIHTOO.js";
23
+ import {
24
+ exitOnHelpFlag
25
+ } from "../chunk-SQOFGPNX.js";
26
+ import "../chunk-GOEXZ5QJ.js";
27
+ import "../chunk-DINDL2CF.js";
28
+ import "../chunk-KZERVKTD.js";
29
+ import "../chunk-MQMPG5X4.js";
30
+
31
+ // bin/pushary-disconnect.ts
32
+ import { readFileSync, writeFileSync } from "fs";
33
+ import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
34
+
35
+ // src/disconnect.ts
36
+ var DISCONNECTABLE_AGENTS = ["claude", "codex", "gemini", "cursor"];
37
+ var isDisconnectableAgent = (value) => DISCONNECTABLE_AGENTS.includes(value);
38
+ var removeCursorHooks = (config) => {
39
+ const hooks = config.hooks;
40
+ if (!hooks) return false;
41
+ let changed = false;
42
+ for (const [event, entries] of Object.entries(hooks)) {
43
+ if (!Array.isArray(entries)) continue;
44
+ const kept = entries.filter((entry) => !String(entry?.command ?? "").includes("pushary"));
45
+ if (kept.length === entries.length) continue;
46
+ changed = true;
47
+ if (kept.length === 0) delete hooks[event];
48
+ else hooks[event] = kept;
49
+ }
50
+ if (changed && Object.keys(hooks).length === 0) delete config.hooks;
51
+ return changed;
52
+ };
53
+ var disconnectPlan = (agent) => {
54
+ switch (agent) {
55
+ case "claude":
56
+ return [
57
+ { path: claudeSettings(), format: "json", remove: removePusharySettings },
58
+ { path: claudeSettingsLocal(), format: "json", remove: removePusharySettings },
59
+ { path: claudeJson(), format: "json", remove: removeClaudeMcpServers }
60
+ ];
61
+ case "codex":
62
+ return [
63
+ { path: codexHooksJson(), format: "json", remove: removeCodexHooks },
64
+ { path: codexConfigToml(), format: "toml", remove: (config) => removeCodexSettings(config, codexHooksJson()) }
65
+ ];
66
+ case "gemini":
67
+ return [{ path: geminiSettings(), format: "json", remove: removeGeminiSettings }];
68
+ case "cursor":
69
+ return [
70
+ { path: cursorUserHooks(), format: "json", remove: removeCursorHooks },
71
+ { path: cursorUserMcp(), format: "json", remove: removeClaudeMcpServers }
72
+ ];
73
+ }
74
+ };
75
+ var disconnectAgent = (agent, io) => {
76
+ const changed = [];
77
+ const untouched = [];
78
+ for (const edit of disconnectPlan(agent)) {
79
+ const raw = io.read(edit.path);
80
+ if (raw === null) continue;
81
+ try {
82
+ const config = edit.format === "toml" ? io.parseToml(raw) : JSON.parse(raw);
83
+ if (!edit.remove(config)) {
84
+ untouched.push(edit.path);
85
+ continue;
86
+ }
87
+ io.write(
88
+ edit.path,
89
+ edit.format === "toml" ? io.stringifyToml(config) : `${JSON.stringify(config, null, 2)}
90
+ `
91
+ );
92
+ changed.push(edit.path);
93
+ } catch {
94
+ untouched.push(edit.path);
95
+ }
96
+ }
97
+ return { agent, changed, untouched };
98
+ };
99
+
100
+ // bin/pushary-disconnect.ts
101
+ exitOnHelpFlag("disconnect");
102
+ var rest = process.argv.slice(2);
103
+ var requested = rest[0] === "disconnect" ? rest[1] : rest[0];
104
+ if (!requested || !isDisconnectableAgent(requested)) {
105
+ console.error(`Usage: pushary disconnect <${DISCONNECTABLE_AGENTS.join("|")}>`);
106
+ process.exit(1);
107
+ }
108
+ var result = disconnectAgent(requested, {
109
+ read: (path) => {
110
+ try {
111
+ return readFileSync(path, "utf-8");
112
+ } catch {
113
+ return null;
114
+ }
115
+ },
116
+ write: (path, contents) => writeFileSync(path, contents, "utf-8"),
117
+ parseToml: (raw) => parseTOML(raw),
118
+ stringifyToml: (config) => stringifyTOML(config)
119
+ });
120
+ if (result.changed.length === 0) {
121
+ console.log(`${requested} was not connected.`);
122
+ } else {
123
+ console.log(`Disconnected ${requested}:`);
124
+ for (const path of result.changed) console.log(` ${path}`);
125
+ }
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- describeWaitLadder
4
- } from "../chunk-IIENZE2J.js";
5
2
  import {
6
3
  claudeWired,
7
4
  codexWired,
8
5
  geminiWired
9
- } from "../chunk-HZNOAJGB.js";
6
+ } from "../chunk-4QPOMJUB.js";
7
+ import {
8
+ describeWaitLadder
9
+ } from "../chunk-IIENZE2J.js";
10
10
  import {
11
11
  readDaemonStatus
12
- } from "../chunk-CCH775Y6.js";
12
+ } from "../chunk-WEAQQSHQ.js";
13
13
  import {
14
14
  agentProbes,
15
15
  detectAgent,
@@ -18,7 +18,7 @@ import {
18
18
  isDetected,
19
19
  isPluginRegistered,
20
20
  vscodeSettingsTargets
21
- } from "../chunk-UXWEE3QI.js";
21
+ } from "../chunk-ADISVXZL.js";
22
22
  import {
23
23
  GEMINI_HOOK_BINARY,
24
24
  hasGeminiHooks,
@@ -46,7 +46,7 @@ import {
46
46
  readCodexMcpAuth,
47
47
  untrustedCodexHookEvents,
48
48
  vscodePluginDir
49
- } from "../chunk-SEAHGHCE.js";
49
+ } from "../chunk-HVZIHTOO.js";
50
50
  import {
51
51
  readLedgerSummary
52
52
  } from "../chunk-NJ7JT26G.js";
@@ -77,8 +77,8 @@ import {
77
77
  } from "../chunk-GMXKITVA.js";
78
78
  import {
79
79
  exitOnHelpFlag
80
- } from "../chunk-J4KFVOCQ.js";
81
- import "../chunk-MGJBC6DD.js";
80
+ } from "../chunk-SQOFGPNX.js";
81
+ import "../chunk-GOEXZ5QJ.js";
82
82
  import "../chunk-BC3VCZ3E.js";
83
83
  import {
84
84
  getPackageVersion
@@ -10,14 +10,14 @@ import "../chunk-GCKAWHFP.js";
10
10
  import {
11
11
  startProcessOwnership,
12
12
  withSpawnProcessOwnership
13
- } from "../chunk-ILB6UOAF.js";
13
+ } from "../chunk-YKW6JCWI.js";
14
14
  import {
15
15
  spawnClaude
16
16
  } from "../chunk-XHKBHWLX.js";
17
17
  import {
18
18
  resolveBinary
19
19
  } from "../chunk-VT4IVERX.js";
20
- import "../chunk-SEAHGHCE.js";
20
+ import "../chunk-HVZIHTOO.js";
21
21
  import {
22
22
  getMachineId
23
23
  } from "../chunk-RN3NOEJF.js";
@@ -3,12 +3,15 @@ import {
3
3
  isGatingMoment,
4
4
  recordKeylessMoment
5
5
  } from "../chunk-NJ7JT26G.js";
6
+ import {
7
+ readHookInput
8
+ } from "../chunk-6CUUA7HO.js";
6
9
  import {
7
10
  KILL_REASON,
8
11
  denyReasonFrom,
9
12
  isDeferAnswer,
10
13
  resolveGate
11
- } from "../chunk-BLDDXHHA.js";
14
+ } from "../chunk-GXIFADGD.js";
12
15
  import {
13
16
  DEFAULT_SESSION,
14
17
  askUser,
@@ -31,7 +34,7 @@ import {
31
34
  scopePathFor,
32
35
  sendNotification,
33
36
  waitForAnswer
34
- } from "../chunk-CCCJ6BPW.js";
37
+ } from "../chunk-EXMUM226.js";
35
38
  import {
36
39
  getMachineId
37
40
  } from "../chunk-RN3NOEJF.js";
@@ -278,17 +281,8 @@ var emit = (wire) => {
278
281
  if (wire) process.stdout.write(JSON.stringify(wire));
279
282
  };
280
283
  var main = async () => {
281
- let rawInput = "";
282
- for await (const chunk of process.stdin) {
283
- rawInput += chunk;
284
- }
285
- if (!rawInput.trim()) {
286
- process.exit(0);
287
- }
288
- let input;
289
- try {
290
- input = JSON.parse(rawInput);
291
- } catch {
284
+ const input = await readHookInput("gemini");
285
+ if (!input) {
292
286
  process.exit(0);
293
287
  }
294
288
  try {
@@ -1,16 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePreToolUse
4
- } from "../chunk-YR5TSPXB.js";
5
- import "../chunk-UKSQWTBH.js";
4
+ } from "../chunk-GFM3STWO.js";
5
+ import "../chunk-64PXDATC.js";
6
+ import "../chunk-PWTKKQQI.js";
7
+ import "../chunk-VT4IVERX.js";
6
8
  import "../chunk-NJ7JT26G.js";
7
- import "../chunk-BLDDXHHA.js";
8
- import "../chunk-CCCJ6BPW.js";
9
+ import {
10
+ readHookInput
11
+ } from "../chunk-6CUUA7HO.js";
12
+ import "../chunk-GXIFADGD.js";
13
+ import "../chunk-EXMUM226.js";
9
14
  import "../chunk-RN3NOEJF.js";
10
15
  import {
11
16
  exitOnHelpFlag
12
- } from "../chunk-J4KFVOCQ.js";
13
- import "../chunk-MGJBC6DD.js";
17
+ } from "../chunk-SQOFGPNX.js";
18
+ import "../chunk-GOEXZ5QJ.js";
14
19
  import "../chunk-DINDL2CF.js";
15
20
  import "../chunk-BSZYIAZL.js";
16
21
  import "../chunk-SAF6HGAA.js";
@@ -23,20 +28,8 @@ import "../chunk-MQMPG5X4.js";
23
28
  // bin/pushary-hook.ts
24
29
  exitOnHelpFlag("hook");
25
30
  var main = async () => {
26
- let rawInput = "";
27
- for await (const chunk of process.stdin) {
28
- rawInput += chunk;
29
- }
30
- if (!rawInput.trim()) {
31
- process.exit(0);
32
- }
33
- let input;
34
- try {
35
- input = JSON.parse(rawInput);
36
- } catch {
37
- process.exit(0);
38
- }
39
- if (!input.tool_name) {
31
+ const input = await readHookInput("claude", "PreToolUse");
32
+ if (!input?.tool_name) {
40
33
  process.exit(0);
41
34
  }
42
35
  try {
@@ -19,8 +19,8 @@ import {
19
19
  } from "../chunk-GMXKITVA.js";
20
20
  import {
21
21
  exitOnHelpFlag
22
- } from "../chunk-J4KFVOCQ.js";
23
- import "../chunk-MGJBC6DD.js";
22
+ } from "../chunk-SQOFGPNX.js";
23
+ import "../chunk-GOEXZ5QJ.js";
24
24
  import "../chunk-BC3VCZ3E.js";
25
25
  import {
26
26
  getPackageVersion