@pushary/agent-hooks 0.89.13 → 0.90.1

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 (78) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/data/SKILL.md +1 -1
  3. package/data/cursor-plugin/skills/pushary/SKILL.md +1 -1
  4. package/data/vscode-plugin/skills/pushary/SKILL.md +1 -1
  5. package/dist/bin/pushary-bell-hook.js +4 -4
  6. package/dist/bin/pushary-bell.js +8 -8
  7. package/dist/bin/pushary-claude.js +72 -21
  8. package/dist/bin/pushary-clean.js +16 -42
  9. package/dist/bin/pushary-codex-bridge.js +37 -12
  10. package/dist/bin/pushary-codex-hook.js +45 -12
  11. package/dist/bin/pushary-codex.js +7 -7
  12. package/dist/bin/pushary-connect.js +11 -10
  13. package/dist/bin/pushary-daemon.js +187 -63
  14. package/dist/bin/pushary-disconnect.js +8 -8
  15. package/dist/bin/pushary-doctor.js +108 -25
  16. package/dist/bin/pushary-elicitation-hook.js +4 -4
  17. package/dist/bin/pushary-gemini-bridge.js +33 -11
  18. package/dist/bin/pushary-gemini-hook.js +21 -10
  19. package/dist/bin/pushary-hook.js +13 -13
  20. package/dist/bin/pushary-login.js +18 -7
  21. package/dist/bin/pushary-logout.js +6 -6
  22. package/dist/bin/pushary-mode.js +28 -21
  23. package/dist/bin/pushary-notification-hook.js +7 -7
  24. package/dist/bin/pushary-opencode-hook.js +8 -8
  25. package/dist/bin/pushary-permission-denied-hook.js +11 -11
  26. package/dist/bin/pushary-permission-hook.js +11 -11
  27. package/dist/bin/pushary-post-hook.js +14 -8
  28. package/dist/bin/pushary-prompt-hook.js +7 -7
  29. package/dist/bin/pushary-session-end-hook.js +7 -7
  30. package/dist/bin/pushary-session-start-hook.js +7 -7
  31. package/dist/bin/pushary-setup.js +168 -45
  32. package/dist/bin/pushary-stats.js +4 -4
  33. package/dist/bin/pushary-status.js +11 -10
  34. package/dist/bin/pushary-stop-hook.js +14 -8
  35. package/dist/bin/pushary-stopfailure-hook.js +7 -7
  36. package/dist/bin/pushary-suggestions.js +2 -2
  37. package/dist/bin/pushary-transcripts.js +6 -6
  38. package/dist/bin/pushary-upgrade.js +15 -15
  39. package/dist/bin/pushary-wait.js +5 -5
  40. package/dist/bin/pushary.js +1 -1
  41. package/dist/{chunk-B2HND22S.js → chunk-2LAHXHBR.js} +1 -1
  42. package/dist/{chunk-GMJDQDXU.js → chunk-43GMYSS4.js} +1 -0
  43. package/dist/{chunk-OX35BSPV.js → chunk-4LOPSGLP.js} +70 -11
  44. package/dist/{chunk-JTBDBKHU.js → chunk-54ELC7D7.js} +1 -1
  45. package/dist/{chunk-C56VHSXU.js → chunk-5NAZ7SFS.js} +1 -1
  46. package/dist/{chunk-4IPSMEGT.js → chunk-7FE2KABY.js} +12 -2
  47. package/dist/{chunk-RAEPAUNJ.js → chunk-7TPQEWUZ.js} +1 -1
  48. package/dist/{chunk-ZO43JTT3.js → chunk-AJYV3VGU.js} +1 -1
  49. package/dist/{chunk-QFJZHVVL.js → chunk-AZPIQG4G.js} +35 -1
  50. package/dist/{chunk-5MNTWAAJ.js → chunk-B6H2KAQC.js} +29 -22
  51. package/dist/{chunk-MNTZKFZI.js → chunk-BQBEH6TV.js} +5 -5
  52. package/dist/{chunk-WHDSJ6PD.js → chunk-BVBEURWJ.js} +1 -1
  53. package/dist/{chunk-ZWEKONU6.js → chunk-CELX75MW.js} +1 -1
  54. package/dist/{chunk-ZP3SNUP7.js → chunk-CNPAT3HL.js} +3 -2
  55. package/dist/{chunk-YXT55PYF.js → chunk-DYP6SMOR.js} +1 -1
  56. package/dist/chunk-DZDI62LY.js +145 -0
  57. package/dist/{chunk-VF3RTVWY.js → chunk-EZIEXHYM.js} +15 -7
  58. package/dist/{chunk-7JZCADBR.js → chunk-F2ICEWZL.js} +101 -19
  59. package/dist/{chunk-JHJHCMAF.js → chunk-F7OURW3C.js} +24 -6
  60. package/dist/{chunk-VASZ6TWW.js → chunk-FQL5E6NG.js} +2 -2
  61. package/dist/{chunk-JVLB5CAJ.js → chunk-GL3FFM7A.js} +7 -4
  62. package/dist/{chunk-5YEF55AX.js → chunk-H2QZRQR2.js} +1 -1
  63. package/dist/{chunk-S4BLNILH.js → chunk-I463AEG3.js} +1 -1
  64. package/dist/{chunk-ANMHIZZY.js → chunk-JW4KO5AF.js} +1 -1
  65. package/dist/{chunk-3YGGEDJK.js → chunk-KUZWXPUS.js} +3 -2
  66. package/dist/{chunk-N4QJ3CLX.js → chunk-L4E2BIJ2.js} +80 -7
  67. package/dist/{chunk-NBDU3R3G.js → chunk-OSALSIUF.js} +1 -1
  68. package/dist/{chunk-KNLKHJZR.js → chunk-PYA4FLKI.js} +32 -21
  69. package/dist/chunk-QCGNGEGE.js +15 -0
  70. package/dist/chunk-S6LYP7QA.js +127 -0
  71. package/dist/{chunk-M3UABYRT.js → chunk-UZNKVRLE.js} +1 -1
  72. package/dist/{chunk-FOGW6O2Y.js → chunk-VHWCVD42.js} +1 -1
  73. package/dist/{chunk-QINYXLA5.js → chunk-VNMKIJZB.js} +15 -2
  74. package/dist/{chunk-CBGGUEKE.js → chunk-Y6BWPERV.js} +90 -7
  75. package/dist/src/index.d.ts +3 -0
  76. package/dist/src/index.js +11 -11
  77. package/package.json +1 -1
  78. package/dist/chunk-MSTHT2M7.js +0 -72
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  reapplyAllAgents
4
- } from "../chunk-MNTZKFZI.js";
5
- import "../chunk-5YEF55AX.js";
4
+ } from "../chunk-BQBEH6TV.js";
5
+ import "../chunk-H2QZRQR2.js";
6
6
  import {
7
7
  waitForMachineReadiness
8
- } from "../chunk-RAEPAUNJ.js";
9
- import "../chunk-MSTHT2M7.js";
10
- import "../chunk-JVLB5CAJ.js";
11
- import "../chunk-B2HND22S.js";
12
- import "../chunk-VF3RTVWY.js";
8
+ } from "../chunk-7TPQEWUZ.js";
9
+ import "../chunk-DZDI62LY.js";
10
+ import "../chunk-GL3FFM7A.js";
11
+ import "../chunk-2LAHXHBR.js";
12
+ import "../chunk-EZIEXHYM.js";
13
13
  import {
14
14
  daemonHasRemoteProof,
15
15
  daemonServiceManagerAvailable,
@@ -20,7 +20,7 @@ import {
20
20
  replaceDaemonService,
21
21
  stopDaemonService,
22
22
  waitForDaemonRemoteProof
23
- } from "../chunk-7JZCADBR.js";
23
+ } from "../chunk-F2ICEWZL.js";
24
24
  import {
25
25
  detectProviderLiveCapabilities,
26
26
  hasSpawnProvider,
@@ -34,32 +34,32 @@ import {
34
34
  npmErrorMessage,
35
35
  resolveGlobalBinary
36
36
  } from "../chunk-L4ZCFMWW.js";
37
- import "../chunk-JTBDBKHU.js";
37
+ import "../chunk-54ELC7D7.js";
38
38
  import {
39
39
  claudeJson,
40
40
  codexConfigToml,
41
41
  cursorPluginDir,
42
42
  geminiSettings,
43
43
  vscodePluginDir
44
- } from "../chunk-3YGGEDJK.js";
44
+ } from "../chunk-KUZWXPUS.js";
45
45
  import {
46
46
  exitOnHelpFlag
47
- } from "../chunk-WHDSJ6PD.js";
48
- import "../chunk-GMJDQDXU.js";
47
+ } from "../chunk-BVBEURWJ.js";
48
+ import "../chunk-43GMYSS4.js";
49
49
  import {
50
50
  isNewerVersion
51
51
  } from "../chunk-DINDL2CF.js";
52
52
  import {
53
53
  readControlMode
54
- } from "../chunk-NBDU3R3G.js";
54
+ } from "../chunk-OSALSIUF.js";
55
55
  import "../chunk-BC3VCZ3E.js";
56
56
  import "../chunk-KZERVKTD.js";
57
- import "../chunk-ANMHIZZY.js";
57
+ import "../chunk-JW4KO5AF.js";
58
58
  import "../chunk-4LL6LG5X.js";
59
59
  import {
60
60
  getApiKey
61
61
  } from "../chunk-2UMNXADU.js";
62
- import "../chunk-QINYXLA5.js";
62
+ import "../chunk-VNMKIJZB.js";
63
63
 
64
64
  // bin/pushary-upgrade.ts
65
65
  import { existsSync } from "fs";
@@ -4,8 +4,8 @@ import {
4
4
  } from "../chunk-IIENZE2J.js";
5
5
  import {
6
6
  exitOnFailedResponse
7
- } from "../chunk-YXT55PYF.js";
8
- import "../chunk-ZO43JTT3.js";
7
+ } from "../chunk-DYP6SMOR.js";
8
+ import "../chunk-AJYV3VGU.js";
9
9
  import {
10
10
  createIo
11
11
  } from "../chunk-5RUIFDTP.js";
@@ -14,8 +14,8 @@ import {
14
14
  } from "../chunk-GMXKITVA.js";
15
15
  import {
16
16
  exitOnHelpFlag
17
- } from "../chunk-WHDSJ6PD.js";
18
- import "../chunk-GMJDQDXU.js";
17
+ } from "../chunk-BVBEURWJ.js";
18
+ import "../chunk-43GMYSS4.js";
19
19
  import "../chunk-DINDL2CF.js";
20
20
  import "../chunk-SAF6HGAA.js";
21
21
  import {
@@ -28,7 +28,7 @@ import {
28
28
  getApiKey,
29
29
  getBaseUrl
30
30
  } from "../chunk-2UMNXADU.js";
31
- import "../chunk-QINYXLA5.js";
31
+ import "../chunk-VNMKIJZB.js";
32
32
 
33
33
  // bin/pushary-wait.ts
34
34
  exitOnHelpFlag("wait");
@@ -3,7 +3,7 @@ import {
3
3
  COMMANDS,
4
4
  isCommandName,
5
5
  renderHelp
6
- } from "../chunk-GMJDQDXU.js";
6
+ } from "../chunk-43GMYSS4.js";
7
7
  import {
8
8
  getPackageVersion
9
9
  } from "../chunk-DINDL2CF.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ASKED_IN_EVERY_MODE_TOOLS
3
- } from "./chunk-QINYXLA5.js";
3
+ } from "./chunk-VNMKIJZB.js";
4
4
 
5
5
  // src/claude-tools.ts
6
6
  var PRETOOLUSE_GATED_TOOLS = [
@@ -149,6 +149,7 @@ var SETUP_OPTIONS = [
149
149
  ["--control auto|on|off", "Manage phone-start automatically (default), require it, or disable its background service"],
150
150
  ["--transcripts on|off", "Enable or disable encrypted transcript sync on this machine"],
151
151
  ["--skip-phone", "Skip the phone connect step"],
152
+ ["--take-over-hooks", "Replace hooks the Pushary Mac app owns with the CLI's. Without it the app's wiring is kept"],
152
153
  ["--verify roundtrip", "Send a real question and wait for you to answer it (default when a human is present)"],
153
154
  ["--verify push", "Only prove a notification was delivered. Automatic when nobody is at the terminal"],
154
155
  ["--verify none", "Skip the final check entirely"],
@@ -4,6 +4,7 @@ import {
4
4
  isDefaultSession,
5
5
  isPolicyConfig,
6
6
  listPendingQuestions,
7
+ listPendingQuestionsForToolUse,
7
8
  markPendingCommandDelivered,
8
9
  readPendingCommand,
9
10
  removePendingCommand,
@@ -12,9 +13,10 @@ import {
12
13
  savePendingCommand,
13
14
  sendNotification,
14
15
  waitForAnswer
15
- } from "./chunk-JHJHCMAF.js";
16
+ } from "./chunk-F7OURW3C.js";
16
17
  import {
17
18
  AGENT_IDENTITIES,
19
+ compactionAction,
18
20
  deriveReceiptMeta,
19
21
  deriveToolTarget,
20
22
  describeToolCall,
@@ -22,20 +24,22 @@ import {
22
24
  parseApplyPatchFiles,
23
25
  parseApplyPatchOps,
24
26
  sessionEndAction,
27
+ sessionIdentityOf,
25
28
  sessionStartAction,
29
+ subagentStopSummary,
26
30
  summarizeStop,
27
31
  taskTitleFrom,
28
32
  toolResultErrorText
29
- } from "./chunk-N4QJ3CLX.js";
33
+ } from "./chunk-L4E2BIJ2.js";
30
34
  import {
31
35
  getMachineId
32
- } from "./chunk-JTBDBKHU.js";
36
+ } from "./chunk-54ELC7D7.js";
33
37
  import {
34
38
  withRetry
35
39
  } from "./chunk-BSZYIAZL.js";
36
40
  import {
37
41
  reportedInstallSource
38
- } from "./chunk-ANMHIZZY.js";
42
+ } from "./chunk-JW4KO5AF.js";
39
43
  import {
40
44
  getApiKey,
41
45
  getBaseUrl
@@ -51,7 +55,7 @@ import {
51
55
  pendingCommandEvents,
52
56
  resolveAutoResolveOrigin,
53
57
  resolvePolicy
54
- } from "./chunk-QINYXLA5.js";
58
+ } from "./chunk-VNMKIJZB.js";
55
59
 
56
60
  // src/policy.ts
57
61
  import { createHash } from "crypto";
@@ -505,6 +509,15 @@ var permissionTimeoutDecision = (timeoutAction) => {
505
509
  };
506
510
  var preToolUseTimeoutDecision = (timeoutAction, denyReason = "No response within timeout") => timeoutAction === "deny" ? codexDeny(denyReason) : codexPass();
507
511
 
512
+ // src/driver.ts
513
+ var DRIVER_ENV = "PUSHARY_DRIVER";
514
+ var PHONE_DRIVER = "phone";
515
+ var driverFromEnv = (env) => env[DRIVER_ENV] === PHONE_DRIVER ? PHONE_DRIVER : void 0;
516
+ var phoneDrivenEnv = (base) => ({
517
+ ...base,
518
+ [DRIVER_ENV]: PHONE_DRIVER
519
+ });
520
+
508
521
  // src/throttle.ts
509
522
  import { join as join4 } from "path";
510
523
  import { tmpdir as tmpdir3 } from "os";
@@ -552,10 +565,13 @@ var readLastPrompt = (sessionId) => {
552
565
  return void 0;
553
566
  }
554
567
  };
555
- var reconcilePendingQuestions = async (sessionId) => {
568
+ var pendingQuestionsToSettle = (sessionId, toolUseId) => {
569
+ const settledElsewhere = toolUseId ? listPendingQuestionsForToolUse(sessionId, toolUseId) : [];
570
+ return [.../* @__PURE__ */ new Set([...settledElsewhere, ...listPendingQuestions(sessionId)])];
571
+ };
572
+ var reconcileQuestions = async (sessionId, files) => {
556
573
  const late = [];
557
574
  try {
558
- const files = listPendingQuestions(sessionId);
559
575
  if (files.length === 0) return late;
560
576
  const apiKey = getApiKey();
561
577
  for (const correlationId of files) {
@@ -576,6 +592,7 @@ var reconcilePendingQuestions = async (sessionId) => {
576
592
  }
577
593
  return late;
578
594
  };
595
+ var reconcilePendingQuestions = (sessionId, toolUseId) => reconcileQuestions(sessionId, pendingQuestionsToSettle(sessionId, toolUseId));
579
596
  var describeLateAnswer = (value) => {
580
597
  const v = (value ?? "").trim();
581
598
  if (v === "yes") return "approved it";
@@ -724,6 +741,7 @@ var reportEvent = async (event, options = {}) => {
724
741
  // Link-back for a phone-spawned session: forward the spawn id the daemon
725
742
  // set in the environment so the server can map spawnId -> sessionId.
726
743
  ...process.env.PUSHARY_SPAWN_ID ? { spawnId: process.env.PUSHARY_SPAWN_ID } : {},
744
+ ...driverFromEnv(process.env) ? { driver: driverFromEnv(process.env) } : {},
727
745
  canDrainCommand: clientCanDrain && !storedCommand,
728
746
  ackMode: clientCanDrain && !storedCommand,
729
747
  skipCommandDrain: storedCommand != null
@@ -780,6 +798,11 @@ var reportEvent = async (event, options = {}) => {
780
798
  }, { maxAttempts: options.maxAttempts ?? 2, baseDelayMs: 300 });
781
799
  };
782
800
  var NON_GATED_MIRROR_TOOLS = /* @__PURE__ */ new Set(["TodoWrite"]);
801
+ var settleQuestionsForToolUse = async (sessionId, toolUseId) => {
802
+ if (!toolUseId) return;
803
+ const late = await reconcileQuestions(sessionId, listPendingQuestionsForToolUse(sessionId, toolUseId));
804
+ for (const answer of late) removePendingQuestion(sessionId, answer.correlationId);
805
+ };
783
806
  var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
784
807
  try {
785
808
  const projectName = basename2(input.cwd ?? process.cwd());
@@ -790,7 +813,7 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
790
813
  const receiptsEnabled = process.env.PUSHARY_RECEIPTS !== "off";
791
814
  const sessionKey = input.session_id || DEFAULT_SESSION;
792
815
  const liveMode = await fetchModeState(getApiKey(), input.session_id, MODE_REUSE_MS);
793
- const late = await reconcilePendingQuestions(sessionKey);
816
+ const late = await reconcilePendingQuestions(sessionKey, input.tool_use_id);
794
817
  let additionalContext;
795
818
  if (late.length > 0 && agent.type === CLAUDE_CODE_AGENT.type) {
796
819
  additionalContext = buildLateAnswerContext(late);
@@ -875,7 +898,7 @@ var handleStop = async (input, agent = CLAUDE_CODE_AGENT) => {
875
898
  agentType: agent.type,
876
899
  agentName: `${agent.label} - ${projectName}`,
877
900
  action: summarizeStop(input),
878
- sessionId: input.session_id,
901
+ ...sessionIdentityOf(input),
879
902
  usage: deriveUsage(input.transcript_path, input.session_id)
880
903
  }, { maxAttempts: 1 })
881
904
  ];
@@ -897,16 +920,46 @@ var handleStop = async (input, agent = CLAUDE_CODE_AGENT) => {
897
920
  return void 0;
898
921
  }
899
922
  };
923
+ var isSubagentStop = (input) => input.hook_event_name === "SubagentStop" || typeof input.agent_id === "string" && input.agent_id.length > 0;
924
+ var SUBAGENT_STOP_REPORT_TIMEOUT_MS = 4e3;
925
+ var handleSubagentStop = async (input, agent = CLAUDE_CODE_AGENT) => {
926
+ try {
927
+ const projectName = basename2(input.cwd ?? process.cwd());
928
+ await reportEvent({
929
+ event: "session_end",
930
+ agentType: agent.type,
931
+ agentName: `${agent.label} - ${projectName}`,
932
+ action: subagentStopSummary(input),
933
+ ...sessionIdentityOf(input)
934
+ }, { maxAttempts: 1, timeoutMs: SUBAGENT_STOP_REPORT_TIMEOUT_MS });
935
+ } catch {
936
+ }
937
+ };
938
+ var isCompactionEvent = (hookEventName) => hookEventName === "PreCompact" || hookEventName === "PostCompact";
939
+ var COMPACTION_REPORT_TIMEOUT_MS = 4e3;
940
+ var handleCompaction = async (input, agent = CLAUDE_CODE_AGENT) => {
941
+ try {
942
+ const projectName = basename2(input.cwd ?? process.cwd());
943
+ await reportEvent({
944
+ event: "compaction",
945
+ agentType: agent.type,
946
+ agentName: `${agent.label} - ${projectName}`,
947
+ action: compactionAction(input.hook_event_name, input.trigger),
948
+ sessionId: input.session_id
949
+ }, { maxAttempts: 1, timeoutMs: COMPACTION_REPORT_TIMEOUT_MS });
950
+ } catch {
951
+ }
952
+ };
900
953
  var handleSessionStart = async (input, agent = CLAUDE_CODE_AGENT) => {
901
954
  try {
902
955
  const projectName = basename2(input.cwd ?? process.cwd());
903
- const action = sessionStartAction(input.source);
956
+ const action = input.agent_id ? "Subagent started" : sessionStartAction(input.source);
904
957
  await reportEvent({
905
958
  event: "session_start",
906
959
  agentType: agent.type,
907
960
  agentName: `${agent.label} - ${projectName}`,
908
961
  action,
909
- sessionId: input.session_id
962
+ ...sessionIdentityOf(input)
910
963
  }, { maxAttempts: 2, timeoutMs: 4e3 });
911
964
  } catch {
912
965
  }
@@ -1033,6 +1086,7 @@ export {
1033
1086
  getPolicy,
1034
1087
  fetchModeState,
1035
1088
  fetchModeOverride,
1089
+ phoneDrivenEnv,
1036
1090
  repoKeyFor,
1037
1091
  throttlePass,
1038
1092
  readLastUserPrompt,
@@ -1048,9 +1102,14 @@ export {
1048
1102
  preToolUseTimeoutDecision,
1049
1103
  readLastPrompt,
1050
1104
  reportEvent,
1105
+ settleQuestionsForToolUse,
1051
1106
  handlePostToolUse,
1052
1107
  handleUserPrompt,
1053
1108
  handleStop,
1109
+ isSubagentStop,
1110
+ handleSubagentStop,
1111
+ isCompactionEvent,
1112
+ handleCompaction,
1054
1113
  handleSessionStart,
1055
1114
  handleSessionEnd,
1056
1115
  handleNotification,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pusharyDir
3
- } from "./chunk-3YGGEDJK.js";
3
+ } from "./chunk-KUZWXPUS.js";
4
4
  import {
5
5
  writeFileAtomic
6
6
  } from "./chunk-4LL6LG5X.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readConfigFileKey
3
- } from "./chunk-NBDU3R3G.js";
3
+ } from "./chunk-OSALSIUF.js";
4
4
 
5
5
  // src/bell/fleet.ts
6
6
  import { closeSync, constants, futimesSync, lstatSync, mkdirSync, openSync, readdirSync, unlinkSync } from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  redactSecrets
3
- } from "./chunk-QINYXLA5.js";
3
+ } from "./chunk-VNMKIJZB.js";
4
4
 
5
5
  // src/crypto.ts
6
6
  import nacl from "tweetnacl";
@@ -98,7 +98,17 @@ var INTERNAL_TYPES = /* @__PURE__ */ new Set([
98
98
  "file-history-snapshot",
99
99
  "change",
100
100
  "queue-operation",
101
- "summary"
101
+ "summary",
102
+ "last-prompt",
103
+ "mode",
104
+ "permission-mode",
105
+ "atis-latch",
106
+ "frame-link",
107
+ "cost-state",
108
+ "agent-name",
109
+ "bridge-session",
110
+ "artifact-autoreact-ledger",
111
+ "artifact-comment-monitor"
102
112
  ]);
103
113
  var redactDeep = (value) => {
104
114
  if (typeof value === "string") return redactSecrets(value);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getMachineId
3
- } from "./chunk-JTBDBKHU.js";
3
+ } from "./chunk-54ELC7D7.js";
4
4
  import {
5
5
  getPackageVersion
6
6
  } from "./chunk-DINDL2CF.js";
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-2UMNXADU.js";
13
13
  import {
14
14
  isValidApiKey
15
- } from "./chunk-QINYXLA5.js";
15
+ } from "./chunk-VNMKIJZB.js";
16
16
 
17
17
  // src/session.ts
18
18
  var IDENTITY_PATH = "/api/v1/server/identity";
@@ -232,9 +232,43 @@ var runHermesPythonScript = (python, script, ...args) => {
232
232
  }
233
233
  };
234
234
 
235
+ // src/cli/dry-run.ts
236
+ import { execSync } from "child_process";
237
+ import { rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
238
+ var createGuards = (isDryRun, note) => ({
239
+ write: (path, contents) => {
240
+ if (isDryRun()) return note("rewrite", path);
241
+ writeFileSync2(path, contents, "utf-8");
242
+ },
243
+ remove: (path, options = {}) => {
244
+ if (isDryRun()) return note("remove ", path);
245
+ rmSync2(path, { recursive: true, force: options.force ?? false });
246
+ },
247
+ exec: (command, options, describe) => {
248
+ if (isDryRun()) return note("run ", describe);
249
+ execSync(command, options);
250
+ }
251
+ });
252
+ var describeService = (effects) => {
253
+ if (effects.controlMode === "off") return "skip the phone-start background service (--control off)";
254
+ const where = effects.serviceDefinitionPath ?? "the phone-start service definition";
255
+ const condition = effects.controlMode === "on" ? "" : ", when a supported agent and a service manager are present";
256
+ return `write ${where} and register it with the OS${condition}`;
257
+ };
258
+ var describeSetupSideEffects = (effects) => [
259
+ `run npm install -g @pushary/agent-hooks@${effects.version} (the hooks run from the global copy; up to two minutes)`,
260
+ `write ${effects.configFile} (the API key, mode 600)`,
261
+ effects.rcPath ? `edit ${effects.rcPath} (export PUSHARY_API_KEY)` : "print the export line for your shell, since no rc file was found",
262
+ describeService(effects),
263
+ "ask Add Pushary instructions to this project's CLAUDE.md/AGENTS.md? (default no)",
264
+ "ask Alias claude to pushary claude? (default no)"
265
+ ];
266
+
235
267
  export {
236
268
  isHermesConfigReceipt,
237
269
  HERMES_CONFIG_SCRIPT,
238
270
  resolveHermesPython,
239
- runHermesPythonScript
271
+ runHermesPythonScript,
272
+ createGuards,
273
+ describeSetupSideEffects
240
274
  };
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  PRETOOLUSE_HANDLED_TOOLS,
3
3
  PRETOOLUSE_PHONE_ANSWERED_TOOLS
4
- } from "./chunk-B2HND22S.js";
4
+ } from "./chunk-2LAHXHBR.js";
5
5
  import {
6
6
  defersToNativeMode
7
- } from "./chunk-S4BLNILH.js";
7
+ } from "./chunk-I463AEG3.js";
8
8
  import {
9
9
  isGatingMoment,
10
10
  recordKeylessMoment
11
- } from "./chunk-FOGW6O2Y.js";
11
+ } from "./chunk-VHWCVD42.js";
12
12
  import {
13
13
  denyReasonFrom,
14
14
  isDeferAnswer
@@ -19,8 +19,9 @@ import {
19
19
  readLastPrompt,
20
20
  readLastUserPrompt,
21
21
  repoKeyFor,
22
+ settleQuestionsForToolUse,
22
23
  throttlePass
23
- } from "./chunk-OX35BSPV.js";
24
+ } from "./chunk-4LOPSGLP.js";
24
25
  import {
25
26
  DEFAULT_SESSION,
26
27
  askUser,
@@ -28,7 +29,7 @@ import {
28
29
  pollForAnswer,
29
30
  savePendingQuestion,
30
31
  sendNotification
31
- } from "./chunk-JHJHCMAF.js";
32
+ } from "./chunk-F7OURW3C.js";
32
33
  import {
33
34
  UNNAMED_ACTION,
34
35
  deriveAction,
@@ -37,10 +38,10 @@ import {
37
38
  deriveToolTarget,
38
39
  describeToolCall,
39
40
  scopePathFor
40
- } from "./chunk-N4QJ3CLX.js";
41
+ } from "./chunk-L4E2BIJ2.js";
41
42
  import {
42
43
  getMachineId
43
- } from "./chunk-JTBDBKHU.js";
44
+ } from "./chunk-54ELC7D7.js";
44
45
  import {
45
46
  getApiKey,
46
47
  getBaseUrl
@@ -52,10 +53,12 @@ import {
52
53
  effectiveWaitSeconds,
53
54
  hookWaitClamped,
54
55
  hookWaitDeadline,
56
+ isPusharyOwnTool,
55
57
  parseAgentQuestionAnswers,
56
58
  parseAgentQuestions,
57
- resolveGate
58
- } from "./chunk-QINYXLA5.js";
59
+ resolveGate,
60
+ stoppedOutput
61
+ } from "./chunk-VNMKIJZB.js";
59
62
 
60
63
  // src/decision-episode.ts
61
64
  var EPISODE_PATH = "/api/agent/decision-episode";
@@ -88,6 +91,7 @@ var allow = () => claudePreToolUseOutput("allow");
88
91
  var deny = (reason) => claudePreToolUseOutput("deny", reason);
89
92
  var allowWithInput = (updatedInput) => claudePreToolUseOutput("allow", void 0, updatedInput);
90
93
  var ask = (reason) => claudePreToolUseOutput("ask", reason);
94
+ var halted = (reason) => stoppedOutput(deny(reason), reason);
91
95
  var storedWaitDeadline = (result, requestedDeadline) => {
92
96
  const stored = result.waitEndsAt ? Date.parse(result.waitEndsAt) : Number.NaN;
93
97
  return Number.isFinite(stored) ? Math.min(stored, requestedDeadline) : requestedDeadline;
@@ -148,7 +152,7 @@ var handlePushOnly = async (apiKey, description, projectName, timeoutSeconds, ti
148
152
  return answer.value === "yes" ? allow() : deny(denyReasonFrom(answer.value, answer.note));
149
153
  }
150
154
  if (timeoutAction === "wait" || clampCut) {
151
- savePendingQuestion(sessionId || DEFAULT_SESSION, result.correlationId);
155
+ savePendingQuestion(sessionId || DEFAULT_SESSION, result.correlationId, decision.toolUseId);
152
156
  return ask(timeoutAction === "wait" ? "Still waiting on your phone. Answer here, or on your phone and it will be applied on the next step." : "This step cannot wait any longer. Answer here, or on your phone and it will be applied on the next step.");
153
157
  }
154
158
  switch (timeoutAction) {
@@ -157,7 +161,7 @@ var handlePushOnly = async (apiKey, description, projectName, timeoutSeconds, ti
157
161
  case "deny":
158
162
  return deny("No response within timeout");
159
163
  default:
160
- savePendingQuestion(sessionId || DEFAULT_SESSION, result.correlationId);
164
+ savePendingQuestion(sessionId || DEFAULT_SESSION, result.correlationId, decision.toolUseId);
161
165
  return ask("No push response, asking in terminal");
162
166
  }
163
167
  };
@@ -201,7 +205,7 @@ var handlePushFirst = async (apiKey, description, projectName, pushFirstSeconds,
201
205
  signals.humanDecision = true;
202
206
  return answer.value === "yes" ? allow() : deny(denyReasonFrom(answer.value, answer.note));
203
207
  }
204
- savePendingQuestion(sessionId || DEFAULT_SESSION, result.correlationId);
208
+ savePendingQuestion(sessionId || DEFAULT_SESSION, result.correlationId, decision.toolUseId);
205
209
  return ask("Sent as push notification. You can also approve here.");
206
210
  };
207
211
  var handleNotifyOnly = async (apiKey, description, projectName, sessionId, machineId) => {
@@ -359,7 +363,7 @@ var askAsOneCard = async (apiKey, input, parsed, projectName, deadline) => {
359
363
  const answer = returnedAnswer(result) ?? await pollForAnswer(apiKey, result.correlationId, storedWaitDeadline(result, deadline));
360
364
  const values = answer.answered && answer.value ? parseAgentQuestionAnswers(parsed, answer.value) : null;
361
365
  if (!values || isDeferAnswer(answer.value)) {
362
- savePendingQuestion(input.session_id || DEFAULT_SESSION, result.correlationId);
366
+ savePendingQuestion(input.session_id || DEFAULT_SESSION, result.correlationId, input.tool_use_id);
363
367
  return void 0;
364
368
  }
365
369
  return values;
@@ -400,14 +404,15 @@ var askQuestionByQuestion = async (apiKey, input, parsed, projectName, deadline)
400
404
  })) : null;
401
405
  const value = values?.[question.question];
402
406
  if (!value || isDeferAnswer(answer.value)) {
403
- savePendingQuestion(input.session_id || DEFAULT_SESSION, result.correlationId);
407
+ savePendingQuestion(input.session_id || DEFAULT_SESSION, result.correlationId, input.tool_use_id);
404
408
  return void 0;
405
409
  }
406
410
  answers[question.question] = value;
407
411
  }
408
412
  return answers;
409
413
  };
410
- var handleAskUserQuestion = async (apiKey, input) => {
414
+ var handleAskUserQuestion = async (apiKey, input, modeState) => {
415
+ if (modeState.askHandoff) return void 0;
411
416
  const parsed = parseQuestions(input.tool_input ?? {});
412
417
  if (!parsed) return void 0;
413
418
  const projectName = basename(input.cwd ?? process.cwd());
@@ -452,7 +457,7 @@ var handleExitPlanMode = async (apiKey, input) => {
452
457
  const answer = returnedAnswer(result) ?? await pollForAnswer(apiKey, result.correlationId, storedWaitDeadline(result, deadline));
453
458
  const value = answer.answered ? (answer.value ?? "").trim() : "";
454
459
  if (!value || isDeferAnswer(answer.value)) {
455
- savePendingQuestion(input.session_id || DEFAULT_SESSION, result.correlationId);
460
+ savePendingQuestion(input.session_id || DEFAULT_SESSION, result.correlationId, input.tool_use_id);
456
461
  return void 0;
457
462
  }
458
463
  if (value === PLAN_APPROVE) return allow();
@@ -487,7 +492,7 @@ var claudeGateInput = (modeState, config, input) => {
487
492
  };
488
493
  };
489
494
  var handlePreToolUse = async (input) => {
490
- if (input.tool_name.startsWith("mcp__pushary__")) return void 0;
495
+ if (isPusharyOwnTool(input.tool_name)) return void 0;
491
496
  let apiKey;
492
497
  try {
493
498
  apiKey = getApiKey();
@@ -498,10 +503,10 @@ var handlePreToolUse = async (input) => {
498
503
  const modeState = await fetchModeState(apiKey, input.session_id);
499
504
  const policy = await getPolicy(apiKey, modeState.policyVersion, "claude_code", true, input.session_id);
500
505
  const verdict = resolveGate(claudeGateInput(modeState, policy, input));
501
- if (verdict.kind === "kill") return deny(verdict.reason);
506
+ if (verdict.kind === "kill") return halted(verdict.reason);
502
507
  if (verdict.kind === "deny") return deny(verdict.reason);
503
508
  if (input.tool_name === "AskUserQuestion") {
504
- return handleAskUserQuestion(apiKey, input);
509
+ return handleAskUserQuestion(apiKey, input, modeState);
505
510
  }
506
511
  if (input.tool_name === "ExitPlanMode") {
507
512
  return handleExitPlanMode(apiKey, input);
@@ -528,6 +533,7 @@ var handlePreToolUse = async (input) => {
528
533
  };
529
534
  var permReqAllow = (updatedInput) => claudePermissionRequestOutput("allow", void 0, updatedInput);
530
535
  var permReqDeny = (message) => claudePermissionRequestOutput("deny", message);
536
+ var permReqHalted = (reason) => stoppedOutput(permReqDeny(reason), reason);
531
537
  var toPermissionRequestOutput = (hookOutput) => {
532
538
  if (!hookOutput) return void 0;
533
539
  const d = hookOutput.hookSpecificOutput;
@@ -540,7 +546,7 @@ var handlePermissionRequest = async (input) => {
540
546
  const reclaimDeferredExec = !PRETOOLUSE_PHONE_ANSWERED_TOOLS.includes(input.tool_name) && shouldDeferToNativeMode(input.permission_mode, input.tool_name);
541
547
  if (!reclaimDeferredExec) return void 0;
542
548
  }
543
- if (input.tool_name.startsWith("mcp__pushary__")) return void 0;
549
+ if (isPusharyOwnTool(input.tool_name)) return void 0;
544
550
  let apiKey;
545
551
  try {
546
552
  apiKey = getApiKey();
@@ -553,7 +559,7 @@ var handlePermissionRequest = async (input) => {
553
559
  const verdict = resolveGate(claudeGateInput(modeState, policy, input));
554
560
  switch (verdict.kind) {
555
561
  case "kill":
556
- return permReqDeny(verdict.reason);
562
+ return permReqHalted(verdict.reason);
557
563
  case "allow":
558
564
  return permReqAllow();
559
565
  case "deny":
@@ -577,7 +583,7 @@ var automodeRetryEnabled = () => {
577
583
  return flag === "1" || flag === "true";
578
584
  };
579
585
  var handlePermissionDenied = async (input) => {
580
- if (input.tool_name.startsWith("mcp__pushary__")) return void 0;
586
+ if (isPusharyOwnTool(input.tool_name)) return void 0;
581
587
  let apiKey;
582
588
  try {
583
589
  apiKey = getApiKey();
@@ -587,6 +593,7 @@ var handlePermissionDenied = async (input) => {
587
593
  try {
588
594
  const projectName = basename(input.cwd ?? process.cwd());
589
595
  const sessionKey = input.session_id || DEFAULT_SESSION;
596
+ await settleQuestionsForToolUse(sessionKey, input.tool_use_id);
590
597
  if (!throttlePass(`permdenied:${sessionKey}:${input.tool_name}`, PERMISSION_DENIED_WINDOW_MS)) return void 0;
591
598
  const mode = await fetchModeState(apiKey, input.session_id).catch(() => null);
592
599
  if (mode?.kill || mode?.mode === "terminal_only") return void 0;
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  detectClaudeVersion
3
- } from "./chunk-5YEF55AX.js";
3
+ } from "./chunk-H2QZRQR2.js";
4
4
  import {
5
5
  claudeWired,
6
6
  codexWired,
7
7
  geminiWired
8
- } from "./chunk-MSTHT2M7.js";
8
+ } from "./chunk-DZDI62LY.js";
9
9
  import {
10
10
  GEMINI_HOOK_BINARY,
11
11
  addClaudeMcpServer,
@@ -14,10 +14,10 @@ import {
14
14
  addPusharyHooks,
15
15
  addPusharyToolPermissions,
16
16
  hasGeminiHooks
17
- } from "./chunk-JVLB5CAJ.js";
17
+ } from "./chunk-GL3FFM7A.js";
18
18
  import {
19
19
  guardBinary
20
- } from "./chunk-VF3RTVWY.js";
20
+ } from "./chunk-EZIEXHYM.js";
21
21
  import {
22
22
  resolveGlobalBinDir,
23
23
  resolveGlobalBinary
@@ -32,7 +32,7 @@ import {
32
32
  codexHooksJson,
33
33
  hasCodexHooks,
34
34
  vscodePluginMcp
35
- } from "./chunk-3YGGEDJK.js";
35
+ } from "./chunk-KUZWXPUS.js";
36
36
  import {
37
37
  readJsonSafe
38
38
  } from "./chunk-4LL6LG5X.js";