@pushary/agent-hooks 1.5.1 → 1.6.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.
Files changed (81) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/bin/pushary-bell-hook.js +18 -18
  3. package/dist/bin/pushary-bell.js +6 -6
  4. package/dist/bin/pushary-claude.js +18 -18
  5. package/dist/bin/pushary-clean.js +19 -19
  6. package/dist/bin/pushary-codex-bridge.js +10 -10
  7. package/dist/bin/pushary-codex-hook.js +23 -23
  8. package/dist/bin/pushary-codex.js +6 -6
  9. package/dist/bin/pushary-connect.js +6 -6
  10. package/dist/bin/pushary-cowork.js +3 -3
  11. package/dist/bin/pushary-daemon.js +23 -23
  12. package/dist/bin/pushary-disconnect.js +10 -10
  13. package/dist/bin/pushary-doctor.js +22 -22
  14. package/dist/bin/pushary-elicitation-hook.js +17 -17
  15. package/dist/bin/pushary-gemini-bridge.js +9 -9
  16. package/dist/bin/pushary-gemini-hook.js +20 -20
  17. package/dist/bin/pushary-hook.js +23 -23
  18. package/dist/bin/pushary-login.js +7 -7
  19. package/dist/bin/pushary-logout.js +4 -4
  20. package/dist/bin/pushary-mode.js +3 -3
  21. package/dist/bin/pushary-notification-hook.js +20 -20
  22. package/dist/bin/pushary-opencode-hook.js +19 -19
  23. package/dist/bin/pushary-permission-denied-hook.js +24 -24
  24. package/dist/bin/pushary-permission-hook.js +23 -23
  25. package/dist/bin/pushary-post-hook.js +20 -20
  26. package/dist/bin/pushary-prompt-hook.js +20 -20
  27. package/dist/bin/pushary-session-end-hook.js +20 -20
  28. package/dist/bin/pushary-session-start-hook.js +24 -24
  29. package/dist/bin/pushary-setup.js +28 -28
  30. package/dist/bin/pushary-stats.js +2 -2
  31. package/dist/bin/pushary-status.js +10 -10
  32. package/dist/bin/pushary-stop-hook.js +20 -20
  33. package/dist/bin/pushary-stopfailure-hook.js +20 -20
  34. package/dist/bin/pushary-transcript-register.js +16 -16
  35. package/dist/bin/pushary-transcripts.js +4 -4
  36. package/dist/bin/pushary-upgrade.js +44 -26
  37. package/dist/bin/pushary-wait.js +3 -3
  38. package/dist/{chunk-5ZZG76S2.js → chunk-5MH5P366.js} +2 -2
  39. package/dist/{chunk-HVBF35GT.js → chunk-5QCZYSYR.js} +1 -1
  40. package/dist/{chunk-PJ27EHCD.js → chunk-644CGYOB.js} +66 -12
  41. package/dist/{chunk-D573TLP6.js → chunk-66BIMA62.js} +6 -5
  42. package/dist/{chunk-WOLPADR6.js → chunk-7JSE6JTZ.js} +1 -1
  43. package/dist/{chunk-TZGCUNOX.js → chunk-A2GS2ENL.js} +6 -6
  44. package/dist/{chunk-TFKBFQCE.js → chunk-A5URWZTP.js} +1 -1
  45. package/dist/{chunk-M2LMXPJZ.js → chunk-ALG3IBLB.js} +1 -1
  46. package/dist/{chunk-TUXFIVOH.js → chunk-B6TYEKJR.js} +1 -1
  47. package/dist/{chunk-MDJJW3LP.js → chunk-BE4P7ERZ.js} +3 -3
  48. package/dist/{chunk-2AUIEZYS.js → chunk-BK5F3FGE.js} +3 -3
  49. package/dist/{chunk-IV3RHICU.js → chunk-BW3Y2D24.js} +4 -4
  50. package/dist/{chunk-43LJSM4F.js → chunk-CSW6A2EW.js} +1 -1
  51. package/dist/{chunk-X7FESZTD.js → chunk-DZ75BJ7V.js} +3 -3
  52. package/dist/{chunk-DTQNDR7C.js → chunk-E7MJBWSR.js} +1 -1
  53. package/dist/{chunk-6IU45EHE.js → chunk-F2OPOBRO.js} +1 -1
  54. package/dist/{chunk-43ZDACBO.js → chunk-F4KRNFDE.js} +1 -1
  55. package/dist/{chunk-6QFEQIPM.js → chunk-FDF72XHK.js} +2 -2
  56. package/dist/{chunk-R5KY3PBN.js → chunk-FI3LQCUH.js} +5 -5
  57. package/dist/{chunk-KHXVTWYS.js → chunk-G5LENVCZ.js} +3 -3
  58. package/dist/{chunk-K3QVDAZW.js → chunk-GDXSCXQC.js} +1 -1
  59. package/dist/{chunk-5HYNICS7.js → chunk-GOXINLDU.js} +1 -1
  60. package/dist/{chunk-2QT3GCU4.js → chunk-GP6SFVEN.js} +1 -1
  61. package/dist/{chunk-4ERLRNOK.js → chunk-HWG7X3VI.js} +3 -3
  62. package/dist/{chunk-WNJSGZY7.js → chunk-KZBGITM4.js} +4 -4
  63. package/dist/{chunk-Z4VGIBJ7.js → chunk-MOQOJOMD.js} +3 -3
  64. package/dist/{chunk-HUAOMX4U.js → chunk-NDS27FXU.js} +1 -1
  65. package/dist/{chunk-YAWXKL2X.js → chunk-NYD7W7AT.js} +1 -1
  66. package/dist/{chunk-JKBDGZFL.js → chunk-OP7HFIWE.js} +22 -12
  67. package/dist/{chunk-5UQ5ATIE.js → chunk-OR3A3RLH.js} +1 -1
  68. package/dist/{chunk-XWEONSLV.js → chunk-PCVVCS4A.js} +1 -1
  69. package/dist/{chunk-KJRALILH.js → chunk-PRZXYILJ.js} +2 -2
  70. package/dist/{chunk-MU3WU2FO.js → chunk-RBPJO4KG.js} +1 -1
  71. package/dist/{chunk-TIWURSLS.js → chunk-SFNRAEEW.js} +1 -1
  72. package/dist/{chunk-USQDVBEV.js → chunk-TDKE3V6W.js} +1 -1
  73. package/dist/{chunk-HU5LSYL2.js → chunk-VMNI33F5.js} +1 -1
  74. package/dist/{chunk-UYDTFCHW.js → chunk-VZANUMIF.js} +1 -1
  75. package/dist/{chunk-3ZSGKLSO.js → chunk-XGL5JC6U.js} +2 -2
  76. package/dist/{chunk-6EEANS74.js → chunk-XQOT4CCK.js} +8 -3
  77. package/dist/{chunk-T4QY64OR.js → chunk-YFD7CRIZ.js} +376 -10
  78. package/dist/{reapply-5CZSTJZI.js → reapply-RRDVJATI.js} +9 -9
  79. package/dist/src/index.d.ts +1 -0
  80. package/dist/src/index.js +12 -12
  81. package/package.json +1 -1
@@ -614,8 +614,10 @@ var CURSOR_GATE_EVENTS = ["beforeShellExecution", "beforeMCPExecution", "preTool
614
614
  var SUPPORT_EMAIL = "business@pushary.com";
615
615
  var SUPPORT_DISCORD = "https://discord.gg/9v3VvUByrr";
616
616
  var HOOK_LOCATOR_BINARY = "pushary-bridge";
617
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
617
618
  var HOOK_BATCH_MAX_BYTES = 4 * 1024 * 1024;
618
619
  var REPO_KEY_MAX_LENGTH = 200;
620
+ var WILDCARD_TOOL_PATTERN = "*";
619
621
  var isRepoKeyMatch = (ruleRepoKey, currentRepoKey) => {
620
622
  if (!ruleRepoKey) return true;
621
623
  return ruleRepoKey === currentRepoKey;
@@ -1121,6 +1123,280 @@ var selectGoverningRule = (policies, toolName, args, repoKey, sessionId) => {
1121
1123
  };
1122
1124
  var ARG_PREFIX_TARGET_TOOLS = Object.keys(POLICY_COMMAND_KEYS);
1123
1125
  var FILE_TARGET_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit"]);
1126
+ var isCoveredByPolicy = (policyPatterns, toolName, toolTarget) => {
1127
+ const candidateWeight = matchRankWeight(toolTarget ? "prefix" : "tool");
1128
+ return policyPatterns.some(
1129
+ (pattern) => matchRankWeight(matchToolPattern(pattern, toolName, toolTarget ?? void 0, PATTERN_INTENT.restrict)) >= candidateWeight
1130
+ );
1131
+ };
1132
+ var COMMAND_RUNNERS = /* @__PURE__ */ new Set([
1133
+ "sh",
1134
+ "bash",
1135
+ "zsh",
1136
+ "dash",
1137
+ "ksh",
1138
+ "fish",
1139
+ "csh",
1140
+ "tcsh",
1141
+ "eval",
1142
+ "exec",
1143
+ "source",
1144
+ ".",
1145
+ "command",
1146
+ "builtin",
1147
+ "env",
1148
+ "xargs",
1149
+ "nohup",
1150
+ "time",
1151
+ "nice",
1152
+ "timeout",
1153
+ "watch",
1154
+ "parallel",
1155
+ "script",
1156
+ "su",
1157
+ "doas",
1158
+ "npx",
1159
+ "bunx",
1160
+ "pnpx",
1161
+ "uvx"
1162
+ ]);
1163
+ var INLINE_CODE_INTERPRETERS = /* @__PURE__ */ new Set([
1164
+ "python",
1165
+ "python2",
1166
+ "python3",
1167
+ "node",
1168
+ "deno",
1169
+ "ruby",
1170
+ "perl",
1171
+ "php",
1172
+ "lua",
1173
+ "osascript",
1174
+ "pwsh",
1175
+ "powershell"
1176
+ ]);
1177
+ var INLINE_CODE_LONG_FLAG = /^-{1,2}(?:eval|print|require|import|command|encodedcommand|enc|ec)(?:=|$)/i;
1178
+ var INLINE_CODE_SHORT_FLAG_LETTERS = /* @__PURE__ */ new Set(["c", "e", "E", "p", "r"]);
1179
+ var SHORT_FLAG_CLUSTER = /^-([A-Za-z]+)/;
1180
+ var INLINE_CODE_SUBCOMMAND = "eval";
1181
+ var STANDARD_INPUT_ARGUMENT = "-";
1182
+ var DESTRUCTIVE_FLAGS_BY_PROGRAM = /* @__PURE__ */ new Map([
1183
+ ["find", /* @__PURE__ */ new Set(["-delete", "-exec", "-execdir", "-ok", "-okdir"])],
1184
+ ["rsync", /* @__PURE__ */ new Set(["--delete", "--delete-before", "--delete-during", "--delete-after", "--delete-excluded", "--remove-source-files"])]
1185
+ ]);
1186
+ var RUNNER_SUBCOMMANDS = /* @__PURE__ */ new Set(["exec", "dlx"]);
1187
+ var SUBCOMMAND_CLIS = /* @__PURE__ */ new Set([
1188
+ "git",
1189
+ "docker",
1190
+ "podman",
1191
+ "kubectl",
1192
+ "helm",
1193
+ "terraform",
1194
+ "npm",
1195
+ "pnpm",
1196
+ "yarn",
1197
+ "bun",
1198
+ "cargo",
1199
+ "pip",
1200
+ "brew",
1201
+ "gh",
1202
+ "glab",
1203
+ "aws",
1204
+ "gcloud",
1205
+ "gsutil",
1206
+ "az",
1207
+ "doctl",
1208
+ "firebase",
1209
+ "vercel",
1210
+ "netlify",
1211
+ "fly",
1212
+ "flyctl",
1213
+ "heroku",
1214
+ "supabase",
1215
+ "wrangler",
1216
+ "railway"
1217
+ ]);
1218
+ var DESTRUCTIVE_SUBCOMMANDS = /* @__PURE__ */ new Set([
1219
+ "delete",
1220
+ "destroy",
1221
+ "remove",
1222
+ "rm",
1223
+ "rb",
1224
+ "rmi",
1225
+ "purge",
1226
+ "prune",
1227
+ "drop",
1228
+ "terminate",
1229
+ "uninstall",
1230
+ "wipe",
1231
+ "reset"
1232
+ ]);
1233
+ var DATA_LOSS_COMMAND_PATTERNS = [
1234
+ "Bash(git branch -D:*)",
1235
+ "Bash(git branch --delete:*)",
1236
+ "Bash(git checkout --:*)",
1237
+ "Bash(git checkout .:*)",
1238
+ "Bash(git restore:*)",
1239
+ "Bash(git stash drop:*)",
1240
+ "Bash(git stash clear:*)",
1241
+ "Bash(git filter-branch:*)",
1242
+ "Bash(git update-ref -d:*)",
1243
+ "Bash(dd :*)",
1244
+ "Bash(shred:*)",
1245
+ "Bash(unlink:*)",
1246
+ "Bash(crontab:*)",
1247
+ "Bash(chmod -R:*)",
1248
+ "Bash(chown -R:*)",
1249
+ "Bash(kill:*)",
1250
+ "Bash(pkill:*)",
1251
+ "Bash(killall:*)",
1252
+ "Bash(launchctl:*)",
1253
+ "Bash(systemctl:*)",
1254
+ "Bash(diskutil:*)"
1255
+ ];
1256
+ var SHELL_ENV_ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
1257
+ var PLAIN_PROGRAM_WORD = /^[A-Za-z0-9_./+@:-]+$/;
1258
+ var SHELL_RESERVED_WORDS = /* @__PURE__ */ new Set([
1259
+ "if",
1260
+ "then",
1261
+ "elif",
1262
+ "else",
1263
+ "fi",
1264
+ "case",
1265
+ "esac",
1266
+ "for",
1267
+ "select",
1268
+ "while",
1269
+ "until",
1270
+ "do",
1271
+ "done",
1272
+ "function",
1273
+ "coproc",
1274
+ "!",
1275
+ "{",
1276
+ "}",
1277
+ "[[",
1278
+ "]]"
1279
+ ]);
1280
+ var HARMLESS_GLOBAL_FLAGS = /* @__PURE__ */ new Set(["--no-pager", "--version", "-v", "-V", "--help", "-h"]);
1281
+ var END_OF_OPTIONS = "--";
1282
+ var SUBCOMMAND_DEPTH = 3;
1283
+ var SHELL_COMMENT_MARK = "#";
1284
+ var SHELL_LINE_CONTINUATION = /\\\n/g;
1285
+ var SHELL_WORD_BREAK = /\s/;
1286
+ var DOUBLE_QUOTE_ESCAPABLE = /* @__PURE__ */ new Set([SHELL_DOUBLE_QUOTE, SHELL_ESCAPE, SHELL_SUBSTITUTION_SIGIL, "`"]);
1287
+ var shellWordsOf = (segment) => {
1288
+ const words = [];
1289
+ let text = "";
1290
+ let plain = true;
1291
+ let expands = false;
1292
+ let comment = false;
1293
+ let started = false;
1294
+ let quote = null;
1295
+ const finishWord = () => {
1296
+ if (started) words.push({ text, plain, expands, comment });
1297
+ text = "";
1298
+ plain = true;
1299
+ expands = false;
1300
+ comment = false;
1301
+ started = false;
1302
+ };
1303
+ for (let index = 0; index < segment.length; index += 1) {
1304
+ const char = segment[index];
1305
+ const next = segment[index + 1];
1306
+ if (quote === "'") {
1307
+ if (char === quote) quote = null;
1308
+ else text += char;
1309
+ continue;
1310
+ }
1311
+ if (char === SHELL_ESCAPE && next !== void 0 && (quote === null || DOUBLE_QUOTE_ESCAPABLE.has(next))) {
1312
+ text += next;
1313
+ plain = false;
1314
+ started = true;
1315
+ index += 1;
1316
+ continue;
1317
+ }
1318
+ if (quote === SHELL_DOUBLE_QUOTE) {
1319
+ if (char === quote) quote = null;
1320
+ else text += char;
1321
+ expands ||= char === SHELL_SUBSTITUTION_SIGIL;
1322
+ continue;
1323
+ }
1324
+ if (SHELL_QUOTES.has(char)) {
1325
+ quote = char;
1326
+ plain = false;
1327
+ started = true;
1328
+ continue;
1329
+ }
1330
+ if (SHELL_WORD_BREAK.test(char)) {
1331
+ finishWord();
1332
+ continue;
1333
+ }
1334
+ comment ||= !started && char === SHELL_COMMENT_MARK;
1335
+ expands ||= char === SHELL_SUBSTITUTION_SIGIL;
1336
+ text += char;
1337
+ started = true;
1338
+ }
1339
+ finishWord();
1340
+ return words;
1341
+ };
1342
+ var invocationOf = (segment) => {
1343
+ const [program, ...args] = shellWordsOf(segment);
1344
+ return { program, args };
1345
+ };
1346
+ var argsAfterHarmlessGlobalFlags = (args) => {
1347
+ const firstMeaningful = args.findIndex((arg) => !HARMLESS_GLOBAL_FLAGS.has(arg.text));
1348
+ return firstMeaningful === -1 ? [] : args.slice(firstMeaningful);
1349
+ };
1350
+ var subcommandWordsOf = (args) => {
1351
+ const endOfOptions = args.findIndex((arg) => arg.text === END_OF_OPTIONS);
1352
+ const options = endOfOptions === -1 ? args : args.slice(0, endOfOptions);
1353
+ return options.filter((arg) => !arg.text.startsWith("-")).slice(0, SUBCOMMAND_DEPTH);
1354
+ };
1355
+ var passesInlineCode = (arg) => {
1356
+ if (arg === INLINE_CODE_SUBCOMMAND || arg === STANDARD_INPUT_ARGUMENT || INLINE_CODE_LONG_FLAG.test(arg)) return true;
1357
+ if (arg.startsWith(END_OF_OPTIONS)) return false;
1358
+ const cluster = SHORT_FLAG_CLUSTER.exec(arg)?.[1] ?? "";
1359
+ return [...cluster].some((letter) => INLINE_CODE_SHORT_FLAG_LETTERS.has(letter));
1360
+ };
1361
+ var interpreterRunsUnreadableCode = (args) => args.some(passesInlineCode) || args.every((arg) => arg.startsWith("-"));
1362
+ var programHidesItsEffect = (program) => SHELL_RESERVED_WORDS.has(program.text) || !program.plain || program.expands || SHELL_ENV_ASSIGNMENT.test(program.text) || !PLAIN_PROGRAM_WORD.test(program.text) || COMMAND_RUNNERS.has(basenameOf(program.text));
1363
+ var argumentsHideTheEffect = (name, args) => {
1364
+ const texts = args.map((arg) => arg.text);
1365
+ if (INLINE_CODE_INTERPRETERS.has(name.replace(/\d+(?:\.\d+)*$/, "")) && interpreterRunsUnreadableCode(texts)) return true;
1366
+ const destructiveFlags = DESTRUCTIVE_FLAGS_BY_PROGRAM.get(name);
1367
+ if (destructiveFlags && texts.some((text) => destructiveFlags.has(text))) return true;
1368
+ if (!SUBCOMMAND_CLIS.has(name)) return false;
1369
+ const meaningful = argsAfterHarmlessGlobalFlags(args);
1370
+ return (meaningful[0]?.text.startsWith("-") ?? false) || subcommandWordsOf(meaningful).some((word) => word.expands || RUNNER_SUBCOMMANDS.has(word.text));
1371
+ };
1372
+ var invocationHidesItsEffect = ({ program, args }) => program !== void 0 && ([program, ...args].some((word) => word.comment) || programHidesItsEffect(program) || argumentsHideTheEffect(basenameOf(program.text), args));
1373
+ var readableCommandSegments = (command) => shellCommandSegments(command.replace(SHELL_LINE_CONTINUATION, "").replace(SAFE_REDIRECTION, ""));
1374
+ var normalizedInvocation = ({ program, args }) => {
1375
+ if (program === void 0) return "";
1376
+ const name = basenameOf(program.text);
1377
+ const kept = SUBCOMMAND_CLIS.has(name) ? argsAfterHarmlessGlobalFlags(args) : args;
1378
+ return [name, ...kept.map((arg) => arg.text)].join(" ");
1379
+ };
1380
+ var normalizedCommand = (command) => {
1381
+ const segments = readableCommandSegments(command);
1382
+ return segments === null ? null : segments.map((segment) => normalizedInvocation(invocationOf(segment))).join("; ");
1383
+ };
1384
+ var subcommandDestroys = ({ program, args }) => program !== void 0 && SUBCOMMAND_CLIS.has(basenameOf(program.text)) && subcommandWordsOf(argsAfterHarmlessGlobalFlags(args)).some((word) => DESTRUCTIVE_SUBCOMMANDS.has(word.text));
1385
+ var segmentNeedsAPerson = (toolName, segment) => {
1386
+ const invocation = invocationOf(segment);
1387
+ const normalized = normalizedInvocation(invocation);
1388
+ return invocationHidesItsEffect(invocation) || subcommandDestroys(invocation) || classifyDecisionRisk(toolName, normalized) !== "standard" || isCoveredByPolicy(CAPABILITY_PATTERNS.destructive, toolName, normalized) || isCoveredByPolicy(CAPABILITY_PATTERNS.network, toolName, normalized) || isCoveredByPolicy(DATA_LOSS_COMMAND_PATTERNS, toolName, normalized);
1389
+ };
1390
+ var commandNeedsAPerson = (toolName, command) => {
1391
+ const segments = readableCommandSegments(command);
1392
+ return segments === null || classifyDecisionRisk(toolName, command) !== "standard" || segments.some((segment) => segmentNeedsAPerson(toolName, segment));
1393
+ };
1394
+ var withoutSessionToolGrants = (config) => ({
1395
+ ...config,
1396
+ policies: config.policies.filter((policy) => !isSessionToolGrant(policy))
1397
+ });
1398
+ var SESSION_TOOL_GRANT_TOOLS = /* @__PURE__ */ new Set(["Bash"]);
1399
+ var isSessionToolGrant = (policy) => Boolean(policy.sessionId) && SESSION_TOOL_GRANT_TOOLS.has(policy.tool) && isAutoApprove(policy);
1124
1400
  var API_KEY_PATTERN = /^pk_[a-f0-9]+\.[a-f0-9]+$/;
1125
1401
  var isValidApiKey = (value) => API_KEY_PATTERN.test(value);
1126
1402
  var ACTION_BODY_MAX = 4e3;
@@ -1568,6 +1844,28 @@ var isScopeContract = (value) => {
1568
1844
  if (c.promises !== void 0 && !strings(c.promises)) return false;
1569
1845
  return strings(c.allowedPaths) && strings(c.offLimitsPaths) && typeof c.doneWhen === "string";
1570
1846
  };
1847
+ var findBestRoute = (routes, toolName, args, repoKey) => {
1848
+ let best;
1849
+ let bestWeight = 0;
1850
+ let bestScoped = -1;
1851
+ let bestLength = -1;
1852
+ for (const candidate of routes) {
1853
+ if (!isRepoKeyMatch(candidate.repoKey, repoKey)) continue;
1854
+ const rank = matchToolPatternAny(candidate.toolPattern, toolName, args, PATTERN_INTENT.restrict);
1855
+ if (rank === "none") continue;
1856
+ const weight = matchRankWeight(rank);
1857
+ const scoped = candidate.repoKey ? 1 : 0;
1858
+ const length = rank === "prefix" ? candidate.toolPattern.length : -1;
1859
+ const better = weight > bestWeight || weight === bestWeight && scoped > bestScoped || weight === bestWeight && scoped === bestScoped && length > bestLength;
1860
+ if (better) {
1861
+ best = candidate;
1862
+ bestWeight = weight;
1863
+ bestScoped = scoped;
1864
+ bestLength = length;
1865
+ }
1866
+ }
1867
+ return best ?? routes.find((r) => r.toolPattern === "*");
1868
+ };
1571
1869
  var autoApprove = (tool) => ({
1572
1870
  tool,
1573
1871
  timeoutSeconds: 0,
@@ -1585,17 +1883,21 @@ var resolveAutoResolveOrigin = (config, toolName, toolInput, cwd, repoKey, sessi
1585
1883
  }
1586
1884
  return DECISION_ORIGIN.autopilot;
1587
1885
  };
1886
+ var wildcardRuleOf = (pool) => {
1887
+ const wildcard = pool.find((policy) => policy.tool === WILDCARD_TOOL_PATTERN);
1888
+ return wildcard ? { policy: wildcard, rank: "wildcard" } : void 0;
1889
+ };
1890
+ var withSiteDelivery = (rule, siteMode) => isAutoApprove(rule.policy) || isAutoDeny(rule.policy) ? rule : { ...rule, policy: { ...rule.policy, mode: siteMode.mode, pushFirstSeconds: siteMode.pushFirstSeconds } };
1588
1891
  var resolvePolicy = (config, toolName, modeOverride, toolInput, cwd, repoKey, sessionId) => {
1589
1892
  const args = toolInput ? policyArgForms(toolName, toolInput, cwd) : [];
1590
1893
  const arg = args[0];
1591
- const governing = (pool) => {
1592
- if (pool.length === 0) return void 0;
1593
- const rule = selectGoverningRule(pool, toolName, args, repoKey, sessionId);
1594
- if (rule) return rule;
1595
- const wildcard = pool.find((p) => p.tool === "*");
1596
- return wildcard ? { policy: wildcard, rank: "wildcard" } : void 0;
1597
- };
1598
- const match = governing(config.policies.filter((p) => !p.origin)) ?? governing(config.policies.filter((p) => p.origin === "preset")) ?? governing(config.policies.filter((p) => p.origin === "builtin"));
1894
+ const specificRule = (pool) => pool.length === 0 ? void 0 : selectGoverningRule(pool, toolName, args, repoKey, sessionId);
1895
+ const written = config.policies.filter((p) => !p.origin);
1896
+ const presets = config.policies.filter((p) => p.origin === "preset");
1897
+ const builtins = config.policies.filter((p) => p.origin === "builtin");
1898
+ const siteMode = wildcardRuleOf(written);
1899
+ const presetRule = specificRule(presets);
1900
+ const match = specificRule(written) ?? (presetRule && siteMode ? withSiteDelivery(presetRule, siteMode.policy) : presetRule) ?? siteMode ?? wildcardRuleOf(presets) ?? specificRule(builtins) ?? wildcardRuleOf(builtins);
1599
1901
  let base = match?.policy ?? {
1600
1902
  tool: toolName,
1601
1903
  timeoutSeconds: config.defaultTimeoutSeconds,
@@ -1604,8 +1906,13 @@ var resolvePolicy = (config, toolName, modeOverride, toolInput, cwd, repoKey, se
1604
1906
  pushFirstSeconds: config.defaultPushFirstSeconds ?? 20
1605
1907
  };
1606
1908
  const governedBySpecificRule = match?.rank === "exact" || match?.rank === "prefix";
1909
+ const governedBySessionToolGrant = match?.rank === "tool" && isSessionToolGrant(match.policy);
1607
1910
  const governingMode = base.mode;
1608
- if (!governedBySpecificRule && toolName === "Bash" && typeof arg === "string" && isSafeReadOnlyCommand(arg)) {
1911
+ const approvedByReadOnlyFloor = !governedBySpecificRule && toolName === "Bash" && typeof arg === "string" && isSafeReadOnlyCommand(arg);
1912
+ if (governedBySessionToolGrant && !approvedByReadOnlyFloor && typeof arg === "string" && commandNeedsAPerson(toolName, arg)) {
1913
+ return resolvePolicy(withoutSessionToolGrants(config), toolName, modeOverride, toolInput, cwd, repoKey, sessionId);
1914
+ }
1915
+ if (approvedByReadOnlyFloor) {
1609
1916
  base = autoApprove(base.tool);
1610
1917
  }
1611
1918
  const wouldAutoApprove = isAutoApprove(base);
@@ -1756,8 +2063,63 @@ var resolveGate = (input) => {
1756
2063
  scopePath: scopeReason && "path" in scopeVerdict ? widenablePath(scopeVerdict.path) : void 0
1757
2064
  };
1758
2065
  };
1759
- var editAsksAtTheAgentsPrompt = (input, verdict) => verdict.kind === "gate" && !verdict.scopeReason && (input.modeState.mode ?? input.config.modeOverride ?? null) === null && verdict.policy.origin === "builtin" && verdict.policy.mode === "push_first" && ACCEPT_EDITS_DEFER_TOOLS.has(input.toolName);
2066
+ var editAsksAtTheAgentsPrompt = (input, verdict) => verdict.kind === "gate" && !verdict.scopeReason && (input.modeState.mode ?? input.config.modeOverride ?? null) === null && !aChosenRuleGoverns(input) && verdict.policy.mode === "push_first" && ACCEPT_EDITS_DEFER_TOOLS.has(input.toolName);
1760
2067
  var claudePromptsBeforeAnEdit = (permissionMode) => permissionMode === "default";
2068
+ var MAX_AGENT_PERMISSION_RULES_PER_KIND = 256;
2069
+ var MAX_AGENT_PERMISSION_RULE_LENGTH = 512;
2070
+ var isAgentPermissionRule = (value) => typeof value === "string" && value.length > 0 && value.length <= MAX_AGENT_PERMISSION_RULE_LENGTH;
2071
+ var settingsPermissionList = (permissions, kind) => {
2072
+ const list = permissions[kind];
2073
+ return Array.isArray(list) ? list.filter(isAgentPermissionRule) : [];
2074
+ };
2075
+ var boundedUnion = (lists) => [...new Set(lists.flat())].slice(0, MAX_AGENT_PERMISSION_RULES_PER_KIND);
2076
+ var claudePermissionRulesFromSettings = (documents) => {
2077
+ const permissionBlocks = documents.flatMap((document) => isRecord(document) && isRecord(document.permissions) ? [document.permissions] : []);
2078
+ const collect = (kind) => boundedUnion(permissionBlocks.map((permissions) => settingsPermissionList(permissions, kind)));
2079
+ return { allow: collect("allow"), ask: collect("ask"), deny: collect("deny") };
2080
+ };
2081
+ var claudeConsultsItsAllowlist = (permissionMode) => permissionMode === "default" || permissionMode === "acceptEdits";
2082
+ var anyRuleRestricts = (rules, toolName, args) => rules.some((rule) => matchToolPatternAny(rule, toolName, args, PATTERN_INTENT.restrict) !== "none");
2083
+ var anyRuleGrants = (rules, toolName, args) => rules.some((rule) => matchToolPatternAny(rule, toolName, args, PATTERN_INTENT.grant) !== "none");
2084
+ var everyCommandSegmentGranted = (rules, toolName, command) => {
2085
+ const segments = readableCommandSegments(command);
2086
+ return segments !== null && segments.every((segment) => isSafeReadOnlyCommand(segment) || anyRuleGrants(rules, toolName, [segment]));
2087
+ };
2088
+ var restrictionFormsOf = (toolName, args) => {
2089
+ const command = toolName in POLICY_COMMAND_KEYS ? args[0] : void 0;
2090
+ const normalized = command === void 0 ? null : normalizedCommand(command);
2091
+ return normalized === null ? args : [...args, normalized];
2092
+ };
2093
+ var allowRulesGrant = (rules, toolName, args) => {
2094
+ const command = args[0];
2095
+ return toolName in POLICY_COMMAND_KEYS && command !== void 0 ? everyCommandSegmentGranted(rules, toolName, command) : anyRuleGrants(rules, toolName, args);
2096
+ };
2097
+ var inputNeedsAPerson = (toolName, toolInput) => {
2098
+ const arg = extractPolicyArg(toolName, toolInput);
2099
+ if (arg === void 0) return false;
2100
+ return toolName in POLICY_COMMAND_KEYS ? commandNeedsAPerson(toolName, arg) : classifyDecisionRisk(toolName, arg) !== "standard";
2101
+ };
2102
+ var agentRulesAllowEveryInput = (rules, toolName, toolInputs, cwd) => rules.allow.length > 0 && toolInputs.length > 0 && toolInputs.every((toolInput) => {
2103
+ const args = policyArgForms(toolName, toolInput, cwd);
2104
+ const restrictionForms = restrictionFormsOf(toolName, args);
2105
+ return allowRulesGrant(rules.allow, toolName, args) && !anyRuleRestricts(rules.ask, toolName, restrictionForms) && !anyRuleRestricts(rules.deny, toolName, restrictionForms) && !inputNeedsAPerson(toolName, toolInput);
2106
+ });
2107
+ var isDefaultRule = (policy) => policy.origin === "builtin" || policy.tool === WILDCARD_TOOL_PATTERN;
2108
+ var isApprovalRoutePattern = (value) => typeof value === "object" && value !== null && typeof value.toolPattern === "string" && ["string", "undefined"].includes(typeof value.repoKey);
2109
+ var approvalRoutesOf = (config) => {
2110
+ const routes = config.approvalRoutes ?? [];
2111
+ return Array.isArray(routes) && routes.every(isApprovalRoutePattern) ? routes : null;
2112
+ };
2113
+ var aChosenRuleGoverns = (input) => {
2114
+ const chosen = input.config.policies.filter((policy) => !isDefaultRule(policy));
2115
+ const routes = approvalRoutesOf(input.config);
2116
+ if (routes === null) return true;
2117
+ return input.toolInputs.some((toolInput) => {
2118
+ const args = policyArgForms(input.toolName, toolInput, input.cwd);
2119
+ return selectGoverningRule(chosen, input.toolName, args, input.repoKey, input.sessionId) !== void 0 || findBestRoute(routes, input.toolName, args, input.repoKey) !== void 0;
2120
+ });
2121
+ };
2122
+ var claudeAllowlistOwnsCall = (input, verdict, permissionMode, rules) => rules !== null && verdict.kind === "gate" && !verdict.scopeReason && !aChosenRuleGoverns(input) && !isAskedInEveryMode(input.toolName) && claudeConsultsItsAllowlist(permissionMode) && agentRulesAllowEveryInput(rules, input.toolName, input.toolInputs, input.cwd);
1761
2123
  var toPolicyVersion = (value) => typeof value === "string" || typeof value === "number" ? String(value) : null;
1762
2124
  var modeStateFromResponse = (data) => {
1763
2125
  const mode = data.override?.mode;
@@ -2139,6 +2501,10 @@ export {
2139
2501
  resolveGate,
2140
2502
  editAsksAtTheAgentsPrompt,
2141
2503
  claudePromptsBeforeAnEdit,
2504
+ claudePermissionRulesFromSettings,
2505
+ claudeConsultsItsAllowlist,
2506
+ agentRulesAllowEveryInput,
2507
+ claudeAllowlistOwnsCall,
2142
2508
  modeStateFromResponse,
2143
2509
  GATE_WIRE,
2144
2510
  GATE_MAX_TOOL_INPUTS,
@@ -9,17 +9,17 @@ import {
9
9
  reapplyGeminiSettings,
10
10
  reapplyVsCodePlugin,
11
11
  repairCodexHolds
12
- } from "./chunk-JKBDGZFL.js";
13
- import "./chunk-HUAOMX4U.js";
14
- import "./chunk-6EEANS74.js";
15
- import "./chunk-4ERLRNOK.js";
16
- import "./chunk-Z4VGIBJ7.js";
17
- import "./chunk-2AUIEZYS.js";
12
+ } from "./chunk-OP7HFIWE.js";
13
+ import "./chunk-NDS27FXU.js";
14
+ import "./chunk-XQOT4CCK.js";
15
+ import "./chunk-HWG7X3VI.js";
16
+ import "./chunk-MOQOJOMD.js";
17
+ import "./chunk-BK5F3FGE.js";
18
18
  import "./chunk-XHKBHWLX.js";
19
- import "./chunk-UYDTFCHW.js";
20
- import "./chunk-6IU45EHE.js";
19
+ import "./chunk-VZANUMIF.js";
20
+ import "./chunk-F2OPOBRO.js";
21
21
  import "./chunk-T7E75EKA.js";
22
- import "./chunk-T4QY64OR.js";
22
+ import "./chunk-YFD7CRIZ.js";
23
23
  import "./chunk-HWJW3CPO.js";
24
24
  export {
25
25
  ensureCodexTrustAfterReapply,
@@ -157,6 +157,7 @@ interface AskUserParams {
157
157
  toolUseId?: string;
158
158
  waitEndsAt?: string;
159
159
  requestId?: string;
160
+ sessionToolAware?: true;
160
161
  }
161
162
  interface AskUserResponse {
162
163
  correlationId: string;
package/dist/src/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  handlePreToolUse
3
- } from "../chunk-PJ27EHCD.js";
4
- import "../chunk-R5KY3PBN.js";
5
- import "../chunk-4ERLRNOK.js";
6
- import "../chunk-MDJJW3LP.js";
7
- import "../chunk-43ZDACBO.js";
3
+ } from "../chunk-644CGYOB.js";
4
+ import "../chunk-FI3LQCUH.js";
5
+ import "../chunk-HWG7X3VI.js";
6
+ import "../chunk-BE4P7ERZ.js";
7
+ import "../chunk-F4KRNFDE.js";
8
8
  import "../chunk-YHG74UFF.js";
9
- import "../chunk-2AUIEZYS.js";
9
+ import "../chunk-BK5F3FGE.js";
10
10
  import {
11
11
  fetchAccountPublicKey
12
12
  } from "../chunk-66H2QQAK.js";
@@ -18,20 +18,20 @@ import {
18
18
  handlePostToolUse,
19
19
  handleStop,
20
20
  reportEvent
21
- } from "../chunk-D573TLP6.js";
22
- import "../chunk-UYDTFCHW.js";
21
+ } from "../chunk-66BIMA62.js";
22
+ import "../chunk-VZANUMIF.js";
23
23
  import {
24
24
  askUser,
25
25
  cancelQuestion,
26
26
  waitForAnswer
27
27
  } from "../chunk-PYCQXCI5.js";
28
- import "../chunk-WOLPADR6.js";
29
- import "../chunk-6IU45EHE.js";
28
+ import "../chunk-7JSE6JTZ.js";
29
+ import "../chunk-F2OPOBRO.js";
30
30
  import "../chunk-HETOKNIL.js";
31
31
  import "../chunk-SAF6HGAA.js";
32
32
  import "../chunk-7QLSKOSU.js";
33
33
  import "../chunk-KZERVKTD.js";
34
- import "../chunk-HU5LSYL2.js";
34
+ import "../chunk-VMNI33F5.js";
35
35
  import "../chunk-T7E75EKA.js";
36
36
  import {
37
37
  getApiKey,
@@ -39,7 +39,7 @@ import {
39
39
  } from "../chunk-OSJEMXSR.js";
40
40
  import {
41
41
  resolvePolicy
42
- } from "../chunk-T4QY64OR.js";
42
+ } from "../chunk-YFD7CRIZ.js";
43
43
  import "../chunk-EA3IELHP.js";
44
44
  import "../chunk-HWJW3CPO.js";
45
45
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushary/agent-hooks",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
5
5
  "keywords": [
6
6
  "pushary",