@pushary/agent-hooks 1.9.23 → 1.9.25

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 (105) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/data/cursor-plugin/.cursor-plugin/plugin.json +1 -1
  3. package/data/cursor-plugin/CHANGELOG.md +4 -0
  4. package/data/cursor-plugin/scripts/pushary-gate.mjs +4 -2
  5. package/data/cursor-plugin/scripts/pushary-gate.test.mjs +14 -1
  6. package/dist/bin/pushary-bell-hook.js +25 -25
  7. package/dist/bin/pushary-bell.js +9 -9
  8. package/dist/bin/pushary-claude.js +27 -26
  9. package/dist/bin/pushary-clean.js +41 -93
  10. package/dist/bin/pushary-codex-bridge.js +17 -17
  11. package/dist/bin/pushary-codex-hook.js +30 -30
  12. package/dist/bin/pushary-codex.js +12 -12
  13. package/dist/bin/pushary-connect.js +24 -24
  14. package/dist/bin/pushary-cowork.js +5 -5
  15. package/dist/bin/pushary-daemon.js +31 -31
  16. package/dist/bin/pushary-disconnect.js +24 -24
  17. package/dist/bin/pushary-doctor.js +33 -33
  18. package/dist/bin/pushary-elicitation-hook.js +25 -25
  19. package/dist/bin/pushary-gemini-bridge.js +13 -13
  20. package/dist/bin/pushary-gemini-hook.js +27 -27
  21. package/dist/bin/pushary-hook.js +29 -29
  22. package/dist/bin/pushary-login.js +16 -16
  23. package/dist/bin/pushary-logout.js +77 -26
  24. package/dist/bin/pushary-mcp.js +9 -9
  25. package/dist/bin/pushary-mode.js +12 -12
  26. package/dist/bin/pushary-notification-hook.js +24 -24
  27. package/dist/bin/pushary-opencode-hook.js +26 -26
  28. package/dist/bin/pushary-permission-denied-hook.js +29 -29
  29. package/dist/bin/pushary-permission-hook.js +28 -28
  30. package/dist/bin/pushary-post-hook.js +24 -24
  31. package/dist/bin/pushary-prompt-hook.js +24 -24
  32. package/dist/bin/pushary-session-end-hook.js +24 -24
  33. package/dist/bin/pushary-session-start-hook.js +28 -28
  34. package/dist/bin/pushary-setup.js +41 -38
  35. package/dist/bin/pushary-stats.js +5 -5
  36. package/dist/bin/pushary-status.js +26 -26
  37. package/dist/bin/pushary-stop-hook.js +24 -24
  38. package/dist/bin/pushary-stopfailure-hook.js +24 -24
  39. package/dist/bin/pushary-suggestions.js +12 -12
  40. package/dist/bin/pushary-transcript-register.js +17 -17
  41. package/dist/bin/pushary-transcripts.js +7 -7
  42. package/dist/bin/pushary-upgrade.js +30 -30
  43. package/dist/bin/pushary-wait.js +12 -12
  44. package/dist/bin/pushary.js +6 -6
  45. package/dist/{chunk-GN6BJXC7.js → chunk-2CUE3XXS.js} +1 -1
  46. package/dist/{chunk-OH6OGEOY.js → chunk-2J2WFX7X.js} +4 -4
  47. package/dist/{chunk-QIODXPTP.js → chunk-2VQZC6DW.js} +4 -4
  48. package/dist/{chunk-SWQLZQE3.js → chunk-2XHBYMVN.js} +14 -13
  49. package/dist/{chunk-HXZG5WHU.js → chunk-3UYMOWX6.js} +2 -2
  50. package/dist/{chunk-R5C3QCVT.js → chunk-4KZP4YMV.js} +1 -1
  51. package/dist/{chunk-73HGV4R6.js → chunk-5ETE7F45.js} +2 -2
  52. package/dist/{chunk-OQPEHKH2.js → chunk-5Q2QJ2AL.js} +1 -1
  53. package/dist/{chunk-K2EYK5RL.js → chunk-5WTEKIAS.js} +4 -4
  54. package/dist/{chunk-AV5VX7OK.js → chunk-7UZD2F4Y.js} +8 -8
  55. package/dist/{chunk-E2LGKG75.js → chunk-7V6PJFDF.js} +3 -3
  56. package/dist/{chunk-KJA6IGOZ.js → chunk-A3QQWXIE.js} +1 -1
  57. package/dist/{chunk-GYP6DLA4.js → chunk-AXB4ABUD.js} +8 -8
  58. package/dist/{chunk-I46QTKYI.js → chunk-BGJDOHNF.js} +5 -5
  59. package/dist/{chunk-FBV2KS3Z.js → chunk-BHRMHDOO.js} +2 -2
  60. package/dist/{chunk-RN5NRRHX.js → chunk-EJJNZYDS.js} +2 -2
  61. package/dist/{chunk-6HT2TUZD.js → chunk-EJMXZH5E.js} +2 -2
  62. package/dist/{chunk-N4DMADJM.js → chunk-FCXYDR62.js} +1 -1
  63. package/dist/{chunk-ZGYO6OQE.js → chunk-FJKV64M7.js} +5 -5
  64. package/dist/{chunk-QFNY4KUQ.js → chunk-FLC4TVXH.js} +1 -1
  65. package/dist/{chunk-NHBPW6C4.js → chunk-G446AVR5.js} +2 -2
  66. package/dist/{chunk-AQ3TSQA2.js → chunk-GC5HJE3T.js} +21 -8
  67. package/dist/{chunk-CJTQNUUT.js → chunk-HEJMZVJI.js} +2 -2
  68. package/dist/{chunk-OH647UT3.js → chunk-KGSN2SOL.js} +793 -18
  69. package/dist/{chunk-7RGEJOQS.js → chunk-KM7AEGKF.js} +3 -3
  70. package/dist/{chunk-FIYCICHC.js → chunk-KP4BIZLP.js} +2 -2
  71. package/dist/{chunk-YXHVMZPR.js → chunk-KZLOVLA6.js} +4 -4
  72. package/dist/{chunk-AXSHPFU3.js → chunk-LDNKGG5G.js} +3 -3
  73. package/dist/{chunk-DKBPNHAI.js → chunk-N3ACK3YA.js} +4 -4
  74. package/dist/{chunk-4GKQDFH6.js → chunk-NFH2H7PD.js} +5 -5
  75. package/dist/{chunk-BY5EKA6W.js → chunk-OFHSTCXK.js} +3 -3
  76. package/dist/{chunk-LEQRIJ4H.js → chunk-OOKIWOMK.js} +3 -3
  77. package/dist/{chunk-7J2AX5T6.js → chunk-OWOSNGEQ.js} +2 -2
  78. package/dist/{chunk-SSWK2WYX.js → chunk-PAMW5M53.js} +5 -5
  79. package/dist/{chunk-JNKHCGHR.js → chunk-PM2WJSUH.js} +1 -1
  80. package/dist/{chunk-JCEUDLGW.js → chunk-PPGLIWOR.js} +1 -1
  81. package/dist/{chunk-PFB7P4F3.js → chunk-PSNF27BC.js} +6 -6
  82. package/dist/{chunk-2AUKCSLQ.js → chunk-Q37XFSPO.js} +4 -4
  83. package/dist/{chunk-S2R2U5W5.js → chunk-RSENVGBQ.js} +4 -4
  84. package/dist/{chunk-M7DCI44L.js → chunk-SGGR5MN2.js} +1 -1
  85. package/dist/{chunk-NSCETODW.js → chunk-TLUSUDRU.js} +1 -1
  86. package/dist/chunk-UJB6HHP4.js +166 -0
  87. package/dist/{chunk-YZPFJCFE.js → chunk-UK7OY3EJ.js} +1 -1
  88. package/dist/{chunk-ISAKLEKE.js → chunk-UUOC7A7M.js} +7 -7
  89. package/dist/{chunk-Z4UDB7EC.js → chunk-VEGS4NYF.js} +3 -3
  90. package/dist/{chunk-USUI4P63.js → chunk-VFF7ZBIS.js} +2 -2
  91. package/dist/{chunk-RHIKMNWJ.js → chunk-VN5Q4KOD.js} +2 -2
  92. package/dist/{chunk-6GHZAS7S.js → chunk-WEKXYS2F.js} +4 -4
  93. package/dist/{chunk-SLBO7PHS.js → chunk-WKEP4JAW.js} +2 -2
  94. package/dist/{chunk-M6R3SZZS.js → chunk-YD3DIFIU.js} +1 -1
  95. package/dist/{chunk-EDN4F6GX.js → chunk-ZLGCNHJG.js} +1 -1
  96. package/dist/{chunk-A5U62Q6K.js → chunk-ZLY7BHN4.js} +5 -5
  97. package/dist/{chunk-AFP3HZVK.js → chunk-ZNT4ZZXJ.js} +1 -1
  98. package/dist/{chunk-XBETSM5T.js → chunk-ZV3262AA.js} +3 -3
  99. package/dist/{global-upgrade-SKY7A3SI.js → global-upgrade-4M4TJKQR.js} +6 -6
  100. package/dist/{paths-XUUEK7OU.js → paths-6JY6J56N.js} +2 -2
  101. package/dist/{reapply-WQDP26EA.js → reapply-LFEQ5GF6.js} +20 -20
  102. package/dist/src/index.js +19 -19
  103. package/dist/{upgrade-lock-AYW3TB7X.js → upgrade-lock-CZRCHYVU.js} +3 -3
  104. package/package.json +1 -1
  105. package/dist/chunk-OYIN77HO.js +0 -72
@@ -708,12 +708,14 @@ var scanShell = (command) => {
708
708
  }
709
709
  return quote === null ? lexemes : null;
710
710
  };
711
- var shellCommandSegments = (command) => {
711
+ var PIPE = "|";
712
+ var splitShellSegments = (command) => {
712
713
  const lexemes = scanShell(command);
713
714
  if (lexemes === null) return null;
714
715
  const segments = [];
715
716
  let start = 0;
716
717
  let consumed = -1;
718
+ let readsPipe = false;
717
719
  for (const lexeme of lexemes) {
718
720
  const { index, text, quote, kind } = lexeme;
719
721
  if (index <= consumed || kind !== "text" || quote === "'") continue;
@@ -721,14 +723,103 @@ var shellCommandSegments = (command) => {
721
723
  if (quote !== null) continue;
722
724
  if (UNDECOMPOSABLE.has(text)) return null;
723
725
  if (!SEGMENT_SEPARATORS.has(text)) continue;
724
- consumed = index + (DOUBLED_SEPARATORS.has(text) && command[index + 1] === text ? 1 : 0);
725
- segments.push(trimShellWhitespace(command.slice(start, index)));
726
+ const doubled = DOUBLED_SEPARATORS.has(text) && command[index + 1] === text;
727
+ consumed = index + (doubled ? 1 : 0);
728
+ segments.push({ text: trimShellWhitespace(command.slice(start, index)), readsPipe });
729
+ readsPipe = text === PIPE && !doubled;
726
730
  start = consumed + 1;
727
731
  }
728
- segments.push(trimShellWhitespace(command.slice(start)));
729
- const present = segments.filter((segment) => segment.length > 0);
732
+ segments.push({ text: trimShellWhitespace(command.slice(start)), readsPipe });
733
+ const present = segments.filter((segment) => segment.text.length > 0);
730
734
  return present.length > 0 ? present : null;
731
735
  };
736
+ var shellCommandSegments = (command) => splitShellSegments(command)?.map((segment) => segment.text) ?? null;
737
+ var shellSegmentsReadingAPipe = (command) => splitShellSegments(command)?.filter((segment) => segment.readsPipe).map((segment) => segment.text) ?? null;
738
+ var SUBSTITUTION_OPEN = "$(";
739
+ var QUOTED_HEREDOC_CAT = /^[ \t]*cat[ \t]+<<[ \t]*(?:'([A-Za-z_][A-Za-z0-9_]*)'|"([A-Za-z_][A-Za-z0-9_]*)")[ \t]*\n/;
740
+ var CLOSING_PARENTHESIS = /^\s*\)/;
741
+ var LEADING_TABS = /^\t+/;
742
+ var CHARACTERS_ESCAPED_IN_DOUBLE_QUOTES = /["\\$`]/g;
743
+ var isHeredocTerminator = (line, delimiter) => line.replace(LEADING_TABS, "").trimEnd() === delimiter;
744
+ var mightEndAHeredoc = (line, delimiter) => line.trimStart().startsWith(delimiter);
745
+ var BODY_ESCAPES = /[\\`]/;
746
+ var COMMENT_START = "#";
747
+ var WHITESPACE = /\s/;
748
+ var parenthesesBalanceInBody = (body, readsComments) => {
749
+ let depth = 0;
750
+ let quote = null;
751
+ let comment = false;
752
+ let wordStart = true;
753
+ for (const char of body) {
754
+ if (comment) {
755
+ comment = char !== "\n";
756
+ wordStart = true;
757
+ continue;
758
+ }
759
+ if (quote !== null) {
760
+ if (char === quote) quote = null;
761
+ wordStart = false;
762
+ continue;
763
+ }
764
+ if (readsComments && wordStart && char === COMMENT_START) {
765
+ comment = true;
766
+ continue;
767
+ }
768
+ if (char === "'" || char === '"') quote = char;
769
+ if (char === "(") depth += 1;
770
+ if (char === ")") depth -= 1;
771
+ if (depth < 0) return false;
772
+ wordStart = WHITESPACE.test(char);
773
+ }
774
+ return depth === 0 && quote === null;
775
+ };
776
+ var everyBashReadsTheBodyAsText = (body) => !BODY_ESCAPES.test(body) && parenthesesBalanceInBody(body, true) && parenthesesBalanceInBody(body, false);
777
+ var quotedHeredocSubstitutionAt = (command, open) => {
778
+ const header = QUOTED_HEREDOC_CAT.exec(command.slice(open + SUBSTITUTION_OPEN.length));
779
+ const delimiter = header?.[1] ?? header?.[2];
780
+ if (!header || !delimiter) return null;
781
+ const bodyStart = open + SUBSTITUTION_OPEN.length + header[0].length;
782
+ for (let lineStart = bodyStart; lineStart <= command.length; ) {
783
+ const newline = command.indexOf("\n", lineStart);
784
+ const lineEnd = newline === -1 ? command.length : newline;
785
+ const line = command.slice(lineStart, lineEnd);
786
+ if (line === delimiter) {
787
+ const closing = CLOSING_PARENTHESIS.exec(command.slice(lineEnd));
788
+ const body = command.slice(bodyStart, Math.max(bodyStart, lineStart - 1));
789
+ return closing && everyBashReadsTheBodyAsText(body) ? { body, end: lineEnd + closing[0].length } : null;
790
+ }
791
+ if (mightEndAHeredoc(line, delimiter)) return null;
792
+ if (newline === -1) return null;
793
+ lineStart = newline + 1;
794
+ }
795
+ return null;
796
+ };
797
+ var asDoubleQuotedText = (body) => body.replace(CHARACTERS_ESCAPED_IN_DOUBLE_QUOTES, (character) => `\\${character}`);
798
+ var withHeredocSubstitutionsAsQuotedText = (command) => {
799
+ let result = "";
800
+ let copied = 0;
801
+ let quote = null;
802
+ for (let index = 0; index < command.length; index += 1) {
803
+ const char = command.charAt(index);
804
+ if (char === "\\" && quote !== "'") {
805
+ index += 1;
806
+ continue;
807
+ }
808
+ if ((char === "'" || char === '"') && (quote === null || quote === char)) {
809
+ quote = quote === null ? char : null;
810
+ continue;
811
+ }
812
+ if (quote === "'") continue;
813
+ if (char === "`") break;
814
+ if (char !== "$" || command.charAt(index + 1) !== "(") continue;
815
+ const substitution = quote === '"' ? quotedHeredocSubstitutionAt(command, index) : null;
816
+ if (substitution === null) break;
817
+ result += command.slice(copied, index) + asDoubleQuotedText(substitution.body);
818
+ copied = substitution.end;
819
+ index = substitution.end - 1;
820
+ }
821
+ return result + command.slice(copied);
822
+ };
732
823
  var shellVisibleText = (command) => {
733
824
  const lexemes = scanShell(command);
734
825
  if (lexemes === null) return null;
@@ -913,6 +1004,8 @@ var approvalModeWithoutLocalPrompt = (mode) => {
913
1004
  return mode;
914
1005
  }
915
1006
  };
1007
+ var TIMEOUT_ACTION_THAT_REFUSES = "deny";
1008
+ var timeoutActionWithoutLocalPrompt = ({ mode, timeoutAction }) => mode !== "push_only" && timeoutAction === "approve" ? TIMEOUT_ACTION_THAT_REFUSES : timeoutAction;
916
1009
  var MAX_AGENT_QUESTIONS = 4;
917
1010
  var parseAgentQuestion = (raw) => {
918
1011
  const q = raw;
@@ -1181,11 +1274,12 @@ var PATTERN_INTENT = {
1181
1274
  grant: "grant",
1182
1275
  restrict: "restrict"
1183
1276
  };
1277
+ var segmentsForMatching = (command) => shellCommandSegments(withHeredocSubstitutionsAsQuotedText(command));
1184
1278
  var everySegmentMatches = (command, matches) => {
1185
- const segments = shellCommandSegments(command);
1279
+ const segments = segmentsForMatching(command);
1186
1280
  return segments !== null && segments.every(matches);
1187
1281
  };
1188
- var anySegmentMatches = (command, matches) => (shellCommandSegments(command) ?? [command]).some(matches);
1282
+ var anySegmentMatches = (command, matches) => (segmentsForMatching(command) ?? [command]).some(matches);
1189
1283
  var shellSegmentsMatch = (command, intent, matches) => intent === PATTERN_INTENT.restrict ? anySegmentMatches(command, matches) : everySegmentMatches(command, matches);
1190
1284
  var rankWholeOrSegments = (toolName, arg, intent, matches) => {
1191
1285
  const matched = toolName in POLICY_COMMAND_KEYS ? shellSegmentsMatch(arg, intent, matches) : matches(arg);
@@ -1644,7 +1738,9 @@ var INLINE_CODE_INTERPRETERS = /* @__PURE__ */ new Set([
1644
1738
  "lua",
1645
1739
  "osascript",
1646
1740
  "pwsh",
1647
- "powershell"
1741
+ "powershell",
1742
+ "mongosh",
1743
+ "mongo"
1648
1744
  ]);
1649
1745
  var INLINE_CODE_LONG_FLAG = /^-{1,2}(?:eval|print|require|import|command|encodedcommand|enc|ec)(?:=|$)/i;
1650
1746
  var INLINE_CODE_SHORT_FLAG_LETTERS = /* @__PURE__ */ new Set(["c", "e", "E", "p", "r"]);
@@ -1667,7 +1763,15 @@ var DESTRUCTIVE_ARGUMENTS_BY_COMMAND = /* @__PURE__ */ new Map([
1667
1763
  ])],
1668
1764
  ["git checkout", /* @__PURE__ */ new Set(["-f", "--force", "--", "-B"])],
1669
1765
  ["git switch", /* @__PURE__ */ new Set(["-f", "--force", "--discard-changes", "-C", "--force-create"])],
1670
- ["git branch", /* @__PURE__ */ new Set(["-f", "--force", "-D", "-M", "-C"])]
1766
+ ["git branch", /* @__PURE__ */ new Set(["-f", "--force", "-D", "-M", "-C"])],
1767
+ ["git push", /* @__PURE__ */ new Set(["-f", "--force", "--force-with-lease", "--force-if-includes", "--mirror", "-d", "--delete", "--prune"])],
1768
+ ["git clean", /* @__PURE__ */ new Set(["-f", "--force"])],
1769
+ ["rm", /* @__PURE__ */ new Set(["-r", "-R", "--recursive"])],
1770
+ ["pg_restore", /* @__PURE__ */ new Set(["-c", "--clean"])],
1771
+ ["mongorestore", /* @__PURE__ */ new Set(["--drop"])],
1772
+ ["aws s3", /* @__PURE__ */ new Set(["--delete"])],
1773
+ ["gsutil rsync", /* @__PURE__ */ new Set(["-d", "--delete-unmatched-destination-objects"])],
1774
+ ["gcloud storage", /* @__PURE__ */ new Set(["--delete-unmatched-destination-objects"])]
1671
1775
  ]);
1672
1776
  var DESTRUCTIVE_WORDS_IN_ANY_CASE_BY_COMMAND = /* @__PURE__ */ new Map([
1673
1777
  ["redis-cli", /* @__PURE__ */ new Set(["flushall", "flushdb"])]
@@ -1708,7 +1812,8 @@ var SUBCOMMAND_CLIS = /* @__PURE__ */ new Set([
1708
1812
  "heroku",
1709
1813
  "supabase",
1710
1814
  "wrangler",
1711
- "railway"
1815
+ "railway",
1816
+ "bq"
1712
1817
  ]);
1713
1818
  var DESTRUCTIVE_SUBCOMMANDS = /* @__PURE__ */ new Set([
1714
1819
  "delete",
@@ -1810,33 +1915,681 @@ var argumentsHideTheEffect = (name, args) => {
1810
1915
  return (meaningful[0]?.text.startsWith("-") ?? false) || subcommandWordsOf(meaningful).some((word) => word.expands || RUNNER_SUBCOMMANDS.has(word.text));
1811
1916
  };
1812
1917
  var invocationHidesItsEffect = ({ program, args }) => program !== void 0 && ([program, ...args].some((word) => word.comment) || programHidesItsEffect(program) || argumentsHideTheEffect(basenameOf(program.text), args));
1813
- var readableCommandSegments = (command) => shellCommandSegments(command.replace(SHELL_LINE_CONTINUATION, "").replace(SAFE_REDIRECTION, ""));
1814
- var normalizedInvocation = ({ program, args }) => {
1918
+ var commandForReading = (command) => withHeredocSubstitutionsAsQuotedText(command).replace(SHELL_LINE_CONTINUATION, "").replace(SAFE_REDIRECTION, "");
1919
+ var readableCommandSegments = (command) => shellCommandSegments(commandForReading(command));
1920
+ var invocationTextWith = ({ program, args }, wordText) => {
1815
1921
  if (program === void 0) return "";
1816
1922
  const name = basenameOf(program.text);
1817
1923
  const kept = SUBCOMMAND_CLIS.has(name) ? argsAfterHarmlessGlobalFlags(args) : args;
1818
- return [name, ...kept.map((arg) => arg.text)].join(" ");
1819
- };
1924
+ return [name, ...kept.map(wordText)].join(" ");
1925
+ };
1926
+ var normalizedInvocation = (invocation) => invocationTextWith(invocation, (word) => word.text);
1927
+ var SHELL_METACHARACTER = /[\s;&|<>()$`\\"'*?[\]#~{}!]/;
1928
+ var SINGLE_QUOTE = "'";
1929
+ var ESCAPED_SINGLE_QUOTE = `'\\''`;
1930
+ var asOneShellWord = (text) => SHELL_METACHARACTER.test(text) ? `${SINGLE_QUOTE}${text.replaceAll(SINGLE_QUOTE, ESCAPED_SINGLE_QUOTE)}${SINGLE_QUOTE}` : text;
1931
+ var quotedInvocation = (invocation) => invocationTextWith(invocation, (word) => asOneShellWord(word.text));
1820
1932
  var normalizedCommand = (command) => {
1821
1933
  const segments = readableCommandSegments(command);
1822
1934
  return segments === null ? null : segments.map((segment) => normalizedInvocation(invocationOf(segment))).join("; ");
1823
1935
  };
1824
1936
  var subcommandDestroys = ({ program, args }) => program !== void 0 && SUBCOMMAND_CLIS.has(basenameOf(program.text)) && subcommandWordsOf(argsAfterHarmlessGlobalFlags(args)).some((word) => subcommandWordDestroys(word.text));
1937
+ var wordsOfInvocation = ({ program, args }) => program === void 0 ? args : [program, ...args];
1938
+ var PRODUCTION_NAMES = /* @__PURE__ */ new Set(["prod", "production"]);
1939
+ var PRODUCTION_FLAGS = /* @__PURE__ */ new Set(["--prod", "--production"]);
1940
+ var ENVIRONMENT_FLAGS = /* @__PURE__ */ new Set([
1941
+ "-e",
1942
+ "--env",
1943
+ "--environment",
1944
+ "--stage",
1945
+ "--profile",
1946
+ "--context",
1947
+ "--target"
1948
+ ]);
1949
+ var ENVIRONMENT_VARIABLE = /^[A-Z_]*(?:ENV|ENVIRONMENT|STAGE)$/;
1950
+ var FLAG_VALUE_SEPARATOR = "=";
1951
+ var DEPLOY_CLIS = /* @__PURE__ */ new Set([
1952
+ "vercel",
1953
+ "netlify",
1954
+ "fly",
1955
+ "flyctl",
1956
+ "heroku",
1957
+ "railway",
1958
+ "firebase",
1959
+ "wrangler",
1960
+ "supabase",
1961
+ "serverless",
1962
+ "sls"
1963
+ ]);
1964
+ var SCHEMA_CHANGE_WORD = /(?:^|[\s:_./-])(?:migrat(?:e|es|ion|ions)|rollback|seed|db[:\s]push)(?=$|[\s:_./-])(?![\s:_./-]+(?:status|version|list|ls|show|check|diff|history|info)(?:$|[\s:_./-]))/i;
1965
+ var PRODUCTION_READ_VERBS = /* @__PURE__ */ new Set([
1966
+ "logs",
1967
+ "log",
1968
+ "tail",
1969
+ "status",
1970
+ "list",
1971
+ "ls",
1972
+ "info",
1973
+ "inspect",
1974
+ "describe",
1975
+ "get",
1976
+ "show",
1977
+ "whoami",
1978
+ "build",
1979
+ "dev",
1980
+ "open",
1981
+ "history",
1982
+ "metrics",
1983
+ "help",
1984
+ "version",
1985
+ "login",
1986
+ "link",
1987
+ "pull"
1988
+ ]);
1989
+ var PRODUCTION_SETTING_NAMESPACES = /* @__PURE__ */ new Set(["env", "secret", "secrets", "config", "domains", "dns", "certs"]);
1990
+ var deployCliOperandsAfter = (words, cli) => {
1991
+ const after = words.slice(cli + 1);
1992
+ const firstFlag = after.findIndex((word) => FLAG.test(word.text));
1993
+ return (firstFlag === -1 ? after : after.slice(0, firstFlag)).map((word) => word.text.toLowerCase());
1994
+ };
1995
+ var deployCliOnlyReads = (operands) => {
1996
+ const [first, second] = operands.map((operand) => operand.split(":")[0] ?? "");
1997
+ const verb = PRODUCTION_SETTING_NAMESPACES.has(first ?? "") ? second : first;
1998
+ return verb !== void 0 && PRODUCTION_READ_VERBS.has(verb);
1999
+ };
2000
+ var deployCliChangesSomething = (words) => words.some((word, index) => DEPLOY_CLIS.has(basenameOf(word.text)) && !deployCliOnlyReads(deployCliOperandsAfter(words, index)));
2001
+ var valueSelectsProduction = (name, value, names) => names.has(name) && PRODUCTION_NAMES.has(value.toLowerCase());
2002
+ var wordSelectsProduction = (word, previous) => {
2003
+ const separator = word.text.indexOf(FLAG_VALUE_SEPARATOR);
2004
+ const name = separator > 0 ? word.text.slice(0, separator) : "";
2005
+ const value = separator > 0 ? word.text.slice(separator + 1) : "";
2006
+ return PRODUCTION_FLAGS.has(word.text.toLowerCase()) || valueSelectsProduction(name.toLowerCase(), value, ENVIRONMENT_FLAGS) || ENVIRONMENT_VARIABLE.test(name) && PRODUCTION_NAMES.has(value.toLowerCase()) || valueSelectsProduction((previous?.text ?? "").toLowerCase(), word.text, ENVIRONMENT_FLAGS);
2007
+ };
2008
+ var changesProduction = (invocation) => {
2009
+ const words = wordsOfInvocation(invocation);
2010
+ return words.some((word, index) => wordSelectsProduction(word, words[index - 1])) && (deployCliChangesSomething(words) || SCHEMA_CHANGE_WORD.test(normalizedInvocation(invocation)));
2011
+ };
2012
+ var MYSQL_SYNTAX = { inlineFlags: /* @__PURE__ */ new Set(["-e", "--execute"]), scriptFlags: /* @__PURE__ */ new Set(), positionalSql: false };
2013
+ var SQLITE_SYNTAX = { inlineFlags: /* @__PURE__ */ new Set(["-cmd"]), scriptFlags: /* @__PURE__ */ new Set(["-init"]), positionalSql: true };
2014
+ var SQL_CLIENT_SYNTAX = /* @__PURE__ */ new Map([
2015
+ ["psql", { inlineFlags: /* @__PURE__ */ new Set(["-c", "--command"]), scriptFlags: /* @__PURE__ */ new Set(["-f", "--file"]), positionalSql: false }],
2016
+ ["mysql", MYSQL_SYNTAX],
2017
+ ["mariadb", MYSQL_SYNTAX],
2018
+ ["sqlite3", SQLITE_SYNTAX],
2019
+ ["sqlite", SQLITE_SYNTAX],
2020
+ ["duckdb", { inlineFlags: /* @__PURE__ */ new Set(["-c", "-s", "-cmd"]), scriptFlags: /* @__PURE__ */ new Set(["-f", "-init"]), positionalSql: true }],
2021
+ ["clickhouse-client", { inlineFlags: /* @__PURE__ */ new Set(["-q", "--query"]), scriptFlags: /* @__PURE__ */ new Set(["--queries-file"]), positionalSql: false }],
2022
+ ["bq", { inlineFlags: /* @__PURE__ */ new Set(), scriptFlags: /* @__PURE__ */ new Set(), positionalSql: true }],
2023
+ ["mongosh", { inlineFlags: /* @__PURE__ */ new Set(["--eval"]), scriptFlags: /* @__PURE__ */ new Set(["-f", "--file"]), positionalSql: false }],
2024
+ ["mongo", { inlineFlags: /* @__PURE__ */ new Set(["--eval"]), scriptFlags: /* @__PURE__ */ new Set(), positionalSql: false }]
2025
+ ]);
2026
+ var SQL_WRITE_STATEMENT = new RegExp([
2027
+ String.raw`\b(?:insert|update|delete|merge|upsert|alter|create|drop|truncate|grant|revoke|copy|vacuum|reindex|rename|attach|detach)\b`,
2028
+ String.raw`\breplace\s+into\b`,
2029
+ String.raw`\bload\s+data\b`,
2030
+ String.raw`\binto\s+(?:out|dump)file\b`,
2031
+ String.raw`\bset\s+(?:global|persist)\b`,
2032
+ String.raw`\bkill\s+(?:query|connection|\d)`,
2033
+ String.raw`\bcall\s+[\w.]+\s*\(`,
2034
+ String.raw`\bdo\s+(?:\$\w*\$|')`,
2035
+ String.raw`\bpg_terminate_backend\b`,
2036
+ String.raw`\bsetval\b`,
2037
+ String.raw`\bpragma\s+writable_schema\b`,
2038
+ String.raw`\.(?:insert|update|delete|replace|remove|drop|rename|create|bulkwrite|findoneand)\w*\s*\(`
2039
+ ].join("|"), "i");
2040
+ var SQL_READ_PHRASE = /\bshow\s+create\b/gi;
2041
+ var SQL_STRING_LITERAL = /'(?:[^']|'')*'/g;
2042
+ var EMPTY_SQL_STRING = "''";
2043
+ var SQL_COMMENT = /--[^\n]*|\/\*[\s\S]*?\*\//g;
2044
+ var writesThroughSql = (sql) => {
2045
+ const statement = sql.replace(SQL_COMMENT, " ").replace(SQL_STRING_LITERAL, EMPTY_SQL_STRING).replace(SQL_READ_PHRASE, "");
2046
+ return SQL_WRITE_STATEMENT.test(statement) || SQL_CLIENT_FILE_COMMAND.test(statement);
2047
+ };
2048
+ var SQL_CLIENT_FILE_COMMAND = new RegExp([
2049
+ String.raw`(?:^|[\s;=])\\(?:i|ir|include|include_relative|o|out|w|write|gexec|!|\.)(?=\s|$)`,
2050
+ String.raw`(?:^|[\s;=])\\g\s*\|`,
2051
+ String.raw`(?:^|[\s;=])\.(?:read|import|restore|load|output|once|shell|system|backup|save|open)(?=\s|$)`,
2052
+ String.raw`(?:^|[;=])\s*(?:system|source)\s`
2053
+ ].join("|"), "i");
2054
+ var SHORT_FLAG_CLUSTER_ONLY = /^-([A-Za-z0-9]+)$/;
2055
+ var NO_SQL = { script: false, sql: null, hidden: false };
2056
+ var shortFlagOf = (flags, text) => [...flags].find((flag) => /^-[A-Za-z]$/.test(flag) && text.startsWith(flag) && text.length > flag.length && !text.startsWith("--"));
2057
+ var sqlArgumentAt = (args, index, syntax) => {
2058
+ const arg = args[index];
2059
+ if (arg === void 0) return NO_SQL;
2060
+ const next = args[index + 1];
2061
+ const valueOf = (word) => ({ script: false, sql: word?.text ?? null, hidden: word?.expands ?? false });
2062
+ if (syntax.scriptFlags.has(arg.text) || namesALongFlagValue(arg.text, syntax.scriptFlags) || shortFlagOf(syntax.scriptFlags, arg.text)) {
2063
+ return { script: true, sql: null, hidden: false };
2064
+ }
2065
+ if (syntax.inlineFlags.has(arg.text)) return valueOf(next);
2066
+ const longInline = [...syntax.inlineFlags].find((flag) => arg.text.startsWith(`${flag}${FLAG_VALUE_SEPARATOR}`));
2067
+ if (longInline) return { script: false, sql: arg.text.slice(longInline.length + 1), hidden: arg.expands };
2068
+ const shortInline = shortFlagOf(syntax.inlineFlags, arg.text);
2069
+ if (shortInline) return { script: false, sql: arg.text.slice(shortInline.length), hidden: arg.expands };
2070
+ const cluster = SHORT_FLAG_CLUSTER_ONLY.exec(arg.text)?.[1];
2071
+ const last = cluster ? `-${cluster.slice(-1)}` : "";
2072
+ if (cluster && cluster.length > 1 && syntax.scriptFlags.has(last)) return { script: true, sql: null, hidden: false };
2073
+ if (cluster && cluster.length > 1 && syntax.inlineFlags.has(last)) return valueOf(next);
2074
+ return { script: false, sql: arg.text, hidden: false };
2075
+ };
2076
+ var namesALongFlagValue = (text, flags) => [...flags].some((flag) => flag.startsWith("--") && text.startsWith(`${flag}${FLAG_VALUE_SEPARATOR}`));
2077
+ var positionalSqlIsHidden = (args, syntax) => syntax.positionalSql && args.filter((arg) => !arg.text.startsWith("-")).slice(1).some((arg) => arg.expands);
2078
+ var sqlClientSyntaxOf = ({ program }) => program === void 0 ? void 0 : SQL_CLIENT_SYNTAX.get(basenameOf(program.text));
2079
+ var sqlClientChangesData = (invocation) => {
2080
+ const syntax = sqlClientSyntaxOf(invocation);
2081
+ if (syntax === void 0) return false;
2082
+ return positionalSqlIsHidden(invocation.args, syntax) || invocation.args.some((_, index) => {
2083
+ const { script, sql, hidden } = sqlArgumentAt(invocation.args, index, syntax);
2084
+ return script || hidden || sql !== null && writesThroughSql(sql);
2085
+ });
2086
+ };
2087
+ var PULL_REQUEST_CLIS = /* @__PURE__ */ new Set(["gh", "glab"]);
2088
+ var PULL_REQUEST_NOUNS = /* @__PURE__ */ new Set(["pr", "mr"]);
2089
+ var MERGE_SUBCOMMAND = "merge";
2090
+ var PULL_REQUEST_MERGE_PATH = /(?:^|\/)pulls\/\d+\/merge$/;
2091
+ var mergesAPullRequest = ({ program, args }) => {
2092
+ if (program === void 0 || !PULL_REQUEST_CLIS.has(basenameOf(program.text))) return false;
2093
+ const words = args.filter((arg) => !arg.text.startsWith("-"));
2094
+ return words.some((word, index) => PULL_REQUEST_NOUNS.has(word.text) && words[index + 1]?.text === MERGE_SUBCOMMAND) || args.some((arg) => PULL_REQUEST_MERGE_PATH.test(arg.text));
2095
+ };
2096
+ var DEPLOY_AND_SCHEMA_COMMAND_PATTERNS = [
2097
+ "Bash(kubectl apply:*)",
2098
+ "Bash(kubectl replace:*)",
2099
+ "Bash(kubectl scale:*)",
2100
+ "Bash(kubectl rollout restart:*)",
2101
+ "Bash(kubectl rollout undo:*)",
2102
+ "Bash(helm install:*)",
2103
+ "Bash(helm upgrade:*)",
2104
+ "Bash(helm rollback:*)",
2105
+ "Bash(vercel promote:*)",
2106
+ "Bash(vercel rollback:*)",
2107
+ "Bash(railway up:*)",
2108
+ "Bash(prisma db push:*)",
2109
+ "Bash(prisma migrate reset:*)",
2110
+ "Bash(supabase db push:*)",
2111
+ "Bash(supabase db reset:*)",
2112
+ "Bash(drizzle-kit push:*)",
2113
+ "Bash(docker push:*)",
2114
+ "Bash(podman push:*)",
2115
+ "Bash(twine upload:*)",
2116
+ "Bash(npm publish:*)",
2117
+ "Bash(npm unpublish:*)",
2118
+ "Bash(cargo publish:*)",
2119
+ "Bash(gem push:*)",
2120
+ "Bash(poetry publish:*)",
2121
+ "Bash(uv publish:*)",
2122
+ "Bash(pnpm publish:*)",
2123
+ "Bash(yarn publish:*)",
2124
+ "Bash(yarn npm publish:*)",
2125
+ "Bash(bun publish:*)",
2126
+ "Bash(gh release create:*)",
2127
+ "Bash(pulumi up:*)",
2128
+ "Bash(pulumi destroy:*)",
2129
+ "Bash(cdk deploy:*)",
2130
+ "Bash(cdk destroy:*)",
2131
+ "Bash(tofu apply:*)",
2132
+ "Bash(tofu destroy:*)",
2133
+ "Bash(terraform apply:*)",
2134
+ "Bash(terraform destroy:*)",
2135
+ "Bash(firebase deploy:*)",
2136
+ "Bash(fly deploy:*)",
2137
+ "Bash(flyctl deploy:*)",
2138
+ "Bash(wrangler deploy:*)",
2139
+ "Bash(wrangler publish:*)",
2140
+ "Bash(serverless deploy:*)",
2141
+ "Bash(sls deploy:*)",
2142
+ "Bash(gcloud app deploy:*)",
2143
+ "Bash(gcloud run deploy:*)",
2144
+ "Bash(gcloud functions deploy:*)"
2145
+ ];
2146
+ var SECRET_FILE_NAME = /^(?:\.env(?:\.(?!example$|sample$|template$)[\w.-]+)?|(?:secrets?|credentials)\.(?:json|ya?ml|env|toml|ini)|credentials)$/i;
2147
+ var REDIRECTS_INTO_A_SECRET_FILE = />>?\s*(?:[^\s;|&<>]*\/)?\.env(?:\.[\w-]+)?(?=$|[\s;|&)])/;
2148
+ var COPIES_ONTO_ITS_LAST_OPERAND = /* @__PURE__ */ new Set(["cp", "install", "ln", "rsync", "scp"]);
2149
+ var WRITES_EVERY_OPERAND = /* @__PURE__ */ new Set(["mv", "tee", "rm", "unlink", "shred", "truncate"]);
2150
+ var EDITS_IN_PLACE = /* @__PURE__ */ new Set(["sed", "gsed", "perl"]);
2151
+ var IN_PLACE_FLAG = /^(?:-[A-Za-z]*i|--in-place(?:=.*)?)$/;
2152
+ var namesASecretFile = (word) => word !== void 0 && SECRET_FILE_NAME.test(basenameOf(word.text));
2153
+ var NETWORK_SENDERS = /* @__PURE__ */ new Set([
2154
+ "curl",
2155
+ "wget",
2156
+ "scp",
2157
+ "sftp",
2158
+ "rsync",
2159
+ "nc",
2160
+ "ncat",
2161
+ "http",
2162
+ "https",
2163
+ "xh",
2164
+ "gh",
2165
+ "aws",
2166
+ "gsutil",
2167
+ "rclone"
2168
+ ]);
2169
+ var FILE_REFERENCE_PREFIX = /^(?:[\w.-]+=)?@|^[\w.-]+:/;
2170
+ var namesASecretFileReference = (word) => SECRET_FILE_NAME.test(basenameOf(word.text.replace(FILE_REFERENCE_PREFIX, "")));
2171
+ var sendsASecretFile = ({ program, args }) => program !== void 0 && NETWORK_SENDERS.has(basenameOf(program.text)) && args.some(namesASecretFileReference);
2172
+ var writesASecretFile = ({ program, args }) => {
2173
+ if (program === void 0) return false;
2174
+ if (sendsASecretFile({ program, args })) return true;
2175
+ const name = basenameOf(program.text);
2176
+ const operands = args.filter((arg) => !FLAG.test(arg.text));
2177
+ if (COPIES_ONTO_ITS_LAST_OPERAND.has(name)) return namesASecretFile(operands.at(-1));
2178
+ if (WRITES_EVERY_OPERAND.has(name)) return operands.some(namesASecretFile);
2179
+ return EDITS_IN_PLACE.has(name) && args.some((arg) => IN_PLACE_FLAG.test(arg.text)) && operands.some(namesASecretFile);
2180
+ };
1825
2181
  var segmentNeedsAPerson = (toolName, segment) => {
1826
2182
  const invocation = invocationOf(segment);
1827
2183
  const normalized = normalizedInvocation(invocation);
1828
- 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);
2184
+ return invocationHidesItsEffect(invocation) || subcommandDestroys(invocation) || changesWhatIsDeployed(toolName, invocation, normalized) || sqlClientChangesData(invocation) || classifyDecisionRisk(toolName, normalized) !== "standard" || isCoveredByPolicy(CAPABILITY_PATTERNS.destructive, toolName, normalized) || isCoveredByPolicy(CAPABILITY_PATTERNS.network, toolName, normalized) || isCoveredByPolicy(DATA_LOSS_COMMAND_PATTERNS, toolName, normalized);
1829
2185
  };
1830
2186
  var commandNeedsAPerson = (toolName, command) => {
1831
2187
  if (toolName === "Bash" && isSafeReadOnlyCommand(command)) return false;
1832
2188
  const segments = readableCommandSegments(command);
1833
- return segments === null || classifyDecisionRisk(toolName, command) !== "standard" || segments.some((segment) => segmentNeedsAPerson(toolName, segment));
2189
+ return segments === null || classifyDecisionRisk(toolName, command) !== "standard" || segments.some((segment) => segmentNeedsAPerson(toolName, segment)) || pipesIntoASqlClient(command);
2190
+ };
2191
+ var VISIBLE_DATA_LOSS_PATTERNS = [
2192
+ "Bash(git branch -D:*)",
2193
+ "Bash(git branch --delete:*)",
2194
+ "Bash(git stash drop:*)",
2195
+ "Bash(git stash clear:*)",
2196
+ "Bash(git filter-branch:*)",
2197
+ "Bash(git update-ref -d:*)",
2198
+ "Bash(git reflog expire:*)",
2199
+ "Bash(git prune:*)",
2200
+ "Bash(dd :*)",
2201
+ "Bash(shred:*)",
2202
+ "Bash(chmod -R:*)",
2203
+ "Bash(chown -R:*)",
2204
+ "Bash(dropdb:*)",
2205
+ "Bash(mkfs:*)",
2206
+ "Bash(rclone sync:*)",
2207
+ "Bash(rclone delete:*)",
2208
+ "Bash(rclone purge:*)",
2209
+ "Bash(diskutil eraseDisk:*)",
2210
+ "Bash(diskutil eraseVolume:*)",
2211
+ "Bash(diskutil zeroDisk:*)",
2212
+ "Bash(diskutil secureErase:*)",
2213
+ "Bash(diskutil partitionDisk:*)",
2214
+ "Bash(diskutil reformat:*)"
2215
+ ];
2216
+ var NEW_BRANCH_FLAGS = /* @__PURE__ */ new Set(["-b", "--orphan"]);
2217
+ var CHECKOUT_PATH_FLAGS = /* @__PURE__ */ new Set(["-p", "--patch", "--ours", "--theirs", "--pathspec-from-file"]);
2218
+ var UNSTAGE_ONLY_FLAGS = /* @__PURE__ */ new Set(["--staged", "-S"]);
2219
+ var WORKTREE_FLAGS = /* @__PURE__ */ new Set(["--worktree", "-W"]);
2220
+ var DISCARDING_RESET_MODES = /* @__PURE__ */ new Set(["--hard", "--merge", "--keep"]);
2221
+ var FORCE_FLAGS = /* @__PURE__ */ new Set(["-f", "--force"]);
2222
+ var REFSPEC_THAT_FORCES_OR_DELETES = /^[+:]/;
2223
+ var LOOKS_LIKE_A_PATH = /^\.{1,2}$|\/$|[*?[]|(?:^|\/)[^/]+\.[A-Za-z][A-Za-z0-9]*$/;
2224
+ var GIT_WORK_DISCARDERS = /* @__PURE__ */ new Map([
2225
+ ["checkout", (flags, operands) => !flags.some((flag) => NEW_BRANCH_FLAGS.has(flag)) && (flags.some((flag) => CHECKOUT_PATH_FLAGS.has(flag)) || operands.length > 1 || operands.some((operand) => LOOKS_LIKE_A_PATH.test(operand)))],
2226
+ ["restore", (flags) => !flags.some((flag) => UNSTAGE_ONLY_FLAGS.has(flag)) || flags.some((flag) => WORKTREE_FLAGS.has(flag))],
2227
+ ["reset", (flags) => flags.some((flag) => DISCARDING_RESET_MODES.has(flag))],
2228
+ ["push", (_flags, operands) => operands.some((operand) => REFSPEC_THAT_FORCES_OR_DELETES.test(operand))],
2229
+ ["worktree", (flags, operands) => operands[0] === "remove" && flags.some((flag) => FORCE_FLAGS.has(flag))]
2230
+ ]);
2231
+ var gitDiscardsWork = ({ program, args }) => {
2232
+ if (program === void 0 || basenameOf(program.text) !== "git") return false;
2233
+ const [subcommand, ...rest] = argsAfterHarmlessGlobalFlags(args);
2234
+ const discards = GIT_WORK_DISCARDERS.get(subcommand?.text ?? "");
2235
+ const texts = rest.map((arg) => arg.text);
2236
+ return discards !== void 0 && discards(texts.filter((text) => FLAG.test(text)), texts.filter((text) => !FLAG.test(text)));
2237
+ };
2238
+ var PACKAGE_MANAGERS = /* @__PURE__ */ new Set([
2239
+ "npm",
2240
+ "pnpm",
2241
+ "yarn",
2242
+ "bun",
2243
+ "pip",
2244
+ "pip3",
2245
+ "cargo",
2246
+ "brew",
2247
+ "gem",
2248
+ "uv",
2249
+ "poetry"
2250
+ ]);
2251
+ var GIT = "git";
2252
+ var removesAPackage = ({ program, args }) => program !== void 0 && PACKAGE_MANAGERS.has(basenameOf(program.text)) && subcommandWordDestroys(subcommandWordsOf(argsAfterHarmlessGlobalFlags(args))[0]?.text ?? "");
2253
+ var subcommandDestroysVisibly = (invocation) => subcommandDestroys(invocation) && basenameOf(invocation.program?.text ?? "") !== GIT && !removesAPackage(invocation);
2254
+ var SERVICE_MANAGER_READ_VERBS = /* @__PURE__ */ new Map([
2255
+ ["systemctl", /* @__PURE__ */ new Set([
2256
+ "status",
2257
+ "show",
2258
+ "cat",
2259
+ "help",
2260
+ "list-units",
2261
+ "list-unit-files",
2262
+ "list-timers",
2263
+ "list-sockets",
2264
+ "list-dependencies",
2265
+ "list-jobs",
2266
+ "is-active",
2267
+ "is-enabled",
2268
+ "is-failed",
2269
+ "is-system-running",
2270
+ "get-default"
2271
+ ])],
2272
+ ["launchctl", /* @__PURE__ */ new Set([
2273
+ "list",
2274
+ "print",
2275
+ "print-disabled",
2276
+ "print-cache",
2277
+ "blame",
2278
+ "help",
2279
+ "version",
2280
+ "getenv",
2281
+ "managerpid",
2282
+ "managername",
2283
+ "manageruid",
2284
+ "hostinfo",
2285
+ "dumpstate"
2286
+ ])]
2287
+ ]);
2288
+ var changesAService = ({ program, args }) => {
2289
+ const readVerbs = program === void 0 ? void 0 : SERVICE_MANAGER_READ_VERBS.get(basenameOf(program.text));
2290
+ const verb = args.find((arg) => !FLAG.test(arg.text))?.text;
2291
+ return readVerbs !== void 0 && verb !== void 0 && !readVerbs.has(verb);
2292
+ };
2293
+ var CRONTAB = "crontab";
2294
+ var CRONTAB_USER_FLAG = "-u";
2295
+ var CRONTAB_REMOVE_FLAG = "-r";
2296
+ var replacesTheCrontab = ({ program, args }) => program !== void 0 && basenameOf(program.text) === CRONTAB && args.some((arg, index) => arg.text === CRONTAB_REMOVE_FLAG || arg.text === STANDARD_INPUT_ARGUMENT || !FLAG.test(arg.text) && args[index - 1]?.text !== CRONTAB_USER_FLAG);
2297
+ var FIND_DELETE = "-delete";
2298
+ var FIND_RUNNERS = /* @__PURE__ */ new Set(["-exec", "-execdir", "-ok", "-okdir"]);
2299
+ var FIND_RUNNER_END = /* @__PURE__ */ new Set([";", "+"]);
2300
+ var losesDataVisibly = (toolName, invocation, normalized, depth) => {
2301
+ const { program, args } = invocation;
2302
+ if (program === void 0) return false;
2303
+ const name = basenameOf(program.text);
2304
+ if (name === "find") {
2305
+ return args.some((arg) => arg.text === FIND_DELETE) || args.some((arg, index) => FIND_RUNNERS.has(arg.text) && invocationHasAVisibleConsequence(toolName, {
2306
+ program: args[index + 1],
2307
+ args: args.slice(index + 2, findRunnerEnd(args, index + 2))
2308
+ }, depth + 1));
2309
+ }
2310
+ const destructiveArguments = destructiveArgumentsOf(name, args);
2311
+ return destructiveArguments !== void 0 && args.some((arg) => namesDestructiveArgument(arg.text, destructiveArguments)) || namesDestructiveWordInAnyCase(name, args.map((arg) => arg.text)) || gitDiscardsWork(invocation) || changesAService(invocation) || replacesTheCrontab(invocation) || isCoveredByPolicy(VISIBLE_DATA_LOSS_PATTERNS, toolName, normalized);
2312
+ };
2313
+ var findRunnerEnd = (args, from) => {
2314
+ const end = args.findIndex((arg, index) => index >= from && FIND_RUNNER_END.has(arg.text));
2315
+ return end === -1 ? args.length : end;
2316
+ };
2317
+ var wrapperSyntax = (optionsWithAValue = [], operandsBeforeTheCommand = 0) => ({ optionsWithAValue: new Set(optionsWithAValue), operandsBeforeTheCommand });
2318
+ var ENVIRONMENT_ASSIGNMENTS = wrapperSyntax();
2319
+ var WRAPPER_SYNTAX = /* @__PURE__ */ new Map([
2320
+ ["env", wrapperSyntax(["-u", "--unset", "-C", "--chdir", "-S", "--split-string", "-P"])],
2321
+ ["xargs", wrapperSyntax([
2322
+ "-I",
2323
+ "-J",
2324
+ "-R",
2325
+ "-S",
2326
+ "-n",
2327
+ "-L",
2328
+ "-P",
2329
+ "-s",
2330
+ "-d",
2331
+ "-E",
2332
+ "-a",
2333
+ "--max-args",
2334
+ "--max-lines",
2335
+ "--max-procs",
2336
+ "--max-chars",
2337
+ "--delimiter",
2338
+ "--arg-file",
2339
+ "--eof",
2340
+ "--replace"
2341
+ ])],
2342
+ ["timeout", wrapperSyntax(["-s", "--signal", "-k", "--kill-after"], 1)],
2343
+ ["nice", wrapperSyntax(["-n", "--adjustment"])],
2344
+ ["ionice", wrapperSyntax(["-c", "--class", "-n", "--classdata"])],
2345
+ ["stdbuf", wrapperSyntax(["-i", "-o", "-e", "--input", "--output", "--error"])],
2346
+ ["flock", wrapperSyntax(["-w", "--wait", "--timeout", "-E", "--conflict-exit-code"], 1)],
2347
+ ["caffeinate", wrapperSyntax(["-t", "-w"])],
2348
+ ["sudo", wrapperSyntax([
2349
+ "-u",
2350
+ "--user",
2351
+ "-g",
2352
+ "--group",
2353
+ "-C",
2354
+ "--close-from",
2355
+ "-h",
2356
+ "--host",
2357
+ "-p",
2358
+ "--prompt",
2359
+ "-U",
2360
+ "--other-user",
2361
+ "-r",
2362
+ "--role",
2363
+ "-t",
2364
+ "--type",
2365
+ "-D",
2366
+ "--chdir"
2367
+ ])],
2368
+ ["doas", wrapperSyntax(["-u", "-C"])],
2369
+ ["time", wrapperSyntax(["-f", "--format", "-o", "--output"])],
2370
+ ["watch", wrapperSyntax(["-n", "--interval"])],
2371
+ ["nohup", wrapperSyntax()],
2372
+ ["command", wrapperSyntax()],
2373
+ ["builtin", wrapperSyntax()],
2374
+ ["exec", wrapperSyntax(["-a"])],
2375
+ ["unbuffer", wrapperSyntax()],
2376
+ ["npx", wrapperSyntax(["-p", "--package", "-c", "--call"])],
2377
+ ["bunx", wrapperSyntax(["-p", "--package"])],
2378
+ ["pnpx", wrapperSyntax()],
2379
+ ["uvx", wrapperSyntax(["--from", "--with", "-p", "--python"])]
2380
+ ]);
2381
+ var SHELLS = /* @__PURE__ */ new Set(["sh", "bash", "zsh", "dash", "ksh"]);
2382
+ var SCRIPT_FLAG_CLUSTER = /^-[A-Za-z]*c$/;
2383
+ var EVAL = "eval";
2384
+ var MAX_CONSEQUENCE_DEPTH = 4;
2385
+ var commandStartAfterWrapper = (words, syntax) => {
2386
+ let index = 0;
2387
+ while (index < words.length) {
2388
+ const text = words[index]?.text ?? "";
2389
+ if (text === END_OF_OPTIONS) return index + 1 + syntax.operandsBeforeTheCommand;
2390
+ if (!SHELL_ENV_ASSIGNMENT.test(text) && (!FLAG.test(text) || text === STANDARD_INPUT_ARGUMENT)) break;
2391
+ index += syntax.optionsWithAValue.has(text) ? 2 : 1;
2392
+ }
2393
+ return index + syntax.operandsBeforeTheCommand;
2394
+ };
2395
+ var wrappedInvocation = ({ program, args }) => {
2396
+ if (program === void 0) return null;
2397
+ const assigns = SHELL_ENV_ASSIGNMENT.test(program.text);
2398
+ const syntax = assigns ? ENVIRONMENT_ASSIGNMENTS : WRAPPER_SYNTAX.get(basenameOf(program.text));
2399
+ if (syntax === void 0) return null;
2400
+ const words = assigns ? [program, ...args] : args;
2401
+ const start = commandStartAfterWrapper(words, syntax);
2402
+ const command = words[start];
2403
+ return command === void 0 ? null : { program: command, args: words.slice(start + 1) };
2404
+ };
2405
+ var innermostInvocation = (invocation, depth = 0) => {
2406
+ const wrapped = depth < MAX_CONSEQUENCE_DEPTH ? wrappedInvocation(invocation) : null;
2407
+ return wrapped === null ? invocation : innermostInvocation(wrapped, depth + 1);
2408
+ };
2409
+ var shellScriptOf = ({ program, args }) => {
2410
+ if (program === void 0) return null;
2411
+ if (basenameOf(program.text) === EVAL) return args.some((arg) => arg.expands) ? null : args.map((arg) => arg.text).join(" ");
2412
+ if (!SHELLS.has(basenameOf(program.text))) return null;
2413
+ const flag = args.findIndex((arg) => SCRIPT_FLAG_CLUSTER.test(arg.text));
2414
+ const script = flag === -1 ? void 0 : args[flag + 1];
2415
+ return script === void 0 || script.expands ? null : script.text;
2416
+ };
2417
+ var FLAG = /^-/;
2418
+ var FLAG_WITH_ATTACHED_VALUE = /^-[^=]*=/;
2419
+ var withoutLeadingFlags = (args, flagsTakeAValue) => {
2420
+ let index = 0;
2421
+ while (index < args.length && FLAG.test(args[index]?.text ?? "")) {
2422
+ const takesNext = flagsTakeAValue && !FLAG_WITH_ATTACHED_VALUE.test(args[index]?.text ?? "") && !FLAG.test(args[index + 1]?.text ?? "-");
2423
+ index += takesNext ? 2 : 1;
2424
+ }
2425
+ return args.slice(index);
2426
+ };
2427
+ var readingsPastGlobalFlags = ({ program, args }) => {
2428
+ const meaningful = argsAfterHarmlessGlobalFlags(args);
2429
+ if (program === void 0 || !SUBCOMMAND_CLIS.has(basenameOf(program.text)) || !FLAG.test(meaningful[0]?.text ?? "")) return [];
2430
+ return [false, true].map((flagsTakeAValue) => ({ program, args: withoutLeadingFlags(meaningful, flagsTakeAValue) }));
2431
+ };
2432
+ var PREVIEW_FLAG = /^--(?:help|dry-?run(?:=(?:client|server|true))?)$/;
2433
+ var TASK_RUNNERS = /* @__PURE__ */ new Set(["make", "just", "rake", "task"]);
2434
+ var PUBLISH_SUBCOMMAND = "publish";
2435
+ var honoursPreviewFlags = ({ program, args }) => {
2436
+ const name = basenameOf(program?.text ?? "");
2437
+ if (TASK_RUNNERS.has(name)) return false;
2438
+ return !PACKAGE_MANAGERS.has(name) || subcommandWordsOf(argsAfterHarmlessGlobalFlags(args))[0]?.text === PUBLISH_SUBCOMMAND;
2439
+ };
2440
+ var onlyPreviews = (invocation) => invocation.program !== void 0 && honoursPreviewFlags(invocation) && invocation.args.some((arg) => !arg.expands && PREVIEW_FLAG.test(arg.text));
2441
+ var changesWhatIsDeployed = (toolName, invocation, normalized) => !onlyPreviews(invocation) && (changesProduction(invocation) || mergesAPullRequest(invocation) || isCoveredByPolicy(DEPLOY_AND_SCHEMA_COMMAND_PATTERNS, toolName, normalized));
2442
+ var invocationHasAVisibleConsequence = (toolName, invocation, depth) => {
2443
+ if (invocation.program === void 0 || depth > MAX_CONSEQUENCE_DEPTH) return false;
2444
+ const normalized = quotedInvocation(invocation);
2445
+ const wrapped = wrappedInvocation(invocation);
2446
+ const script = shellScriptOf(invocation);
2447
+ return classifyDecisionRisk(toolName, normalized) === "destructive" || changesWhatIsDeployed(toolName, invocation, normalized) || writesASecretFile(invocation) || losesDataVisibly(toolName, invocation, normalized, depth) || subcommandDestroysVisibly(invocation) || sqlClientChangesData(invocation) || wrapped !== null && invocationHasAVisibleConsequence(toolName, wrapped, depth + 1) || script !== null && commandHasAVisibleConsequenceAt(toolName, script, depth + 1) || readingsPastGlobalFlags(invocation).some((reading) => invocationHasAVisibleConsequence(toolName, reading, depth + 1));
2448
+ };
2449
+ var RUNS_FETCHED_CODE = /(?:\$\(|`|<\()\s*(?:curl|wget)\b/;
2450
+ var FETCHING_PROGRAMS = /* @__PURE__ */ new Set(["curl", "wget"]);
2451
+ var READS_ITS_SCRIPT_FROM_STANDARD_INPUT = /^-[A-Za-z]*s[A-Za-z]*$/;
2452
+ var interpreterNameOf = (program) => basenameOf(program.text).replace(/\d+(?:\.\d+)*$/, "");
2453
+ var runsScripts = (program) => SHELLS.has(basenameOf(program.text)) || INLINE_CODE_INTERPRETERS.has(interpreterNameOf(program));
2454
+ var runsWhatItReads = ({ program, args }) => program !== void 0 && runsScripts(program) && (args.length === 0 || args.every((arg) => arg.text.startsWith("-")) || args.some((arg) => arg.text === STANDARD_INPUT_ARGUMENT) || SHELLS.has(basenameOf(program.text)) && args.some((arg) => READS_ITS_SCRIPT_FROM_STANDARD_INPUT.test(arg.text)));
2455
+ var fetches = (invocation) => FETCHING_PROGRAMS.has(basenameOf(innermostInvocation(invocation).program?.text ?? ""));
2456
+ var URL_QUERY_OR_FRAGMENT = /[?#].*$/;
2457
+ var SOURCES_A_SCRIPT = /* @__PURE__ */ new Set(["source", "."]);
2458
+ var downloadedNamesOf = (invocations) => new Set(invocations.filter(fetches).flatMap((invocation) => innermostInvocation(invocation).args.filter((arg) => !FLAG.test(arg.text)).map((arg) => basenameOf(arg.text.replace(URL_QUERY_OR_FRAGMENT, "")))));
2459
+ var runsADownloadedScript = (invocations) => {
2460
+ const downloaded = downloadedNamesOf(invocations);
2461
+ return downloaded.size > 0 && invocations.map((invocation) => innermostInvocation(invocation)).some(({ program, args }) => {
2462
+ if (program === void 0) return false;
2463
+ const script = args.find((arg) => !FLAG.test(arg.text))?.text;
2464
+ return downloaded.has(basenameOf(program.text)) || (runsScripts(program) || SOURCES_A_SCRIPT.has(program.text)) && script !== void 0 && downloaded.has(basenameOf(script));
2465
+ });
2466
+ };
2467
+ var pipedSegmentsOf = (command) => (shellSegmentsReadingAPipe(commandForReading(command)) ?? []).map((segment) => innermostInvocation(invocationOf(withoutShellGrouping(segment))));
2468
+ var pipesIntoASqlClient = (command) => pipedSegmentsOf(command).some((invocation) => sqlClientSyntaxOf(invocation) !== void 0);
2469
+ var pipesFetchedCodeIntoAnInterpreter = (command, invocations) => invocations.some(fetches) && pipedSegmentsOf(command).some(runsWhatItReads);
2470
+ var SHELL_GROUPING_PREFIX = /^\s*(?:(?:if|then|elif|else|do|while|until|!)\s+|[({]\s*)+/;
2471
+ var GROUP_OPENER_BY_CLOSER = /* @__PURE__ */ new Map([[")", "("], ["}", "{"]]);
2472
+ var occurrencesOf = (text, character) => text.split(character).length - 1;
2473
+ var closesAGroupItDidNotOpen = (text) => {
2474
+ const last = text.at(-1) ?? "";
2475
+ const opener = GROUP_OPENER_BY_CLOSER.get(last);
2476
+ return opener !== void 0 && occurrencesOf(text, last) > occurrencesOf(text, opener);
2477
+ };
2478
+ var withoutShellGrouping = (segment) => {
2479
+ let text = segment.replace(SHELL_GROUPING_PREFIX, "").trimEnd();
2480
+ while (closesAGroupItDidNotOpen(text)) text = text.slice(0, -1).trimEnd();
2481
+ return text;
2482
+ };
2483
+ var HEREDOC_OPERATOR = /(?<!<)\d*<<(?!<)-?[ \t]*(?:'([A-Za-z_]\w*)'|"([A-Za-z_]\w*)"|\\?([A-Za-z_]\w*))/g;
2484
+ var HEREDOC_MARK = "\uE001";
2485
+ var withHeredocBodiesSetAside = (command) => {
2486
+ const lines = command.split("\n");
2487
+ const kept = [];
2488
+ const bodies = [];
2489
+ for (let index = 0; index < lines.length; index += 1) {
2490
+ const line = lines[index] ?? "";
2491
+ const delimiters = [...line.matchAll(HEREDOC_OPERATOR)].map((match) => match[1] ?? match[2] ?? match[3] ?? "");
2492
+ kept.push(line.replace(HEREDOC_OPERATOR, ` ${HEREDOC_MARK} `));
2493
+ for (const delimiter of delimiters) {
2494
+ const body = [];
2495
+ for (index += 1; index < lines.length && !mightEndAHeredoc(lines[index] ?? "", delimiter); index += 1) {
2496
+ body.push(lines[index] ?? "");
2497
+ }
2498
+ bodies.push(body.join("\n"));
2499
+ const ending = lines[index];
2500
+ if (ending !== void 0 && !isHeredocTerminator(ending, delimiter)) kept.push(ending);
2501
+ }
2502
+ }
2503
+ return { text: kept.join("\n"), bodies };
2504
+ };
2505
+ var REDIRECTION_TARGET = String.raw`(?:'[^']*'|"[^"]*"|[^\s;|&()<>]+)`;
2506
+ var INPUT_REDIRECTION = new RegExp(String.raw`\d*(?:<<<|<(?![<(&>]))\s*${REDIRECTION_TARGET}`, "g");
2507
+ var OUTPUT_REDIRECTION = new RegExp(String.raw`(?:\d*|&)(?:>>?|>\||<>|>&|<&)\s*${REDIRECTION_TARGET}`, "g");
2508
+ var REDIRECTED_INPUT_MARK = "\uE000";
2509
+ var ROUGH_SEPARATORS = ["&&", "||", "$(", "\n", ";", "|", "&", "`", "(", ")", "{", "}"];
2510
+ var SEPARATORS_INSIDE_DOUBLE_QUOTES = /* @__PURE__ */ new Set(["$(", "`", ")"]);
2511
+ var PIPE2 = "|";
2512
+ var SUBSTITUTION_OPENERS = /* @__PURE__ */ new Set(["$(", "`"]);
2513
+ var QUOTE_CHARACTERS = /['"]/g;
2514
+ var roughPiecesOf = (text) => {
2515
+ const pieces = [];
2516
+ let current = "";
2517
+ let before = "";
2518
+ let quote = null;
2519
+ for (let index = 0; index < text.length; index += 1) {
2520
+ const char = text.charAt(index);
2521
+ if (quote === "'") {
2522
+ current += char;
2523
+ if (char === "'") quote = null;
2524
+ continue;
2525
+ }
2526
+ if (char === "\\") {
2527
+ current += text.slice(index, index + 2);
2528
+ index += 1;
2529
+ continue;
2530
+ }
2531
+ const separator = ROUGH_SEPARATORS.find((candidate) => text.startsWith(candidate, index) && (quote === null || SEPARATORS_INSIDE_DOUBLE_QUOTES.has(candidate)));
2532
+ if (separator !== void 0) {
2533
+ pieces.push({ text: current, before });
2534
+ current = "";
2535
+ before = separator;
2536
+ index += separator.length - 1;
2537
+ continue;
2538
+ }
2539
+ if (char === '"' || char === "'") quote = quote === char ? null : quote ?? char;
2540
+ current += char;
2541
+ }
2542
+ return [...pieces, { text: current, before }];
2543
+ };
2544
+ var invocationOfRoughPiece = (text) => {
2545
+ const piece = withoutShellGrouping(text.replaceAll(REDIRECTED_INPUT_MARK, "").replaceAll(HEREDOC_MARK, ""));
2546
+ const parsed = invocationOf(piece);
2547
+ return parsed.program !== void 0 ? parsed : invocationOf(piece.replace(QUOTE_CHARACTERS, ""));
2548
+ };
2549
+ var roughSegmentsOf = (command) => {
2550
+ const { text, bodies } = withHeredocBodiesSetAside(commandForReading(command));
2551
+ const pieces = roughPiecesOf(text.replace(INPUT_REDIRECTION, ` ${REDIRECTED_INPUT_MARK} `).replace(OUTPUT_REDIRECTION, " "));
2552
+ let heredocsSeen = 0;
2553
+ return pieces.map((piece, index) => {
2554
+ const heredocCount = occurrencesOf(piece.text, HEREDOC_MARK);
2555
+ const heredocs = bodies.slice(heredocsSeen, heredocsSeen + heredocCount);
2556
+ heredocsSeen += heredocCount;
2557
+ return {
2558
+ invocation: invocationOfRoughPiece(piece.text),
2559
+ readsInput: piece.text.includes(REDIRECTED_INPUT_MARK) || heredocCount > 0 || piece.before === PIPE2,
2560
+ readsAPipe: piece.before === PIPE2,
2561
+ feedsASubstitution: SUBSTITUTION_OPENERS.has(pieces[index + 1]?.before ?? ""),
2562
+ heredocs
2563
+ };
2564
+ });
2565
+ };
2566
+ var roughSegmentHasAVisibleConsequence = (toolName, segment, fetchesCode, depth) => {
2567
+ const innermost = innermostInvocation(segment.invocation);
2568
+ const runsAHeredocScript = innermost.program !== void 0 && SHELLS.has(basenameOf(innermost.program.text));
2569
+ return invocationHasAVisibleConsequence(toolName, segment.invocation, depth) || sqlClientSyntaxOf(innermost) !== void 0 && (segment.readsInput || segment.feedsASubstitution) || segment.readsAPipe && fetchesCode && runsWhatItReads(innermost) || runsAHeredocScript && segment.heredocs.some((body) => commandHasAVisibleConsequenceAt(toolName, body, depth + 1));
2570
+ };
2571
+ var roughReadingHasAVisibleConsequence = (toolName, command, depth) => {
2572
+ const segments = roughSegmentsOf(command);
2573
+ const invocations = segments.map((segment) => segment.invocation);
2574
+ const fetchesCode = invocations.some(fetches);
2575
+ return segments.some((segment) => roughSegmentHasAVisibleConsequence(toolName, segment, fetchesCode, depth)) || runsADownloadedScript(invocations);
2576
+ };
2577
+ var commandHasAVisibleConsequenceAt = (toolName, command, depth) => {
2578
+ if (toolName === "Bash" && isSafeReadOnlyCommand(command)) return false;
2579
+ const readable = withHeredocSubstitutionsAsQuotedText(command);
2580
+ if (classifyDecisionRisk(toolName, readable) === "destructive" || RUNS_FETCHED_CODE.test(readable) || REDIRECTS_INTO_A_SECRET_FILE.test(readable)) return true;
2581
+ const segments = readableCommandSegments(command);
2582
+ if (segments === null) return roughReadingHasAVisibleConsequence(toolName, command, depth);
2583
+ const invocations = segments.map((segment) => invocationOf(withoutShellGrouping(segment)));
2584
+ return invocations.some((invocation) => invocationHasAVisibleConsequence(toolName, invocation, depth)) || pipesIntoASqlClient(command) || pipesFetchedCodeIntoAnInterpreter(command, invocations) || runsADownloadedScript(invocations);
1834
2585
  };
2586
+ var commandHasAVisibleConsequence = (toolName, command) => commandHasAVisibleConsequenceAt(toolName, command, 0);
1835
2587
  var withoutSessionToolGrants = (config) => ({
1836
2588
  ...config,
1837
2589
  policies: config.policies.filter((policy) => !isSessionToolGrant(policy))
1838
2590
  });
1839
2591
  var SESSION_TOOL_GRANT_TOOLS = /* @__PURE__ */ new Set(["Bash"]);
2592
+ var isStandingShellAllow = (policy) => !policy.origin && !isSessionToolGrant(policy) && SESSION_TOOL_GRANT_TOOLS.has(policy.tool) && isAutoApprove(policy);
1840
2593
  var MCP_TOOL_PREFIX = "mcp__";
1841
2594
  var parseMcpToolName = (toolName) => {
1842
2595
  if (!toolName.startsWith(MCP_TOOL_PREFIX)) return void 0;
@@ -1908,7 +2661,27 @@ var mcpToolNameNeedsAPerson = (toolName) => {
1908
2661
  const phrase = words.join(" ");
1909
2662
  return words.some(mcpToolWordNeedsAPerson) || classifyDecisionRisk(phrase, phrase) !== "standard";
1910
2663
  };
1911
- var allowsSessionToolGrant = (toolName) => SESSION_TOOL_GRANT_TOOLS.has(toolName) || parseMcpToolName(toolName) !== void 0 && !isPusharyOwnTool(toolName.toLowerCase()) && !mcpToolNameNeedsAPerson(toolName);
2664
+ var MCP_TOOL_VERBS_THAT_ONLY_READ = /* @__PURE__ */ new Set([
2665
+ "get",
2666
+ "list",
2667
+ "search",
2668
+ "read",
2669
+ "fetch",
2670
+ "find",
2671
+ "view",
2672
+ "show",
2673
+ "describe",
2674
+ "lookup",
2675
+ "retrieve",
2676
+ "inspect",
2677
+ "browse",
2678
+ "count"
2679
+ ]);
2680
+ var mcpToolLeadsWithAReadVerb = (toolName) => {
2681
+ const tool = parseMcpToolName(toolName)?.tool;
2682
+ return tool !== void 0 && MCP_TOOL_VERBS_THAT_ONLY_READ.has(wordsOfMcpToolName(tool)[0] ?? "");
2683
+ };
2684
+ var allowsSessionToolGrant = (toolName) => SESSION_TOOL_GRANT_TOOLS.has(toolName) || mcpToolLeadsWithAReadVerb(toolName) && !isPusharyOwnTool(toolName.toLowerCase()) && !mcpToolNameNeedsAPerson(toolName);
1912
2685
  var isSessionToolGrant = (policy) => Boolean(policy.sessionId) && allowsSessionToolGrant(policy.tool) && isAutoApprove(policy);
1913
2686
  var API_KEY_PREFIX_SHAPE = "pk_[a-f0-9]+";
1914
2687
  var API_KEY_PREFIX_PATTERN = new RegExp(`^${API_KEY_PREFIX_SHAPE}$`);
@@ -2438,6 +3211,7 @@ var resolvePolicy = (config, toolName, modeOverride, toolInput, cwd, repoKey, se
2438
3211
  };
2439
3212
  const governedBySpecificRule = isSpecificArgumentRank(match?.rank);
2440
3213
  const governedBySessionToolGrant = match?.rank === "tool" && isSessionToolGrant(match.policy);
3214
+ const governedByStandingShellAllow = match?.rank === "tool" && isStandingShellAllow(match.policy);
2441
3215
  const governingMode = base.mode;
2442
3216
  const approvedByReadOnlyFloor = !isAutoDeny(base) && (shellReadOnlyFloorApplies(toolName, arg, match?.rank) || coordinationFloorApplies(toolName, match?.rank));
2443
3217
  if (governedBySessionToolGrant && !approvedByReadOnlyFloor && typeof arg === "string" && commandNeedsAPerson(toolName, arg)) {
@@ -2447,7 +3221,7 @@ var resolvePolicy = (config, toolName, modeOverride, toolInput, cwd, repoKey, se
2447
3221
  base = autoApprove(base.tool);
2448
3222
  }
2449
3223
  const wouldAutoApprove = isAutoApprove(base);
2450
- if (!governedBySpecificRule && wouldAutoApprove && toolName === "Bash" && typeof arg === "string" && classifyDecisionRisk(toolName, arg) === "destructive") {
3224
+ if (!governedBySpecificRule && wouldAutoApprove && toolName === "Bash" && typeof arg === "string" && (classifyDecisionRisk(toolName, arg) === "destructive" || governedByStandingShellAllow && commandHasAVisibleConsequence(toolName, arg))) {
2451
3225
  base = {
2452
3226
  tool: base.tool,
2453
3227
  timeoutSeconds: config.defaultTimeoutSeconds,
@@ -3200,6 +3974,7 @@ export {
3200
3974
  normalizeKeyScope,
3201
3975
  isApprovalMode,
3202
3976
  approvalModeWithoutLocalPrompt,
3977
+ timeoutActionWithoutLocalPrompt,
3203
3978
  parseAgentQuestion,
3204
3979
  parseAgentQuestions,
3205
3980
  parseAgentQuestionAnswers,