@pushary/agent-hooks 0.20.0 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/pushary-clean.js +1 -1
- package/dist/bin/pushary-codex-hook.js +44 -22
- package/dist/bin/pushary-codex.js +2 -2
- package/dist/bin/pushary-doctor.js +61 -18
- package/dist/bin/pushary-gemini-hook.js +10 -4
- package/dist/bin/pushary-hook.js +3 -2
- package/dist/bin/pushary-post-hook.js +2 -2
- package/dist/bin/pushary-prompt-hook.js +2 -2
- package/dist/bin/pushary-setup.js +2 -2
- package/dist/bin/pushary-stop-hook.js +2 -2
- package/dist/chunk-2Q6XPZ4Q.js +395 -0
- package/dist/chunk-6A3WCJO2.js +416 -0
- package/dist/chunk-6QWFMVCD.js +328 -0
- package/dist/chunk-BHAMEPOP.js +323 -0
- package/dist/chunk-BYNYYZWW.js +412 -0
- package/dist/chunk-FXYTRZHC.js +177 -0
- package/dist/chunk-GTJGZBTQ.js +328 -0
- package/dist/chunk-M5F2L4KF.js +177 -0
- package/dist/chunk-N7VXDBQU.js +6 -0
- package/dist/chunk-PSSHNBEL.js +177 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +4 -3
- package/package.json +1 -1
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
denyReasonFrom
|
|
4
|
+
} from "../chunk-N7VXDBQU.js";
|
|
2
5
|
import {
|
|
3
6
|
CODEX_AGENT,
|
|
4
7
|
codexAllow,
|
|
5
8
|
codexDeny,
|
|
6
9
|
codexPass,
|
|
10
|
+
describeApplyPatch,
|
|
7
11
|
handlePostToolUse,
|
|
8
12
|
handleStop,
|
|
9
13
|
handleUserPrompt,
|
|
@@ -12,7 +16,7 @@ import {
|
|
|
12
16
|
reportEvent,
|
|
13
17
|
toCodexWire,
|
|
14
18
|
toPolicyLookup
|
|
15
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-BYNYYZWW.js";
|
|
16
20
|
import {
|
|
17
21
|
DEFAULT_SESSION,
|
|
18
22
|
askUser,
|
|
@@ -25,7 +29,7 @@ import {
|
|
|
25
29
|
savePendingQuestion,
|
|
26
30
|
sendNotification,
|
|
27
31
|
waitForAnswer
|
|
28
|
-
} from "../chunk-
|
|
32
|
+
} from "../chunk-6QWFMVCD.js";
|
|
29
33
|
import "../chunk-USUCPCUC.js";
|
|
30
34
|
import "../chunk-DWED7BS3.js";
|
|
31
35
|
import {
|
|
@@ -38,6 +42,7 @@ import { tmpdir, userInfo } from "os";
|
|
|
38
42
|
import { existsSync, mkdirSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
39
43
|
var KILL_REASON = "Stopped by user: this agent was halted from Pushary";
|
|
40
44
|
var MAX_WAIT_SECONDS = 170;
|
|
45
|
+
var START_MS = Date.now();
|
|
41
46
|
var APPROVAL_TTL_MS = 10 * 60 * 1e3;
|
|
42
47
|
var sanitizeId = (value) => value.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 128);
|
|
43
48
|
var userScope = () => {
|
|
@@ -69,6 +74,19 @@ var consumeApproval = (toolUseId) => {
|
|
|
69
74
|
return false;
|
|
70
75
|
}
|
|
71
76
|
};
|
|
77
|
+
var NOTIFY_TTL_MS = 60 * 1e3;
|
|
78
|
+
var claimNotify = (toolUseId) => {
|
|
79
|
+
if (!toolUseId) return true;
|
|
80
|
+
const path = join(APPROVAL_DIR, `notify-${sanitizeId(toolUseId)}`);
|
|
81
|
+
try {
|
|
82
|
+
if (existsSync(path) && Date.now() - statSync(path).mtimeMs < NOTIFY_TTL_MS) return false;
|
|
83
|
+
if (!existsSync(APPROVAL_DIR)) mkdirSync(APPROVAL_DIR, { recursive: true, mode: 448 });
|
|
84
|
+
writeFileSync(path, "", { encoding: "utf-8", mode: 384 });
|
|
85
|
+
return true;
|
|
86
|
+
} catch {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
72
90
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
73
91
|
var pollForAnswer = async (apiKey, correlationId, deadlineMs, pollInterval = 2e3) => {
|
|
74
92
|
while (Date.now() < deadlineMs) {
|
|
@@ -88,11 +106,10 @@ var pollForAnswer = async (apiKey, correlationId, deadlineMs, pollInterval = 2e3
|
|
|
88
106
|
return { answered: false };
|
|
89
107
|
};
|
|
90
108
|
var agentNameFor = (input) => `Codex - ${basename(input.cwd ?? process.cwd())}`;
|
|
91
|
-
var
|
|
92
|
-
|
|
93
|
-
const toolInput = input.tool_input ?? {};
|
|
109
|
+
var describeFor = (input, lookup) => input.tool_name === "apply_patch" ? describeApplyPatch(input.tool_input?.command) ?? describeToolCall(lookup.tool, lookup.input, "hook") : describeToolCall(lookup.tool, lookup.input, "hook");
|
|
110
|
+
var pushQuestion = async (apiKey, input, lookup, waitSeconds) => {
|
|
94
111
|
const projectName = basename(input.cwd ?? process.cwd());
|
|
95
|
-
const description =
|
|
112
|
+
const description = describeFor(input, lookup);
|
|
96
113
|
const result = await askUser(apiKey, {
|
|
97
114
|
question: `Allow ${description}?`,
|
|
98
115
|
type: "confirm",
|
|
@@ -100,18 +117,21 @@ var pushQuestion = async (apiKey, input, waitSeconds) => {
|
|
|
100
117
|
agentName: agentNameFor(input),
|
|
101
118
|
sessionId: input.session_id,
|
|
102
119
|
machineId: getMachineId(),
|
|
103
|
-
toolName,
|
|
104
|
-
toolTarget: deriveToolTarget(
|
|
120
|
+
toolName: lookup.tool,
|
|
121
|
+
toolTarget: deriveToolTarget(lookup.tool, lookup.input)
|
|
105
122
|
});
|
|
106
|
-
const deadline =
|
|
123
|
+
const deadline = Math.min(
|
|
124
|
+
Date.now() + Math.min(waitSeconds, MAX_WAIT_SECONDS) * 1e3,
|
|
125
|
+
START_MS + MAX_WAIT_SECONDS * 1e3
|
|
126
|
+
);
|
|
107
127
|
const answer = await pollForAnswer(apiKey, result.correlationId, deadline);
|
|
108
128
|
return { answer, correlationId: result.correlationId };
|
|
109
129
|
};
|
|
110
|
-
var notifyApprovalNeeded = async (apiKey, input) => {
|
|
130
|
+
var notifyApprovalNeeded = async (apiKey, input, lookup) => {
|
|
111
131
|
try {
|
|
112
132
|
await sendNotification(apiKey, {
|
|
113
133
|
title: "Agent needs approval",
|
|
114
|
-
body:
|
|
134
|
+
body: describeFor(input, lookup),
|
|
115
135
|
agentName: agentNameFor(input),
|
|
116
136
|
sessionId: input.session_id,
|
|
117
137
|
machineId: getMachineId()
|
|
@@ -124,7 +144,7 @@ var decidePermissionRequest = async (input) => {
|
|
|
124
144
|
const apiKey = getApiKey();
|
|
125
145
|
const modeState = await fetchModeState(apiKey, input.session_id);
|
|
126
146
|
if (modeState.kill) return codexDeny(KILL_REASON);
|
|
127
|
-
const lookup = toPolicyLookup(input.tool_name ?? "", input.tool_input ?? {});
|
|
147
|
+
const lookup = toPolicyLookup(input.tool_name ?? "", input.tool_input ?? {}, input.cwd);
|
|
128
148
|
const policy = await getPolicy(apiKey, modeState.policyVersion);
|
|
129
149
|
const toolPolicy = resolvePolicy(policy, lookup.tool, modeState.mode, lookup.input);
|
|
130
150
|
if (toolPolicy.timeoutSeconds === 0 && toolPolicy.timeoutAction === "approve") return codexAllow();
|
|
@@ -133,17 +153,17 @@ var decidePermissionRequest = async (input) => {
|
|
|
133
153
|
}
|
|
134
154
|
if (toolPolicy.mode === "terminal_only") return codexPass();
|
|
135
155
|
if (toolPolicy.mode === "notify_only") {
|
|
136
|
-
await notifyApprovalNeeded(apiKey, input);
|
|
156
|
+
if (claimNotify(input.tool_use_id)) await notifyApprovalNeeded(apiKey, input, lookup);
|
|
137
157
|
return codexPass();
|
|
138
158
|
}
|
|
139
159
|
const waitSeconds = toolPolicy.mode === "push_first" ? toolPolicy.pushFirstSeconds : toolPolicy.timeoutSeconds;
|
|
140
|
-
const { answer, correlationId } = await pushQuestion(apiKey, input, waitSeconds);
|
|
160
|
+
const { answer, correlationId } = await pushQuestion(apiKey, input, lookup, waitSeconds);
|
|
141
161
|
if (answer.answered) {
|
|
142
162
|
if (answer.value === "yes") {
|
|
143
163
|
if (toolPolicy.mode === "push_only") markApproved(input.tool_use_id);
|
|
144
164
|
return codexAllow();
|
|
145
165
|
}
|
|
146
|
-
return codexDeny(
|
|
166
|
+
return codexDeny(denyReasonFrom(answer.value));
|
|
147
167
|
}
|
|
148
168
|
savePendingQuestion(input.session_id || DEFAULT_SESSION, correlationId);
|
|
149
169
|
if (toolPolicy.mode === "push_first") return codexPass();
|
|
@@ -159,7 +179,7 @@ var decidePreToolUse = async (input) => {
|
|
|
159
179
|
const apiKey = getApiKey();
|
|
160
180
|
const modeState = await fetchModeState(apiKey, input.session_id);
|
|
161
181
|
if (modeState.kill) return codexDeny(KILL_REASON);
|
|
162
|
-
const lookup = toPolicyLookup(input.tool_name ?? "", input.tool_input ?? {});
|
|
182
|
+
const lookup = toPolicyLookup(input.tool_name ?? "", input.tool_input ?? {}, input.cwd);
|
|
163
183
|
const policy = await getPolicy(apiKey, modeState.policyVersion);
|
|
164
184
|
const toolPolicy = resolvePolicy(policy, lookup.tool, modeState.mode, lookup.input);
|
|
165
185
|
if (toolPolicy.timeoutSeconds === 0 && toolPolicy.timeoutAction === "approve") return codexPass();
|
|
@@ -170,19 +190,19 @@ var decidePreToolUse = async (input) => {
|
|
|
170
190
|
if (consumeApproval(input.tool_use_id)) return codexPass();
|
|
171
191
|
let pushed;
|
|
172
192
|
try {
|
|
173
|
-
pushed = await pushQuestion(apiKey, input, toolPolicy.timeoutSeconds);
|
|
193
|
+
pushed = await pushQuestion(apiKey, input, lookup, toolPolicy.timeoutSeconds);
|
|
174
194
|
} catch {
|
|
175
195
|
return preToolUseTimeoutDecision(toolPolicy.timeoutAction, "Push notification failed, denying per policy");
|
|
176
196
|
}
|
|
177
197
|
const { answer, correlationId } = pushed;
|
|
178
198
|
if (answer.answered) {
|
|
179
|
-
return answer.value === "yes" ? codexPass() : codexDeny(
|
|
199
|
+
return answer.value === "yes" ? codexPass() : codexDeny(denyReasonFrom(answer.value));
|
|
180
200
|
}
|
|
181
201
|
savePendingQuestion(input.session_id || DEFAULT_SESSION, correlationId);
|
|
182
202
|
return preToolUseTimeoutDecision(toolPolicy.timeoutAction);
|
|
183
203
|
}
|
|
184
204
|
if (toolPolicy.mode === "notify_only") {
|
|
185
|
-
await notifyApprovalNeeded(apiKey, input);
|
|
205
|
+
if (claimNotify(input.tool_use_id)) await notifyApprovalNeeded(apiKey, input, lookup);
|
|
186
206
|
return codexPass();
|
|
187
207
|
}
|
|
188
208
|
return codexPass();
|
|
@@ -228,15 +248,17 @@ var main = async () => {
|
|
|
228
248
|
case "PreToolUse":
|
|
229
249
|
emit(toCodexWire("PreToolUse", await decidePreToolUse(input)));
|
|
230
250
|
break;
|
|
231
|
-
case "PostToolUse":
|
|
251
|
+
case "PostToolUse": {
|
|
252
|
+
const lookup = toPolicyLookup(input.tool_name ?? "", input.tool_input ?? {}, input.cwd);
|
|
232
253
|
await handlePostToolUse({
|
|
233
|
-
tool_name:
|
|
234
|
-
tool_input: input
|
|
254
|
+
tool_name: lookup.tool,
|
|
255
|
+
tool_input: lookup.input,
|
|
235
256
|
tool_result: asToolResult(input.tool_response),
|
|
236
257
|
cwd: input.cwd,
|
|
237
258
|
session_id: input.session_id
|
|
238
259
|
}, CODEX_AGENT);
|
|
239
260
|
break;
|
|
261
|
+
}
|
|
240
262
|
case "UserPromptSubmit":
|
|
241
263
|
await handleUserPrompt({
|
|
242
264
|
prompt: input.prompt,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
reportEvent
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-BYNYYZWW.js";
|
|
5
5
|
import {
|
|
6
6
|
askUser,
|
|
7
7
|
getMachineId,
|
|
8
8
|
waitForAnswer
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-6QWFMVCD.js";
|
|
10
10
|
import "../chunk-USUCPCUC.js";
|
|
11
11
|
import "../chunk-DWED7BS3.js";
|
|
12
12
|
import {
|
|
@@ -6,8 +6,9 @@ import {
|
|
|
6
6
|
hasGeminiHooks,
|
|
7
7
|
hasInstructionBlock,
|
|
8
8
|
missingCodexHookEvents,
|
|
9
|
-
missingGeminiHookEvents
|
|
10
|
-
|
|
9
|
+
missingGeminiHookEvents,
|
|
10
|
+
untrustedCodexHookEvents
|
|
11
|
+
} from "../chunk-BHAMEPOP.js";
|
|
11
12
|
import {
|
|
12
13
|
callMcpTool,
|
|
13
14
|
sendMcpRequest
|
|
@@ -62,6 +63,20 @@ var extractHookCommand = (entries, needle) => {
|
|
|
62
63
|
}
|
|
63
64
|
return null;
|
|
64
65
|
};
|
|
66
|
+
var extractHookTimeout = (entries, needle) => {
|
|
67
|
+
if (!Array.isArray(entries)) return null;
|
|
68
|
+
for (const entry of entries) {
|
|
69
|
+
const hookList = entry.hooks;
|
|
70
|
+
if (!Array.isArray(hookList)) continue;
|
|
71
|
+
for (const candidate of hookList) {
|
|
72
|
+
const hook = candidate;
|
|
73
|
+
if (typeof hook.command === "string" && hook.command.includes(needle) && typeof hook.timeout === "number") {
|
|
74
|
+
return hook.timeout;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
};
|
|
65
80
|
var results = [];
|
|
66
81
|
var check = (passed, label, detail) => {
|
|
67
82
|
results.push({ passed, label, detail });
|
|
@@ -149,15 +164,30 @@ var main = async () => {
|
|
|
149
164
|
const codexHooksJson = readJson(codexHooksPath);
|
|
150
165
|
if (existsSync(codexConfigPath) || codexHooksJson) {
|
|
151
166
|
const codexConfig = existsSync(codexConfigPath) ? readFileSync(codexConfigPath, "utf-8") : "";
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
167
|
+
let codexParsed = {};
|
|
168
|
+
try {
|
|
169
|
+
codexParsed = parseTOML(codexConfig);
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
const codexMcp = codexParsed.mcp_servers?.pushary;
|
|
173
|
+
const codexTransport = !!codexMcp && (typeof codexMcp.url === "string" || typeof codexMcp.command === "string");
|
|
174
|
+
const codexEnvVar = codexMcp && typeof codexMcp.bearer_token_env_var === "string" ? codexMcp.bearer_token_env_var : void 0;
|
|
175
|
+
const codexHasCred = !!codexEnvVar || !!codexMcp && typeof codexMcp.bearer_token === "string";
|
|
176
|
+
const codexMcpOk = !!codexMcp && codexTransport && codexHasCred;
|
|
177
|
+
check(codexMcpOk, "Codex: MCP server configured", codexMcpOk ? void 0 : !codexMcp ? "no [mcp_servers.pushary] \u2014 re-run setup" : !codexTransport ? "entry has no url \u2014 `codex mcp add` likely failed, re-run setup" : "entry has no bearer_token/_env_var \u2014 re-run setup");
|
|
178
|
+
if (codexMcp) {
|
|
179
|
+
const hasAutoApprove = codexMcp.default_tools_approval_mode === "approve";
|
|
180
|
+
check(hasAutoApprove, "Codex: tools auto-allowed", hasAutoApprove ? "default_tools_approval_mode = approve" : "missing \u2014 MCP calls will prompt for approval");
|
|
181
|
+
if (codexMcp.tools && typeof codexMcp.tools === "object") {
|
|
159
182
|
console.log(` ${warn} Codex: per-tool approval overrides detected ${dim("(redundant with default_tools_approval_mode)")}`);
|
|
160
183
|
}
|
|
184
|
+
if (codexEnvVar) {
|
|
185
|
+
const envValue = process.env[codexEnvVar]?.trim();
|
|
186
|
+
check(!!envValue, `Codex: MCP key available in shell ($${codexEnvVar})`, envValue ? "set" : `not set \u2014 Codex reads its key from your shell; the ~/.pushary/config.json fallback only covers hooks. Add the export to your profile or re-run setup`);
|
|
187
|
+
if (envValue && apiKey && envValue !== apiKey) {
|
|
188
|
+
console.log(` ${warn} Codex: $${codexEnvVar} differs from your active key ${dim("(rotate or re-run setup so hooks and MCP match)")}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
161
191
|
}
|
|
162
192
|
const codexNotifyPath = codexConfig.match(/["']([^"']*pushary-codex[^"']*)["']/)?.[1] ?? null;
|
|
163
193
|
const hooksInstalled = !!codexHooksJson && hasCodexHooks(codexHooksJson);
|
|
@@ -169,18 +199,16 @@ var main = async () => {
|
|
|
169
199
|
const resolves = commandResolves(hookCommand);
|
|
170
200
|
check(resolves, "Codex: hook command resolves", resolves ? hookCommand : `not on PATH: ${hookCommand}`);
|
|
171
201
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const parsed = parseTOML(codexConfig);
|
|
175
|
-
const features = parsed.features;
|
|
176
|
-
hooksFeatureDisabled = !!features && typeof features === "object" && features.hooks === false;
|
|
177
|
-
} catch {
|
|
178
|
-
}
|
|
202
|
+
const features = codexParsed.features;
|
|
203
|
+
const hooksFeatureDisabled = !!features && typeof features === "object" && features.hooks === false;
|
|
179
204
|
check(!hooksFeatureDisabled, "Codex: hooks feature enabled", hooksFeatureDisabled ? "[features].hooks = false in config.toml" : void 0);
|
|
180
205
|
if (codexNotifyPath) {
|
|
181
206
|
console.log(` ${warn} Codex: stale legacy notify entry ${dim("(double-push risk, re-run setup to remove it)")}`);
|
|
182
207
|
}
|
|
183
|
-
|
|
208
|
+
if (hookCommand) {
|
|
209
|
+
const untrusted = untrustedCodexHookEvents(codexParsed, codexHooksPath, hookCommand);
|
|
210
|
+
check(untrusted.length === 0, "Codex: hooks trusted", untrusted.length === 0 ? "all events trusted" : `untrusted (${untrusted.join(", ")}) \u2014 type /hooks in Codex and trust them, once`);
|
|
211
|
+
}
|
|
184
212
|
} else {
|
|
185
213
|
check(!!codexNotifyPath, "Codex: notify handler configured (deprecated)", codexNotifyPath ? "upgrade Codex and re-run setup for native hooks" : "missing, re-run setup");
|
|
186
214
|
if (codexNotifyPath) {
|
|
@@ -203,17 +231,32 @@ var main = async () => {
|
|
|
203
231
|
if (geminiPushary) {
|
|
204
232
|
check(typeof geminiPushary.httpUrl === "string", "Gemini CLI: MCP transport", geminiPushary.httpUrl ? String(geminiPushary.httpUrl) : "missing \u2014 add httpUrl");
|
|
205
233
|
check(geminiPushary.trust === true, "Gemini CLI: tools auto-allowed", geminiPushary.trust === true ? "trust: true" : "missing \u2014 MCP calls will prompt for confirmation");
|
|
234
|
+
const geminiAuth = geminiPushary.headers?.Authorization;
|
|
235
|
+
if (typeof geminiAuth === "string") {
|
|
236
|
+
if (geminiAuth.includes("${PUSHARY_API_KEY}")) {
|
|
237
|
+
check(false, "Gemini CLI: API key embedded", "header has an unexpanded ${PUSHARY_API_KEY} \u2014 re-run setup to embed the key");
|
|
238
|
+
} else if (apiKey && geminiAuth !== `Bearer ${apiKey}`) {
|
|
239
|
+
check(false, "Gemini CLI: API key matches active key", "embedded key differs from your active key (rotated?) \u2014 re-run setup");
|
|
240
|
+
} else {
|
|
241
|
+
check(true, "Gemini CLI: API key embedded");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
206
244
|
}
|
|
207
245
|
const geminiHooksInstalled = hasGeminiHooks(geminiSettings);
|
|
208
246
|
if (geminiHooksInstalled) {
|
|
209
247
|
const missingEvents = missingGeminiHookEvents(geminiSettings);
|
|
210
248
|
check(missingEvents.length === 0, "Gemini CLI: native hooks installed", missingEvents.length === 0 ? "all 5 events" : `missing ${missingEvents.join(", ")}, re-run setup`);
|
|
211
249
|
const geminiHooks = geminiSettings.hooks;
|
|
212
|
-
const hookCommand = extractHookCommand(geminiHooks?.BeforeTool, GEMINI_HOOK_BINARY);
|
|
250
|
+
const hookCommand = extractHookCommand(geminiHooks?.BeforeTool, GEMINI_HOOK_BINARY) ?? extractHookCommand(geminiHooks?.AfterTool, GEMINI_HOOK_BINARY) ?? extractHookCommand(geminiHooks?.SessionStart, GEMINI_HOOK_BINARY);
|
|
213
251
|
if (hookCommand) {
|
|
214
252
|
const resolves = commandResolves(hookCommand);
|
|
215
253
|
check(resolves, "Gemini CLI: hook command resolves", resolves ? hookCommand : `not on PATH: ${hookCommand}`);
|
|
216
254
|
}
|
|
255
|
+
const geminiTimeout = extractHookTimeout(geminiHooks?.BeforeTool, GEMINI_HOOK_BINARY);
|
|
256
|
+
if (typeof geminiTimeout === "number") {
|
|
257
|
+
const ok = geminiTimeout >= 3e4;
|
|
258
|
+
check(ok, "Gemini CLI: hook timeout", ok ? `${geminiTimeout}ms` : `${geminiTimeout}ms too short (Gemini timeouts are milliseconds) \u2014 re-run setup`);
|
|
259
|
+
}
|
|
217
260
|
} else {
|
|
218
261
|
check(false, "Gemini CLI: native hooks installed", "no Pushary hooks in ~/.gemini/settings.json \u2014 re-run setup");
|
|
219
262
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
denyReasonFrom
|
|
4
|
+
} from "../chunk-N7VXDBQU.js";
|
|
2
5
|
import {
|
|
3
6
|
handlePostToolUse,
|
|
4
7
|
handleStop,
|
|
5
8
|
handleUserPrompt,
|
|
6
9
|
reportEvent
|
|
7
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-BYNYYZWW.js";
|
|
8
11
|
import {
|
|
9
12
|
DEFAULT_SESSION,
|
|
10
13
|
askUser,
|
|
@@ -17,7 +20,7 @@ import {
|
|
|
17
20
|
savePendingQuestion,
|
|
18
21
|
sendNotification,
|
|
19
22
|
waitForAnswer
|
|
20
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-6QWFMVCD.js";
|
|
21
24
|
import "../chunk-USUCPCUC.js";
|
|
22
25
|
import "../chunk-DWED7BS3.js";
|
|
23
26
|
import {
|
|
@@ -63,8 +66,8 @@ var geminiTimeoutDecision = (timeoutAction, denyReason = "No response within tim
|
|
|
63
66
|
// bin/pushary-gemini-hook.ts
|
|
64
67
|
var KILL_REASON = "Stopped by user: this agent was halted from Pushary";
|
|
65
68
|
var MAX_WAIT_SECONDS = 170;
|
|
69
|
+
var START_MS = Date.now();
|
|
66
70
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
67
|
-
var denyReasonFrom = (value) => value && value !== "no" && value !== "yes" ? `Denied from your phone: ${value}` : "Denied via push notification";
|
|
68
71
|
var pollForAnswer = async (apiKey, correlationId, deadlineMs, pollInterval = 2e3) => {
|
|
69
72
|
while (Date.now() < deadlineMs) {
|
|
70
73
|
const remaining = Math.min(Math.max(deadlineMs - Date.now(), 1e3), 3e4);
|
|
@@ -96,7 +99,10 @@ var pushQuestion = async (apiKey, input, lookup, waitSeconds, pollInterval = 2e3
|
|
|
96
99
|
toolName: lookup.tool,
|
|
97
100
|
toolTarget: deriveToolTarget(lookup.tool, lookup.input)
|
|
98
101
|
});
|
|
99
|
-
const deadline =
|
|
102
|
+
const deadline = Math.min(
|
|
103
|
+
Date.now() + Math.min(waitSeconds, MAX_WAIT_SECONDS) * 1e3,
|
|
104
|
+
START_MS + MAX_WAIT_SECONDS * 1e3
|
|
105
|
+
);
|
|
100
106
|
const answer = await pollForAnswer(apiKey, result.correlationId, deadline, pollInterval);
|
|
101
107
|
return { answer, correlationId: result.correlationId };
|
|
102
108
|
};
|
package/dist/bin/pushary-hook.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handlePreToolUse
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-M5F2L4KF.js";
|
|
5
|
+
import "../chunk-N7VXDBQU.js";
|
|
6
|
+
import "../chunk-6QWFMVCD.js";
|
|
6
7
|
import "../chunk-USUCPCUC.js";
|
|
7
8
|
import "../chunk-DWED7BS3.js";
|
|
8
9
|
import "../chunk-NKXSILEW.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handlePostToolUse
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-BYNYYZWW.js";
|
|
5
|
+
import "../chunk-6QWFMVCD.js";
|
|
6
6
|
import "../chunk-USUCPCUC.js";
|
|
7
7
|
import "../chunk-DWED7BS3.js";
|
|
8
8
|
import "../chunk-NKXSILEW.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handleUserPrompt
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-BYNYYZWW.js";
|
|
5
|
+
import "../chunk-6QWFMVCD.js";
|
|
6
6
|
import "../chunk-USUCPCUC.js";
|
|
7
7
|
import "../chunk-DWED7BS3.js";
|
|
8
8
|
import "../chunk-NKXSILEW.js";
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
npmErrorMessage,
|
|
15
15
|
renderAgentInstructions,
|
|
16
16
|
writeInstructionBlock
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-BHAMEPOP.js";
|
|
18
18
|
import {
|
|
19
19
|
isValidApiKey
|
|
20
20
|
} from "../chunk-USUCPCUC.js";
|
|
@@ -541,7 +541,7 @@ var setupHermes = async (_apiKey) => {
|
|
|
541
541
|
};
|
|
542
542
|
var CODEX_HOOKS_JSON = join(CODEX_HOME, "hooks.json");
|
|
543
543
|
var CODEX_HOOKS_MIN_VERSION = [0, 122, 0];
|
|
544
|
-
var CODEX_TRUST_VERIFIED_MAX = [0,
|
|
544
|
+
var CODEX_TRUST_VERIFIED_MAX = [0, 142, 2];
|
|
545
545
|
var parseCodexVersion = (raw) => {
|
|
546
546
|
const match = raw.match(/(\d+)\.(\d+)\.(\d+)/);
|
|
547
547
|
if (!match) return null;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handleStop
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-BYNYYZWW.js";
|
|
5
|
+
import "../chunk-6QWFMVCD.js";
|
|
6
6
|
import "../chunk-USUCPCUC.js";
|
|
7
7
|
import "../chunk-DWED7BS3.js";
|
|
8
8
|
import "../chunk-NKXSILEW.js";
|