@pushary/agent-hooks 0.95.8 → 0.98.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/CHANGELOG.md +27 -0
- package/dist/bin/pushary-bell-hook.js +19 -21
- package/dist/bin/pushary-bell.js +6 -8
- package/dist/bin/pushary-claude.js +21 -23
- package/dist/bin/pushary-clean.js +19 -22
- package/dist/bin/pushary-codex-bridge.js +13 -14
- package/dist/bin/pushary-codex-hook.js +452 -104
- package/dist/bin/pushary-codex.js +8 -8
- package/dist/bin/pushary-connect.js +6 -6
- package/dist/bin/pushary-cowork.js +3 -3
- package/dist/bin/pushary-daemon.js +25 -27
- package/dist/bin/pushary-disconnect.js +6 -8
- package/dist/bin/pushary-doctor.js +28 -23
- package/dist/bin/pushary-elicitation-hook.js +19 -21
- package/dist/bin/pushary-gemini-bridge.js +11 -12
- package/dist/bin/pushary-gemini-hook.js +22 -24
- package/dist/bin/pushary-hook.js +24 -26
- package/dist/bin/pushary-login.js +7 -8
- package/dist/bin/pushary-logout.js +4 -4
- package/dist/bin/pushary-mode.js +3 -3
- package/dist/bin/pushary-notification-hook.js +21 -23
- package/dist/bin/pushary-opencode-hook.js +22 -24
- package/dist/bin/pushary-permission-denied-hook.js +28 -27
- package/dist/bin/pushary-permission-hook.js +24 -26
- package/dist/bin/pushary-post-hook.js +21 -23
- package/dist/bin/pushary-prompt-hook.js +21 -23
- package/dist/bin/pushary-session-end-hook.js +21 -23
- package/dist/bin/pushary-session-start-hook.js +24 -26
- package/dist/bin/pushary-setup.js +45 -40
- package/dist/bin/pushary-stats.js +2 -2
- package/dist/bin/pushary-status.js +10 -11
- package/dist/bin/pushary-stop-hook.js +21 -23
- package/dist/bin/pushary-stopfailure-hook.js +21 -23
- package/dist/bin/pushary-transcript-register.js +17 -19
- package/dist/bin/pushary-transcripts.js +5 -5
- package/dist/bin/pushary-upgrade.js +17 -20
- package/dist/bin/pushary-wait.js +3 -3
- package/dist/{chunk-GOPIMNVC.js → chunk-2GLOHBYB.js} +1 -1
- package/dist/{chunk-BQL7UDIB.js → chunk-3RVCQDC4.js} +1 -1
- package/dist/chunk-53QCTSWY.js +202 -0
- package/dist/{chunk-3YFJGKJQ.js → chunk-5B5QV3KC.js} +8 -8
- package/dist/{chunk-FRXZMCVA.js → chunk-5KLAETSU.js} +1 -1
- package/dist/{chunk-SDNTRS76.js → chunk-6C6MS57P.js} +1 -1
- package/dist/{chunk-A22VQ5ZL.js → chunk-6CYB77VD.js} +111 -55
- package/dist/{chunk-QD73WATQ.js → chunk-6LRGZJFB.js} +21 -21
- package/dist/{chunk-Z4JVEL7R.js → chunk-A76GNRIK.js} +191 -2
- package/dist/{chunk-RE25RJ5A.js → chunk-B35OCFXH.js} +4 -4
- package/dist/{chunk-UKMLSQXA.js → chunk-CP34FI4B.js} +2 -2
- package/dist/{chunk-I7LKI4WO.js → chunk-DOD3A6EU.js} +6 -8
- package/dist/{chunk-N6FAXQDD.js → chunk-FAJ4R7IB.js} +1 -1
- package/dist/{chunk-U5RIXR7I.js → chunk-HB2KB7QL.js} +1 -1
- package/dist/{chunk-QV266EGS.js → chunk-HFQ7WSHZ.js} +11 -14
- package/dist/{chunk-QJPYJVL3.js → chunk-IRLTW6KF.js} +1 -1
- package/dist/{chunk-Y6SCMXR6.js → chunk-J44RPHUZ.js} +2 -2
- package/dist/{chunk-R6LBGKWQ.js → chunk-JQU6PMH4.js} +17 -15
- package/dist/{chunk-4DUEIUUO.js → chunk-K6CH5NVW.js} +1 -1
- package/dist/{chunk-XZWUOCJZ.js → chunk-LBNAGGLV.js} +1 -1
- package/dist/{chunk-XS33QBJA.js → chunk-LGXUGYUH.js} +50 -1
- package/dist/{chunk-XO3JR3OP.js → chunk-LX4NNYII.js} +2 -2
- package/dist/{chunk-XEVOPOKT.js → chunk-M4TVEMLH.js} +1 -1
- package/dist/{chunk-TY6IJY6I.js → chunk-NIXVMMJM.js} +1 -1
- package/dist/{chunk-VERXHIQF.js → chunk-NQGYPTJQ.js} +1 -1
- package/dist/{chunk-EMGGUO2Q.js → chunk-OBYC6SN4.js} +1 -1
- package/dist/{chunk-XUTSZYYJ.js → chunk-OPR2BPD4.js} +1 -4
- package/dist/{chunk-MC5WUOJJ.js → chunk-OUAE3GKO.js} +75 -1
- package/dist/{chunk-ATKGKAP6.js → chunk-QXIF6R4P.js} +16 -13
- package/dist/chunk-SI7GYBQP.js +15 -0
- package/dist/{chunk-VMQU7YEJ.js → chunk-SJLGOVC6.js} +1 -1
- package/dist/{chunk-54W7ELDQ.js → chunk-TZHDKRMG.js} +2 -2
- package/dist/{chunk-F4TMY6XI.js → chunk-V47GITZV.js} +3 -3
- package/dist/{chunk-L7NOG547.js → chunk-VZD2GEKB.js} +1 -1
- package/dist/{chunk-R3OZ5ISU.js → chunk-W2MG2P46.js} +4 -4
- package/dist/{chunk-E47WV7BJ.js → chunk-WU6LSXJ6.js} +2 -2
- package/dist/{chunk-NOVA7KZ2.js → chunk-XL3RKJYQ.js} +308 -35
- package/dist/{chunk-5GKNAQTG.js → chunk-XOOWC62T.js} +1 -1
- package/dist/{chunk-SKPXQRKN.js → chunk-XPPXOKIG.js} +1 -1
- package/dist/{chunk-HUGIKB5O.js → chunk-YJDRHQLG.js} +6 -6
- package/dist/src/index.js +11 -11
- package/package.json +1 -1
- package/dist/chunk-3AJIK5AO.js +0 -57
- package/dist/chunk-L4ZCFMWW.js +0 -177
- package/dist/chunk-VDI645ZX.js +0 -18
|
@@ -4,6 +4,9 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
installProxyDispatcher
|
|
6
6
|
} from "./chunk-SAF6HGAA.js";
|
|
7
|
+
import {
|
|
8
|
+
getBaseUrl
|
|
9
|
+
} from "./chunk-2UMNXADU.js";
|
|
7
10
|
|
|
8
11
|
// src/api.ts
|
|
9
12
|
import { randomUUID } from "crypto";
|
|
@@ -24,6 +27,21 @@ var isWaitForAnswerResponse = (data) => {
|
|
|
24
27
|
const d = data;
|
|
25
28
|
return typeof d.answered === "boolean";
|
|
26
29
|
};
|
|
30
|
+
var GATE_REPLY_KINDS = ["kill", "allow", "deny", "ask", "no_opinion"];
|
|
31
|
+
var isSettlementOutputs = (value) => {
|
|
32
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
33
|
+
const outputs = value;
|
|
34
|
+
return (outputs.approve === void 0 || typeof outputs.approve === "string") && (outputs.deny === void 0 || typeof outputs.deny === "string");
|
|
35
|
+
};
|
|
36
|
+
var isGateReply = (data) => {
|
|
37
|
+
if (!data || typeof data !== "object") return false;
|
|
38
|
+
const d = data;
|
|
39
|
+
return GATE_REPLY_KINDS.includes(d.kind) && (d.output === void 0 || typeof d.output === "string") && (d.correlationId === void 0 || typeof d.correlationId === "string") && (d.deadlineSeconds === void 0 || typeof d.deadlineSeconds === "number") && (d.noDevices === void 0 || typeof d.noDevices === "boolean") && (d.suppressed === void 0 || typeof d.suppressed === "boolean") && (d.settlementOutputs === void 0 || isSettlementOutputs(d.settlementOutputs));
|
|
40
|
+
};
|
|
41
|
+
var isBlockedActionClaim = (data) => {
|
|
42
|
+
if (!data || typeof data !== "object") return false;
|
|
43
|
+
return typeof data.granted === "boolean";
|
|
44
|
+
};
|
|
27
45
|
|
|
28
46
|
// src/api.ts
|
|
29
47
|
installProxyDispatcher();
|
|
@@ -96,6 +114,34 @@ var waitForQuestion = async (apiKey, question, deadlineMs, pollInterval = 2e3) =
|
|
|
96
114
|
var sendNotification = async (apiKey, params, timeoutMs = 15e3, signal) => {
|
|
97
115
|
await callMcpTool(apiKey, "send_notification", { ...params }, { maxRetries: signal ? 1 : 3, timeoutMs, signal });
|
|
98
116
|
};
|
|
117
|
+
var GATE_PATH = "/api/agent/gate";
|
|
118
|
+
var BLOCKED_ACTION_CLAIM_PATH = "/api/agent/blocked-action/claim";
|
|
119
|
+
var postAgentRequest = async (apiKey, path, body, timeoutMs) => {
|
|
120
|
+
const response = await fetch(`${getBaseUrl()}${path}`, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
|
|
123
|
+
body: JSON.stringify(body),
|
|
124
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
125
|
+
});
|
|
126
|
+
if (!response.ok) throw new Error(`${path} rejected (${response.status})`);
|
|
127
|
+
return response.json();
|
|
128
|
+
};
|
|
129
|
+
var requestGate = async (apiKey, request, timeoutMs = 15e3) => {
|
|
130
|
+
try {
|
|
131
|
+
const reply = await postAgentRequest(apiKey, GATE_PATH, request, timeoutMs);
|
|
132
|
+
return isGateReply(reply) ? reply : null;
|
|
133
|
+
} catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
var claimBlockedAction = async (apiKey, request, timeoutMs) => {
|
|
138
|
+
try {
|
|
139
|
+
const reply = await postAgentRequest(apiKey, BLOCKED_ACTION_CLAIM_PATH, request, timeoutMs);
|
|
140
|
+
return isBlockedActionClaim(reply) ? reply.granted : null;
|
|
141
|
+
} catch {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
99
145
|
|
|
100
146
|
export {
|
|
101
147
|
isPolicyConfig,
|
|
@@ -105,8 +151,11 @@ export {
|
|
|
105
151
|
askUser,
|
|
106
152
|
waitForAnswer,
|
|
107
153
|
nextLongPollMs,
|
|
154
|
+
pollForAnswer,
|
|
108
155
|
cancelQuestion,
|
|
109
156
|
withdrawQuestion,
|
|
110
157
|
waitForQuestion,
|
|
111
|
-
sendNotification
|
|
158
|
+
sendNotification,
|
|
159
|
+
requestGate,
|
|
160
|
+
claimBlockedAction
|
|
112
161
|
};
|
|
@@ -15,10 +15,10 @@ import {
|
|
|
15
15
|
} from "./chunk-EYRGBYZG.js";
|
|
16
16
|
import {
|
|
17
17
|
reportedInstallSource
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-VZD2GEKB.js";
|
|
19
19
|
import {
|
|
20
20
|
isAnswerSource
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-OUAE3GKO.js";
|
|
22
22
|
|
|
23
23
|
// src/reach.ts
|
|
24
24
|
var reachVerdict = (channels) => {
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ASKED_IN_EVERY_MODE_TOOLS,
|
|
3
2
|
PRETOOLUSE_GATED_TOOLS
|
|
4
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-OUAE3GKO.js";
|
|
5
4
|
|
|
6
5
|
// src/claude-tools.ts
|
|
7
|
-
var PRETOOLUSE_PHONE_ANSWERED_TOOLS = ASKED_IN_EVERY_MODE_TOOLS;
|
|
8
6
|
var POSTTOOLUSE_MIRROR_ONLY_TOOLS = ["TodoWrite", "Task", "WebFetch", "WebSearch"];
|
|
9
7
|
var POSTTOOLUSE_MIRRORED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, ...POSTTOOLUSE_MIRROR_ONLY_TOOLS];
|
|
10
8
|
|
|
@@ -34,7 +32,6 @@ var NOTIFICATION_PUSH_TYPES = /* @__PURE__ */ new Set([
|
|
|
34
32
|
]);
|
|
35
33
|
|
|
36
34
|
export {
|
|
37
|
-
PRETOOLUSE_PHONE_ANSWERED_TOOLS,
|
|
38
35
|
POSTTOOLUSE_MIRROR_ONLY_TOOLS,
|
|
39
36
|
POSTTOOLUSE_MIRRORED_TOOLS,
|
|
40
37
|
NOTIFICATION_MATCHED_TYPES,
|
|
@@ -293,6 +293,26 @@ var HOOK_BUDGETS = {
|
|
|
293
293
|
opencode: { budgetSeconds: 120, guardSeconds: 10 }
|
|
294
294
|
};
|
|
295
295
|
var hookMaxWaitSeconds = (agent) => Math.max(HOOK_BUDGETS[agent].budgetSeconds - HOOK_BUDGETS[agent].guardSeconds, 1);
|
|
296
|
+
var HOOK_HOLD_BUDGET_FLAG = "--hold-budget";
|
|
297
|
+
var HOOK_HOLD_BUDGET_ENV = "PUSHARY_HOLD_BUDGET_SECONDS";
|
|
298
|
+
var HOOK_BRIDGE_SOURCE_FLAG = "--source";
|
|
299
|
+
var HOOK_HOLD_BUDGET_SECONDS = /^[1-9]\d{0,5}$/;
|
|
300
|
+
var hookHoldBudgetSeconds = (text) => text !== void 0 && HOOK_HOLD_BUDGET_SECONDS.test(text) ? Number(text) : void 0;
|
|
301
|
+
var hookHoldBudgetArgument = (seconds) => `${HOOK_HOLD_BUDGET_FLAG}=${seconds}`;
|
|
302
|
+
var withHookHoldBudget = (command, holdBudgetSeconds) => holdBudgetSeconds === void 0 ? command : `${command} ${hookHoldBudgetArgument(holdBudgetSeconds)}`;
|
|
303
|
+
var registeredHookHoldBudget = (args) => {
|
|
304
|
+
const prefix = `${HOOK_HOLD_BUDGET_FLAG}=`;
|
|
305
|
+
const proofs = args.filter((arg) => arg.startsWith(prefix));
|
|
306
|
+
return proofs.length === 1 ? hookHoldBudgetSeconds(proofs[0].slice(prefix.length)) : void 0;
|
|
307
|
+
};
|
|
308
|
+
var hookCommandHoldBudget = (command) => registeredHookHoldBudget(command.trim().split(/\s+/));
|
|
309
|
+
var hookHoldBudgetProof = (args, env) => {
|
|
310
|
+
const handedDown = hookHoldBudgetSeconds(env[HOOK_HOLD_BUDGET_ENV]);
|
|
311
|
+
const registered = args.includes(HOOK_BRIDGE_SOURCE_FLAG) ? void 0 : registeredHookHoldBudget(args);
|
|
312
|
+
if (handedDown === void 0) return registered;
|
|
313
|
+
return registered === void 0 ? handedDown : Math.min(handedDown, registered);
|
|
314
|
+
};
|
|
315
|
+
var hookHoldWindowMs = (agent, holdBudgetSeconds) => holdBudgetSeconds === void 0 ? 0 : Math.max((Math.min(holdBudgetSeconds, HOOK_BUDGETS[agent].budgetSeconds) - HOOK_BUDGETS[agent].guardSeconds) * 1e3, 0);
|
|
296
316
|
var hookWaitDeadline = (startMs, policyWaitSeconds, agent, nowMs) => {
|
|
297
317
|
const maxWait = hookMaxWaitSeconds(agent);
|
|
298
318
|
return Math.min(
|
|
@@ -1275,6 +1295,30 @@ var shouldDeferToNativeMode = (permissionMode, toolName, options = {}) => {
|
|
|
1275
1295
|
var ASKED_IN_EVERY_MODE_TOOLS = ["AskUserQuestion", "ExitPlanMode"];
|
|
1276
1296
|
var ASKED_IN_EVERY_MODE = new Set(ASKED_IN_EVERY_MODE_TOOLS);
|
|
1277
1297
|
var isAskedInEveryMode = (toolName) => ASKED_IN_EVERY_MODE.has(toolName);
|
|
1298
|
+
var NATIVE_BLOCK_EVENTS = /* @__PURE__ */ new Set(["PermissionDenied"]);
|
|
1299
|
+
var isNativeBlockEvent = (event) => typeof event === "string" && NATIVE_BLOCK_EVENTS.has(event);
|
|
1300
|
+
var CODEX_RESCUE_TOOL_NAME = "Bash";
|
|
1301
|
+
var isBlockedActionEvent = ({ source, event, blockedBy }) => isNativeBlockEvent(event) || source === "codex" && event === "Stop" && blockedBy === "auto_review";
|
|
1302
|
+
var blockedActionRetryReachesGate = (source, toolName) => source === "claude" ? PRETOOLUSE_HANDLED_TOOLS.has(toolName) && !isAskedInEveryMode(toolName) : source === "codex" && toolName === CODEX_RESCUE_TOOL_NAME;
|
|
1303
|
+
var isBlockedActionRequest = (request) => isBlockedActionEvent(request) && blockedActionRetryReachesGate(request.source, request.toolName);
|
|
1304
|
+
var canonicalJsonText = (value) => {
|
|
1305
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJsonText).join(",")}]`;
|
|
1306
|
+
if (value !== null && typeof value === "object") {
|
|
1307
|
+
const record = value;
|
|
1308
|
+
return `{${Object.keys(record).filter((key) => record[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonicalJsonText(record[key])}`).join(",")}}`;
|
|
1309
|
+
}
|
|
1310
|
+
return JSON.stringify(value) ?? "null";
|
|
1311
|
+
};
|
|
1312
|
+
var BLOCKED_ACTION_IDENTITY_VERSION = "blocked-action/v1";
|
|
1313
|
+
var CLAUDE_BLOCKED_ACTION_IDENTITY_VERSION = "blocked-action/v2";
|
|
1314
|
+
var BLOCKED_ACTION_GRANT_TTL_SECONDS = 120;
|
|
1315
|
+
var BLOCKED_ACTION_PRESENTATION_ONLY_KEYS = ["description"];
|
|
1316
|
+
var isPresentationOnlyInputKey = (key) => BLOCKED_ACTION_PRESENTATION_ONLY_KEYS.includes(key);
|
|
1317
|
+
var identifyingBlockedActionInput = (toolInput) => Object.fromEntries(Object.entries(toolInput).filter(([key]) => !isPresentationOnlyInputKey(key)));
|
|
1318
|
+
var blockedActionIdentity = (subject) => {
|
|
1319
|
+
const { sessionId, toolName, toolInput } = subject;
|
|
1320
|
+
return subject.source === "claude" ? canonicalJsonText([CLAUDE_BLOCKED_ACTION_IDENTITY_VERSION, sessionId, subject.cwd, toolName, identifyingBlockedActionInput(toolInput)]) : canonicalJsonText([BLOCKED_ACTION_IDENTITY_VERSION, sessionId, toolName, identifyingBlockedActionInput(toolInput)]);
|
|
1321
|
+
};
|
|
1278
1322
|
var PRETOOLUSE_GATED_TOOLS = [
|
|
1279
1323
|
"Bash",
|
|
1280
1324
|
"Write",
|
|
@@ -1286,6 +1330,7 @@ var PRETOOLUSE_GATED_TOOLS = [
|
|
|
1286
1330
|
];
|
|
1287
1331
|
var PRETOOLUSE_HANDLED_TOOLS = /* @__PURE__ */ new Set([...PRETOOLUSE_GATED_TOOLS, ...ASKED_IN_EVERY_MODE_TOOLS]);
|
|
1288
1332
|
var isPermissionRequestOwnedByPreToolUse = (toolName, permissionMode, defers = shouldDeferToNativeMode) => PRETOOLUSE_HANDLED_TOOLS.has(toolName) && (isAskedInEveryMode(toolName) || !defers(permissionMode, toolName));
|
|
1333
|
+
var CLAUDE_PRETOOLUSE_MATCHER = [...PRETOOLUSE_HANDLED_TOOLS].join("|");
|
|
1289
1334
|
var resolveGate = (input) => {
|
|
1290
1335
|
const { modeState, config, toolName, toolInputs, cwd, repoKey, sessionId } = input;
|
|
1291
1336
|
if (isPusharyOwnTool(toolName)) {
|
|
@@ -1342,6 +1387,19 @@ var modeStateFromResponse = (data) => {
|
|
|
1342
1387
|
askHandoff: data.askHandoff === true
|
|
1343
1388
|
};
|
|
1344
1389
|
};
|
|
1390
|
+
var GATE_WIRE = 1;
|
|
1391
|
+
var GATE_MAX_TOOL_INPUTS = 32;
|
|
1392
|
+
var GATE_BLOCK_REASON_MAX_LENGTH = 200;
|
|
1393
|
+
var claudePermissionDeniedOutput = (decision) => ({
|
|
1394
|
+
hookSpecificOutput: {
|
|
1395
|
+
hookEventName: "PermissionDenied",
|
|
1396
|
+
retry: decision === "allow"
|
|
1397
|
+
}
|
|
1398
|
+
});
|
|
1399
|
+
var CODEX_RESCUE_COMMAND_MAX_LENGTH = 2e3;
|
|
1400
|
+
var CODEX_RESCUE_APPROVED = "I approved this command in Pushary after the auto-reviewer denied it. If it is denied again, stop and tell me.";
|
|
1401
|
+
var codexRescueRetryInstruction = (command) => command.length <= CODEX_RESCUE_COMMAND_MAX_LENGTH ? `Run it again now, exactly as before: ${command}` : `Run it again now, exactly as before. It is too long to repeat in full here and begins: ${command.slice(0, CODEX_RESCUE_COMMAND_MAX_LENGTH)}`;
|
|
1402
|
+
var codexStopRescueOutput = (decision, command) => decision === "allow" ? { decision: "block", reason: `${CODEX_RESCUE_APPROVED} ${codexRescueRetryInstruction(command)}` } : { continue: true };
|
|
1345
1403
|
var stoppedOutput = (output, stopReason) => ({ ...output, continue: false, stopReason });
|
|
1346
1404
|
var claudePreToolUseOutput = (decision, reason, updatedInput) => ({
|
|
1347
1405
|
hookSpecificOutput: {
|
|
@@ -1387,6 +1445,8 @@ var gateOutputFor = (source, event, decision, reason) => {
|
|
|
1387
1445
|
output = claudePreToolUseOutput(decision, reason);
|
|
1388
1446
|
} else if (event === "PermissionRequest" && decision !== "ask") {
|
|
1389
1447
|
output = claudePermissionRequestOutput(decision, reason);
|
|
1448
|
+
} else if (source === "claude" && event === "PermissionDenied" && decision !== "ask") {
|
|
1449
|
+
output = claudePermissionDeniedOutput(decision);
|
|
1390
1450
|
}
|
|
1391
1451
|
} else if (source === "codex") {
|
|
1392
1452
|
if (event === "PermissionRequest" && decision !== "ask") {
|
|
@@ -1582,6 +1642,11 @@ export {
|
|
|
1582
1642
|
parseAgentQuestionAnswers,
|
|
1583
1643
|
normalizeInstallSource,
|
|
1584
1644
|
HOOK_BUDGETS,
|
|
1645
|
+
HOOK_HOLD_BUDGET_ENV,
|
|
1646
|
+
withHookHoldBudget,
|
|
1647
|
+
hookCommandHoldBudget,
|
|
1648
|
+
hookHoldBudgetProof,
|
|
1649
|
+
hookHoldWindowMs,
|
|
1585
1650
|
hookWaitDeadline,
|
|
1586
1651
|
hookWaitClamped,
|
|
1587
1652
|
effectiveWaitSeconds,
|
|
@@ -1605,11 +1670,20 @@ export {
|
|
|
1605
1670
|
KILL_REASON,
|
|
1606
1671
|
isPusharyOwnTool,
|
|
1607
1672
|
shouldDeferToNativeMode,
|
|
1608
|
-
|
|
1673
|
+
CODEX_RESCUE_TOOL_NAME,
|
|
1674
|
+
isBlockedActionRequest,
|
|
1675
|
+
BLOCKED_ACTION_GRANT_TTL_SECONDS,
|
|
1676
|
+
blockedActionIdentity,
|
|
1609
1677
|
PRETOOLUSE_GATED_TOOLS,
|
|
1610
1678
|
isPermissionRequestOwnedByPreToolUse,
|
|
1679
|
+
CLAUDE_PRETOOLUSE_MATCHER,
|
|
1611
1680
|
resolveGate,
|
|
1612
1681
|
modeStateFromResponse,
|
|
1682
|
+
GATE_WIRE,
|
|
1683
|
+
GATE_MAX_TOOL_INPUTS,
|
|
1684
|
+
GATE_BLOCK_REASON_MAX_LENGTH,
|
|
1685
|
+
claudePermissionDeniedOutput,
|
|
1686
|
+
codexStopRescueOutput,
|
|
1613
1687
|
stoppedOutput,
|
|
1614
1688
|
claudePreToolUseOutput,
|
|
1615
1689
|
PENDING_COMMAND_PREFIX,
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CLAUDE_HOOK_EVENTS,
|
|
3
3
|
supportedClaudeEvents
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HFQ7WSHZ.js";
|
|
5
5
|
import {
|
|
6
|
-
guardBinary
|
|
7
|
-
|
|
6
|
+
guardBinary,
|
|
7
|
+
holdBudgetOf,
|
|
8
|
+
isProtectedByScope,
|
|
9
|
+
registerHookEntry
|
|
10
|
+
} from "./chunk-XL3RKJYQ.js";
|
|
8
11
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
HOOK_LOCATOR_BINARY
|
|
13
|
-
} from "./chunk-MC5WUOJJ.js";
|
|
12
|
+
HOOK_LOCATOR_BINARY,
|
|
13
|
+
withHookHoldBudget
|
|
14
|
+
} from "./chunk-OUAE3GKO.js";
|
|
14
15
|
|
|
15
16
|
// src/claude-config.ts
|
|
16
17
|
import { join } from "path";
|
|
@@ -126,12 +127,14 @@ var addPusharyHooks = (settings, binDir, version = null) => {
|
|
|
126
127
|
const hooks = ensureRecord(settings, "hooks");
|
|
127
128
|
const supported = new Map(supportedClaudeEvents(version).map((hook) => [hook.event, hook]));
|
|
128
129
|
for (const known of CLAUDE_HOOK_EVENTS) {
|
|
129
|
-
const current = hooks[known.event];
|
|
130
|
-
const others = (Array.isArray(current) ? current : []).filter((item) => !isPusharyHook(item));
|
|
130
|
+
const current = Array.isArray(hooks[known.event]) ? hooks[known.event] : [];
|
|
131
131
|
const definition = supported.get(known.event);
|
|
132
132
|
if (definition) {
|
|
133
|
-
hooks[known.event] =
|
|
134
|
-
|
|
133
|
+
hooks[known.event] = registerHookEntry(current, isPusharyHook, entry(definition, resolve));
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const others = current.filter((item) => !isPusharyHook(item));
|
|
137
|
+
if (others.length > 0) {
|
|
135
138
|
hooks[known.event] = others;
|
|
136
139
|
} else {
|
|
137
140
|
delete hooks[known.event];
|
|
@@ -142,7 +145,7 @@ var entry = (definition, resolve) => ({
|
|
|
142
145
|
...definition.matcher ? { matcher: definition.matcher } : {},
|
|
143
146
|
hooks: [{
|
|
144
147
|
type: "command",
|
|
145
|
-
command: resolve(definition.binary),
|
|
148
|
+
command: withHookHoldBudget(resolve(definition.binary), holdBudgetOf(definition)),
|
|
146
149
|
timeout: definition.timeout
|
|
147
150
|
}]
|
|
148
151
|
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HOOK_HOLD_BUDGET_ENV,
|
|
3
|
+
hookHoldBudgetProof
|
|
4
|
+
} from "./chunk-OUAE3GKO.js";
|
|
5
|
+
|
|
6
|
+
// src/hold-budget.ts
|
|
7
|
+
var takeHookHoldBudget = (args = process.argv.slice(2), env = process.env) => {
|
|
8
|
+
const proof = hookHoldBudgetProof(args, env);
|
|
9
|
+
delete env[HOOK_HOLD_BUDGET_ENV];
|
|
10
|
+
return proof;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
takeHookHoldBudget
|
|
15
|
+
};
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
resolveBinary,
|
|
3
3
|
resolveGlobalPackageVersion,
|
|
4
4
|
resolvePackageVersionFromBinary
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-XL3RKJYQ.js";
|
|
6
6
|
import {
|
|
7
7
|
MANAGED_PROVIDERS
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-OUAE3GKO.js";
|
|
9
9
|
|
|
10
10
|
// src/live-capabilities.ts
|
|
11
11
|
var CLAUDE_BRIDGE_CAPABILITY = "claude-bridge";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
openCodeConfigDirFrom
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-HB2KB7QL.js";
|
|
4
4
|
import {
|
|
5
5
|
codexHomeFrom
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XL3RKJYQ.js";
|
|
7
7
|
|
|
8
8
|
// src/vscode-config.ts
|
|
9
9
|
import { homedir } from "os";
|
|
@@ -264,7 +264,7 @@ You have Pushary MCP tools that reach the user on their phone. Use them proactiv
|
|
|
264
264
|
|
|
265
265
|
- When you need the user to make a decision or answer a clarifying question, call \`ask_user\` instead of guessing or stalling. Use type "confirm" for yes/no, "select" for a fixed set of options, and "input" for free text. Read \`answered\`, \`status\` and the returned handoff instead of assuming the tool blocked. Silence is not consent; choice/text answers do not authorize a separate action.
|
|
266
266
|
- Ask once, on one channel. If you also have a built-in way to prompt the user, use that or \`ask_user\` for a given question, never both. \`ask_user\` is the one that reaches the user when they are away from this machine, so prefer it. Raising both strands the user in whichever prompt you are not waiting on.
|
|
267
|
-
- Honor authorization already granted in this session. Ask before a risky or irreversible action outside that authorization, or when an enforced host policy requires it. Do not ask again for an already authorized step, and never bypass an enforced gate.
|
|
267
|
+
- Honor authorization already granted in this session. Ask before a risky or irreversible action outside that authorization, or when an enforced host policy requires it. Do not ask again for an already authorized step, and never bypass an enforced gate. When a Pushary hook result says the user approved a specific command after a denial, rerunning that exact command is the approved path and not a bypass of that gate.
|
|
268
268
|
- Call \`propose_scope\` only for an unresolved or requested file boundary. A ratified scope narrows what may proceed; it does not bypass other approval rules. Do not add a plan approval merely because work spans several files, and do not propose a new scope mid-run just to widen it. Let the installed gate request any scope expansion before the edit executes.
|
|
269
269
|
- When you are blocked, stuck, or hit an error you cannot resolve on your own, call \`send_notification\` so the user knows, and call \`ask_user\` if you need a decision to continue.
|
|
270
270
|
- When meaningful work finishes while the user is away, or they requested an alert, call \`send_notification\` so the user knows it is done. Skip trivial completions and duplicate reports to someone already reading. Always pass \`context\` with a \`type\` of "task_complete", "error" or "info": it is what tells Pushary this is a task update, so the user's own setting for where updates land can route it.
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-2UMNXADU.js";
|
|
4
4
|
import {
|
|
5
5
|
normalizeInstallSource
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-OUAE3GKO.js";
|
|
7
7
|
|
|
8
8
|
// src/cli/fsx.ts
|
|
9
9
|
import { copyFileSync, existsSync, fsyncSync, mkdirSync, openSync, closeSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AGENT_CHOICES
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LBNAGGLV.js";
|
|
4
4
|
import {
|
|
5
5
|
isBridgeLocator
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-IRLTW6KF.js";
|
|
7
7
|
import {
|
|
8
8
|
pusharyHookExecutable
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6LRGZJFB.js";
|
|
10
10
|
import {
|
|
11
11
|
BELL_HOOK_BINARY
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-2GLOHBYB.js";
|
|
13
13
|
|
|
14
14
|
// src/setup/hook-ownership.ts
|
|
15
15
|
var commandsIn = (value) => {
|