@pushary/agent-hooks 0.95.2 → 0.95.5

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 (98) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1 -1
  3. package/data/cursor-plugin/.cursor-plugin/plugin.json +1 -1
  4. package/data/cursor-plugin/CHANGELOG.md +5 -0
  5. package/data/cursor-plugin/README.md +6 -8
  6. package/data/cursor-plugin/hooks/hooks.json +56 -1
  7. package/data/cursor-plugin/scripts/pushary-gate.mjs +120 -71
  8. package/data/vscode-plugin/.claude-plugin/plugin.json +1 -1
  9. package/data/vscode-plugin/CHANGELOG.md +5 -0
  10. package/data/vscode-plugin/README.md +7 -15
  11. package/data/vscode-plugin/hooks/hooks.json +49 -0
  12. package/data/vscode-plugin/scripts/pushary-gate.mjs +208 -88
  13. package/dist/bin/pushary-bell-hook.js +20 -22
  14. package/dist/bin/pushary-bell.js +9 -11
  15. package/dist/bin/pushary-claude.js +58 -46
  16. package/dist/bin/pushary-clean.js +21 -20
  17. package/dist/bin/pushary-codex-bridge.js +120 -25
  18. package/dist/bin/pushary-codex-hook.js +43 -63
  19. package/dist/bin/pushary-codex.js +11 -10
  20. package/dist/bin/pushary-connect.js +8 -10
  21. package/dist/bin/pushary-cowork.js +5 -5
  22. package/dist/bin/pushary-daemon.js +26 -28
  23. package/dist/bin/pushary-disconnect.js +11 -10
  24. package/dist/bin/pushary-doctor.js +25 -25
  25. package/dist/bin/pushary-elicitation-hook.js +30 -31
  26. package/dist/bin/pushary-gemini-bridge.js +9 -11
  27. package/dist/bin/pushary-gemini-hook.js +45 -79
  28. package/dist/bin/pushary-hook.js +27 -29
  29. package/dist/bin/pushary-login.js +57 -31
  30. package/dist/bin/pushary-logout.js +6 -8
  31. package/dist/bin/pushary-mode.js +5 -5
  32. package/dist/bin/pushary-notification-hook.js +22 -24
  33. package/dist/bin/pushary-opencode-hook.js +38 -74
  34. package/dist/bin/pushary-permission-denied-hook.js +25 -27
  35. package/dist/bin/pushary-permission-hook.js +25 -27
  36. package/dist/bin/pushary-post-hook.js +22 -24
  37. package/dist/bin/pushary-prompt-hook.js +22 -24
  38. package/dist/bin/pushary-session-end-hook.js +22 -24
  39. package/dist/bin/pushary-session-start-hook.js +25 -27
  40. package/dist/bin/pushary-setup.js +78 -55
  41. package/dist/bin/pushary-stats.js +4 -4
  42. package/dist/bin/pushary-status.js +10 -12
  43. package/dist/bin/pushary-stop-hook.js +22 -24
  44. package/dist/bin/pushary-stopfailure-hook.js +22 -24
  45. package/dist/bin/pushary-suggestions.js +2 -2
  46. package/dist/bin/pushary-transcript-register.js +18 -20
  47. package/dist/bin/pushary-transcripts.js +7 -9
  48. package/dist/bin/pushary-upgrade.js +17 -19
  49. package/dist/bin/pushary-wait.js +5 -5
  50. package/dist/bin/pushary.js +1 -1
  51. package/dist/{chunk-7LUFYRH4.js → chunk-2D7BAOMY.js} +7 -7
  52. package/dist/{chunk-3ZUTNTZA.js → chunk-2ZTL3PGN.js} +1 -1
  53. package/dist/{chunk-EPFDN2ZT.js → chunk-32RMQO5Z.js} +1 -1
  54. package/dist/{chunk-EZIEXHYM.js → chunk-3AJIK5AO.js} +5 -2
  55. package/dist/{chunk-IPHOUBTU.js → chunk-4PX4QK2Z.js} +1 -1
  56. package/dist/{chunk-UW4LWAWY.js → chunk-4RF52LSU.js} +8 -8
  57. package/dist/{chunk-UOTSWS5N.js → chunk-67YNQ3QA.js} +43 -98
  58. package/dist/{chunk-G4TL4YWH.js → chunk-6AEM5RCS.js} +1 -1
  59. package/dist/{chunk-G24SEVCI.js → chunk-6VANQN5Q.js} +3 -7
  60. package/dist/{chunk-CKOLDI47.js → chunk-BDI2MXTT.js} +2 -2
  61. package/dist/{chunk-YKLCWWEI.js → chunk-BMANRGJQ.js} +1 -1
  62. package/dist/{chunk-2XUPP4WM.js → chunk-CUEZMPLJ.js} +1 -1
  63. package/dist/{chunk-A4R6BZCK.js → chunk-D62EONG3.js} +1 -1
  64. package/dist/{chunk-ZDAT5KMU.js → chunk-D6PRC3YQ.js} +1 -1
  65. package/dist/{chunk-MOY5X6HJ.js → chunk-DLLAWCQB.js} +1 -1
  66. package/dist/{chunk-DSTLA2TC.js → chunk-GOPIMNVC.js} +1 -1
  67. package/dist/{chunk-CH6DTGQR.js → chunk-HBHEX3JQ.js} +3 -3
  68. package/dist/{chunk-DNVDKHQD.js → chunk-HCMM3BOW.js} +226 -58
  69. package/dist/{chunk-76XICHYT.js → chunk-HGUZOUB2.js} +4 -4
  70. package/dist/{chunk-E3NF5CL2.js → chunk-HQIVR7MM.js} +6 -3
  71. package/dist/{chunk-JDFB3YKG.js → chunk-I6GZX3FT.js} +3 -3
  72. package/dist/{chunk-3OXHYPZG.js → chunk-IM2A5H33.js} +4 -1
  73. package/dist/{chunk-V27AHID3.js → chunk-IVQMNLSA.js} +3 -14
  74. package/dist/{chunk-4LL6LG5X.js → chunk-KAVDAZ7A.js} +43 -1
  75. package/dist/chunk-KBITFQST.js +6 -0
  76. package/dist/{chunk-AMZJ3CKW.js → chunk-KI4PA7MQ.js} +1 -1
  77. package/dist/{chunk-IAEXPTXA.js → chunk-N4VNLISN.js} +2 -2
  78. package/dist/{chunk-VX3BWMC5.js → chunk-OEKFD5BC.js} +1 -1
  79. package/dist/{chunk-QF4RI5CD.js → chunk-OI3DJA7N.js} +1 -1
  80. package/dist/{chunk-WB2C7VPF.js → chunk-OW6AZDY2.js} +3 -3
  81. package/dist/{chunk-4XXUHWIK.js → chunk-QHWXUNMN.js} +1 -1
  82. package/dist/{chunk-M7WWEFG6.js → chunk-QQGNFHIK.js} +2 -2
  83. package/dist/{chunk-YJAQRKH5.js → chunk-RLXVW4AM.js} +1 -1
  84. package/dist/{chunk-GUVCYYDK.js → chunk-S5CMLR35.js} +94 -15
  85. package/dist/{chunk-EUAQ4YAN.js → chunk-UCS65VVR.js} +1 -1
  86. package/dist/{chunk-WM5XMCID.js → chunk-VOSGZ6PH.js} +4 -4
  87. package/dist/{chunk-QUE76J4H.js → chunk-VTO3TNIB.js} +1 -1
  88. package/dist/{chunk-6FAHPGCZ.js → chunk-WDKHZRAS.js} +183 -25
  89. package/dist/{chunk-5GLPYGKS.js → chunk-WRDLHR2F.js} +2 -2
  90. package/dist/{chunk-RVSEGFPD.js → chunk-XLOELLAS.js} +9 -4
  91. package/dist/chunk-XS33QBJA.js +112 -0
  92. package/dist/{chunk-FQUV5KTM.js → chunk-Z2UWFEJW.js} +8 -8
  93. package/dist/src/index.d.ts +8 -1
  94. package/dist/src/index.js +11 -12
  95. package/package.json +1 -1
  96. package/dist/chunk-BC3VCZ3E.js +0 -86
  97. package/dist/chunk-RER3FRTD.js +0 -265
  98. package/dist/chunk-X7YWD6IS.js +0 -44
@@ -1,47 +1,43 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  readHookInput
4
- } from "../chunk-VX3BWMC5.js";
4
+ } from "../chunk-OEKFD5BC.js";
5
5
  import {
6
6
  isDeferAnswer
7
7
  } from "../chunk-YHG74UFF.js";
8
- import "../chunk-UW4LWAWY.js";
9
- import "../chunk-YKLCWWEI.js";
10
- import "../chunk-WM5XMCID.js";
11
- import "../chunk-3ZUTNTZA.js";
12
- import "../chunk-2XUPP4WM.js";
13
- import "../chunk-CH6DTGQR.js";
14
- import "../chunk-RVSEGFPD.js";
15
- import "../chunk-7LUFYRH4.js";
16
- import "../chunk-DSTLA2TC.js";
17
- import "../chunk-EZIEXHYM.js";
18
- import "../chunk-IPHOUBTU.js";
8
+ import "../chunk-4RF52LSU.js";
9
+ import "../chunk-BMANRGJQ.js";
10
+ import "../chunk-VOSGZ6PH.js";
11
+ import "../chunk-2ZTL3PGN.js";
12
+ import "../chunk-CUEZMPLJ.js";
13
+ import "../chunk-HBHEX3JQ.js";
14
+ import "../chunk-XLOELLAS.js";
15
+ import "../chunk-2D7BAOMY.js";
16
+ import "../chunk-GOPIMNVC.js";
17
+ import "../chunk-3AJIK5AO.js";
18
+ import "../chunk-4PX4QK2Z.js";
19
19
  import "../chunk-EQRS3SGM.js";
20
- import "../chunk-QF4RI5CD.js";
20
+ import "../chunk-OI3DJA7N.js";
21
21
  import "../chunk-XHKBHWLX.js";
22
22
  import "../chunk-L4ZCFMWW.js";
23
23
  import {
24
- DEFAULT_SESSION,
25
24
  askUser,
26
- cancelQuestion,
27
- pollForAnswer,
28
- savePendingQuestion
29
- } from "../chunk-RER3FRTD.js";
30
- import "../chunk-V27AHID3.js";
25
+ isDecisionStopped,
26
+ waitForQuestion
27
+ } from "../chunk-XS33QBJA.js";
28
+ import "../chunk-IVQMNLSA.js";
31
29
  import {
32
30
  getMachineId
33
- } from "../chunk-IAEXPTXA.js";
34
- import "../chunk-WB2C7VPF.js";
31
+ } from "../chunk-N4VNLISN.js";
32
+ import "../chunk-OW6AZDY2.js";
35
33
  import "../chunk-GMXKITVA.js";
36
34
  import "../chunk-DINDL2CF.js";
37
- import "../chunk-GUVCYYDK.js";
38
- import "../chunk-BC3VCZ3E.js";
35
+ import "../chunk-S5CMLR35.js";
39
36
  import "../chunk-EYRGBYZG.js";
40
37
  import "../chunk-SAF6HGAA.js";
41
38
  import "../chunk-7QLSKOSU.js";
42
39
  import "../chunk-KZERVKTD.js";
43
- import "../chunk-X7YWD6IS.js";
44
- import "../chunk-4LL6LG5X.js";
40
+ import "../chunk-KAVDAZ7A.js";
45
41
  import {
46
42
  getApiKey
47
43
  } from "../chunk-2UMNXADU.js";
@@ -55,7 +51,7 @@ import {
55
51
  planElicitationAsk,
56
52
  readElicitationFields,
57
53
  renderElicitationOutput
58
- } from "../chunk-6FAHPGCZ.js";
54
+ } from "../chunk-WDKHZRAS.js";
59
55
 
60
56
  // bin/pushary-elicitation-hook.ts
61
57
  import { basename } from "path";
@@ -109,20 +105,23 @@ var main = async () => {
109
105
  try {
110
106
  created = await askUser(apiKey, { ...common, ...prompt });
111
107
  } catch {
108
+ process.stdout.write(renderElicitationOutput(input.hook_event_name ?? "Elicitation", "cancel") ?? "");
112
109
  return;
113
110
  }
114
- if (created.suppressed || created.noDevices) {
115
- await cancelQuestion(apiKey, created.correlationId).catch(() => {
116
- });
111
+ if (isDecisionStopped(created)) {
112
+ process.stdout.write(renderElicitationOutput(input.hook_event_name ?? "Elicitation", "cancel") ?? "");
113
+ return;
114
+ }
115
+ const answer = await waitForQuestion(apiKey, created, deadline);
116
+ if (isDecisionStopped(answer)) {
117
+ process.stdout.write(renderElicitationOutput(input.hook_event_name ?? "Elicitation", "cancel") ?? "");
117
118
  return;
118
119
  }
119
- const answer = await pollForAnswer(apiKey, created.correlationId, deadline);
120
120
  if (ask.kind === "questions") {
121
121
  const question = "questions" in prompt ? prompt.questions[0] : void 0;
122
122
  const parsed = question && answer.answered && answer.value ? parseAgentQuestionAnswers([question], answer.value) : null;
123
123
  if (parsed) Object.assign(questionAnswers, parsed);
124
124
  else {
125
- savePendingQuestion(input.session_id || DEFAULT_SESSION, created.correlationId);
126
125
  return;
127
126
  }
128
127
  } else {
@@ -5,19 +5,19 @@ import {
5
5
  postLiveSession,
6
6
  postLiveSessionUntilAccepted,
7
7
  startLiveSessionHeartbeat
8
- } from "../chunk-4XXUHWIK.js";
8
+ } from "../chunk-QHWXUNMN.js";
9
9
  import {
10
10
  SESSION_IDLE_TIMEOUT_MS,
11
11
  describeIdleWindow,
12
12
  idleDeadlinePassed,
13
13
  startProcessOwnership,
14
14
  withSpawnProcessOwnership
15
- } from "../chunk-M7WWEFG6.js";
16
- import "../chunk-IPHOUBTU.js";
15
+ } from "../chunk-QQGNFHIK.js";
16
+ import "../chunk-4PX4QK2Z.js";
17
17
  import "../chunk-EQRS3SGM.js";
18
18
  import {
19
19
  transcriptsEnabled
20
- } from "../chunk-QF4RI5CD.js";
20
+ } from "../chunk-OI3DJA7N.js";
21
21
  import {
22
22
  spawnClaude
23
23
  } from "../chunk-XHKBHWLX.js";
@@ -26,17 +26,15 @@ import {
26
26
  } from "../chunk-L4ZCFMWW.js";
27
27
  import {
28
28
  getMachineId
29
- } from "../chunk-IAEXPTXA.js";
30
- import "../chunk-WB2C7VPF.js";
31
- import "../chunk-GUVCYYDK.js";
32
- import "../chunk-BC3VCZ3E.js";
33
- import "../chunk-X7YWD6IS.js";
34
- import "../chunk-4LL6LG5X.js";
29
+ } from "../chunk-N4VNLISN.js";
30
+ import "../chunk-OW6AZDY2.js";
31
+ import "../chunk-S5CMLR35.js";
32
+ import "../chunk-KAVDAZ7A.js";
35
33
  import {
36
34
  getApiKey,
37
35
  getBaseUrl
38
36
  } from "../chunk-2UMNXADU.js";
39
- import "../chunk-6FAHPGCZ.js";
37
+ import "../chunk-WDKHZRAS.js";
40
38
 
41
39
  // bin/pushary-gemini-bridge.ts
42
40
  import { existsSync } from "fs";
@@ -2,30 +2,31 @@
2
2
  import {
3
3
  isGatingMoment,
4
4
  recordKeylessMoment
5
- } from "../chunk-EUAQ4YAN.js";
5
+ } from "../chunk-UCS65VVR.js";
6
6
  import {
7
7
  readHookInput
8
- } from "../chunk-VX3BWMC5.js";
8
+ } from "../chunk-OEKFD5BC.js";
9
9
  import {
10
10
  denyReasonFrom,
11
11
  isDeferAnswer
12
12
  } from "../chunk-YHG74UFF.js";
13
- import "../chunk-UW4LWAWY.js";
14
- import "../chunk-YKLCWWEI.js";
15
- import "../chunk-WM5XMCID.js";
16
- import "../chunk-3ZUTNTZA.js";
17
- import "../chunk-2XUPP4WM.js";
18
- import "../chunk-CH6DTGQR.js";
19
- import "../chunk-RVSEGFPD.js";
20
- import "../chunk-7LUFYRH4.js";
21
- import "../chunk-DSTLA2TC.js";
22
- import "../chunk-EZIEXHYM.js";
23
- import "../chunk-IPHOUBTU.js";
13
+ import "../chunk-4RF52LSU.js";
14
+ import "../chunk-BMANRGJQ.js";
15
+ import "../chunk-VOSGZ6PH.js";
16
+ import "../chunk-2ZTL3PGN.js";
17
+ import "../chunk-CUEZMPLJ.js";
18
+ import "../chunk-HBHEX3JQ.js";
19
+ import "../chunk-XLOELLAS.js";
20
+ import "../chunk-2D7BAOMY.js";
21
+ import "../chunk-GOPIMNVC.js";
22
+ import "../chunk-3AJIK5AO.js";
23
+ import "../chunk-4PX4QK2Z.js";
24
24
  import "../chunk-EQRS3SGM.js";
25
- import "../chunk-QF4RI5CD.js";
25
+ import "../chunk-OI3DJA7N.js";
26
26
  import "../chunk-XHKBHWLX.js";
27
27
  import "../chunk-L4ZCFMWW.js";
28
28
  import {
29
+ DEFAULT_SESSION,
29
30
  fetchModeState,
30
31
  getPolicy,
31
32
  handlePostToolUse,
@@ -37,15 +38,15 @@ import {
37
38
  readLastUserPrompt,
38
39
  repoKeyFor,
39
40
  reportEvent
40
- } from "../chunk-DNVDKHQD.js";
41
+ } from "../chunk-HCMM3BOW.js";
41
42
  import {
42
- DEFAULT_SESSION,
43
+ DECISION_STOP_REASON,
43
44
  askUser,
44
- cancelQuestion,
45
- savePendingQuestion,
45
+ isDecisionStopped,
46
+ isLocalQuestionHandoff,
46
47
  sendNotification,
47
- waitForAnswer
48
- } from "../chunk-RER3FRTD.js";
48
+ waitForQuestion
49
+ } from "../chunk-XS33QBJA.js";
49
50
  import {
50
51
  UNNAMED_ACTION,
51
52
  deriveActionBody,
@@ -53,22 +54,20 @@ import {
53
54
  deriveToolTarget,
54
55
  describeToolCall,
55
56
  scopePathFor
56
- } from "../chunk-CKOLDI47.js";
57
- import "../chunk-V27AHID3.js";
57
+ } from "../chunk-BDI2MXTT.js";
58
+ import "../chunk-IVQMNLSA.js";
58
59
  import {
59
60
  getMachineId
60
- } from "../chunk-IAEXPTXA.js";
61
- import "../chunk-WB2C7VPF.js";
61
+ } from "../chunk-N4VNLISN.js";
62
+ import "../chunk-OW6AZDY2.js";
62
63
  import "../chunk-GMXKITVA.js";
63
64
  import "../chunk-DINDL2CF.js";
64
- import "../chunk-GUVCYYDK.js";
65
- import "../chunk-BC3VCZ3E.js";
65
+ import "../chunk-S5CMLR35.js";
66
66
  import "../chunk-EYRGBYZG.js";
67
67
  import "../chunk-SAF6HGAA.js";
68
68
  import "../chunk-7QLSKOSU.js";
69
69
  import "../chunk-KZERVKTD.js";
70
- import "../chunk-X7YWD6IS.js";
71
- import "../chunk-4LL6LG5X.js";
70
+ import "../chunk-KAVDAZ7A.js";
72
71
  import {
73
72
  getApiKey
74
73
  } from "../chunk-2UMNXADU.js";
@@ -80,7 +79,7 @@ import {
80
79
  hookWaitClamped,
81
80
  hookWaitDeadline,
82
81
  resolveGate
83
- } from "../chunk-6FAHPGCZ.js";
82
+ } from "../chunk-WDKHZRAS.js";
84
83
 
85
84
  // bin/pushary-gemini-hook.ts
86
85
  import { basename } from "path";
@@ -96,7 +95,10 @@ var GEMINI_TOOL_MAP = {
96
95
  read_file: "Read"
97
96
  };
98
97
  var firstString = (...values) => values.find((v) => typeof v === "string" && v.length > 0);
99
- var toGeminiPolicyLookup = (toolName, toolInput, cwd) => {
98
+ var toGeminiPolicyLookup = (toolName, toolInput, cwd, mcpContext) => {
99
+ if (mcpContext?.server_name && mcpContext.tool_name) {
100
+ return { tool: `mcp__${mcpContext.server_name}__${mcpContext.tool_name}`, input: toolInput };
101
+ }
100
102
  const canonical = GEMINI_TOOL_MAP[toolName];
101
103
  if (!canonical) return { tool: toolName, input: toolInput };
102
104
  if (canonical === "Bash") {
@@ -130,24 +132,6 @@ var geminiTimeoutDecision = (timeoutAction, denyReason = "No response within tim
130
132
 
131
133
  // bin/pushary-gemini-hook.ts
132
134
  var START_MS = Date.now();
133
- var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
134
- var pollForAnswer = async (apiKey, correlationId, deadlineMs, pollInterval = 2e3) => {
135
- while (Date.now() < deadlineMs) {
136
- const remaining = Math.min(Math.max(deadlineMs - Date.now(), 1e3), 3e4);
137
- let answer;
138
- try {
139
- answer = await waitForAnswer(apiKey, correlationId, remaining);
140
- } catch {
141
- if (Date.now() + pollInterval >= deadlineMs) break;
142
- await sleep(pollInterval);
143
- continue;
144
- }
145
- if (answer.answered) return answer;
146
- if (Date.now() + pollInterval >= deadlineMs) break;
147
- await sleep(pollInterval);
148
- }
149
- return { answered: false };
150
- };
151
135
  var agentNameFor = (input) => `${GEMINI_AGENT.label} - ${basename(input.cwd ?? process.cwd())}`;
152
136
  var pushQuestion = async (apiKey, input, lookup, waitSeconds, mode, pollInterval = 2e3) => {
153
137
  const projectName = basename(input.cwd ?? process.cwd());
@@ -166,21 +150,12 @@ var pushQuestion = async (apiKey, input, lookup, waitSeconds, mode, pollInterval
166
150
  blocker: deriveBlocker(mode),
167
151
  actionBody: deriveActionBody(input.tool_name ?? "", input.tool_input ?? {}),
168
152
  repoKey: repoKeyFor(input.cwd)
169
- });
170
- if (result.suppressed || result.noDevices) {
171
- return {
172
- answer: { answered: false },
173
- correlationId: result.correlationId,
174
- suppressed: !!result.suppressed,
175
- noDevices: !!result.noDevices,
176
- clampCut: false
177
- };
178
- }
153
+ }).catch(() => ({ correlationId: "", status: "unavailable" }));
179
154
  const now = Date.now();
180
155
  const deadline = hookWaitDeadline(START_MS, waitSeconds, "gemini", now);
181
156
  const clampCut = hookWaitClamped(START_MS, waitSeconds, "gemini", now);
182
- const answer = await pollForAnswer(apiKey, result.correlationId, deadline, pollInterval);
183
- return { answer, correlationId: result.correlationId, suppressed: false, noDevices: false, clampCut };
157
+ const answer = await waitForQuestion(apiKey, result, deadline, pollInterval);
158
+ return { answer, localHandoff: !answer.answered && isLocalQuestionHandoff(result), clampCut };
184
159
  };
185
160
  var notifyApprovalNeeded = async (apiKey, input, lookup) => {
186
161
  try {
@@ -199,19 +174,15 @@ var handlePushOnly = async (apiKey, input, lookup, timeoutSeconds, timeoutAction
199
174
  try {
200
175
  pushed = await pushQuestion(apiKey, input, lookup, effectiveWaitSeconds(timeoutAction, timeoutSeconds, "gemini"), "push_only");
201
176
  } catch {
202
- return geminiTimeoutDecision(timeoutAction, "Push notification failed, denying per policy");
203
- }
204
- const { answer, correlationId, suppressed, clampCut } = pushed;
205
- if (suppressed) {
206
- await cancelQuestion(apiKey, correlationId).catch(() => {
207
- });
208
- return geminiPass();
177
+ return geminiDeny("Pushary could not create a verifiable approval. Retry the action.");
209
178
  }
179
+ const { answer, localHandoff, clampCut } = pushed;
180
+ if (isDecisionStopped(answer)) return geminiDeny(DECISION_STOP_REASON);
181
+ if (localHandoff) return geminiPass();
210
182
  if (answer.answered) {
211
183
  if (isDeferAnswer(answer.value)) return geminiPass();
212
184
  return answer.value === "yes" ? geminiAllow() : geminiDeny(denyReasonFrom(answer.value, answer.note));
213
185
  }
214
- savePendingQuestion(input.session_id || DEFAULT_SESSION, correlationId);
215
186
  if (clampCut) return geminiPass();
216
187
  return geminiTimeoutDecision(timeoutAction);
217
188
  };
@@ -222,18 +193,13 @@ var handlePushFirst = async (apiKey, input, lookup, pushFirstSeconds) => {
222
193
  } catch {
223
194
  return geminiPass();
224
195
  }
225
- const { answer, correlationId, suppressed, noDevices } = pushed;
226
- if (suppressed) {
227
- await cancelQuestion(apiKey, correlationId).catch(() => {
228
- });
229
- return geminiPass();
230
- }
231
- if (noDevices) return geminiPass();
196
+ const { answer, localHandoff } = pushed;
197
+ if (isDecisionStopped(answer)) return geminiDeny(DECISION_STOP_REASON);
198
+ if (localHandoff) return geminiPass();
232
199
  if (answer.answered) {
233
200
  if (isDeferAnswer(answer.value)) return geminiPass();
234
201
  return answer.value === "yes" ? geminiAllow() : geminiDeny(denyReasonFrom(answer.value, answer.note));
235
202
  }
236
- savePendingQuestion(input.session_id || DEFAULT_SESSION, correlationId);
237
203
  return geminiPass();
238
204
  };
239
205
  var decideBeforeTool = async (input) => {
@@ -242,7 +208,7 @@ var decideBeforeTool = async (input) => {
242
208
  apiKey = getApiKey();
243
209
  } catch {
244
210
  try {
245
- const lookup = toGeminiPolicyLookup(input.tool_name ?? "", input.tool_input ?? {});
211
+ const lookup = toGeminiPolicyLookup(input.tool_name ?? "", input.tool_input ?? {}, input.cwd, input.mcp_context);
246
212
  if (isGatingMoment(lookup.tool, lookup.input)) {
247
213
  recordKeylessMoment({
248
214
  ts: Date.now(),
@@ -258,7 +224,7 @@ var decideBeforeTool = async (input) => {
258
224
  try {
259
225
  const modeState = await fetchModeState(apiKey, input.session_id);
260
226
  const policyRequest = policyRequestFor("gemini_cli");
261
- const lookup = toGeminiPolicyLookup(input.tool_name ?? "", input.tool_input ?? {}, input.cwd);
227
+ const lookup = toGeminiPolicyLookup(input.tool_name ?? "", input.tool_input ?? {}, input.cwd, input.mcp_context);
262
228
  const config = await getPolicy(apiKey, modeState.policyVersion, policyRequest.agent, policyRequest.repoAware, input.session_id);
263
229
  const scopePath = modeState.scope ? scopePathFor(lookup.tool, lookup.input, input.cwd) : void 0;
264
230
  const verdict = resolveGate({
@@ -330,7 +296,7 @@ var main = async () => {
330
296
  emit(toGeminiWire(await decideBeforeTool(input)));
331
297
  break;
332
298
  case "AfterTool": {
333
- const lookup = toGeminiPolicyLookup(input.tool_name ?? "", input.tool_input ?? {});
299
+ const lookup = toGeminiPolicyLookup(input.tool_name ?? "", input.tool_input ?? {}, input.cwd, input.mcp_context);
334
300
  emitContext("AfterTool", await handlePostToolUse({
335
301
  tool_name: lookup.tool,
336
302
  tool_input: lookup.input,
@@ -1,50 +1,48 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePreToolUse
4
- } from "../chunk-UOTSWS5N.js";
5
- import "../chunk-A4R6BZCK.js";
6
- import "../chunk-EUAQ4YAN.js";
4
+ } from "../chunk-67YNQ3QA.js";
5
+ import "../chunk-D62EONG3.js";
6
+ import "../chunk-UCS65VVR.js";
7
7
  import {
8
8
  readHookInput
9
- } from "../chunk-VX3BWMC5.js";
9
+ } from "../chunk-OEKFD5BC.js";
10
10
  import "../chunk-YHG74UFF.js";
11
- import "../chunk-UW4LWAWY.js";
12
- import "../chunk-YKLCWWEI.js";
13
- import "../chunk-WM5XMCID.js";
14
- import "../chunk-3ZUTNTZA.js";
15
- import "../chunk-2XUPP4WM.js";
16
- import "../chunk-CH6DTGQR.js";
17
- import "../chunk-RVSEGFPD.js";
18
- import "../chunk-7LUFYRH4.js";
19
- import "../chunk-DSTLA2TC.js";
20
- import "../chunk-EZIEXHYM.js";
21
- import "../chunk-IPHOUBTU.js";
11
+ import "../chunk-4RF52LSU.js";
12
+ import "../chunk-BMANRGJQ.js";
13
+ import "../chunk-VOSGZ6PH.js";
14
+ import "../chunk-2ZTL3PGN.js";
15
+ import "../chunk-CUEZMPLJ.js";
16
+ import "../chunk-HBHEX3JQ.js";
17
+ import "../chunk-XLOELLAS.js";
18
+ import "../chunk-2D7BAOMY.js";
19
+ import "../chunk-GOPIMNVC.js";
20
+ import "../chunk-3AJIK5AO.js";
21
+ import "../chunk-4PX4QK2Z.js";
22
22
  import "../chunk-EQRS3SGM.js";
23
- import "../chunk-QF4RI5CD.js";
23
+ import "../chunk-OI3DJA7N.js";
24
24
  import "../chunk-XHKBHWLX.js";
25
25
  import "../chunk-L4ZCFMWW.js";
26
- import "../chunk-DNVDKHQD.js";
27
- import "../chunk-RER3FRTD.js";
28
- import "../chunk-CKOLDI47.js";
29
- import "../chunk-V27AHID3.js";
30
- import "../chunk-IAEXPTXA.js";
31
- import "../chunk-WB2C7VPF.js";
26
+ import "../chunk-HCMM3BOW.js";
27
+ import "../chunk-XS33QBJA.js";
28
+ import "../chunk-BDI2MXTT.js";
29
+ import "../chunk-IVQMNLSA.js";
30
+ import "../chunk-N4VNLISN.js";
31
+ import "../chunk-OW6AZDY2.js";
32
32
  import {
33
33
  exitOnHelpFlag
34
- } from "../chunk-MOY5X6HJ.js";
35
- import "../chunk-ZDAT5KMU.js";
34
+ } from "../chunk-DLLAWCQB.js";
35
+ import "../chunk-D6PRC3YQ.js";
36
36
  import "../chunk-GMXKITVA.js";
37
37
  import "../chunk-DINDL2CF.js";
38
- import "../chunk-GUVCYYDK.js";
39
- import "../chunk-BC3VCZ3E.js";
38
+ import "../chunk-S5CMLR35.js";
40
39
  import "../chunk-EYRGBYZG.js";
41
40
  import "../chunk-SAF6HGAA.js";
42
41
  import "../chunk-7QLSKOSU.js";
43
42
  import "../chunk-KZERVKTD.js";
44
- import "../chunk-X7YWD6IS.js";
45
- import "../chunk-4LL6LG5X.js";
43
+ import "../chunk-KAVDAZ7A.js";
46
44
  import "../chunk-2UMNXADU.js";
47
- import "../chunk-6FAHPGCZ.js";
45
+ import "../chunk-WDKHZRAS.js";
48
46
 
49
47
  // bin/pushary-hook.ts
50
48
  exitOnHelpFlag("hook");
@@ -5,23 +5,23 @@ import {
5
5
  import "../chunk-PUZZELE6.js";
6
6
  import {
7
7
  recoverDaemonAfterLogin
8
- } from "../chunk-RVSEGFPD.js";
8
+ } from "../chunk-XLOELLAS.js";
9
9
  import "../chunk-XHKBHWLX.js";
10
10
  import "../chunk-L4ZCFMWW.js";
11
- import "../chunk-IAEXPTXA.js";
12
- import "../chunk-WB2C7VPF.js";
11
+ import "../chunk-N4VNLISN.js";
12
+ import "../chunk-OW6AZDY2.js";
13
13
  import "../chunk-3EGEA4KH.js";
14
14
  import {
15
15
  checkApiKey,
16
16
  describeKeyCheck
17
- } from "../chunk-JDFB3YKG.js";
17
+ } from "../chunk-I6GZX3FT.js";
18
18
  import {
19
19
  createIo
20
20
  } from "../chunk-5RUIFDTP.js";
21
21
  import {
22
22
  exitOnHelpFlag
23
- } from "../chunk-MOY5X6HJ.js";
24
- import "../chunk-ZDAT5KMU.js";
23
+ } from "../chunk-DLLAWCQB.js";
24
+ import "../chunk-D6PRC3YQ.js";
25
25
  import {
26
26
  parseFlags
27
27
  } from "../chunk-GMXKITVA.js";
@@ -29,10 +29,11 @@ import {
29
29
  getPackageVersion
30
30
  } from "../chunk-DINDL2CF.js";
31
31
  import {
32
+ readConfigFileKey,
33
+ readControlMode,
32
34
  readKeySource,
33
35
  writeKey
34
- } from "../chunk-GUVCYYDK.js";
35
- import "../chunk-BC3VCZ3E.js";
36
+ } from "../chunk-S5CMLR35.js";
36
37
  import "../chunk-SAF6HGAA.js";
37
38
  import {
38
39
  UsageError
@@ -40,12 +41,11 @@ import {
40
41
  import {
41
42
  EXIT
42
43
  } from "../chunk-KZERVKTD.js";
43
- import "../chunk-X7YWD6IS.js";
44
- import "../chunk-4LL6LG5X.js";
44
+ import "../chunk-KAVDAZ7A.js";
45
45
  import "../chunk-2UMNXADU.js";
46
46
  import {
47
47
  isValidApiKey
48
- } from "../chunk-6FAHPGCZ.js";
48
+ } from "../chunk-WDKHZRAS.js";
49
49
 
50
50
  // bin/pushary-login.ts
51
51
  exitOnHelpFlag("login");
@@ -87,21 +87,47 @@ var readStdin = async () => {
87
87
  for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
88
88
  return Buffer.concat(chunks).toString("utf8").trim();
89
89
  };
90
- var store = (apiKey, siteSlug, keyName) => {
90
+ var recoverControl = () => {
91
+ const daemon = recoverDaemonAfterLogin();
92
+ if (daemon?.cleared) {
93
+ say(readControlMode() === "off" ? ` ${check} ${dim("Account verified. Phone-start remains off.")}` : daemon.restarted ? ` ${check} ${dim("Background daemon restarted with the verified key.")}` : ` ${yellow("!")} ${dim(`Background daemon may start again${daemon.detail ? ` (${daemon.detail})` : ""}`)}`);
94
+ }
95
+ return daemon;
96
+ };
97
+ var store = async (apiKey, siteSlug, keyName) => {
98
+ const verdict = await checkApiKey(apiKey);
99
+ const report = describeKeyCheck(verdict);
100
+ if (verdict.kind !== "ok") {
101
+ say(` ${yellow("!")} ${report.message}`);
102
+ for (const line of report.next) say(` ${dim(line)}`);
103
+ if (report.fatal) {
104
+ emit({ ok: false, reason: verdict.kind, keyCheck: verdict.kind, exitCode: report.exitCode });
105
+ return report.exitCode;
106
+ }
107
+ }
108
+ if (verdict.kind === "ok") siteSlug = verdict.identity.siteSlug;
91
109
  const result = writeKey(apiKey);
92
110
  say("");
93
- say(` ${check} ${bold("Signed in.")}${siteSlug ? ` ${dim(`Site ${siteSlug}`)}` : ""}`);
111
+ say(verdict.kind === "ok" ? ` ${check} ${bold("Signed in.")}${siteSlug ? ` ${dim(`Site ${siteSlug}`)}` : ""}` : ` ${yellow("!")} ${verdict.kind === "locked" ? "Key saved, approvals inactive." : "Key saved, account readiness unverified."}`);
94
112
  say(` ${dim(`Key saved to ${result.configPath}`)}`);
95
113
  if (result.rc.kind === "written" || result.rc.kind === "updated") {
96
114
  say(` ${dim(`Shell export ${result.rc.kind} in ${result.rc.path}`)}`);
97
115
  } else if (result.rc.kind === "declined") {
98
116
  say(` ${yellow("!")} ${dim(`Left ${result.rc.path} alone: line ${result.rc.declinedLine} already sets PUSHARY_API_KEY.`)}`);
99
117
  }
100
- const daemon = recoverDaemonAfterLogin();
101
- if (daemon.cleared) {
102
- say(daemon.restarted ? ` ${check} ${dim("Background daemon restarted with the new key.")}` : ` ${yellow("!")} ${dim(`Background daemon may start again${daemon.detail ? ` (${daemon.detail})` : ""}`)}`);
103
- }
104
- emit({ ok: true, siteSlug, keyName, configPath: result.configPath, rc: result.rc.kind, daemon });
118
+ const daemon = verdict.kind === "ok" ? recoverControl() : null;
119
+ emit({
120
+ ok: verdict.kind === "ok",
121
+ siteSlug,
122
+ keyName,
123
+ configPath: result.configPath,
124
+ rc: result.rc.kind,
125
+ daemon,
126
+ keyCheck: verdict.kind,
127
+ ...verdict.kind !== "ok" ? { reason: verdict.kind } : {},
128
+ exitCode: report.exitCode
129
+ });
130
+ return report.exitCode;
105
131
  };
106
132
  var loginWithToken = async () => {
107
133
  const token = await readStdin();
@@ -115,16 +141,7 @@ var loginWithToken = async () => {
115
141
  emit({ ok: false, reason: "malformed" });
116
142
  process.exit(EXIT.USAGE);
117
143
  }
118
- const verdict = await checkApiKey(token);
119
- if (verdict.kind !== "ok") {
120
- const report = describeKeyCheck(verdict);
121
- say(` ${yellow("!")} ${report.message}`);
122
- for (const line of report.next) say(` ${dim(line)}`);
123
- emit({ ok: false, reason: verdict.kind });
124
- if (verdict.kind !== "unreachable") process.exit(report.exitCode);
125
- }
126
- store(token, verdict.kind === "ok" ? verdict.identity.siteSlug : "", "pasted key");
127
- process.exit(EXIT.OK);
144
+ process.exit(await store(token, "", "pasted key"));
128
145
  };
129
146
  var main = async () => {
130
147
  if (options.withToken) await loginWithToken();
@@ -136,9 +153,19 @@ var main = async () => {
136
153
  say("");
137
154
  say(` ${check} Already signed in ${dim(`(${verdict.identity.siteSlug})`)}`);
138
155
  say(` ${dim("Run")} ${cyan("pushary login --force")} ${dim("to replace this key.")}`);
139
- emit({ ok: true, reused: true, siteSlug: verdict.identity.siteSlug });
156
+ const daemon = existing.key === readConfigFileKey() ? recoverControl() : null;
157
+ if (daemon === null) say(" The saved service key differs from this shell. Run pushary setup with the intended key before starting managed control.");
158
+ emit({ ok: true, reused: true, siteSlug: verdict.identity.siteSlug, keyCheck: "ok", daemon, exitCode: EXIT.OK });
140
159
  process.exit(EXIT.OK);
141
160
  }
161
+ if (verdict.kind === "locked" || verdict.kind === "unreachable") {
162
+ const report = describeKeyCheck(verdict);
163
+ say(` ${yellow("!")} ${report.message}`);
164
+ for (const line of report.next) say(` ${dim(line)}`);
165
+ say(" Existing key kept. Re-run pushary login to recheck readiness without replacing it.");
166
+ emit({ ok: false, reused: true, reason: verdict.kind, keyCheck: verdict.kind, exitCode: report.exitCode });
167
+ process.exit(report.exitCode);
168
+ }
142
169
  }
143
170
  }
144
171
  const outcome = await runBrowserLogin(
@@ -146,8 +173,7 @@ var main = async () => {
146
173
  { cliVersion: getPackageVersion(), noBrowser: options.noBrowser }
147
174
  );
148
175
  if (outcome.kind === "ok") {
149
- store(outcome.apiKey, outcome.siteSlug, outcome.keyName);
150
- process.exit(EXIT.OK);
176
+ process.exit(await store(outcome.apiKey, outcome.siteSlug, outcome.keyName));
151
177
  }
152
178
  if (outcome.kind === "unavailable") {
153
179
  say(` ${yellow("!")} Couldn't start a login ${dim(`(${outcome.detail})`)}`);