@pushary/agent-hooks 0.26.0 → 0.28.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.
- package/data/cursor-plugin/scripts/pushary-gate.mjs +21 -1
- package/dist/bin/pushary-clean.js +3 -2
- package/dist/bin/pushary-codex-hook.js +37 -12
- package/dist/bin/pushary-codex.js +2 -1
- package/dist/bin/pushary-doctor.js +32 -2
- package/dist/bin/pushary-gemini-hook.js +36 -11
- package/dist/bin/pushary-hook.js +3 -2
- package/dist/bin/pushary-mode.js +5 -3
- package/dist/bin/pushary-post-hook.js +8 -2
- package/dist/bin/pushary-prompt-hook.js +8 -2
- package/dist/bin/pushary-setup.js +6 -4
- package/dist/bin/pushary-stop-hook.js +2 -1
- package/dist/bin/pushary-wait.d.ts +1 -0
- package/dist/bin/pushary-wait.js +86 -0
- package/dist/bin/pushary.js +4 -0
- package/dist/{chunk-SA4BDS7T.js → chunk-2BHYQCF7.js} +40 -3
- package/dist/{chunk-5MA3CPZB.js → chunk-76F75WQQ.js} +5 -1
- package/dist/chunk-IIENZE2J.js +15 -0
- package/dist/{chunk-A7DQCA2N.js → chunk-NFKYZY74.js} +74 -184
- package/dist/{chunk-SLX4AONG.js → chunk-QDPUTE2V.js} +7 -3
- package/dist/chunk-YRL4ZB4R.js +322 -0
- package/dist/src/index.d.ts +7 -1
- package/dist/src/index.js +3 -2
- package/package.json +4 -3
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/wait-ladder.ts
|
|
2
|
+
var describeWaitLadder = (p) => {
|
|
3
|
+
if (p.mode === "terminal_only") return "decide in the terminal, no push";
|
|
4
|
+
if (p.mode === "notify_only") return "send a heads-up, the terminal decides";
|
|
5
|
+
if (p.mode === "push_only") {
|
|
6
|
+
if (p.timeoutAction === "wait") return "wait for your phone, then ask in the terminal";
|
|
7
|
+
const tail = p.timeoutAction === "approve" ? "then auto-approve" : p.timeoutAction === "deny" ? "then auto-deny" : "then ask in the terminal";
|
|
8
|
+
return `wait for your phone up to ${p.timeoutSeconds}s, ${tail}`;
|
|
9
|
+
}
|
|
10
|
+
return `ping your phone ${p.pushFirstSeconds}s, then ask in the terminal`;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
describeWaitLadder
|
|
15
|
+
};
|
|
@@ -2,185 +2,22 @@ import {
|
|
|
2
2
|
callMcpTool,
|
|
3
3
|
withRetry
|
|
4
4
|
} from "./chunk-DWED7BS3.js";
|
|
5
|
+
import {
|
|
6
|
+
ACTION_BODY_MAX,
|
|
7
|
+
DECISION_LINE_MAX,
|
|
8
|
+
extractPolicyArg,
|
|
9
|
+
isApprovalMode,
|
|
10
|
+
isSafeReadOnlyCommand,
|
|
11
|
+
matchRankWeight,
|
|
12
|
+
matchToolPattern,
|
|
13
|
+
redactSecrets,
|
|
14
|
+
redactSecretsDeep
|
|
15
|
+
} from "./chunk-YRL4ZB4R.js";
|
|
5
16
|
import {
|
|
6
17
|
getApiKey,
|
|
7
18
|
getBaseUrl
|
|
8
19
|
} from "./chunk-NKXSILEW.js";
|
|
9
20
|
|
|
10
|
-
// ../../../../../packages/contracts/src/index.ts
|
|
11
|
-
var APPROVAL_MODES = ["push_only", "terminal_only", "push_first", "notify_only"];
|
|
12
|
-
var isApprovalMode = (value) => typeof value === "string" && APPROVAL_MODES.includes(value);
|
|
13
|
-
var MATCH_RANKS = ["none", "tool", "prefix", "exact"];
|
|
14
|
-
var matchRankWeight = (rank) => MATCH_RANKS.indexOf(rank);
|
|
15
|
-
var matchToolPattern = (pattern, toolName, arg) => {
|
|
16
|
-
const open = pattern.indexOf("(");
|
|
17
|
-
if (open === -1 || !pattern.endsWith(")")) {
|
|
18
|
-
return pattern === toolName ? "tool" : "none";
|
|
19
|
-
}
|
|
20
|
-
if (pattern.slice(0, open) !== toolName || arg === void 0) return "none";
|
|
21
|
-
const inner = pattern.slice(open + 1, -1);
|
|
22
|
-
if (inner.endsWith(":*")) {
|
|
23
|
-
return arg.startsWith(inner.slice(0, -2)) ? "prefix" : "none";
|
|
24
|
-
}
|
|
25
|
-
return arg === inner ? "exact" : "none";
|
|
26
|
-
};
|
|
27
|
-
var POLICY_ARG_KEYS = {
|
|
28
|
-
Bash: "command",
|
|
29
|
-
Edit: "file_path",
|
|
30
|
-
Write: "file_path"
|
|
31
|
-
};
|
|
32
|
-
var extractPolicyArg = (toolName, toolInput) => {
|
|
33
|
-
const key = POLICY_ARG_KEYS[toolName];
|
|
34
|
-
if (!key) return void 0;
|
|
35
|
-
const value = toolInput[key];
|
|
36
|
-
return typeof value === "string" ? value : void 0;
|
|
37
|
-
};
|
|
38
|
-
var SAFE_SHELL_COMMANDS = /* @__PURE__ */ new Set([
|
|
39
|
-
"ls",
|
|
40
|
-
"pwd",
|
|
41
|
-
"cd",
|
|
42
|
-
"cat",
|
|
43
|
-
"head",
|
|
44
|
-
"tail",
|
|
45
|
-
"wc",
|
|
46
|
-
"echo",
|
|
47
|
-
"printf",
|
|
48
|
-
"which",
|
|
49
|
-
"type",
|
|
50
|
-
"whoami",
|
|
51
|
-
"id",
|
|
52
|
-
"uname",
|
|
53
|
-
"arch",
|
|
54
|
-
"printenv",
|
|
55
|
-
"locale",
|
|
56
|
-
"tty",
|
|
57
|
-
"dirname",
|
|
58
|
-
"basename",
|
|
59
|
-
"realpath",
|
|
60
|
-
"readlink",
|
|
61
|
-
"stat",
|
|
62
|
-
"cut",
|
|
63
|
-
"nl",
|
|
64
|
-
"tr",
|
|
65
|
-
"comm",
|
|
66
|
-
"diff",
|
|
67
|
-
"cmp",
|
|
68
|
-
"grep",
|
|
69
|
-
"egrep",
|
|
70
|
-
"fgrep",
|
|
71
|
-
"jq",
|
|
72
|
-
"cksum",
|
|
73
|
-
"md5sum",
|
|
74
|
-
"sha1sum",
|
|
75
|
-
"sha256sum",
|
|
76
|
-
"du",
|
|
77
|
-
"df",
|
|
78
|
-
"ps",
|
|
79
|
-
"true"
|
|
80
|
-
]);
|
|
81
|
-
var SAFE_GIT_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
82
|
-
"status",
|
|
83
|
-
"log",
|
|
84
|
-
"diff",
|
|
85
|
-
"show",
|
|
86
|
-
"rev-parse",
|
|
87
|
-
"describe",
|
|
88
|
-
"blame",
|
|
89
|
-
"shortlog",
|
|
90
|
-
"ls-files",
|
|
91
|
-
"ls-tree",
|
|
92
|
-
"cat-file",
|
|
93
|
-
"whatchanged",
|
|
94
|
-
"rev-list",
|
|
95
|
-
"name-rev",
|
|
96
|
-
"for-each-ref",
|
|
97
|
-
"var",
|
|
98
|
-
"count-objects"
|
|
99
|
-
]);
|
|
100
|
-
var GIT_WRITE_FLAGS = (token) => token === "--output" || token.startsWith("--output=");
|
|
101
|
-
var UNSAFE_SHELL_CHARS = /[;&|<>(){}`\\\n\r]/;
|
|
102
|
-
var basenameOf = (token) => {
|
|
103
|
-
const slash = Math.max(token.lastIndexOf("/"), token.lastIndexOf("\\"));
|
|
104
|
-
return slash === -1 ? token : token.slice(slash + 1);
|
|
105
|
-
};
|
|
106
|
-
var tokenizeShellCommand = (command) => {
|
|
107
|
-
const tokens = [];
|
|
108
|
-
let current = "";
|
|
109
|
-
let quote = null;
|
|
110
|
-
let started = false;
|
|
111
|
-
for (const ch of command) {
|
|
112
|
-
if (quote) {
|
|
113
|
-
if (ch === quote) quote = null;
|
|
114
|
-
else current += ch;
|
|
115
|
-
started = true;
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
if (ch === '"' || ch === "'") {
|
|
119
|
-
quote = ch;
|
|
120
|
-
started = true;
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
if (ch === " " || ch === " ") {
|
|
124
|
-
if (started) {
|
|
125
|
-
tokens.push(current);
|
|
126
|
-
current = "";
|
|
127
|
-
started = false;
|
|
128
|
-
}
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
current += ch;
|
|
132
|
-
started = true;
|
|
133
|
-
}
|
|
134
|
-
if (quote) return null;
|
|
135
|
-
if (started) tokens.push(current);
|
|
136
|
-
return tokens;
|
|
137
|
-
};
|
|
138
|
-
var isSafeReadOnlyCommand = (command) => {
|
|
139
|
-
const trimmed = command.trim();
|
|
140
|
-
if (!trimmed || trimmed.length > 2e3) return false;
|
|
141
|
-
if (UNSAFE_SHELL_CHARS.test(trimmed)) return false;
|
|
142
|
-
const tokens = tokenizeShellCommand(trimmed);
|
|
143
|
-
if (!tokens || tokens.length === 0) return false;
|
|
144
|
-
const first = tokens[0];
|
|
145
|
-
if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(first) || first.includes("$")) return false;
|
|
146
|
-
const exe = basenameOf(first);
|
|
147
|
-
if (exe === "git") {
|
|
148
|
-
const sub = tokens[1];
|
|
149
|
-
if (!sub || sub.startsWith("-")) return false;
|
|
150
|
-
if (!SAFE_GIT_SUBCOMMANDS.has(sub)) return false;
|
|
151
|
-
return !tokens.some(GIT_WRITE_FLAGS);
|
|
152
|
-
}
|
|
153
|
-
return SAFE_SHELL_COMMANDS.has(exe);
|
|
154
|
-
};
|
|
155
|
-
var API_KEY_PATTERN = /^pk_[a-f0-9]+\.[a-f0-9]+$/;
|
|
156
|
-
var isValidApiKey = (value) => API_KEY_PATTERN.test(value);
|
|
157
|
-
var ACTION_BODY_MAX = 4e3;
|
|
158
|
-
var DECISION_LINE_MAX = 500;
|
|
159
|
-
var SECRET_REDACTION_RULES = [
|
|
160
|
-
{ pattern: /-----BEGIN[A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END[A-Z0-9 ]*PRIVATE KEY-----/g, replacement: "[redacted key]" },
|
|
161
|
-
{ pattern: /\bsk-[A-Za-z0-9_-]{16,}\b/g, replacement: "[redacted]" },
|
|
162
|
-
{ pattern: /\b[spr]k_(?:live|test)_[A-Za-z0-9]{8,}\b/g, replacement: "[redacted]" },
|
|
163
|
-
{ pattern: /\bwhsec_[A-Za-z0-9]{16,}\b/g, replacement: "[redacted]" },
|
|
164
|
-
{ pattern: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b/g, replacement: "[redacted]" },
|
|
165
|
-
{ pattern: /\bgithub_pat_[A-Za-z0-9_]{22,}\b/g, replacement: "[redacted]" },
|
|
166
|
-
{ pattern: /\bglpat-[A-Za-z0-9_-]{20,}\b/g, replacement: "[redacted]" },
|
|
167
|
-
{ pattern: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, replacement: "[redacted]" },
|
|
168
|
-
{ pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g, replacement: "[redacted]" },
|
|
169
|
-
{ pattern: /\bAKIA[0-9A-Z]{16}\b/g, replacement: "[redacted]" },
|
|
170
|
-
{ pattern: /\bnpm_[A-Za-z0-9]{36}\b/g, replacement: "[redacted]" },
|
|
171
|
-
{ pattern: /\bxai-[A-Za-z0-9]{16,}\b/g, replacement: "[redacted]" },
|
|
172
|
-
{ pattern: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, replacement: "[redacted]" },
|
|
173
|
-
{ pattern: /\bbearer\s+[A-Za-z0-9._~+/=-]+/gi, replacement: "bearer [redacted]" },
|
|
174
|
-
{ pattern: /\bauthorization:\s*\S+/gi, replacement: "authorization: [redacted]" },
|
|
175
|
-
{
|
|
176
|
-
pattern: /((?:secret|token|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)\s*[=:]\s*)("[^"]*"|'[^']*'|\S+)/gi,
|
|
177
|
-
replacement: "$1[redacted]"
|
|
178
|
-
}
|
|
179
|
-
];
|
|
180
|
-
var HIGH_ENTROPY_RULE = { pattern: /[A-Za-z0-9+/]{40,}={0,2}/g, replacement: "[redacted]" };
|
|
181
|
-
var redactSecrets = (text) => SECRET_REDACTION_RULES.reduce((acc, rule) => acc.replace(rule.pattern, rule.replacement), text);
|
|
182
|
-
var redactSecretsDeep = (text) => redactSecrets(text).replace(HIGH_ENTROPY_RULE.pattern, HIGH_ENTROPY_RULE.replacement);
|
|
183
|
-
|
|
184
21
|
// src/validate.ts
|
|
185
22
|
var isPolicyConfig = (data) => {
|
|
186
23
|
if (!data || typeof data !== "object") return false;
|
|
@@ -818,20 +655,52 @@ var readLastPrompt = (sessionId) => {
|
|
|
818
655
|
return void 0;
|
|
819
656
|
}
|
|
820
657
|
};
|
|
821
|
-
var
|
|
658
|
+
var reconcilePendingQuestions = async (sessionId) => {
|
|
659
|
+
const late = [];
|
|
822
660
|
try {
|
|
823
661
|
const files = listPendingQuestions(sessionId);
|
|
662
|
+
if (files.length === 0) return late;
|
|
824
663
|
const apiKey = getApiKey();
|
|
825
664
|
for (const correlationId of files) {
|
|
826
665
|
try {
|
|
827
|
-
await
|
|
666
|
+
const answer = await waitForAnswer(apiKey, correlationId, 1e3);
|
|
667
|
+
if (answer.answered) {
|
|
668
|
+
late.push({ correlationId, value: answer.value });
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
await cancelQuestion(apiKey, correlationId).catch(() => {
|
|
672
|
+
});
|
|
828
673
|
} catch {
|
|
674
|
+
continue;
|
|
829
675
|
}
|
|
830
676
|
removePendingQuestion(sessionId, correlationId);
|
|
831
677
|
}
|
|
832
|
-
if (!isDefaultSession(sessionId)) removePendingSession(sessionId);
|
|
833
678
|
} catch {
|
|
834
679
|
}
|
|
680
|
+
return late;
|
|
681
|
+
};
|
|
682
|
+
var describeLateAnswer = (value) => {
|
|
683
|
+
const v = (value ?? "").trim();
|
|
684
|
+
if (v === "yes") return "approved it";
|
|
685
|
+
if (v === "no") return "rejected it";
|
|
686
|
+
if (v === "defer") return "chose to handle it on this machine";
|
|
687
|
+
return v ? `answered "${v.slice(0, 200)}"` : "responded";
|
|
688
|
+
};
|
|
689
|
+
var buildLateAnswerContext = (late) => {
|
|
690
|
+
if (late.length === 0) return void 0;
|
|
691
|
+
const parts = late.map((l) => `you ${describeLateAnswer(l.value)} on your phone`);
|
|
692
|
+
return `Pushary: a permission prompt you were sent was answered late \u2014 ${parts.join("; ")} \u2014 after the terminal already took over. Treat this as the user's latest intent; do not assume the earlier terminal decision matched it.`;
|
|
693
|
+
};
|
|
694
|
+
var notifyLateAnswers = async (apiKey, late, agentName, sessionId) => {
|
|
695
|
+
if (late.length === 0) return;
|
|
696
|
+
const summary = late.map((l) => describeLateAnswer(l.value)).join(", ");
|
|
697
|
+
await sendNotification(apiKey, {
|
|
698
|
+
title: "Answer arrived late",
|
|
699
|
+
body: `You ${summary} after the agent had already moved on.`,
|
|
700
|
+
agentName,
|
|
701
|
+
sessionId
|
|
702
|
+
}, 2500).catch(() => {
|
|
703
|
+
});
|
|
835
704
|
};
|
|
836
705
|
var CLAUDE_CODE_AGENT = { type: "claude_code", label: "Claude Code" };
|
|
837
706
|
var POLICY_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
@@ -917,10 +786,15 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
917
786
|
const receiptsEnabled = process.env.PUSHARY_RECEIPTS !== "off";
|
|
918
787
|
const sessionKey = input.session_id || DEFAULT_SESSION;
|
|
919
788
|
const liveMode = await fetchModeState(getApiKey(), input.session_id);
|
|
789
|
+
const late = await reconcilePendingQuestions(sessionKey);
|
|
790
|
+
let additionalContext;
|
|
791
|
+
if (late.length > 0 && agent.type === CLAUDE_CODE_AGENT.type) {
|
|
792
|
+
additionalContext = buildLateAnswerContext(late);
|
|
793
|
+
for (const l of late) removePendingQuestion(sessionKey, l.correlationId);
|
|
794
|
+
}
|
|
920
795
|
const decisionSource = deriveDecisionSource(lookup.tool, lookup.input, liveMode);
|
|
921
796
|
const beacon = decisionSource === "policy_auto" && throttlePass(`autodecision:${sessionKey}:${lookup.tool}`, AUTO_DECISION_WINDOW_MS) ? deriveAutoDecisionBeacon(lookup.tool, lookup.input, liveMode) : void 0;
|
|
922
797
|
const reports = [
|
|
923
|
-
cleanupPendingQuestions(sessionKey),
|
|
924
798
|
reportEvent({
|
|
925
799
|
event: isError ? "tool_error" : "tool_complete",
|
|
926
800
|
agentType: agent.type,
|
|
@@ -948,16 +822,25 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
948
822
|
);
|
|
949
823
|
}
|
|
950
824
|
await Promise.allSettled(reports);
|
|
825
|
+
return additionalContext;
|
|
951
826
|
} catch {
|
|
827
|
+
return void 0;
|
|
952
828
|
}
|
|
953
829
|
};
|
|
954
830
|
var TASK_TITLE_MAX_LENGTH = 120;
|
|
955
831
|
var handleUserPrompt = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
956
832
|
try {
|
|
957
833
|
const projectName = basename(input.cwd ?? process.cwd());
|
|
834
|
+
const sessionKey = input.session_id || DEFAULT_SESSION;
|
|
958
835
|
const titlesEnabled = process.env.PUSHARY_TASK_TITLES !== "off";
|
|
959
836
|
const taskTitle = titlesEnabled ? input.prompt?.replace(/\s+/g, " ").trim().slice(0, TASK_TITLE_MAX_LENGTH) || void 0 : void 0;
|
|
960
|
-
if (input.prompt) saveLastPrompt(
|
|
837
|
+
if (input.prompt) saveLastPrompt(sessionKey, input.prompt);
|
|
838
|
+
const late = await reconcilePendingQuestions(sessionKey);
|
|
839
|
+
let additionalContext;
|
|
840
|
+
if (late.length > 0 && agent.type === CLAUDE_CODE_AGENT.type) {
|
|
841
|
+
additionalContext = buildLateAnswerContext(late);
|
|
842
|
+
for (const l of late) removePendingQuestion(sessionKey, l.correlationId);
|
|
843
|
+
}
|
|
961
844
|
await reportEvent({
|
|
962
845
|
event: "user_prompt",
|
|
963
846
|
agentType: agent.type,
|
|
@@ -965,14 +848,17 @@ var handleUserPrompt = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
965
848
|
sessionId: input.session_id,
|
|
966
849
|
taskTitle
|
|
967
850
|
}, { maxAttempts: 1, timeoutMs: 800 });
|
|
851
|
+
return additionalContext;
|
|
968
852
|
} catch {
|
|
853
|
+
return void 0;
|
|
969
854
|
}
|
|
970
855
|
};
|
|
971
856
|
var handleStop = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
972
857
|
try {
|
|
973
858
|
const projectName = basename(input.cwd ?? process.cwd());
|
|
974
|
-
const
|
|
975
|
-
|
|
859
|
+
const sessionKey = input.session_id || DEFAULT_SESSION;
|
|
860
|
+
const late = await reconcilePendingQuestions(sessionKey);
|
|
861
|
+
const tasks = [
|
|
976
862
|
reportEvent({
|
|
977
863
|
event: "session_end",
|
|
978
864
|
agentType: agent.type,
|
|
@@ -981,7 +867,13 @@ var handleStop = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
981
867
|
sessionId: input.session_id,
|
|
982
868
|
usage: deriveUsage(input.transcript_path, input.session_id)
|
|
983
869
|
})
|
|
984
|
-
]
|
|
870
|
+
];
|
|
871
|
+
if (late.length > 0) {
|
|
872
|
+
tasks.push(notifyLateAnswers(getApiKey(), late, `${agent.label} - ${projectName}`, input.session_id));
|
|
873
|
+
for (const l of late) removePendingQuestion(sessionKey, l.correlationId);
|
|
874
|
+
}
|
|
875
|
+
if (!isDefaultSession(sessionKey)) removePendingSession(sessionKey);
|
|
876
|
+
const [reported] = await Promise.allSettled(tasks);
|
|
985
877
|
const pendingCommand = reported.status === "fulfilled" ? reported.value?.pendingCommand : void 0;
|
|
986
878
|
if (typeof pendingCommand === "string" && pendingCommand.trim().length > 0) {
|
|
987
879
|
return {
|
|
@@ -1010,8 +902,6 @@ var handleNotification = async (input) => {
|
|
|
1010
902
|
};
|
|
1011
903
|
|
|
1012
904
|
export {
|
|
1013
|
-
isValidApiKey,
|
|
1014
|
-
DECISION_LINE_MAX,
|
|
1015
905
|
askUser,
|
|
1016
906
|
waitForAnswer,
|
|
1017
907
|
cancelQuestion,
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HOOK_BUDGETS
|
|
3
|
+
} from "./chunk-YRL4ZB4R.js";
|
|
4
|
+
|
|
1
5
|
// src/codex-config.ts
|
|
2
6
|
import { createHash } from "crypto";
|
|
3
7
|
var CODEX_HOOK_BINARY = "pushary-codex-hook";
|
|
4
8
|
var CODEX_HOOK_EVENTS = [
|
|
5
|
-
{ event: "PermissionRequest", matcher: "Bash|apply_patch", timeout:
|
|
6
|
-
{ event: "PreToolUse", matcher: "Bash|apply_patch", timeout:
|
|
9
|
+
{ event: "PermissionRequest", matcher: "Bash|apply_patch", timeout: HOOK_BUDGETS.codex.budgetSeconds, statusMessage: "Waiting for your phone" },
|
|
10
|
+
{ event: "PreToolUse", matcher: "Bash|apply_patch", timeout: HOOK_BUDGETS.codex.budgetSeconds, statusMessage: "Checking Pushary policy" },
|
|
7
11
|
{ event: "PostToolUse", matcher: "Bash|apply_patch", timeout: 10 },
|
|
8
12
|
{ event: "UserPromptSubmit", timeout: 10 },
|
|
9
13
|
{ event: "Stop", timeout: 10 },
|
|
@@ -141,7 +145,7 @@ var addCodexHookTrust = (config, hooksJsonPath, command) => {
|
|
|
141
145
|
var GEMINI_HOOK_BINARY = "pushary-gemini-hook";
|
|
142
146
|
var GEMINI_MCP_URL = "https://pushary.com/api/mcp/mcp";
|
|
143
147
|
var GEMINI_HOOK_EVENTS = [
|
|
144
|
-
{ event: "BeforeTool", matcher: "run_shell_command|write_file|replace", timeoutMs:
|
|
148
|
+
{ event: "BeforeTool", matcher: "run_shell_command|write_file|replace", timeoutMs: HOOK_BUDGETS.gemini.budgetSeconds * 1e3 },
|
|
145
149
|
{ event: "AfterTool", matcher: "run_shell_command|write_file|replace", timeoutMs: 1e4 },
|
|
146
150
|
{ event: "BeforeAgent", timeoutMs: 1e4 },
|
|
147
151
|
{ event: "SessionStart", timeoutMs: 1e4 },
|