@pushary/agent-hooks 1.4.1 → 1.5.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 +20 -0
- package/README.md +27 -0
- package/data/vscode-plugin/README.md +1 -1
- package/data/vscode-plugin/scripts/pushary-gate.mjs +2 -2
- package/dist/bin/pushary-bell-hook.js +22 -21
- package/dist/bin/pushary-bell.js +10 -10
- package/dist/bin/pushary-claude.js +28 -24
- package/dist/bin/pushary-clean.js +30 -26
- package/dist/bin/pushary-codex-bridge.js +16 -14
- package/dist/bin/pushary-codex-hook.js +41 -31
- package/dist/bin/pushary-codex.js +15 -10
- package/dist/bin/pushary-connect.js +11 -11
- package/dist/bin/pushary-cowork.js +6 -6
- package/dist/bin/pushary-daemon.js +31 -28
- package/dist/bin/pushary-disconnect.js +16 -16
- package/dist/bin/pushary-doctor.js +81 -38
- package/dist/bin/pushary-elicitation-hook.js +23 -22
- package/dist/bin/pushary-gemini-bridge.js +13 -11
- package/dist/bin/pushary-gemini-hook.js +29 -24
- package/dist/bin/pushary-hook.js +30 -30
- package/dist/bin/pushary-login.js +14 -14
- package/dist/bin/pushary-logout.js +8 -8
- package/dist/bin/pushary-mode.js +7 -7
- package/dist/bin/pushary-notification-hook.js +26 -25
- package/dist/bin/pushary-opencode-hook.js +25 -24
- package/dist/bin/pushary-permission-denied-hook.js +30 -29
- package/dist/bin/pushary-permission-hook.js +29 -28
- package/dist/bin/pushary-post-hook.js +26 -25
- package/dist/bin/pushary-prompt-hook.js +26 -25
- package/dist/bin/pushary-session-end-hook.js +26 -25
- package/dist/bin/pushary-session-start-hook.js +32 -27
- package/dist/bin/pushary-setup.js +85 -59
- package/dist/bin/pushary-stats.js +6 -6
- package/dist/bin/pushary-status.js +15 -15
- package/dist/bin/pushary-stop-hook.js +26 -25
- package/dist/bin/pushary-stopfailure-hook.js +26 -25
- package/dist/bin/pushary-suggestions.js +4 -4
- package/dist/bin/pushary-transcript-register.js +20 -19
- package/dist/bin/pushary-transcripts.js +8 -8
- package/dist/bin/pushary-upgrade.js +231 -37
- package/dist/bin/pushary-wait.js +7 -7
- package/dist/bin/pushary.js +8 -8
- package/dist/{chunk-MN3XOVRK.js → chunk-2QT3GCU4.js} +1 -1
- package/dist/{chunk-LUT2EZLG.js → chunk-3NBODGQS.js} +1 -1
- package/dist/{chunk-43JKGLZZ.js → chunk-3ZSGKLSO.js} +2 -2
- package/dist/{chunk-QBS6LGEK.js → chunk-43LJSM4F.js} +2 -2
- package/dist/{chunk-SWFF5U2N.js → chunk-43ZDACBO.js} +1 -1
- package/dist/{chunk-HK3IXIQJ.js → chunk-5HYNICS7.js} +1 -1
- package/dist/{chunk-EQRS3SGM.js → chunk-66H2QQAK.js} +1 -1
- package/dist/{chunk-3BPB2HYZ.js → chunk-7XT76LWT.js} +7 -7
- package/dist/{chunk-ALFT7H5B.js → chunk-CQYHOHOK.js} +56 -5
- package/dist/{chunk-3UA6FPRC.js → chunk-DLJN5XEU.js} +3 -3
- package/dist/{chunk-BZBUPZC6.js → chunk-DTQNDR7C.js} +1 -1
- package/dist/{chunk-SAF6NNXY.js → chunk-DYHXOXUF.js} +43 -6
- package/dist/{chunk-FAH3D74E.js → chunk-EA3IELHP.js} +6 -0
- package/dist/{chunk-ED5TA2FJ.js → chunk-EADZPVYW.js} +3 -3
- package/dist/{chunk-I6HRQOMT.js → chunk-F57RGL7K.js} +8 -8
- package/dist/{chunk-LNGYW6G4.js → chunk-FDHMNT24.js} +20 -16
- package/dist/{chunk-37VLIYLI.js → chunk-H5LHTC5X.js} +1 -1
- package/dist/{chunk-EYRGBYZG.js → chunk-HETOKNIL.js} +1 -1
- package/dist/{chunk-K6I5M2ME.js → chunk-HU5LSYL2.js} +2 -2
- package/dist/{chunk-SKXLIVFM.js → chunk-HVBF35GT.js} +2 -2
- package/dist/{chunk-DINDL2CF.js → chunk-HWJW3CPO.js} +25 -5
- package/dist/{chunk-GOFDGTEI.js → chunk-IYTQ4B5I.js} +18 -45
- package/dist/{chunk-WIOXWUUH.js → chunk-J4J45VPZ.js} +3 -3
- package/dist/{chunk-HQLAZWJJ.js → chunk-JF736N4C.js} +5 -5
- package/dist/{chunk-LYXX5NSB.js → chunk-K3QVDAZW.js} +1 -1
- package/dist/{chunk-KI36MAT6.js → chunk-KEOLNHR3.js} +2 -2
- package/dist/{chunk-S3EP4B35.js → chunk-KJRALILH.js} +28 -11
- package/dist/{chunk-PHHGHHOW.js → chunk-MYP4UUFH.js} +1 -1
- package/dist/{chunk-TNS3YLFE.js → chunk-NFKVRMTM.js} +8 -8
- package/dist/{chunk-TF4IOINR.js → chunk-NTQSICPJ.js} +3 -3
- package/dist/{chunk-4FN6VV56.js → chunk-ORLJNJEO.js} +2 -2
- package/dist/{chunk-2UMNXADU.js → chunk-OSJEMXSR.js} +5 -1
- package/dist/chunk-OSSDK5RS.js +162 -0
- package/dist/{chunk-TWWLVOPB.js → chunk-P4BNYJ5Q.js} +5 -5
- package/dist/{chunk-KEMEBTCJ.js → chunk-PCGZXWGQ.js} +4 -4
- package/dist/{chunk-2GMI6JH6.js → chunk-PNNBMH4E.js} +5 -5
- package/dist/{chunk-LGXUGYUH.js → chunk-PYCQXCI5.js} +2 -2
- package/dist/{chunk-JOVWYVSR.js → chunk-SOCEY746.js} +1 -1
- package/dist/{chunk-FVKFDTN6.js → chunk-T4QY64OR.js} +19 -14
- package/dist/{chunk-R3AMKNIW.js → chunk-TFKBFQCE.js} +1 -1
- package/dist/{chunk-CRNAXFQ6.js → chunk-TIWURSLS.js} +1 -1
- package/dist/{chunk-VYUDGQM7.js → chunk-TUXFIVOH.js} +1 -1
- package/dist/{chunk-3T52B2OF.js → chunk-UQHUUZ5H.js} +1 -1
- package/dist/{chunk-TI3ZWXZG.js → chunk-USQDVBEV.js} +2 -2
- package/dist/{chunk-WEO5JCB4.js → chunk-UYDTFCHW.js} +1 -1
- package/dist/{chunk-D7ERHWYB.js → chunk-XWEONSLV.js} +1 -1
- package/dist/{chunk-GKIUEIDX.js → chunk-YQMFGWBD.js} +1 -1
- package/dist/{reapply-BAWDJTG7.js → reapply-D2TFN6XK.js} +9 -8
- package/dist/src/index.js +18 -16
- package/package.json +1 -1
|
@@ -1,17 +1,67 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
AUTO_DECISION_WINDOW_MS,
|
|
3
|
+
DEFAULT_SESSION,
|
|
4
|
+
canonicalGateInputs,
|
|
5
|
+
claimThrottle,
|
|
6
|
+
deriveToolTarget,
|
|
7
|
+
permissionDeniedAction,
|
|
8
|
+
releaseThrottle,
|
|
9
|
+
reportEvent
|
|
10
|
+
} from "./chunk-FDHMNT24.js";
|
|
4
11
|
import {
|
|
5
12
|
canonicalJson
|
|
6
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-DYHXOXUF.js";
|
|
7
14
|
import {
|
|
8
15
|
writeFileAtomic
|
|
9
16
|
} from "./chunk-T7E75EKA.js";
|
|
10
17
|
import {
|
|
11
18
|
BLOCKED_ACTION_GRANT_TTL_SECONDS,
|
|
12
19
|
blockedActionIdentity,
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
machineDecisionFor,
|
|
21
|
+
shouldDeferToNativeMode,
|
|
22
|
+
wireVerdictFor
|
|
23
|
+
} from "./chunk-T4QY64OR.js";
|
|
24
|
+
|
|
25
|
+
// src/machine-decision-audit.ts
|
|
26
|
+
import { basename } from "path";
|
|
27
|
+
var reportMachineDenial = async (input, verdict, agent) => {
|
|
28
|
+
const decision = machineDecisionFor(wireVerdictFor(verdict, 0));
|
|
29
|
+
if (!decision) return;
|
|
30
|
+
const sessionKey = input.session_id || DEFAULT_SESSION;
|
|
31
|
+
const toolTarget = deriveToolTarget(input.tool_name, input.tool_input);
|
|
32
|
+
const throttleKey = `machinedecision:${agent.type}:${sessionKey}:${input.tool_name}:${decision.origin}:${toolTarget ?? ""}`;
|
|
33
|
+
const throttle = claimThrottle(throttleKey, AUTO_DECISION_WINDOW_MS);
|
|
34
|
+
if (throttle === "throttled") return;
|
|
35
|
+
if (throttle === "unavailable") {
|
|
36
|
+
console.error("[Pushary] Could not access the audit throttle; reporting this denial without deduplication.");
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const response = await reportEvent({
|
|
40
|
+
event: "permission_denied",
|
|
41
|
+
occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
42
|
+
toolUseId: input.tool_use_id,
|
|
43
|
+
agentType: agent.type,
|
|
44
|
+
agentName: `${agent.label} - ${basename(input.cwd ?? process.cwd())}`,
|
|
45
|
+
action: permissionDeniedAction(input.tool_name),
|
|
46
|
+
sessionId: input.session_id,
|
|
47
|
+
decisionSource: "policy_auto",
|
|
48
|
+
decisionOrigin: decision.origin,
|
|
49
|
+
decisionOutcome: decision.outcome,
|
|
50
|
+
toolName: input.tool_name,
|
|
51
|
+
toolTarget
|
|
52
|
+
}, { maxAttempts: 1, timeoutMs: 800, requireOk: true, skipDrain: true });
|
|
53
|
+
if (response?.ok !== true) throw new Error("Audit delivery was not acknowledged");
|
|
54
|
+
} catch {
|
|
55
|
+
console.error("[Pushary] Could not record the machine denial. The action remains blocked; its audit delivery will be retried on the next matching denial.");
|
|
56
|
+
if (throttle === "passed") {
|
|
57
|
+
try {
|
|
58
|
+
releaseThrottle(throttleKey);
|
|
59
|
+
} catch {
|
|
60
|
+
console.error("[Pushary] Could not reset the failed audit throttle.");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
15
65
|
|
|
16
66
|
// src/native-defer.ts
|
|
17
67
|
var nativeDeferOptions = () => {
|
|
@@ -190,6 +240,7 @@ var forgetBlockedActionHint = (fingerprint) => {
|
|
|
190
240
|
};
|
|
191
241
|
|
|
192
242
|
export {
|
|
243
|
+
reportMachineDenial,
|
|
193
244
|
defersToNativeMode,
|
|
194
245
|
userScope,
|
|
195
246
|
codexCallKey,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
openCodeConfigDirFrom
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TUXFIVOH.js";
|
|
4
4
|
import {
|
|
5
5
|
codexHomeFrom
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-DYHXOXUF.js";
|
|
7
7
|
import {
|
|
8
8
|
HOOK_COMPATIBLE_PROFILES
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-T4QY64OR.js";
|
|
10
10
|
|
|
11
11
|
// src/vscode-config.ts
|
|
12
12
|
import { homedir } from "os";
|
|
@@ -2,12 +2,19 @@ import {
|
|
|
2
2
|
HOOK_BUDGETS,
|
|
3
3
|
HOOK_LOCATOR_BINARY,
|
|
4
4
|
withHookHoldBudget
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-T4QY64OR.js";
|
|
6
|
+
import {
|
|
7
|
+
isReleaseVersion
|
|
8
|
+
} from "./chunk-HWJW3CPO.js";
|
|
6
9
|
|
|
7
10
|
// src/npm.ts
|
|
8
11
|
import { execFileSync, execSync } from "child_process";
|
|
9
12
|
import { existsSync, readFileSync, realpathSync } from "fs";
|
|
10
13
|
import { dirname, isAbsolute, join, relative, resolve } from "path";
|
|
14
|
+
var AGENT_HOOKS_PACKAGE = "@pushary/agent-hooks";
|
|
15
|
+
var LATEST_RELEASE_URL = `https://registry.npmjs.org/${AGENT_HOOKS_PACKAGE}/latest`;
|
|
16
|
+
var REGISTRY_TIMEOUT_MS = 5e3;
|
|
17
|
+
var LATEST_TAG = "latest";
|
|
11
18
|
var cleanNpmEnv = () => {
|
|
12
19
|
const env = {};
|
|
13
20
|
for (const [key, value] of Object.entries(process.env)) {
|
|
@@ -16,10 +23,11 @@ var cleanNpmEnv = () => {
|
|
|
16
23
|
}
|
|
17
24
|
return env;
|
|
18
25
|
};
|
|
26
|
+
var NPM_ERROR_METADATA = /^(code|syscall|path|dest|errno)\s/i;
|
|
19
27
|
var npmErrorMessage = (err) => {
|
|
20
28
|
const e = err;
|
|
21
29
|
const text = [e?.stderr, e?.stdout].map((part) => part ? part.toString() : "").join("\n");
|
|
22
|
-
const line = text.split("\n").map((l) => l.replace(/^npm error\s*/i, "").trim()).find((l) => l && !l.startsWith("A complete log") &&
|
|
30
|
+
const line = text.split("\n").map((l) => l.replace(/^npm error\s*/i, "").trim()).find((l) => l && !l.startsWith("A complete log") && !NPM_ERROR_METADATA.test(l));
|
|
23
31
|
return line || e?.message || String(err);
|
|
24
32
|
};
|
|
25
33
|
var execNpm = (args, options = {}) => {
|
|
@@ -143,6 +151,26 @@ var resolveGlobalBinDir = (probe) => {
|
|
|
143
151
|
return resolved ? resolved.slice(0, resolved.length - probe.length - 1) : void 0;
|
|
144
152
|
};
|
|
145
153
|
var quoteIfNeeded = (path) => /\s/.test(path) ? `"${path}"` : path;
|
|
154
|
+
var fetchLatestPublishedVersion = async (request = {}) => {
|
|
155
|
+
try {
|
|
156
|
+
const response = await (request.fetchImpl ?? fetch)(LATEST_RELEASE_URL, {
|
|
157
|
+
signal: AbortSignal.timeout(request.timeoutMs ?? REGISTRY_TIMEOUT_MS)
|
|
158
|
+
});
|
|
159
|
+
if (!response.ok) return void 0;
|
|
160
|
+
const body = await response.json();
|
|
161
|
+
const version = body && typeof body === "object" && "version" in body ? body.version : void 0;
|
|
162
|
+
return typeof version === "string" && isReleaseVersion(version) ? version : void 0;
|
|
163
|
+
} catch {
|
|
164
|
+
return void 0;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
var POSIX_SHELL_WORD = /^[\w@%+=:,./-]+$/;
|
|
168
|
+
var quoteForPosixShell = (value) => POSIX_SHELL_WORD.test(value) ? value : `'${value.replaceAll("'", `'\\''`)}'`;
|
|
169
|
+
var installAgentHooksGlobally = (request, runNpm = execNpm) => {
|
|
170
|
+
const prefixFlag = request.prefix === void 0 ? "" : ` --prefix ${quoteForPosixShell(request.prefix)}`;
|
|
171
|
+
const spec = quoteForPosixShell(`${AGENT_HOOKS_PACKAGE}@${request.version}`);
|
|
172
|
+
runNpm(`install -g --no-workspaces${prefixFlag} ${spec}`, { timeout: request.timeoutMs });
|
|
173
|
+
};
|
|
146
174
|
var needsGlobalInstall = (requested, installed, binaryPresent) => requested !== installed || !binaryPresent;
|
|
147
175
|
var installState;
|
|
148
176
|
var installGlobally = (options) => {
|
|
@@ -153,13 +181,13 @@ var installGlobally = (options) => {
|
|
|
153
181
|
const pinned = process.env.PUSHARY_PIN_GLOBAL_VERSION !== "0";
|
|
154
182
|
if (pinned && !needsGlobalInstall(
|
|
155
183
|
options.version,
|
|
156
|
-
resolveGlobalPackageVersion(
|
|
157
|
-
globalPackageBinsPresent(
|
|
184
|
+
resolveGlobalPackageVersion(AGENT_HOOKS_PACKAGE),
|
|
185
|
+
globalPackageBinsPresent(AGENT_HOOKS_PACKAGE)
|
|
158
186
|
)) {
|
|
159
187
|
return "skipped";
|
|
160
188
|
}
|
|
161
|
-
const
|
|
162
|
-
|
|
189
|
+
const version = pinned && options.version && options.version !== "0.0.0" ? options.version : LATEST_TAG;
|
|
190
|
+
installAgentHooksGlobally({ version, timeoutMs: options.timeoutMs ?? 12e4 });
|
|
163
191
|
return "installed";
|
|
164
192
|
})();
|
|
165
193
|
installState = started;
|
|
@@ -609,6 +637,9 @@ var claudeSettingsLocal = () => join3(homedir2(), ".claude", "settings.local.jso
|
|
|
609
637
|
var pusharyDir = () => join3(homedir2(), ".pushary");
|
|
610
638
|
var claudeMcpReceipt = () => join3(pusharyDir(), "setup", "claude-mcp.json");
|
|
611
639
|
var bridgeAgentKey = () => join3(pusharyDir(), "bridge-auth", "agent-key.json");
|
|
640
|
+
var autoUpdateState = () => join3(pusharyDir(), "auto-update.json");
|
|
641
|
+
var autoUpdateLock = () => join3(pusharyDir(), "auto-update.lock");
|
|
642
|
+
var autoUpdateLog = () => join3(pusharyDir(), "logs", "auto-update.log");
|
|
612
643
|
var claudeRegistrationReceipt = () => join3(pusharyDir(), "setup", "claude-registration.json");
|
|
613
644
|
var hermesConfigReceipt = () => join3(pusharyDir(), "setup", "hermes-config.json");
|
|
614
645
|
var hookTakeoverReceipt = (agent) => join3(pusharyDir(), "setup", `hook-takeover-${agent}.json`);
|
|
@@ -622,6 +653,7 @@ export {
|
|
|
622
653
|
registeredCommands,
|
|
623
654
|
namesOurBinary,
|
|
624
655
|
registrationHolderOf,
|
|
656
|
+
LATEST_TAG,
|
|
625
657
|
npmErrorMessage,
|
|
626
658
|
execNpm,
|
|
627
659
|
resolveGlobalBinary,
|
|
@@ -630,6 +662,8 @@ export {
|
|
|
630
662
|
resolvePackageVersionFromBinary,
|
|
631
663
|
resolveGlobalPackageVersion,
|
|
632
664
|
resolveGlobalBinDir,
|
|
665
|
+
fetchLatestPublishedVersion,
|
|
666
|
+
installAgentHooksGlobally,
|
|
633
667
|
installGlobally,
|
|
634
668
|
holdBudgetOf,
|
|
635
669
|
guardBinary,
|
|
@@ -675,6 +709,9 @@ export {
|
|
|
675
709
|
pusharyDir,
|
|
676
710
|
claudeMcpReceipt,
|
|
677
711
|
bridgeAgentKey,
|
|
712
|
+
autoUpdateState,
|
|
713
|
+
autoUpdateLock,
|
|
714
|
+
autoUpdateLog,
|
|
678
715
|
claudeRegistrationReceipt,
|
|
679
716
|
hermesConfigReceipt,
|
|
680
717
|
hookTakeoverReceipt,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/cli/commands.ts
|
|
2
|
+
var NPX_LATEST_COMMAND = "npx @pushary/agent-hooks@latest";
|
|
2
3
|
var COMMAND_LIST = [
|
|
3
4
|
{
|
|
4
5
|
name: "cowork",
|
|
@@ -132,6 +133,10 @@ var COMMAND_OPTIONS = {
|
|
|
132
133
|
["--bundle", "Write a redacted diagnostics file you can attach to a support thread"]
|
|
133
134
|
],
|
|
134
135
|
suggestions: [["accept <id>", "Turn a mined suggestion into an always-allow rule"]],
|
|
136
|
+
upgrade: [
|
|
137
|
+
["--auto=off", "Stop Pushary updating itself in the background"],
|
|
138
|
+
["--auto=on", "Update in the background again: once a day at session start, within the same major version"]
|
|
139
|
+
],
|
|
135
140
|
bell: [
|
|
136
141
|
["(no flags)", "Turn the bell on for Claude Code"],
|
|
137
142
|
["--test", "Ring once, now, so you can hear what it does"],
|
|
@@ -232,6 +237,7 @@ var renderCommandHelp = (name, version) => {
|
|
|
232
237
|
};
|
|
233
238
|
|
|
234
239
|
export {
|
|
240
|
+
NPX_LATEST_COMMAND,
|
|
235
241
|
COMMANDS,
|
|
236
242
|
isCommandName,
|
|
237
243
|
renderHelp,
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NOTIFICATION_MATCHED_TYPES,
|
|
3
3
|
POSTTOOLUSE_MIRRORED_TOOLS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UYDTFCHW.js";
|
|
5
5
|
import {
|
|
6
6
|
isProtectedByScope,
|
|
7
7
|
registerHookEntry
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-DYHXOXUF.js";
|
|
9
9
|
import {
|
|
10
10
|
CLAUDE_PRETOOLUSE_MATCHER,
|
|
11
11
|
HOOK_BUDGETS,
|
|
12
12
|
HOOK_LOCATOR_BINARY
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-T4QY64OR.js";
|
|
14
14
|
|
|
15
15
|
// src/gemini-config.ts
|
|
16
16
|
var GEMINI_HOOK_BINARY = "pushary-gemini-hook";
|
|
@@ -2,27 +2,27 @@ import {
|
|
|
2
2
|
detectProviderLiveCapabilities,
|
|
3
3
|
hasSpawnProvider,
|
|
4
4
|
resolveControlPolicy
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-KEOLNHR3.js";
|
|
6
6
|
import {
|
|
7
7
|
daemonHasRemoteProof,
|
|
8
8
|
daemonServiceManagerAvailable,
|
|
9
9
|
hasDaemonServiceDefinition,
|
|
10
10
|
readDaemonNeedsLogin,
|
|
11
11
|
readDaemonStatus
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-7XT76LWT.js";
|
|
13
13
|
import {
|
|
14
14
|
getMachineId
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import {
|
|
17
|
-
getPackageVersion
|
|
18
|
-
} from "./chunk-DINDL2CF.js";
|
|
15
|
+
} from "./chunk-UQHUUZ5H.js";
|
|
19
16
|
import {
|
|
20
17
|
readControlMode,
|
|
21
18
|
readKeySource
|
|
22
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-USQDVBEV.js";
|
|
23
20
|
import {
|
|
24
21
|
getBaseUrl
|
|
25
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-OSJEMXSR.js";
|
|
23
|
+
import {
|
|
24
|
+
getPackageVersion
|
|
25
|
+
} from "./chunk-HWJW3CPO.js";
|
|
26
26
|
|
|
27
27
|
// src/machines.ts
|
|
28
28
|
import { hostname } from "os";
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NOTIFICATION_PUSH_TYPES,
|
|
3
3
|
POSTTOOLUSE_MIRROR_ONLY_TOOLS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UYDTFCHW.js";
|
|
5
5
|
import {
|
|
6
6
|
cancelQuestion,
|
|
7
7
|
isPolicyConfig,
|
|
8
8
|
sendNotification,
|
|
9
9
|
waitForAnswer
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PYCQXCI5.js";
|
|
11
11
|
import {
|
|
12
12
|
getMachineId
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-UQHUUZ5H.js";
|
|
14
14
|
import {
|
|
15
15
|
withRetry
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-HETOKNIL.js";
|
|
17
17
|
import {
|
|
18
18
|
reportedInstallSource
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-HU5LSYL2.js";
|
|
20
20
|
import {
|
|
21
21
|
getApiKey,
|
|
22
22
|
getBaseUrl
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-OSJEMXSR.js";
|
|
24
24
|
import {
|
|
25
25
|
ACTION_BODY_MAX,
|
|
26
26
|
AGENT_LABELS_BY_TYPE,
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
resolveAutoResolveOrigin,
|
|
45
45
|
resolvePolicy,
|
|
46
46
|
toToolLookup
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-T4QY64OR.js";
|
|
48
48
|
|
|
49
49
|
// src/policy.ts
|
|
50
50
|
import { createHash } from "crypto";
|
|
@@ -1368,20 +1368,23 @@ var phoneDrivenEnv = (base) => ({
|
|
|
1368
1368
|
import { join as join5 } from "path";
|
|
1369
1369
|
import { tmpdir as tmpdir4 } from "os";
|
|
1370
1370
|
import { createHash as createHash4 } from "crypto";
|
|
1371
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync3, statSync as statSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1371
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, statSync as statSync4, writeFileSync as writeFileSync4, rmSync as rmSync2 } from "fs";
|
|
1372
1372
|
var THROTTLE_DIR = join5(tmpdir4(), "pushary-throttle");
|
|
1373
1373
|
var markerPath = (key) => join5(THROTTLE_DIR, createHash4("sha256").update(key).digest("hex").slice(0, 16));
|
|
1374
|
-
var
|
|
1374
|
+
var claimThrottle = (key, windowMs) => {
|
|
1375
1375
|
try {
|
|
1376
1376
|
const path = markerPath(key);
|
|
1377
|
-
if (existsSync4(path) && Date.now() - statSync4(path).mtimeMs < windowMs) return
|
|
1377
|
+
if (existsSync4(path) && Date.now() - statSync4(path).mtimeMs < windowMs) return "throttled";
|
|
1378
1378
|
mkdirSync3(THROTTLE_DIR, { recursive: true });
|
|
1379
1379
|
writeFileSync4(path, "", "utf-8");
|
|
1380
|
-
return
|
|
1380
|
+
return "passed";
|
|
1381
1381
|
} catch {
|
|
1382
|
-
return
|
|
1382
|
+
return "unavailable";
|
|
1383
1383
|
}
|
|
1384
1384
|
};
|
|
1385
|
+
var releaseThrottle = (key) => {
|
|
1386
|
+
rmSync2(markerPath(key), { force: true });
|
|
1387
|
+
};
|
|
1385
1388
|
|
|
1386
1389
|
// src/events.ts
|
|
1387
1390
|
import { basename as basename3, join as join6 } from "path";
|
|
@@ -1688,7 +1691,7 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
1688
1691
|
}
|
|
1689
1692
|
const isMirrorOnly = NON_GATED_MIRROR_TOOLS.has(input.tool_name);
|
|
1690
1693
|
const decisionSource = isMirrorOnly ? void 0 : deriveDecisionSource(lookup.tool, lookup.input, liveMode, agent.type, input.cwd, input.session_id);
|
|
1691
|
-
const beacon = !isMirrorOnly && decisionSource === "policy_auto" &&
|
|
1694
|
+
const beacon = !isMirrorOnly && decisionSource === "policy_auto" && claimThrottle(`autodecision:${sessionKey}:${lookup.tool}`, AUTO_DECISION_WINDOW_MS) === "passed" ? deriveAutoDecisionBeacon(lookup.tool, lookup.input, liveMode, agent.type, input.cwd, input.session_id) : void 0;
|
|
1692
1695
|
const toolReport = reportEvent({
|
|
1693
1696
|
event: isError ? "tool_error" : "tool_complete",
|
|
1694
1697
|
occurredAt,
|
|
@@ -1704,7 +1707,7 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
1704
1707
|
usage: deriveUsage(input.transcript_path, input.session_id)
|
|
1705
1708
|
}, { maxAttempts: 1, budgetMs: Math.min(DRAINING_REPORT_BUDGET_MS, Math.max(0, deadline - Date.now())), signal });
|
|
1706
1709
|
const extraReports = [];
|
|
1707
|
-
if (
|
|
1710
|
+
if (claimThrottle(`hookactive:${sessionKey}`, HOOK_ACTIVE_WINDOW_MS) === "passed") {
|
|
1708
1711
|
extraReports.push(
|
|
1709
1712
|
reportEvent(
|
|
1710
1713
|
{
|
|
@@ -1898,7 +1901,7 @@ var handleNotification = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
1898
1901
|
}, { maxAttempts: 1, timeoutMs: 2500, signal }).catch(() => {
|
|
1899
1902
|
});
|
|
1900
1903
|
if (!teammateIdle && NOTIFICATION_PUSH_TYPES.has(notifType)) {
|
|
1901
|
-
if (
|
|
1904
|
+
if (claimThrottle(`notify:${sessionKey}:${notifType}`, NOTIFICATION_THROTTLE_MS) !== "passed") return;
|
|
1902
1905
|
let apiKey;
|
|
1903
1906
|
try {
|
|
1904
1907
|
apiKey = getApiKey();
|
|
@@ -1990,7 +1993,8 @@ export {
|
|
|
1990
1993
|
markPendingCommandFailed,
|
|
1991
1994
|
removePendingCommand,
|
|
1992
1995
|
repoKeyFor,
|
|
1993
|
-
|
|
1996
|
+
claimThrottle,
|
|
1997
|
+
releaseThrottle,
|
|
1994
1998
|
readLastUserPrompt,
|
|
1995
1999
|
CODEX_AGENT,
|
|
1996
2000
|
codexAllow,
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
decodePublicKey,
|
|
4
4
|
generateSessionKey,
|
|
5
5
|
wrapSessionKey
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-TIWURSLS.js";
|
|
7
7
|
import {
|
|
8
8
|
fetchTranscriptRecipients,
|
|
9
9
|
uploadTranscriptRecords
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-66H2QQAK.js";
|
|
11
11
|
|
|
12
12
|
// src/live-session.ts
|
|
13
13
|
var MAX_TRANSCRIPT_QUEUE = 100;
|
|
@@ -3,6 +3,7 @@ import { readFileSync } from "fs";
|
|
|
3
3
|
import { dirname, join, parse } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
var PACKAGE_NAME = "@pushary/agent-hooks";
|
|
6
|
+
var UNKNOWN_VERSION = "0.0.0";
|
|
6
7
|
var findOwnPackageJson = (start) => {
|
|
7
8
|
const { root } = parse(start);
|
|
8
9
|
let dir = start;
|
|
@@ -20,13 +21,24 @@ var findOwnPackageJson = (start) => {
|
|
|
20
21
|
}
|
|
21
22
|
};
|
|
22
23
|
var getPackageVersion = () => {
|
|
24
|
+
const root = ownPackageRoot();
|
|
25
|
+
return (root === void 0 ? void 0 : packageVersionAt(root)) ?? UNKNOWN_VERSION;
|
|
26
|
+
};
|
|
27
|
+
var ownPackageRoot = () => {
|
|
23
28
|
try {
|
|
24
29
|
const found = findOwnPackageJson(dirname(fileURLToPath(import.meta.url)));
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return
|
|
30
|
+
return found ? dirname(found) : void 0;
|
|
31
|
+
} catch {
|
|
32
|
+
return void 0;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var packageVersionAt = (packageRoot) => {
|
|
36
|
+
try {
|
|
37
|
+
const manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf-8"));
|
|
38
|
+
const version = manifest && typeof manifest === "object" && "version" in manifest ? manifest.version : void 0;
|
|
39
|
+
return typeof version === "string" ? version : void 0;
|
|
28
40
|
} catch {
|
|
29
|
-
return
|
|
41
|
+
return void 0;
|
|
30
42
|
}
|
|
31
43
|
};
|
|
32
44
|
var isNewerVersion = (candidate, current) => {
|
|
@@ -38,8 +50,16 @@ var isNewerVersion = (candidate, current) => {
|
|
|
38
50
|
}
|
|
39
51
|
return false;
|
|
40
52
|
};
|
|
53
|
+
var RELEASE_VERSION = /^\d+\.\d+\.\d+$/;
|
|
54
|
+
var isReleaseVersion = (value) => RELEASE_VERSION.test(value);
|
|
55
|
+
var majorOf = (version) => parseInt(version.split(".")[0] ?? "", 10) || 0;
|
|
56
|
+
var isSameMajorVersion = (candidate, current) => majorOf(candidate) === majorOf(current);
|
|
41
57
|
|
|
42
58
|
export {
|
|
43
59
|
getPackageVersion,
|
|
44
|
-
|
|
60
|
+
ownPackageRoot,
|
|
61
|
+
packageVersionAt,
|
|
62
|
+
isNewerVersion,
|
|
63
|
+
isReleaseVersion,
|
|
64
|
+
isSameMajorVersion
|
|
45
65
|
};
|
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
import {
|
|
2
2
|
activeHookSource,
|
|
3
3
|
activeIdentity
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JF736N4C.js";
|
|
5
5
|
import {
|
|
6
6
|
blockedActionFingerprint,
|
|
7
7
|
defersToNativeMode,
|
|
8
8
|
forgetBlockedActionHint,
|
|
9
9
|
hasBlockedActionHint,
|
|
10
|
-
recordBlockedActionHint
|
|
11
|
-
|
|
10
|
+
recordBlockedActionHint,
|
|
11
|
+
reportMachineDenial
|
|
12
|
+
} from "./chunk-CQYHOHOK.js";
|
|
12
13
|
import {
|
|
13
14
|
isGatingMoment,
|
|
14
15
|
recordKeylessMoment
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-43ZDACBO.js";
|
|
16
17
|
import {
|
|
17
18
|
denyReasonFrom,
|
|
18
19
|
isDeferAnswer
|
|
19
20
|
} from "./chunk-YHG74UFF.js";
|
|
20
21
|
import {
|
|
21
|
-
AUTO_DECISION_WINDOW_MS,
|
|
22
22
|
DEFAULT_SESSION,
|
|
23
23
|
UNNAMED_ACTION,
|
|
24
|
+
claimThrottle,
|
|
24
25
|
deriveAction,
|
|
25
26
|
deriveActionBody,
|
|
26
27
|
deriveBlocker,
|
|
@@ -34,9 +35,8 @@ import {
|
|
|
34
35
|
repoKeyFor,
|
|
35
36
|
reportEvent,
|
|
36
37
|
scopePathFor,
|
|
37
|
-
settleQuestionsForToolUse
|
|
38
|
-
|
|
39
|
-
} from "./chunk-LNGYW6G4.js";
|
|
38
|
+
settleQuestionsForToolUse
|
|
39
|
+
} from "./chunk-FDHMNT24.js";
|
|
40
40
|
import {
|
|
41
41
|
DECISION_STOP_REASON,
|
|
42
42
|
askUser,
|
|
@@ -48,14 +48,14 @@ import {
|
|
|
48
48
|
requestGate,
|
|
49
49
|
sendNotification,
|
|
50
50
|
waitForQuestion
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-PYCQXCI5.js";
|
|
52
52
|
import {
|
|
53
53
|
getMachineId
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-UQHUUZ5H.js";
|
|
55
55
|
import {
|
|
56
56
|
getApiKey,
|
|
57
57
|
getBaseUrl
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-OSJEMXSR.js";
|
|
59
59
|
import {
|
|
60
60
|
AGENT_QUESTION_STRATEGY,
|
|
61
61
|
GATE_BLOCK_REASON_MAX_LENGTH,
|
|
@@ -75,13 +75,11 @@ import {
|
|
|
75
75
|
isBlockedActionRequest,
|
|
76
76
|
isPermissionRequestOwnedByPreToolUse,
|
|
77
77
|
isPusharyOwnTool,
|
|
78
|
-
machineDecisionFor,
|
|
79
78
|
parseAgentQuestionAnswers,
|
|
80
79
|
parseAgentQuestions,
|
|
81
80
|
resolveGate,
|
|
82
|
-
stoppedOutput
|
|
83
|
-
|
|
84
|
-
} from "./chunk-FVKFDTN6.js";
|
|
81
|
+
stoppedOutput
|
|
82
|
+
} from "./chunk-T4QY64OR.js";
|
|
85
83
|
|
|
86
84
|
// src/decision-episode.ts
|
|
87
85
|
var EPISODE_PATH = "/api/agent/decision-episode";
|
|
@@ -118,31 +116,6 @@ var deny = (reason) => claudePreToolUseOutput("deny", reason);
|
|
|
118
116
|
var allowWithInput = (updatedInput) => claudePreToolUseOutput("allow", void 0, updatedInput);
|
|
119
117
|
var ask = (reason) => claudePreToolUseOutput("ask", reason);
|
|
120
118
|
var halted = (reason) => stoppedOutput(deny(reason), reason);
|
|
121
|
-
var reportMachineDecision = async (input, verdict) => {
|
|
122
|
-
const decision = machineDecisionFor(wireVerdictFor(verdict, 0));
|
|
123
|
-
if (!decision) return;
|
|
124
|
-
const sessionKey = input.session_id || DEFAULT_SESSION;
|
|
125
|
-
const toolTarget = deriveToolTarget(input.tool_name, input.tool_input);
|
|
126
|
-
const throttleKey = `machinedecision:${sessionKey}:${input.tool_name}:${decision.origin}:${toolTarget ?? ""}`;
|
|
127
|
-
if (!throttlePass(throttleKey, AUTO_DECISION_WINDOW_MS)) return;
|
|
128
|
-
await reportEvent(
|
|
129
|
-
{
|
|
130
|
-
event: "permission_denied",
|
|
131
|
-
occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
132
|
-
toolUseId: input.tool_use_id,
|
|
133
|
-
agentType: ACTIVE_AGENT.type,
|
|
134
|
-
agentName: agentNameIn(basename(input.cwd ?? process.cwd())),
|
|
135
|
-
action: permissionDeniedAction(input.tool_name),
|
|
136
|
-
sessionId: input.session_id,
|
|
137
|
-
decisionSource: "policy_auto",
|
|
138
|
-
decisionOrigin: decision.origin,
|
|
139
|
-
decisionOutcome: decision.outcome,
|
|
140
|
-
toolName: input.tool_name,
|
|
141
|
-
toolTarget
|
|
142
|
-
},
|
|
143
|
-
{ maxAttempts: 1, timeoutMs: 800 }
|
|
144
|
-
).catch(() => void 0);
|
|
145
|
-
};
|
|
146
119
|
var storedWaitDeadline = (result, requestedDeadline) => {
|
|
147
120
|
const stored = result.waitEndsAt ? Date.parse(result.waitEndsAt) : Number.NaN;
|
|
148
121
|
return Number.isFinite(stored) ? Math.min(stored, requestedDeadline) : requestedDeadline;
|
|
@@ -556,11 +529,11 @@ var handlePreToolUse = async (input, canonical) => {
|
|
|
556
529
|
const gateInput = claudeGateInput(modeState, policy, input, canonical);
|
|
557
530
|
const verdict = resolveGate(gateInput);
|
|
558
531
|
if (verdict.kind === "kill") {
|
|
559
|
-
await
|
|
532
|
+
await reportMachineDenial(input, verdict, ACTIVE_AGENT);
|
|
560
533
|
return halted(verdict.reason);
|
|
561
534
|
}
|
|
562
535
|
if (verdict.kind === "deny") {
|
|
563
|
-
await
|
|
536
|
+
await reportMachineDenial(input, verdict, ACTIVE_AGENT);
|
|
564
537
|
return deny(verdict.reason);
|
|
565
538
|
}
|
|
566
539
|
if (canonical === null) return deny(unreadableReason);
|
|
@@ -618,11 +591,11 @@ var handlePermissionRequest = async (input, canonical) => {
|
|
|
618
591
|
const policy = await getPolicy(apiKey, modeState.policyVersion, ACTIVE_AGENT.type, true, input.session_id);
|
|
619
592
|
const verdict = resolveGate(claudeGateInput(modeState, policy, input, canonical));
|
|
620
593
|
if (verdict.kind === "kill") {
|
|
621
|
-
await
|
|
594
|
+
await reportMachineDenial(input, verdict, ACTIVE_AGENT);
|
|
622
595
|
return permReqHalted(verdict.reason);
|
|
623
596
|
}
|
|
624
597
|
if (verdict.kind === "deny") {
|
|
625
|
-
await
|
|
598
|
+
await reportMachineDenial(input, verdict, ACTIVE_AGENT);
|
|
626
599
|
return permReqDeny(verdict.reason);
|
|
627
600
|
}
|
|
628
601
|
if (canonical === null) return permReqDeny(unreadableReason);
|
|
@@ -662,7 +635,7 @@ var PERMISSION_DENIED_NOTICE_WINDOW_MS = 5 * 60 * 1e3;
|
|
|
662
635
|
var blockedActionHoldEndsAt = (holdBudgetSeconds) => START_MS + hookHoldWindowMs("claude", holdBudgetSeconds);
|
|
663
636
|
var notifyPermissionDenied = async (apiKey, input) => {
|
|
664
637
|
const sessionKey = input.session_id || DEFAULT_SESSION;
|
|
665
|
-
if (
|
|
638
|
+
if (claimThrottle(`permdenied:${sessionKey}:${input.tool_name}`, PERMISSION_DENIED_NOTICE_WINDOW_MS) !== "passed") return;
|
|
666
639
|
const mode = await fetchModeState(apiKey, input.session_id).catch(() => null);
|
|
667
640
|
if (mode?.kill || mode?.mode === "terminal_only") return;
|
|
668
641
|
const projectName = basename(input.cwd ?? process.cwd());
|