@pushary/agent-hooks 1.6.4 → 1.7.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 (102) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +3 -2
  3. package/dist/bin/pushary-bell-hook.js +23 -24
  4. package/dist/bin/pushary-bell.js +10 -11
  5. package/dist/bin/pushary-claude.js +27 -28
  6. package/dist/bin/pushary-clean.js +173 -71
  7. package/dist/bin/pushary-codex-bridge.js +17 -18
  8. package/dist/bin/pushary-codex-hook.js +30 -31
  9. package/dist/bin/pushary-codex.js +12 -13
  10. package/dist/bin/pushary-connect.js +14 -15
  11. package/dist/bin/pushary-cowork.js +5 -6
  12. package/dist/bin/pushary-daemon.js +27 -28
  13. package/dist/bin/pushary-disconnect.js +17 -18
  14. package/dist/bin/pushary-doctor.js +104 -41
  15. package/dist/bin/pushary-elicitation-hook.js +24 -25
  16. package/dist/bin/pushary-gemini-bridge.js +12 -13
  17. package/dist/bin/pushary-gemini-hook.js +27 -28
  18. package/dist/bin/pushary-hook.js +31 -32
  19. package/dist/bin/pushary-login.js +14 -16
  20. package/dist/bin/pushary-logout.js +8 -9
  21. package/dist/bin/pushary-mcp.d.ts +1 -0
  22. package/dist/bin/pushary-mcp.js +56 -0
  23. package/dist/bin/pushary-mode.js +10 -11
  24. package/dist/bin/pushary-notification-hook.js +27 -28
  25. package/dist/bin/pushary-opencode-hook.js +26 -27
  26. package/dist/bin/pushary-permission-denied-hook.js +31 -32
  27. package/dist/bin/pushary-permission-hook.js +30 -31
  28. package/dist/bin/pushary-post-hook.js +27 -28
  29. package/dist/bin/pushary-prompt-hook.js +27 -28
  30. package/dist/bin/pushary-session-end-hook.js +27 -28
  31. package/dist/bin/pushary-session-start-hook.js +31 -32
  32. package/dist/bin/pushary-setup.js +235 -100
  33. package/dist/bin/pushary-stats.js +5 -6
  34. package/dist/bin/pushary-status.js +16 -17
  35. package/dist/bin/pushary-stop-hook.js +27 -28
  36. package/dist/bin/pushary-stopfailure-hook.js +27 -28
  37. package/dist/bin/pushary-suggestions.js +5 -5
  38. package/dist/bin/pushary-transcript-register.js +19 -20
  39. package/dist/bin/pushary-transcripts.js +7 -8
  40. package/dist/bin/pushary-upgrade.js +20 -21
  41. package/dist/bin/pushary-wait.js +10 -11
  42. package/dist/bin/pushary.js +6 -7
  43. package/dist/chunk-2FU43B5Q.js +120 -0
  44. package/dist/{chunk-6NLWK6ZV.js → chunk-3QE3BHBW.js} +2 -2
  45. package/dist/{chunk-NYMPLNV3.js → chunk-3QORH5EJ.js} +3 -3
  46. package/dist/{chunk-LFMOYHPY.js → chunk-3T35OE7C.js} +2 -2
  47. package/dist/{chunk-5U3FJ6YF.js → chunk-42XR73I2.js} +8 -8
  48. package/dist/{chunk-UGKDBJJX.js → chunk-43SSQCWO.js} +3 -3
  49. package/dist/{chunk-K32C2RGK.js → chunk-454KMJHF.js} +17 -9
  50. package/dist/{chunk-YUGGNZSF.js → chunk-4C4NRDIC.js} +1 -1
  51. package/dist/{chunk-HUB4Q35G.js → chunk-55RO62FV.js} +1 -1
  52. package/dist/{chunk-YQMFGWBD.js → chunk-62TEPRWQ.js} +1 -1
  53. package/dist/{chunk-P4BNYJ5Q.js → chunk-6PV2JQ64.js} +2 -2
  54. package/dist/{chunk-53DN77WB.js → chunk-6SJQ442W.js} +2 -2
  55. package/dist/{chunk-UAP556WK.js → chunk-7GI6QC3M.js} +2 -2
  56. package/dist/{chunk-D3K2FPPJ.js → chunk-7GYGVQBU.js} +8 -8
  57. package/dist/{chunk-OZE2TQX5.js → chunk-AAGLDXH4.js} +5 -5
  58. package/dist/{chunk-XJG2FUWS.js → chunk-AHWJHLG5.js} +9 -30
  59. package/dist/{chunk-P4UYILQK.js → chunk-BYVB3RX3.js} +2 -2
  60. package/dist/{chunk-EA3IELHP.js → chunk-EIZW73P5.js} +6 -2
  61. package/dist/{chunk-BY2CRWBO.js → chunk-H6JV44TE.js} +1 -1
  62. package/dist/{chunk-3LU74H52.js → chunk-IGBDOZUO.js} +1 -1
  63. package/dist/{chunk-N62KAMMY.js → chunk-JMBG47WV.js} +30 -1
  64. package/dist/{chunk-DESAUCH2.js → chunk-JTQDP4ZL.js} +4 -6
  65. package/dist/{chunk-LJEL7IB5.js → chunk-KBLIVEFJ.js} +5 -5
  66. package/dist/{chunk-VOCZHOXV.js → chunk-KSNAAMU5.js} +4 -4
  67. package/dist/{chunk-5UWV5GHM.js → chunk-MCNS4725.js} +1 -1
  68. package/dist/{chunk-I3XJATMR.js → chunk-MWVCDP64.js} +1 -1
  69. package/dist/chunk-NAAZCNKI.js +757 -0
  70. package/dist/{chunk-3VZX4NSP.js → chunk-NID4UZDN.js} +1 -1
  71. package/dist/{chunk-BJENQBMH.js → chunk-NQFGVAT6.js} +8 -4
  72. package/dist/{chunk-XOMH53NB.js → chunk-O5JD7UI5.js} +1 -1
  73. package/dist/{chunk-5RUIFDTP.js → chunk-O5PRIYFZ.js} +30 -2
  74. package/dist/{chunk-OSJEMXSR.js → chunk-OAL44FM2.js} +1 -1
  75. package/dist/{chunk-66H2QQAK.js → chunk-OTZHT34O.js} +1 -1
  76. package/dist/{chunk-DZTKLE7Q.js → chunk-P5CBNSYL.js} +1 -1
  77. package/dist/{chunk-GBL4BTG3.js → chunk-Q7QRR6YL.js} +2 -2
  78. package/dist/{chunk-YPONELWS.js → chunk-QPR33SHS.js} +6 -6
  79. package/dist/{chunk-LDRGVXLR.js → chunk-SNWNA3MQ.js} +1 -1
  80. package/dist/{chunk-5SWQZ6HY.js → chunk-SVEMF2VO.js} +4 -4
  81. package/dist/{chunk-VHNDE3ZD.js → chunk-UPKP67TA.js} +2 -2
  82. package/dist/{chunk-PJF7L7AA.js → chunk-VCMFKZON.js} +2 -2
  83. package/dist/{chunk-H6XU22TN.js → chunk-WM3U2RUK.js} +8 -8
  84. package/dist/{chunk-ZA5UXRNE.js → chunk-WSC53O7I.js} +3 -3
  85. package/dist/{chunk-7CLTSZOL.js → chunk-WZWXBTRF.js} +3 -3
  86. package/dist/{chunk-YXPGFRRW.js → chunk-XDASEYRS.js} +3 -3
  87. package/dist/{chunk-CAS7GFWI.js → chunk-XFNVG3OV.js} +75 -5
  88. package/dist/{chunk-I2YUMZLE.js → chunk-XMN37YJH.js} +1 -1
  89. package/dist/{chunk-LQI7W4RG.js → chunk-XPMOCJHN.js} +1 -1
  90. package/dist/{chunk-VA2R64I7.js → chunk-XPTCPU6V.js} +1 -1
  91. package/dist/{chunk-PBKEYMAO.js → chunk-Y6GKOZBT.js} +1 -1
  92. package/dist/{chunk-JOGA3TL2.js → chunk-YQN7S57T.js} +6 -6
  93. package/dist/{chunk-R4HVHTNA.js → chunk-YZKS3ME3.js} +2 -2
  94. package/dist/chunk-ZEMSCGDD.js +87 -0
  95. package/dist/{chunk-EREBZHN2.js → chunk-ZIIYTQHC.js} +4 -4
  96. package/dist/{reapply-4DAJKNVP.js → reapply-66GQIBXN.js} +9 -10
  97. package/dist/src/index.js +19 -20
  98. package/package.json +2 -1
  99. package/dist/chunk-GU3EJCVV.js +0 -43
  100. package/dist/chunk-HWJW3CPO.js +0 -65
  101. package/dist/chunk-NFH73H5B.js +0 -360
  102. package/dist/chunk-P32LPT2L.js +0 -6
@@ -2,29 +2,37 @@
2
2
  import {
3
3
  codexTrustOutcome,
4
4
  describeCodexTrustConfirmation
5
- } from "../chunk-BY2CRWBO.js";
5
+ } from "../chunk-H6JV44TE.js";
6
6
  import {
7
7
  runBrowserLogin
8
- } from "../chunk-YQMFGWBD.js";
8
+ } from "../chunk-62TEPRWQ.js";
9
9
  import {
10
10
  coworkOutput,
11
11
  coworkSelection
12
- } from "../chunk-6NLWK6ZV.js";
12
+ } from "../chunk-3QE3BHBW.js";
13
13
  import "../chunk-PUZZELE6.js";
14
14
  import {
15
15
  detectClaudeVersion
16
- } from "../chunk-PBKEYMAO.js";
16
+ } from "../chunk-Y6GKOZBT.js";
17
17
  import {
18
+ AgentConfigError,
19
+ afterAgentFailureNote,
20
+ agentFailureFromError,
21
+ agentFailureWire,
22
+ configFailureKind,
18
23
  describeVersionManagerPin,
24
+ describedAgentFailure,
25
+ failedAgentsContext,
26
+ retryAgentCommand,
19
27
  versionManagerOf
20
- } from "../chunk-GU3EJCVV.js";
28
+ } from "../chunk-ZEMSCGDD.js";
21
29
  import {
22
30
  ensureCodexTrustsPusharyHooks
23
- } from "../chunk-53DN77WB.js";
31
+ } from "../chunk-6SJQ442W.js";
24
32
  import {
25
33
  readManagedControlEvidence,
26
34
  waitForMachineReadiness
27
- } from "../chunk-JOGA3TL2.js";
35
+ } from "../chunk-YQN7S57T.js";
28
36
  import {
29
37
  HERMES_CONFIG_SCRIPT,
30
38
  HERMES_PIP_PACKAGE,
@@ -32,21 +40,46 @@ import {
32
40
  installAgentSkill,
33
41
  installSkillViaSkillsCli,
34
42
  isHermesConfigReceipt,
43
+ registerCursorGate,
35
44
  resolveHermesPython,
36
45
  runHermesPythonScript
37
- } from "../chunk-N62KAMMY.js";
46
+ } from "../chunk-JMBG47WV.js";
38
47
  import {
48
+ FX_PROFILE_REFUSALS,
49
+ FX_PUSHARY_TOOLS_RULE,
50
+ FX_QUESTION_RULE_RECEIPT,
51
+ FX_QUESTION_TOOL,
52
+ FX_SETTINGS_REFUSALS,
53
+ FX_TOOL_DISCOVERY_NOTE,
39
54
  describeDetection,
40
55
  detectAllAgents,
56
+ fxIgnoresInstructionsFile,
57
+ fxProfileText,
58
+ fxPusharyEntry,
59
+ fxPusharyEntryOf,
60
+ fxQuestionRouting,
61
+ fxSettingsText,
41
62
  isDetected,
63
+ isFxPusharyEntry,
42
64
  pluginLocationSnippet,
65
+ readFxFile,
66
+ readFxProfile,
67
+ readFxSettings,
43
68
  registerPluginLocation,
44
69
  renderAgentInstructions,
45
70
  renderProjectAgentInstructions,
46
71
  shortenHome,
47
72
  vscodeSettingsTargets,
73
+ withFxPusharyServer,
74
+ withPusharyToolsAllowed,
75
+ withQuestionsRoutedToPushary,
76
+ workspacesOverridingPusharyRule,
77
+ workspacesShowingQuestionTool,
48
78
  writeInstructionBlock
49
- } from "../chunk-NFH73H5B.js";
79
+ } from "../chunk-NAAZCNKI.js";
80
+ import {
81
+ MCP_BRIDGE_BINARY
82
+ } from "../chunk-2FU43B5Q.js";
50
83
  import {
51
84
  OPENCODE_HOOK_BINARY,
52
85
  addOpenCodeMcpServer,
@@ -57,7 +90,7 @@ import {
57
90
  openCodePluginDir,
58
91
  openCodePluginFile,
59
92
  openCodeWired
60
- } from "../chunk-3VZX4NSP.js";
93
+ } from "../chunk-NID4UZDN.js";
61
94
  import {
62
95
  addCompatibleHooks,
63
96
  addCompatibleMcpServer,
@@ -68,7 +101,7 @@ import {
68
101
  compatibleMcpFile,
69
102
  compatiblePermissionRuleFile,
70
103
  hasCompatibleHooks
71
- } from "../chunk-LJEL7IB5.js";
104
+ } from "../chunk-KBLIVEFJ.js";
72
105
  import {
73
106
  addClaudeMcpServer,
74
107
  addPusharyHooks,
@@ -76,16 +109,16 @@ import {
76
109
  captureClaudeMcpServer,
77
110
  isClaudeMcpSnapshot,
78
111
  updateClaudeMcpSnapshot
79
- } from "../chunk-ZA5UXRNE.js";
112
+ } from "../chunk-WSC53O7I.js";
80
113
  import {
81
114
  detectProviderLiveCapabilities,
82
115
  hasSpawnProvider,
83
116
  resolveControlPolicy
84
- } from "../chunk-GBL4BTG3.js";
117
+ } from "../chunk-Q7QRR6YL.js";
85
118
  import {
86
119
  describeAutoUpdateAnnouncement,
87
120
  takeAutoUpdateAnnouncement
88
- } from "../chunk-P4UYILQK.js";
121
+ } from "../chunk-BYVB3RX3.js";
89
122
  import {
90
123
  KEEP_HINT,
91
124
  captureHookTakeover,
@@ -95,23 +128,23 @@ import {
95
128
  hookOwnerOf,
96
129
  mcpBearerKey,
97
130
  planHooks
98
- } from "../chunk-5SWQZ6HY.js";
131
+ } from "../chunk-SVEMF2VO.js";
99
132
  import {
100
133
  AGENT_CHOICES,
101
134
  effectiveControlMode,
102
135
  effectiveVerify,
103
136
  parseSetupOptions
104
- } from "../chunk-I2YUMZLE.js";
137
+ } from "../chunk-XMN37YJH.js";
105
138
  import {
106
139
  liveBridgeProbe,
107
140
  resolveBridgeStub
108
- } from "../chunk-I3XJATMR.js";
141
+ } from "../chunk-MWVCDP64.js";
109
142
  import {
110
143
  claudeWired,
111
144
  codexWired,
112
145
  geminiWired,
113
146
  pusharyHookExecutable
114
- } from "../chunk-YXPGFRRW.js";
147
+ } from "../chunk-XDASEYRS.js";
115
148
  import {
116
149
  clearDaemonNeedsLogin,
117
150
  daemonHasRemoteProof,
@@ -124,25 +157,25 @@ import {
124
157
  replaceDaemonService,
125
158
  stopDaemonService,
126
159
  waitForDaemonRemoteProof
127
- } from "../chunk-OZE2TQX5.js";
160
+ } from "../chunk-AAGLDXH4.js";
128
161
  import {
129
162
  GEMINI_HOOK_BINARY,
130
163
  addGeminiHooks,
131
164
  addGeminiMcpServer,
132
165
  compareVersion,
133
166
  parseVersion
134
- } from "../chunk-7CLTSZOL.js";
135
- import "../chunk-LQI7W4RG.js";
167
+ } from "../chunk-WZWXBTRF.js";
168
+ import "../chunk-XPMOCJHN.js";
136
169
  import {
137
170
  transcriptPreferenceForSetup
138
- } from "../chunk-VA2R64I7.js";
171
+ } from "../chunk-XPTCPU6V.js";
139
172
  import "../chunk-XHKBHWLX.js";
140
173
  import {
141
174
  reportEvent
142
- } from "../chunk-H6XU22TN.js";
143
- import "../chunk-YUGGNZSF.js";
144
- import "../chunk-EREBZHN2.js";
145
- import "../chunk-VOCZHOXV.js";
175
+ } from "../chunk-WM3U2RUK.js";
176
+ import "../chunk-4C4NRDIC.js";
177
+ import "../chunk-ZIIYTQHC.js";
178
+ import "../chunk-KSNAAMU5.js";
146
179
  import "../chunk-POFBE6ZY.js";
147
180
  import {
148
181
  BROWSER_CONNECT_COMMAND,
@@ -154,19 +187,20 @@ import {
154
187
  printConnectInstructions,
155
188
  roundTripEvidence,
156
189
  verifyRoundTrip
157
- } from "../chunk-XJG2FUWS.js";
190
+ } from "../chunk-AHWJHLG5.js";
158
191
  import "../chunk-3EGEA4KH.js";
159
192
  import {
160
193
  checkApiKey,
161
194
  describeKeyCheck,
162
195
  samePusharyAccount
163
- } from "../chunk-UGKDBJJX.js";
196
+ } from "../chunk-43SSQCWO.js";
164
197
  import {
165
198
  setHumanStream
166
199
  } from "../chunk-QCGNGEGE.js";
167
200
  import {
201
+ createIo,
168
202
  useColor
169
- } from "../chunk-5RUIFDTP.js";
203
+ } from "../chunk-O5PRIYFZ.js";
170
204
  import "../chunk-GMXKITVA.js";
171
205
  import {
172
206
  KEY_FILE_MODE,
@@ -178,17 +212,17 @@ import {
178
212
  readKeySource,
179
213
  resolveShellRc,
180
214
  writeKey
181
- } from "../chunk-R4HVHTNA.js";
182
- import "../chunk-BJENQBMH.js";
183
- import "../chunk-DESAUCH2.js";
184
- import "../chunk-DZTKLE7Q.js";
215
+ } from "../chunk-YZKS3ME3.js";
216
+ import "../chunk-NQFGVAT6.js";
217
+ import "../chunk-JTQDP4ZL.js";
218
+ import "../chunk-P5CBNSYL.js";
185
219
  import {
186
220
  UsageError
187
221
  } from "../chunk-7QLSKOSU.js";
188
222
  import {
189
223
  EXIT
190
224
  } from "../chunk-KZERVKTD.js";
191
- import "../chunk-VHNDE3ZD.js";
225
+ import "../chunk-UPKP67TA.js";
192
226
  import {
193
227
  addCodexHookTrust,
194
228
  addCodexHooks,
@@ -210,6 +244,11 @@ import {
210
244
  cursorUserMcp,
211
245
  dropVacatedCodexHookTrust,
212
246
  fetchLatestPublishedVersion,
247
+ fxAgentsMd,
248
+ fxConfigDir,
249
+ fxMcpProfile,
250
+ fxQuestionRuleReceipt,
251
+ fxSettings,
213
252
  geminiMd,
214
253
  geminiSettings,
215
254
  guardBinary,
@@ -222,36 +261,33 @@ import {
222
261
  pusharyConfigFile,
223
262
  pusharyDir,
224
263
  readCodexMcpAuth,
225
- registerHookEntry,
226
264
  resolveGlobalBinDir,
227
265
  resolveGlobalBinary,
228
266
  vscodePluginDir,
229
267
  vscodePluginMcp
230
- } from "../chunk-K32C2RGK.js";
268
+ } from "../chunk-454KMJHF.js";
231
269
  import {
232
270
  backupFile,
233
271
  readJsonSafe,
234
272
  writeFileAtomic,
235
273
  writeJsonAtomic
236
274
  } from "../chunk-T7E75EKA.js";
237
- import "../chunk-OSJEMXSR.js";
275
+ import "../chunk-OAL44FM2.js";
276
+ import {
277
+ NPX_LATEST_COMMAND,
278
+ renderCommandHelp
279
+ } from "../chunk-EIZW73P5.js";
238
280
  import {
239
281
  HOOK_COMPATIBLE_PROFILES,
240
282
  HOOK_LOCATOR_BINARY,
241
283
  PRETOOLUSE_GATED_TOOLS,
242
284
  SUPPORT_EMAIL,
243
285
  compatibleTargetFiles,
286
+ getPackageVersion,
244
287
  hookCompatibleProfile,
288
+ isNewerVersion,
245
289
  isValidApiKey
246
- } from "../chunk-CAS7GFWI.js";
247
- import {
248
- NPX_LATEST_COMMAND,
249
- renderCommandHelp
250
- } from "../chunk-EA3IELHP.js";
251
- import {
252
- getPackageVersion,
253
- isNewerVersion
254
- } from "../chunk-HWJW3CPO.js";
290
+ } from "../chunk-XFNVG3OV.js";
255
291
 
256
292
  // bin/pushary-setup.ts
257
293
  import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync, rmSync, renameSync, realpathSync, readdirSync, statSync, openSync, readSync, closeSync } from "fs";
@@ -265,10 +301,6 @@ import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
265
301
  // src/cli/exit.ts
266
302
  var isExitPromptError = (err) => err instanceof Error && (err.name === "ExitPromptError" || err.message.includes("User force closed") || /force closed the prompt/i.test(err.message));
267
303
 
268
- // src/cursor-config.ts
269
- var isPusharyCursorEntry = (entry) => pusharyHookExecutable(String(entry?.command ?? "")) !== null;
270
- var registerCursorGate = (existing, entry) => registerHookEntry(existing, isPusharyCursorEntry, entry);
271
-
272
304
  // src/setup/phone-check.ts
273
305
  var planPhoneCheck = (context) => {
274
306
  if (context.locked) return "locked";
@@ -280,35 +312,6 @@ var planPhoneCheck = (context) => {
280
312
  return "connect";
281
313
  };
282
314
 
283
- // src/setup/agent-failure.ts
284
- var AgentConfigError = class extends Error {
285
- kind;
286
- filePath;
287
- constructor(kind, filePath, message) {
288
- super(message);
289
- this.name = "AgentConfigError";
290
- this.kind = kind;
291
- this.filePath = filePath;
292
- }
293
- };
294
- var configFailureKind = (readFailure) => readFailure === "unparseable" ? "config-unparseable" : "config-unreadable";
295
- var AGENT_FAILURE_DETAILS = {
296
- "not-wired": "reported success but its config is not there.",
297
- "app-account-mismatch": "Mac app hooks kept, but their Pushary account could not be matched to this setup."
298
- };
299
- var describedAgentFailure = (agent, kind) => ({
300
- agent,
301
- kind,
302
- detail: AGENT_FAILURE_DETAILS[kind]
303
- });
304
- var agentFailureFromError = (agent, error, describeError) => ({
305
- agent,
306
- kind: error instanceof AgentConfigError ? error.kind : "installer-error",
307
- detail: describeError(error)
308
- });
309
- var retryAgentCommand = (agent) => `${NPX_LATEST_COMMAND} setup --agents ${agent}`;
310
- var agentFailureWire = (failures) => failures.map(({ agent, kind }) => ({ agent, kind }));
311
-
312
315
  // src/setup/closing.ts
313
316
  var ACTIVITY_URL = "pushary.com/dashboard/agent/activity";
314
317
  var COMMAND_SURFACE = [
@@ -778,24 +781,7 @@ var formatError = (err) => {
778
781
  }
779
782
  return String(err);
780
783
  };
781
- var spinner = async (label, fn, options = {}) => {
782
- const frames = [" ", ". ", ".. ", "..."];
783
- let i = 0;
784
- const interval = setInterval(() => {
785
- writeHuman(`\r ${dim(frames[i++ % frames.length])} ${label}`);
786
- }, 200);
787
- try {
788
- await fn();
789
- clearInterval(interval);
790
- writeHuman(`\r ${check} ${label}
791
- `);
792
- } catch (err) {
793
- clearInterval(interval);
794
- writeHuman(`\r ${yellow("!")} ${label} ${dim(`(${formatError(err)})`)}
795
- `);
796
- if (!options.optional) throw err;
797
- }
798
- };
784
+ var spinner = (label, fn, options = {}) => createIo(humanStream, { json: jsonMode }).spinner(label, fn, options);
799
785
  var checkForUpdates = async (current, markAnnounced) => {
800
786
  const announcement = takeAutoUpdateAnnouncement(autoUpdateState(), markAnnounced);
801
787
  if (announcement) {
@@ -1486,6 +1472,147 @@ var saveApiKey = async (apiKey, controlMode, transcriptSync) => {
1486
1472
  }
1487
1473
  return rc;
1488
1474
  };
1475
+ var fxRetryHint = () => `Fix it, then run ${retryAgentCommand("fx")}.`;
1476
+ var readFxProfileForSetup = (filePath) => {
1477
+ const read = readFxFile(filePath, readFxProfile);
1478
+ if (read.kind === "profile") return read.profile;
1479
+ if (read.kind === "missing") return {};
1480
+ if (read.kind === "unreadable") {
1481
+ throw new AgentConfigError(configFailureKind("unreadable"), filePath, `${filePath} could not be read, so it was left untouched. ${fxRetryHint()}`);
1482
+ }
1483
+ throw new AgentConfigError(
1484
+ configFailureKind("unparseable"),
1485
+ filePath,
1486
+ `${filePath} ${FX_PROFILE_REFUSALS[read.reason]}, so it was left untouched. ${fxRetryHint()}`
1487
+ );
1488
+ };
1489
+ var writeFxProfile = (filePath, profile) => {
1490
+ const rendered = fxProfileText(profile);
1491
+ if (rendered.kind === "refused") {
1492
+ throw new Error(`${filePath} would grow past the size fx reads, so it was left untouched. ${fxRetryHint()}`);
1493
+ }
1494
+ writeFileAtomic(filePath, rendered.text, KEY_FILE_MODE);
1495
+ };
1496
+ var FX_SETTINGS_RULES_SNIPPET = `"permission": { "${FX_PUSHARY_TOOLS_RULE}": "allow", "${FX_QUESTION_TOOL}": "deny" }`;
1497
+ var fxSettingsReadRefusal = (filePath, read) => {
1498
+ if (read.kind === "unreadable") return `${filePath} could not be read`;
1499
+ if (read.kind === "refused") return `${filePath} ${FX_SETTINGS_REFUSALS[read.reason]}`;
1500
+ return null;
1501
+ };
1502
+ var recordFxQuestionRule = () => {
1503
+ try {
1504
+ if (!existsSync(fxQuestionRuleReceipt())) writeJsonAtomic(fxQuestionRuleReceipt(), FX_QUESTION_RULE_RECEIPT, 384);
1505
+ return true;
1506
+ } catch {
1507
+ return false;
1508
+ }
1509
+ };
1510
+ var configureFxSettings = (filePath) => {
1511
+ const read = readFxFile(filePath, readFxSettings);
1512
+ const refusal = fxSettingsReadRefusal(filePath, read);
1513
+ if (refusal) return { kind: "refused", detail: refusal };
1514
+ const allowed = withPusharyToolsAllowed(read.kind === "settings" ? read.settings : {});
1515
+ const routed = withQuestionsRoutedToPushary(allowed.settings);
1516
+ const written = {
1517
+ kind: "written",
1518
+ toolsChange: allowed.change,
1519
+ questionChange: routed.change,
1520
+ questionRouting: fxQuestionRouting(routed.settings, process.env),
1521
+ workspacesWithOwnRules: [.../* @__PURE__ */ new Set([...workspacesOverridingPusharyRule(routed.settings), ...workspacesShowingQuestionTool(routed.settings)])],
1522
+ ruleRecorded: true
1523
+ };
1524
+ if (allowed.change !== "added" && routed.change !== "added") return written;
1525
+ const rendered = fxSettingsText(routed.settings);
1526
+ if (rendered.kind === "refused") return { kind: "refused", detail: `${filePath} would grow past the 64 KiB fx reads` };
1527
+ try {
1528
+ writeFileAtomic(filePath, rendered.text, KEY_FILE_MODE);
1529
+ } catch (err) {
1530
+ return { kind: "refused", detail: `${filePath} could not be written (${formatError(err)})` };
1531
+ }
1532
+ return { ...written, ruleRecorded: routed.change !== "added" || recordFxQuestionRule() };
1533
+ };
1534
+ var FX_QUESTION_ROUTING_REPORTS = {
1535
+ "full-access": "fx runs in full-access mode, which ignores permission rules, so its terminal question tool stays on. Its instructions tell it to ask through Pushary instead; leave full-access mode with /permissions to turn the tool off for certain.",
1536
+ overridden: `A rule in ${fxSettings()} keeps fx's terminal question tool on, so fx can still ask there instead of through Pushary.`
1537
+ };
1538
+ var FX_QUESTION_SUMMARIES = {
1539
+ routed: "fx's agent asks through Pushary, which reaches your phone, or the Mac notch while the Pushary Mac app runs",
1540
+ "full-access": "fx's agent is told to ask through Pushary, but full-access mode keeps fx's terminal prompt available to it",
1541
+ overridden: "fx's terminal prompt stays available, so fx's agent is only told to ask through Pushary"
1542
+ };
1543
+ var reportFxSettings = (outcome) => {
1544
+ if (outcome.kind === "refused") {
1545
+ console.log(` ${yellow("!")} ${outcome.detail}, so Pushary tools were not auto-allowed and fx's terminal question tool stays on.`);
1546
+ noteManual(`Add ${FX_SETTINGS_RULES_SNIPPET} to ${fxSettings()} so fx runs Pushary tools without a prompt and asks through Pushary.`);
1547
+ return;
1548
+ }
1549
+ if (outcome.toolsChange === "user-rule-kept") {
1550
+ console.log(` ${yellow("!")} ${fxSettings()} already has a ${FX_PUSHARY_TOOLS_RULE} rule, so it was left as you set it.`);
1551
+ } else {
1552
+ console.log(` ${check} Auto-allowing Pushary tools (${fxSettings()})`);
1553
+ }
1554
+ if (outcome.questionRouting === "routed") {
1555
+ console.log(` ${check} Turning off fx's terminal question tool, so its questions go through Pushary`);
1556
+ } else if (outcome.questionChange === "user-rule-kept") {
1557
+ console.log(` ${yellow("!")} ${fxSettings()} already has a ${FX_QUESTION_TOOL} rule, so it was left as you set it and fx can still ask in the terminal.`);
1558
+ } else {
1559
+ console.log(` ${yellow("!")} ${FX_QUESTION_ROUTING_REPORTS[outcome.questionRouting]}`);
1560
+ }
1561
+ if (!outcome.ruleRecorded) {
1562
+ console.log(` ${yellow("!")} ${fxQuestionRuleReceipt()} could not be written, so pushary clean will treat the ${FX_QUESTION_TOOL} rule as yours and leave it.`);
1563
+ }
1564
+ if (outcome.workspacesWithOwnRules.length > 0) {
1565
+ console.log(` ${yellow("!")} ${outcome.workspacesWithOwnRules.length} fx workspace(s) set their own permission rules, which replace the global ones there. Add "${FX_PUSHARY_TOOLS_RULE}": "allow" and "${FX_QUESTION_TOOL}": "deny" to each to route them through Pushary.`);
1566
+ }
1567
+ };
1568
+ var teachFxToAskViaPush = () => {
1569
+ if (fxIgnoresInstructionsFile(fxAgentsMd(), fxConfigDir())) return false;
1570
+ writeInstructionBlock(fxAgentsMd(), `${renderAgentInstructions("fx")}
1571
+
1572
+ ${FX_TOOL_DISCOVERY_NOTE}`);
1573
+ return true;
1574
+ };
1575
+ var fxWired = () => {
1576
+ const read = readFxFile(fxMcpProfile(), readFxProfile);
1577
+ return read.kind === "profile" && isFxPusharyEntry(fxPusharyEntryOf(read.profile));
1578
+ };
1579
+ var setupFx = async () => {
1580
+ console.log(`
1581
+ ${bold("Setting up fx")}
1582
+ `);
1583
+ if (process.platform === "win32") {
1584
+ console.log(` ${yellow("!")} fx does not run on Windows. Skipping.`);
1585
+ return "skipped";
1586
+ }
1587
+ if (!existsSync(fxConfigDir())) {
1588
+ console.log(` ${yellow("!")} fx not found (${fxConfigDir()} does not exist). Skipping.`);
1589
+ console.log(` ${dim("Install fx from https://fx.sh, run it once, then re-run setup.")}`);
1590
+ return "skipped";
1591
+ }
1592
+ await installGlobally2();
1593
+ await spinner(`Adding the Pushary MCP server (${fxMcpProfile()})`, async () => {
1594
+ const profile = readFxProfileForSetup(fxMcpProfile());
1595
+ const bridge = resolveGlobalBinary(MCP_BRIDGE_BINARY) ?? MCP_BRIDGE_BINARY;
1596
+ const entry = fxPusharyEntry(guardedArgv({ kind: "binary", path: bridge, runtime: "node" }));
1597
+ writeFxProfile(fxMcpProfile(), withFxPusharyServer(profile, entry));
1598
+ });
1599
+ const settingsOutcome = configureFxSettings(fxSettings());
1600
+ reportFxSettings(settingsOutcome);
1601
+ if (teachFxToAskViaPush()) {
1602
+ console.log(` ${check} Teaching fx to ask via push (${fxAgentsMd()})`);
1603
+ } else {
1604
+ console.log(` ${yellow("!")} ${fxAgentsMd()} links outside ${fxConfigDir()}, and fx ignores such a file, so no instructions were written.`);
1605
+ noteManual(`Replace the ${fxAgentsMd()} symlink with a file so fx loads Pushary's instructions, then run ${retryAgentCommand("fx")}.`);
1606
+ }
1607
+ console.log();
1608
+ console.log(` ${dim("What this configured:")}`);
1609
+ console.log(` ${dim("\u2022")} MCP server ${bold("pushary")} in ${fxMcpProfile()}, which runs ${MCP_BRIDGE_BINARY} and signs in with the key saved in ~/.pushary, so no key is written to fx's config`);
1610
+ console.log(` ${dim("\u2022")} Questions: ${FX_QUESTION_SUMMARIES[settingsOutcome.kind === "written" ? settingsOutcome.questionRouting : "overridden"]}`);
1611
+ console.log(` ${dim("\u2022")} fx cannot hand its own approval prompts to Pushary, so those still wait in the terminal`);
1612
+ console.log(` ${dim("Restart fx, or run /mcp reload in a running session.")}`);
1613
+ noteManual("Restart fx, or run /mcp reload in a running session.");
1614
+ return "configured";
1615
+ };
1489
1616
  var setupCustom = async (apiKey, context) => {
1490
1617
  console.log(`
1491
1618
  ${bold("Connect any other agent (MCP or HTTP)")}
@@ -1667,6 +1794,8 @@ var agentIsWired = (agent) => {
1667
1794
  return existsSync(VSCODE_PLUGIN_MCP);
1668
1795
  case "opencode":
1669
1796
  return openCodeWired();
1797
+ case "fx":
1798
+ return fxWired();
1670
1799
  default: {
1671
1800
  const profile = hookCompatibleProfile(agent);
1672
1801
  if (!profile) return true;
@@ -1759,6 +1888,7 @@ var AGENT_SETUP = {
1759
1888
  cursor: setupCursor,
1760
1889
  vscode: setupVsCode,
1761
1890
  opencode: setupOpenCode,
1891
+ fx: setupFx,
1762
1892
  ...COMPATIBLE_SETUP,
1763
1893
  custom: setupCustom
1764
1894
  };
@@ -1863,6 +1993,7 @@ var AGENT_NAMES = {
1863
1993
  cursor: "Cursor",
1864
1994
  vscode: "VS Code",
1865
1995
  opencode: "OpenCode",
1996
+ fx: "fx",
1866
1997
  ...compatibleRecord((profile) => profile.label),
1867
1998
  custom: "Other"
1868
1999
  };
@@ -1874,6 +2005,7 @@ var AGENT_CAPABILITIES = {
1874
2005
  cursor: "plugin + permission gate",
1875
2006
  vscode: "agent plugin + permission gate",
1876
2007
  opencode: "generated plugin + permission gate",
2008
+ fx: "MCP through a local bridge + questions via push",
1877
2009
  ...compatibleRecord((profile) => profile.mcp ? "MCP + native hooks" : "native hooks"),
1878
2010
  custom: "any MCP or HTTP agent (Windsurf, n8n, custom)"
1879
2011
  };
@@ -1952,6 +2084,7 @@ var AGENT_TARGETS = {
1952
2084
  openCodeConfigFile(),
1953
2085
  OPENCODE_INSTRUCTIONS()
1954
2086
  ],
2087
+ fx: [fxMcpProfile(), fxSettings(), fxAgentsMd()],
1955
2088
  ...compatibleRecord((profile) => compatibleTargetFiles(profile).map((file) => join3(homedir(), ...file))),
1956
2089
  custom: ["nothing (prints connection details only)"]
1957
2090
  };
@@ -2222,7 +2355,7 @@ var main = async () => {
2222
2355
  ${check} API key saved. No agents configured.`);
2223
2356
  console.log(` ${dim("Run setup again with --agents <id> when you want one wired up.")}`);
2224
2357
  } else {
2225
- for (const agent of agents) {
2358
+ for (const [index, agent] of agents.entries()) {
2226
2359
  markStep(`configure:${agent}`);
2227
2360
  try {
2228
2361
  const ownerBefore = hookOwnerFor(agent, appBridgeAvailable);
@@ -2262,7 +2395,8 @@ var main = async () => {
2262
2395
  const failure = agentFailureFromError(agent, err, formatError);
2263
2396
  failures.push(failure);
2264
2397
  console.log(` ${yellow("!")} ${AGENT_NAMES[agent]} setup failed: ${failure.detail}`);
2265
- console.log(` ${dim("Other agents will continue. Re-run setup to retry.")}`);
2398
+ const continuation = afterAgentFailureNote(agents.length - index - 1);
2399
+ if (continuation) console.log(` ${dim(continuation)}`);
2266
2400
  }
2267
2401
  }
2268
2402
  if (skipped.length > 0) {
@@ -2271,7 +2405,8 @@ var main = async () => {
2271
2405
  }
2272
2406
  if (failures.length > 0) {
2273
2407
  console.log();
2274
- console.log(` ${yellow("!")} Failed: ${failedAgentNames(failures).join(", ")} ${dim("(others completed successfully)")}`);
2408
+ const configured = failedAgentsContext(completed.map((agent) => AGENT_NAMES[agent]));
2409
+ console.log(` ${yellow("!")} Failed: ${failedAgentNames(failures).join(", ")}${configured ? ` ${dim(configured)}` : ""}`);
2275
2410
  console.log(` ${dim("Run")} npx @pushary/agent-hooks@latest doctor ${dim("for the reason, or send it to")} ${SUPPORT_EMAIL}`);
2276
2411
  }
2277
2412
  markStep("project-instructions");
@@ -1,17 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  readLedgerSummary
4
- } from "../chunk-5UWV5GHM.js";
4
+ } from "../chunk-MCNS4725.js";
5
5
  import {
6
6
  exitOnHelpFlag
7
- } from "../chunk-P4BNYJ5Q.js";
7
+ } from "../chunk-6PV2JQ64.js";
8
8
  import "../chunk-KZERVKTD.js";
9
9
  import {
10
10
  getApiKey
11
- } from "../chunk-OSJEMXSR.js";
12
- import "../chunk-CAS7GFWI.js";
13
- import "../chunk-EA3IELHP.js";
14
- import "../chunk-HWJW3CPO.js";
11
+ } from "../chunk-OAL44FM2.js";
12
+ import "../chunk-EIZW73P5.js";
13
+ import "../chunk-XFNVG3OV.js";
15
14
 
16
15
  // bin/pushary-stats.ts
17
16
  exitOnHelpFlag("stats");
@@ -2,49 +2,48 @@
2
2
  import {
3
3
  describeLastSeen,
4
4
  listMachines
5
- } from "../chunk-JOGA3TL2.js";
6
- import "../chunk-GBL4BTG3.js";
7
- import "../chunk-OZE2TQX5.js";
5
+ } from "../chunk-YQN7S57T.js";
6
+ import "../chunk-Q7QRR6YL.js";
7
+ import "../chunk-AAGLDXH4.js";
8
8
  import "../chunk-XHKBHWLX.js";
9
9
  import {
10
10
  describeReach,
11
11
  fetchChannels,
12
12
  reachVerdict
13
- } from "../chunk-XJG2FUWS.js";
13
+ } from "../chunk-AHWJHLG5.js";
14
14
  import "../chunk-3EGEA4KH.js";
15
15
  import {
16
16
  checkApiKey,
17
17
  describeKeyCheck
18
- } from "../chunk-UGKDBJJX.js";
18
+ } from "../chunk-43SSQCWO.js";
19
19
  import "../chunk-QCGNGEGE.js";
20
20
  import {
21
21
  createIo
22
- } from "../chunk-5RUIFDTP.js";
22
+ } from "../chunk-O5PRIYFZ.js";
23
23
  import {
24
24
  exitOnHelpFlag
25
- } from "../chunk-P4BNYJ5Q.js";
25
+ } from "../chunk-6PV2JQ64.js";
26
26
  import {
27
27
  rejectUnknownFlags
28
28
  } from "../chunk-GMXKITVA.js";
29
29
  import {
30
30
  readKeySource
31
- } from "../chunk-R4HVHTNA.js";
32
- import "../chunk-BJENQBMH.js";
33
- import "../chunk-DESAUCH2.js";
34
- import "../chunk-DZTKLE7Q.js";
31
+ } from "../chunk-YZKS3ME3.js";
32
+ import "../chunk-NQFGVAT6.js";
33
+ import "../chunk-JTQDP4ZL.js";
34
+ import "../chunk-P5CBNSYL.js";
35
35
  import {
36
36
  UsageError
37
37
  } from "../chunk-7QLSKOSU.js";
38
38
  import {
39
39
  EXIT
40
40
  } from "../chunk-KZERVKTD.js";
41
- import "../chunk-VHNDE3ZD.js";
42
- import "../chunk-K32C2RGK.js";
41
+ import "../chunk-UPKP67TA.js";
42
+ import "../chunk-454KMJHF.js";
43
43
  import "../chunk-T7E75EKA.js";
44
- import "../chunk-OSJEMXSR.js";
45
- import "../chunk-CAS7GFWI.js";
46
- import "../chunk-EA3IELHP.js";
47
- import "../chunk-HWJW3CPO.js";
44
+ import "../chunk-OAL44FM2.js";
45
+ import "../chunk-EIZW73P5.js";
46
+ import "../chunk-XFNVG3OV.js";
48
47
 
49
48
  // src/status.ts
50
49
  var keySourceLine = (source) => {