@pushary/agent-hooks 0.95.8 → 0.97.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 +17 -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 +34 -38
- 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-RE25RJ5A.js → chunk-3SNTEHOH.js} +4 -4
- package/dist/{chunk-R3OZ5ISU.js → chunk-4AXWBCCO.js} +4 -4
- package/dist/{chunk-XEVOPOKT.js → chunk-5ODZEFP3.js} +1 -1
- package/dist/{chunk-NOVA7KZ2.js → chunk-67RNDRKL.js} +260 -32
- package/dist/{chunk-3YFJGKJQ.js → chunk-6VXZKOBB.js} +8 -8
- package/dist/{chunk-ATKGKAP6.js → chunk-6WJKYD3Q.js} +8 -8
- package/dist/{chunk-EMGGUO2Q.js → chunk-A4AIISZZ.js} +1 -1
- package/dist/{chunk-N6FAXQDD.js → chunk-AXSDMDJI.js} +1 -1
- package/dist/{chunk-XO3JR3OP.js → chunk-B3557BDL.js} +2 -2
- package/dist/{chunk-QJPYJVL3.js → chunk-BYH75I7Y.js} +1 -1
- package/dist/{chunk-VERXHIQF.js → chunk-C2FYSFTQ.js} +1 -1
- package/dist/{chunk-SKPXQRKN.js → chunk-CDSA3NTB.js} +1 -1
- package/dist/{chunk-HUGIKB5O.js → chunk-DGUMR5LZ.js} +6 -6
- package/dist/{chunk-54W7ELDQ.js → chunk-DNLFSRCF.js} +2 -2
- package/dist/{chunk-R6LBGKWQ.js → chunk-DOKFLZWL.js} +10 -14
- package/dist/{chunk-U5RIXR7I.js → chunk-EHQC3GWL.js} +1 -1
- package/dist/{chunk-QD73WATQ.js → chunk-FU5SQKAY.js} +15 -4
- package/dist/{chunk-TY6IJY6I.js → chunk-GGYH6LIE.js} +1 -1
- package/dist/{chunk-XZWUOCJZ.js → chunk-H4VNAOCG.js} +1 -1
- package/dist/{chunk-MC5WUOJJ.js → chunk-HUZW6SEO.js} +75 -1
- package/dist/{chunk-QV266EGS.js → chunk-IBRX7LRE.js} +8 -10
- package/dist/{chunk-UKMLSQXA.js → chunk-ICUBJNFL.js} +2 -2
- package/dist/{chunk-E47WV7BJ.js → chunk-IZKCA35M.js} +2 -2
- package/dist/{chunk-F4TMY6XI.js → chunk-K7MLXXPY.js} +2 -2
- package/dist/{chunk-Y6SCMXR6.js → chunk-KDPYXMUI.js} +2 -2
- package/dist/{chunk-XS33QBJA.js → chunk-LGXUGYUH.js} +50 -1
- package/dist/{chunk-I7LKI4WO.js → chunk-LYWTLNMG.js} +6 -8
- package/dist/chunk-OYTOLQ3N.js +15 -0
- package/dist/{chunk-XUTSZYYJ.js → chunk-QFAZ6QCT.js} +1 -4
- package/dist/{chunk-FRXZMCVA.js → chunk-ROTIPRM4.js} +1 -1
- package/dist/{chunk-BQL7UDIB.js → chunk-SW37HB27.js} +1 -1
- package/dist/{chunk-Z4JVEL7R.js → chunk-VCKQ45QA.js} +191 -2
- package/dist/{chunk-SDNTRS76.js → chunk-VDTC5DEM.js} +1 -1
- package/dist/{chunk-VMQU7YEJ.js → chunk-VF7YOT2W.js} +1 -1
- package/dist/{chunk-5GKNAQTG.js → chunk-VOC55PQV.js} +1 -1
- package/dist/{chunk-L7NOG547.js → chunk-VTUN7WSG.js} +1 -1
- package/dist/{chunk-GOPIMNVC.js → chunk-WIKEADOS.js} +1 -1
- package/dist/chunk-XDMHLQMH.js +202 -0
- package/dist/{chunk-4DUEIUUO.js → chunk-YRXVC4HL.js} +1 -1
- package/dist/{chunk-A22VQ5ZL.js → chunk-YX3U2CLP.js} +111 -55
- 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
|
@@ -18,26 +18,26 @@ import {
|
|
|
18
18
|
summarizeStop,
|
|
19
19
|
taskTitleFrom,
|
|
20
20
|
toolResultErrorText
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-VCKQ45QA.js";
|
|
22
22
|
import {
|
|
23
23
|
NOTIFICATION_PUSH_TYPES,
|
|
24
24
|
POSTTOOLUSE_MIRROR_ONLY_TOOLS
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-QFAZ6QCT.js";
|
|
26
26
|
import {
|
|
27
27
|
cancelQuestion,
|
|
28
28
|
isPolicyConfig,
|
|
29
29
|
sendNotification,
|
|
30
30
|
waitForAnswer
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-LGXUGYUH.js";
|
|
32
32
|
import {
|
|
33
33
|
getMachineId
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-IZKCA35M.js";
|
|
35
35
|
import {
|
|
36
36
|
withRetry
|
|
37
37
|
} from "./chunk-EYRGBYZG.js";
|
|
38
38
|
import {
|
|
39
39
|
reportedInstallSource
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-VTUN7WSG.js";
|
|
41
41
|
import {
|
|
42
42
|
getApiKey,
|
|
43
43
|
getBaseUrl
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
pendingCommandEvents,
|
|
55
55
|
resolveAutoResolveOrigin,
|
|
56
56
|
resolvePolicy
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-HUZW6SEO.js";
|
|
58
58
|
|
|
59
59
|
// src/policy.ts
|
|
60
60
|
import { createHash } from "crypto";
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
resolveBinary,
|
|
3
3
|
resolveGlobalPackageVersion,
|
|
4
4
|
resolvePackageVersionFromBinary
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-67RNDRKL.js";
|
|
6
6
|
import {
|
|
7
7
|
MANAGED_PROVIDERS
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-HUZW6SEO.js";
|
|
9
9
|
|
|
10
10
|
// src/live-capabilities.ts
|
|
11
11
|
var CLAUDE_BRIDGE_CAPABILITY = "claude-bridge";
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
detectClaudeVersion
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YRXVC4HL.js";
|
|
4
4
|
import {
|
|
5
5
|
addClaudeMcpServer,
|
|
6
6
|
addPusharyHooks,
|
|
7
7
|
addPusharyToolPermissions
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-6WJKYD3Q.js";
|
|
9
9
|
import {
|
|
10
10
|
claudeWired,
|
|
11
11
|
codexWired,
|
|
12
12
|
geminiWired
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-FU5SQKAY.js";
|
|
14
14
|
import {
|
|
15
15
|
CLAUDE_HOOK_EVENTS,
|
|
16
16
|
GEMINI_HOOK_BINARY,
|
|
@@ -21,14 +21,7 @@ import {
|
|
|
21
21
|
needsReregistration,
|
|
22
22
|
registrationSignatures,
|
|
23
23
|
supportedClaudeEvents
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import {
|
|
26
|
-
guardBinary
|
|
27
|
-
} from "./chunk-3AJIK5AO.js";
|
|
28
|
-
import {
|
|
29
|
-
resolveGlobalBinDir,
|
|
30
|
-
resolveGlobalBinary
|
|
31
|
-
} from "./chunk-L4ZCFMWW.js";
|
|
24
|
+
} from "./chunk-IBRX7LRE.js";
|
|
32
25
|
import {
|
|
33
26
|
CODEX_HOOK_BINARY,
|
|
34
27
|
addCodexHookTrust,
|
|
@@ -38,16 +31,19 @@ import {
|
|
|
38
31
|
codexConfigToml,
|
|
39
32
|
codexHookPositions,
|
|
40
33
|
codexHooksJson,
|
|
34
|
+
guardBinary,
|
|
41
35
|
hasCodexHooks,
|
|
36
|
+
resolveGlobalBinDir,
|
|
37
|
+
resolveGlobalBinary,
|
|
42
38
|
vscodePluginMcp
|
|
43
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-67RNDRKL.js";
|
|
44
40
|
import {
|
|
45
41
|
readJsonSafe,
|
|
46
42
|
writeJsonAtomic
|
|
47
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-VTUN7WSG.js";
|
|
48
44
|
import {
|
|
49
45
|
HOOK_LOCATOR_BINARY
|
|
50
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-HUZW6SEO.js";
|
|
51
47
|
|
|
52
48
|
// src/reapply.ts
|
|
53
49
|
import { join } from "path";
|
|
@@ -2,15 +2,16 @@ import {
|
|
|
2
2
|
CLAUDE_HOOK_EVENTS,
|
|
3
3
|
GEMINI_HOOK_EVENTS,
|
|
4
4
|
hasGeminiHooks
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-IBRX7LRE.js";
|
|
6
6
|
import {
|
|
7
7
|
CODEX_HOOK_EVENTS,
|
|
8
8
|
hasCodexHooks
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-67RNDRKL.js";
|
|
10
10
|
import {
|
|
11
11
|
CURSOR_GATE_EVENTS,
|
|
12
|
-
HOOK_LOCATOR_BINARY
|
|
13
|
-
|
|
12
|
+
HOOK_LOCATOR_BINARY,
|
|
13
|
+
hookCommandHoldBudget
|
|
14
|
+
} from "./chunk-HUZW6SEO.js";
|
|
14
15
|
|
|
15
16
|
// src/diagnostics/wiring.ts
|
|
16
17
|
var record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -111,6 +112,14 @@ var claudeOtherHolders = (settings) => otherHolders(record(settings)?.hooks, CLA
|
|
|
111
112
|
var codexOtherHolders = (hooks) => otherHolders(record(hooks)?.hooks, CODEX_GATE_EVENTS, "nested", "seconds");
|
|
112
113
|
var geminiOtherHolders = (settings) => otherHolders(record(settings)?.hooks, GEMINI_GATE_EVENTS, "nested", "milliseconds");
|
|
113
114
|
var cursorOtherHolders = (userHooks) => otherHolders(record(userHooks)?.hooks, CURSOR_GATE_EVENTS, "flat", "seconds");
|
|
115
|
+
var holdEvents = (table) => table.filter((hook) => hook.holds).map((hook) => hook.event);
|
|
116
|
+
var unprovenHolds = (hooks, events) => {
|
|
117
|
+
const table = record(hooks);
|
|
118
|
+
if (!table) return [];
|
|
119
|
+
return events.filter((event) => registeredHooks(table[event], "nested", "seconds").some((hook) => pusharyHookExecutable(hook.command) !== null && hookCommandHoldBudget(hook.command) === void 0));
|
|
120
|
+
};
|
|
121
|
+
var claudeUnprovenHolds = (settings) => unprovenHolds(record(settings)?.hooks, holdEvents(CLAUDE_HOOK_EVENTS));
|
|
122
|
+
var codexUnprovenHolds = (hooks) => unprovenHolds(record(hooks)?.hooks, holdEvents(CODEX_HOOK_EVENTS));
|
|
114
123
|
var holdsLong = (holder) => holder.timeoutSeconds !== null && holder.timeoutSeconds > LONG_HOLD_SECONDS;
|
|
115
124
|
var SHELLS = /* @__PURE__ */ new Set(["/bin/sh", "/bin/bash", "/bin/zsh", "/usr/bin/env"]);
|
|
116
125
|
var holderExecutable = (command) => {
|
|
@@ -139,6 +148,8 @@ export {
|
|
|
139
148
|
codexOtherHolders,
|
|
140
149
|
geminiOtherHolders,
|
|
141
150
|
cursorOtherHolders,
|
|
151
|
+
claudeUnprovenHolds,
|
|
152
|
+
codexUnprovenHolds,
|
|
142
153
|
holdsLong,
|
|
143
154
|
describeOtherHolder,
|
|
144
155
|
describeHoldSentence
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "./chunk-7QLSKOSU.js";
|
|
7
7
|
import {
|
|
8
8
|
isValidApiKey
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-HUZW6SEO.js";
|
|
10
10
|
|
|
11
11
|
// src/setup/options.ts
|
|
12
12
|
var AGENT_CHOICES = ["claude_code", "codex", "gemini_cli", "hermes", "cursor", "vscode", "opencode", "custom"];
|
|
@@ -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 = "The user approved this command from Pushary after the auto-reviewer denied it.";
|
|
1401
|
+
var codexRescueRetryInstruction = (command) => command.length <= CODEX_RESCUE_COMMAND_MAX_LENGTH ? `Run it again exactly as before, unchanged: ${command}` : `Run it again exactly as before, unchanged. 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,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NOTIFICATION_MATCHED_TYPES,
|
|
3
|
-
POSTTOOLUSE_MIRRORED_TOOLS
|
|
4
|
-
|
|
5
|
-
} from "./chunk-XUTSZYYJ.js";
|
|
3
|
+
POSTTOOLUSE_MIRRORED_TOOLS
|
|
4
|
+
} from "./chunk-QFAZ6QCT.js";
|
|
6
5
|
import {
|
|
7
6
|
isProtectedByScope
|
|
8
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-67RNDRKL.js";
|
|
9
8
|
import {
|
|
9
|
+
CLAUDE_PRETOOLUSE_MATCHER,
|
|
10
10
|
HOOK_BUDGETS,
|
|
11
|
-
HOOK_LOCATOR_BINARY
|
|
12
|
-
|
|
13
|
-
} from "./chunk-MC5WUOJJ.js";
|
|
11
|
+
HOOK_LOCATOR_BINARY
|
|
12
|
+
} from "./chunk-HUZW6SEO.js";
|
|
14
13
|
|
|
15
14
|
// src/gemini-config.ts
|
|
16
15
|
var GEMINI_HOOK_BINARY = "pushary-gemini-hook";
|
|
@@ -128,12 +127,11 @@ var atLeast = (version, floor) => compareVersion(version, floor) >= 0;
|
|
|
128
127
|
var formatVersion = (version) => version.join(".");
|
|
129
128
|
|
|
130
129
|
// src/claude-events.ts
|
|
131
|
-
var GATED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, ...PRETOOLUSE_PHONE_ANSWERED_TOOLS].join("|");
|
|
132
130
|
var MIRRORED_TOOLS = POSTTOOLUSE_MIRRORED_TOOLS.join("|");
|
|
133
131
|
var ESTABLISHED = [1, 0, 0];
|
|
134
132
|
var OBSERVED = [2, 0, 0];
|
|
135
133
|
var CLAUDE_HOOK_EVENTS = [
|
|
136
|
-
{ event: "PreToolUse", binary: "pushary-hook", matcher:
|
|
134
|
+
{ event: "PreToolUse", binary: "pushary-hook", matcher: CLAUDE_PRETOOLUSE_MATCHER, timeout: HOOK_BUDGETS.claude.budgetSeconds, delivery: "approval", since: ESTABLISHED },
|
|
137
135
|
{ event: "PostToolUse", binary: "pushary-post-hook", matcher: MIRRORED_TOOLS, timeout: 10, delivery: "telemetry", since: ESTABLISHED },
|
|
138
136
|
{ event: "Stop", binary: "pushary-stop-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
|
|
139
137
|
{ event: "UserPromptSubmit", binary: "pushary-prompt-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
|
|
@@ -142,7 +140,7 @@ var CLAUDE_HOOK_EVENTS = [
|
|
|
142
140
|
{ event: "SessionEnd", binary: "pushary-session-end-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
|
|
143
141
|
{ event: "StopFailure", binary: "pushary-stopfailure-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
|
|
144
142
|
{ event: "PermissionRequest", binary: "pushary-permission-hook", timeout: HOOK_BUDGETS.claude.budgetSeconds, delivery: "approval", since: ESTABLISHED },
|
|
145
|
-
{ event: "PermissionDenied", binary: "pushary-permission-denied-hook", timeout:
|
|
143
|
+
{ event: "PermissionDenied", binary: "pushary-permission-denied-hook", timeout: HOOK_BUDGETS.claude.budgetSeconds, delivery: "approval", holds: true, since: ESTABLISHED },
|
|
146
144
|
// Observability only. Each carries session shape the island cannot get any other
|
|
147
145
|
// way, and none of them decides anything.
|
|
148
146
|
{ event: "SubagentStart", binary: "pushary-session-start-hook", timeout: 10, delivery: "telemetry", since: OBSERVED },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SETUP_FLAGS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-H4VNAOCG.js";
|
|
4
4
|
import {
|
|
5
5
|
parseFlags
|
|
6
6
|
} from "./chunk-GMXKITVA.js";
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
CLAUDE_CONNECTOR_URL,
|
|
15
15
|
COWORK_CONNECTOR_LIMIT,
|
|
16
16
|
COWORK_STANDING_INSTRUCTIONS
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-HUZW6SEO.js";
|
|
18
18
|
|
|
19
19
|
// src/cli/cowork.ts
|
|
20
20
|
import { readFileSync } from "fs";
|
|
@@ -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
|
};
|
|
@@ -2,27 +2,25 @@ import {
|
|
|
2
2
|
needsShell,
|
|
3
3
|
spawnClaude
|
|
4
4
|
} from "./chunk-XHKBHWLX.js";
|
|
5
|
-
import {
|
|
6
|
-
resolveGlobalBinary
|
|
7
|
-
} from "./chunk-L4ZCFMWW.js";
|
|
8
5
|
import {
|
|
9
6
|
getMachineId
|
|
10
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-IZKCA35M.js";
|
|
11
8
|
import {
|
|
12
|
-
pusharyDir
|
|
13
|
-
|
|
9
|
+
pusharyDir,
|
|
10
|
+
resolveGlobalBinary
|
|
11
|
+
} from "./chunk-67RNDRKL.js";
|
|
14
12
|
import {
|
|
15
13
|
getPackageVersion
|
|
16
14
|
} from "./chunk-DINDL2CF.js";
|
|
17
15
|
import {
|
|
18
16
|
readControlMode
|
|
19
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-VF7YOT2W.js";
|
|
20
18
|
import {
|
|
21
19
|
readJsonSafe,
|
|
22
20
|
writeFileAtomic,
|
|
23
21
|
writeJsonAtomic,
|
|
24
22
|
writeJsonAtomicDurable
|
|
25
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-VTUN7WSG.js";
|
|
26
24
|
import {
|
|
27
25
|
getApiKey
|
|
28
26
|
} from "./chunk-2UMNXADU.js";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HOOK_HOLD_BUDGET_ENV,
|
|
3
|
+
hookHoldBudgetProof
|
|
4
|
+
} from "./chunk-HUZW6SEO.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
|
+
};
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ASKED_IN_EVERY_MODE_TOOLS,
|
|
3
2
|
PRETOOLUSE_GATED_TOOLS
|
|
4
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-HUZW6SEO.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,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
isValidApiKey,
|
|
15
15
|
normalizeKeyScope
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-HUZW6SEO.js";
|
|
17
17
|
|
|
18
18
|
// src/session.ts
|
|
19
19
|
var samePusharyAccount = (left, right) => left.kind === "ok" && right.kind === "ok" && left.identity.workspaceId !== "" && left.identity.workspaceId === right.identity.workspaceId && left.identity.siteId === right.identity.siteId;
|