@pushary/agent-hooks 1.7.0 → 1.7.2

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 +28 -0
  2. package/dist/bin/pushary-bell-hook.js +23 -23
  3. package/dist/bin/pushary-bell.js +10 -10
  4. package/dist/bin/pushary-claude.js +46 -35
  5. package/dist/bin/pushary-clean.js +194 -102
  6. package/dist/bin/pushary-codex-bridge.js +18 -17
  7. package/dist/bin/pushary-codex-hook.js +53 -39
  8. package/dist/bin/pushary-codex.js +14 -12
  9. package/dist/bin/pushary-connect.js +16 -16
  10. package/dist/bin/pushary-cowork.js +5 -5
  11. package/dist/bin/pushary-daemon.js +27 -27
  12. package/dist/bin/pushary-disconnect.js +19 -17
  13. package/dist/bin/pushary-doctor.js +99 -43
  14. package/dist/bin/pushary-elicitation-hook.js +35 -26
  15. package/dist/bin/pushary-gemini-bridge.js +12 -12
  16. package/dist/bin/pushary-gemini-hook.js +47 -32
  17. package/dist/bin/pushary-hook.js +34 -32
  18. package/dist/bin/pushary-login.js +16 -16
  19. package/dist/bin/pushary-logout.js +8 -8
  20. package/dist/bin/pushary-mcp.js +9 -8
  21. package/dist/bin/pushary-mode.js +10 -10
  22. package/dist/bin/pushary-notification-hook.js +29 -27
  23. package/dist/bin/pushary-opencode-hook.js +46 -32
  24. package/dist/bin/pushary-permission-denied-hook.js +34 -32
  25. package/dist/bin/pushary-permission-hook.js +33 -31
  26. package/dist/bin/pushary-post-hook.js +29 -27
  27. package/dist/bin/pushary-prompt-hook.js +29 -27
  28. package/dist/bin/pushary-session-end-hook.js +29 -27
  29. package/dist/bin/pushary-session-start-hook.js +33 -31
  30. package/dist/bin/pushary-setup.js +143 -105
  31. package/dist/bin/pushary-stats.js +5 -5
  32. package/dist/bin/pushary-status.js +19 -19
  33. package/dist/bin/pushary-stop-hook.js +29 -27
  34. package/dist/bin/pushary-stopfailure-hook.js +29 -27
  35. package/dist/bin/pushary-suggestions.js +5 -5
  36. package/dist/bin/pushary-transcript-register.js +19 -19
  37. package/dist/bin/pushary-transcripts.js +7 -7
  38. package/dist/bin/pushary-upgrade.js +20 -20
  39. package/dist/bin/pushary-wait.js +10 -10
  40. package/dist/bin/pushary.js +6 -6
  41. package/dist/{chunk-IJ6ECPA6.js → chunk-2B4XCMH6.js} +75 -232
  42. package/dist/{chunk-EGKXSQCY.js → chunk-2XOHXZRC.js} +12 -4
  43. package/dist/{chunk-D6BULEJW.js → chunk-3NSRL5E7.js} +2 -2
  44. package/dist/{chunk-UC65FJJT.js → chunk-3RO2UWJQ.js} +2 -2
  45. package/dist/{chunk-73T6MSU5.js → chunk-4S7CCOXB.js} +5 -5
  46. package/dist/{chunk-7OS4IHGI.js → chunk-5GIBNUBD.js} +2 -2
  47. package/dist/chunk-5OP5MQI7.js +45 -0
  48. package/dist/{chunk-B3UXMSMW.js → chunk-65RN6ZCO.js} +1 -1
  49. package/dist/{chunk-2PS6QWDW.js → chunk-6NHXKTQU.js} +2 -2
  50. package/dist/{chunk-V6QRSU2G.js → chunk-6QZK4O36.js} +4 -4
  51. package/dist/{chunk-ZQ7IDOKY.js → chunk-A6WQF7FQ.js} +3 -3
  52. package/dist/{chunk-QXAK5RFU.js → chunk-AWZNDM3B.js} +1 -1
  53. package/dist/{chunk-JNXVOU6Y.js → chunk-D4OGEWLH.js} +19 -2
  54. package/dist/{chunk-R2XCLT6I.js → chunk-E3PLF7YB.js} +4 -4
  55. package/dist/{chunk-2C7CCWVX.js → chunk-F6BMJOSW.js} +1 -1
  56. package/dist/{chunk-XNCMT7YY.js → chunk-HOIGXMI7.js} +1 -1
  57. package/dist/{chunk-CVALVGA7.js → chunk-I7B2DNVU.js} +1 -1
  58. package/dist/{chunk-S3UD4V6W.js → chunk-INR3RVQ3.js} +13 -3
  59. package/dist/{chunk-52NVBNJT.js → chunk-IZVAVXHQ.js} +6 -4
  60. package/dist/{chunk-5HLTWFJ6.js → chunk-JMSB6CJT.js} +1 -1
  61. package/dist/{chunk-KYQXUGH7.js → chunk-KAJT6HPI.js} +3 -3
  62. package/dist/{chunk-VKVIAZQO.js → chunk-KLXYMPTM.js} +1 -1
  63. package/dist/{chunk-PQ4F64M2.js → chunk-L6IF4JOF.js} +3 -3
  64. package/dist/{chunk-ROQK7IN3.js → chunk-LI3C2IQY.js} +2 -2
  65. package/dist/{chunk-B234346F.js → chunk-M2JGLFFS.js} +1 -1
  66. package/dist/chunk-MY3UZO5U.js +99 -0
  67. package/dist/chunk-N6IOSZOE.js +185 -0
  68. package/dist/{chunk-DNJUSFBL.js → chunk-NYBZJ44G.js} +40 -5
  69. package/dist/{chunk-BBKNJJVX.js → chunk-OJRB5QKN.js} +6 -6
  70. package/dist/{chunk-PUDBG3GM.js → chunk-OXEF6JHD.js} +4 -4
  71. package/dist/{chunk-LEZFOTMI.js → chunk-PWNQGITG.js} +1 -1
  72. package/dist/{chunk-B76WVEDX.js → chunk-Q7CDBJXU.js} +1 -1
  73. package/dist/{chunk-KXMZMZD3.js → chunk-QSZ37ROP.js} +1 -1
  74. package/dist/{chunk-BH2SKSSK.js → chunk-R7ZETVNR.js} +1 -1
  75. package/dist/{chunk-DZURML2D.js → chunk-RLRDPZG4.js} +1 -1
  76. package/dist/{chunk-J2355HR7.js → chunk-SEIZQZEE.js} +1 -1
  77. package/dist/{chunk-V4AQBAVG.js → chunk-SJN64NJX.js} +1 -1
  78. package/dist/{chunk-B3YQANFN.js → chunk-SKEW3TQX.js} +1 -1
  79. package/dist/{chunk-L4H2Q2S4.js → chunk-SKMWPXGV.js} +500 -46
  80. package/dist/{chunk-WUNZAE7I.js → chunk-T3PRPFDY.js} +5 -5
  81. package/dist/{chunk-YYINL576.js → chunk-TVJYGZXB.js} +2 -2
  82. package/dist/{chunk-O2LEPIU6.js → chunk-U3MS6D5X.js} +1 -1
  83. package/dist/{chunk-5RUIFDTP.js → chunk-U4TMAANR.js} +33 -2
  84. package/dist/{chunk-KW2RRR7D.js → chunk-UFNBKYWT.js} +3 -3
  85. package/dist/{chunk-DVQDPI3T.js → chunk-UUTWHVSV.js} +35 -35
  86. package/dist/{chunk-X6KDKOV5.js → chunk-VQDJ6KB3.js} +3 -3
  87. package/dist/{chunk-UOAQ6QMP.js → chunk-VSGKQ3HI.js} +2 -2
  88. package/dist/{chunk-YROGUPOZ.js → chunk-WWTLAZQA.js} +25 -8
  89. package/dist/{chunk-SQRWHALT.js → chunk-WXIVUIXA.js} +2 -2
  90. package/dist/{chunk-HDRNWNVP.js → chunk-YLCSKVQQ.js} +9 -28
  91. package/dist/{chunk-JXUAXO74.js → chunk-YNJ2H2FD.js} +2 -2
  92. package/dist/{chunk-BWYJ6AAF.js → chunk-YU4222G2.js} +2 -2
  93. package/dist/{chunk-4F46VIEE.js → chunk-YU54LNC6.js} +6 -6
  94. package/dist/{chunk-EAQMWJPG.js → chunk-ZMWX5SDA.js} +8 -8
  95. package/dist/{chunk-6ADZQFVW.js → chunk-ZUKZJQGR.js} +1 -1
  96. package/dist/{reapply-6PH3FMPX.js → reapply-D6RSDYCK.js} +9 -9
  97. package/dist/src/index.d.ts +1 -0
  98. package/dist/src/index.js +22 -20
  99. package/package.json +2 -1
  100. package/dist/chunk-DANOZVZK.js +0 -307
  101. package/dist/chunk-P32LPT2L.js +0 -6
  102. package/dist/chunk-YHG74UFF.js +0 -12
@@ -1,40 +1,45 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- HERMES_CONFIG_SCRIPT,
4
- HERMES_PIP_PACKAGE,
5
3
  PUSHARY_SKILL_NAME,
6
4
  PUSHARY_SKILL_SOURCE,
7
5
  createGuards,
8
- resolveHermesPython,
9
- runHermesPythonScript
10
- } from "../chunk-DANOZVZK.js";
11
- import "../chunk-P32LPT2L.js";
6
+ withoutPusharyCursorHooks
7
+ } from "../chunk-MY3UZO5U.js";
12
8
  import {
13
9
  FX_PROFILE_REFUSALS,
10
+ FX_QUESTION_TOOL,
14
11
  FX_SETTINGS_REFUSALS,
12
+ HERMES_PIP_PACKAGE,
15
13
  fxProfileText,
16
14
  fxSettingsText,
15
+ isFxQuestionRuleReceipt,
17
16
  readFxFile,
18
17
  readFxProfile,
19
18
  readFxSettings,
19
+ readHermesStatus,
20
20
  removeInstructionBlock,
21
+ resolveHermesPython,
22
+ runHermesConfigScript,
21
23
  shortenHome,
22
24
  unregisterPluginLocation,
23
25
  vscodeSettingsTargets,
24
26
  withoutFxPusharyServer,
25
- withoutPusharyToolsAllowed
26
- } from "../chunk-L4H2Q2S4.js";
27
- import "../chunk-YYINL576.js";
27
+ withoutPusharyToolsAllowed,
28
+ withoutQuestionsRoutedToPushary
29
+ } from "../chunk-SKMWPXGV.js";
30
+ import "../chunk-TVJYGZXB.js";
28
31
  import {
29
32
  OPENCODE_PLUGIN_SIBLING,
30
33
  OPENCODE_PLUGIN_SIBLING_CONTENTS,
31
34
  hasForeignPlugins,
32
35
  isOpenCodePluginOurs,
36
+ openCodeConfigDir,
33
37
  openCodeConfigFile,
38
+ openCodeInstructionsFile,
34
39
  openCodePluginDir,
35
40
  openCodePluginFile,
36
41
  removeOpenCodeMcpServer
37
- } from "../chunk-B3YQANFN.js";
42
+ } from "../chunk-SKEW3TQX.js";
38
43
  import {
39
44
  compatibleConfigFile,
40
45
  compatibleInstructionsFile,
@@ -42,44 +47,47 @@ import {
42
47
  compatiblePermissionRuleFile,
43
48
  removeCompatibleHooks,
44
49
  removeCompatibleMcpServer
45
- } from "../chunk-WUNZAE7I.js";
50
+ } from "../chunk-T3PRPFDY.js";
46
51
  import {
47
52
  isClaudeMcpSnapshot,
48
53
  removeClaudeMcpServers,
49
54
  removePusharySettings,
50
55
  removePusharyToolPermissions,
51
56
  restoreClaudeMcpServer
52
- } from "../chunk-KYQXUGH7.js";
57
+ } from "../chunk-KAJT6HPI.js";
53
58
  import {
54
59
  hookOwnerOf,
55
60
  isHookTakeoverReceipt,
56
61
  restoreHookTakeover,
57
62
  restoreMcpServer
58
- } from "../chunk-R2XCLT6I.js";
59
- import "../chunk-CVALVGA7.js";
63
+ } from "../chunk-E3PLF7YB.js";
64
+ import "../chunk-I7B2DNVU.js";
60
65
  import {
61
66
  liveBridgeProbe,
62
67
  resolveBridgeStub
63
- } from "../chunk-5HLTWFJ6.js";
64
- import {
65
- pusharyHookExecutable
66
- } from "../chunk-PQ4F64M2.js";
68
+ } from "../chunk-JMSB6CJT.js";
69
+ import "../chunk-L6IF4JOF.js";
67
70
  import {
68
71
  disableDaemonService
69
- } from "../chunk-73T6MSU5.js";
72
+ } from "../chunk-4S7CCOXB.js";
70
73
  import {
71
74
  removeGeminiSettings
72
- } from "../chunk-ZQ7IDOKY.js";
73
- import "../chunk-VKVIAZQO.js";
75
+ } from "../chunk-A6WQF7FQ.js";
76
+ import "../chunk-KLXYMPTM.js";
74
77
  import "../chunk-XHKBHWLX.js";
75
- import "../chunk-IJ6ECPA6.js";
76
- import "../chunk-DZURML2D.js";
77
- import "../chunk-EGKXSQCY.js";
78
- import "../chunk-V6QRSU2G.js";
78
+ import "../chunk-2B4XCMH6.js";
79
+ import "../chunk-N6IOSZOE.js";
80
+ import "../chunk-RLRDPZG4.js";
81
+ import "../chunk-2XOHXZRC.js";
82
+ import "../chunk-6QZK4O36.js";
79
83
  import "../chunk-POFBE6ZY.js";
84
+ import {
85
+ ansiPainter,
86
+ useColor
87
+ } from "../chunk-U4TMAANR.js";
80
88
  import {
81
89
  exitOnHelpFlag
82
- } from "../chunk-2PS6QWDW.js";
90
+ } from "../chunk-6NHXKTQU.js";
83
91
  import {
84
92
  rejectUnknownFlags
85
93
  } from "../chunk-GMXKITVA.js";
@@ -87,16 +95,18 @@ import {
87
95
  CANDIDATE_RCS,
88
96
  isDisabledExport,
89
97
  removeClaudeAlias
90
- } from "../chunk-UOAQ6QMP.js";
91
- import "../chunk-JNXVOU6Y.js";
92
- import "../chunk-KW2RRR7D.js";
93
- import "../chunk-XNCMT7YY.js";
98
+ } from "../chunk-VSGKQ3HI.js";
99
+ import "../chunk-D4OGEWLH.js";
100
+ import "../chunk-VQDJ6KB3.js";
101
+ import "../chunk-UFNBKYWT.js";
102
+ import "../chunk-HOIGXMI7.js";
94
103
  import "../chunk-7QLSKOSU.js";
95
104
  import {
96
105
  EXIT
97
106
  } from "../chunk-KZERVKTD.js";
98
- import "../chunk-ROQK7IN3.js";
107
+ import "../chunk-LI3C2IQY.js";
99
108
  import {
109
+ AGENT_HOOKS_PACKAGE,
100
110
  bridgeAgentKey,
101
111
  claudeJson,
102
112
  claudeMcpReceipt,
@@ -113,13 +123,17 @@ import {
113
123
  cursorUserMcp,
114
124
  execNpm,
115
125
  fxAgentsMd,
126
+ fxConfigDir,
116
127
  fxMcpProfile,
128
+ fxQuestionRuleReceipt,
117
129
  fxSettings,
118
130
  geminiMd,
119
131
  geminiSettings,
132
+ globalPackageState,
133
+ hermesConfig,
120
134
  hermesConfigReceipt,
121
135
  hookTakeoverReceipt,
122
- isProtectedByScope,
136
+ npmIsOnPath,
123
137
  pusharyDir,
124
138
  readCodexMcpAuth,
125
139
  removeCodexHookTrust,
@@ -127,23 +141,22 @@ import {
127
141
  restoreCodexHookTrust,
128
142
  vscodePluginDir,
129
143
  vscodePluginMcp
130
- } from "../chunk-DNJUSFBL.js";
144
+ } from "../chunk-NYBZJ44G.js";
131
145
  import "../chunk-T7E75EKA.js";
132
- import "../chunk-V4AQBAVG.js";
133
- import "../chunk-B3UXMSMW.js";
146
+ import "../chunk-SJN64NJX.js";
147
+ import "../chunk-65RN6ZCO.js";
134
148
  import {
135
- CURSOR_GATE_EVENTS,
136
149
  HOOK_COMPATIBLE_PROFILES,
137
150
  HOOK_LOCATOR_BINARY,
138
151
  SUPPORT_DISCORD,
139
152
  SUPPORT_EMAIL,
140
153
  isValidApiKey,
141
154
  redactSecrets
142
- } from "../chunk-YROGUPOZ.js";
155
+ } from "../chunk-WWTLAZQA.js";
143
156
 
144
157
  // bin/pushary-clean.ts
145
- import { existsSync as existsSync6, readFileSync as readFileSync4, copyFileSync, readdirSync as readdirSync3 } from "fs";
146
- import { dirname, join as join5 } from "path";
158
+ import { existsSync as existsSync6, readFileSync as readFileSync4, copyFileSync, readdirSync as readdirSync4 } from "fs";
159
+ import { dirname, join as join6 } from "path";
147
160
  import { homedir as homedir5, tmpdir } from "os";
148
161
  import { confirm } from "@inquirer/prompts";
149
162
  import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
@@ -166,7 +179,7 @@ var TEST_DEFAULTS_PREFIXES = [
166
179
  var isTestDefaultsDomain = (domain) => TEST_DEFAULTS_PREFIXES.some((prefix) => domain.startsWith(prefix));
167
180
  var leakedTestDefaultsDomains = () => {
168
181
  try {
169
- return execSync("defaults domains", { encoding: "utf-8", timeout: 2e4 }).split(",").map((entry) => entry.trim()).filter(isTestDefaultsDomain);
182
+ return execSync("defaults domains", { encoding: "utf-8", timeout: 2e4 }).split(",").map((entry) => entry.trim()).filter(isTestDefaultsDomain).filter(liveMacStatePresence.defaultsDomain);
170
183
  } catch {
171
184
  return [];
172
185
  }
@@ -208,6 +221,28 @@ var MAC_KEYCHAIN_ACCOUNTS = [
208
221
  "cachedEnvironment"
209
222
  ];
210
223
  var MAC_DEFAULTS_DOMAINS = ["com.pushary.app", "pushary-bridge", "pushary.render"];
224
+ var PRESENCE_PROBE_TIMEOUT_MS = 1e4;
225
+ var commandSucceeds = (file, args) => {
226
+ try {
227
+ execFileSync(file, args, { stdio: "ignore", timeout: PRESENCE_PROBE_TIMEOUT_MS });
228
+ return true;
229
+ } catch {
230
+ return false;
231
+ }
232
+ };
233
+ var KEYCHAIN_ITEM_NOT_FOUND = 44;
234
+ var keychainItemMayExist = (service, account) => {
235
+ try {
236
+ execFileSync("security", ["find-generic-password", "-s", service, "-a", account], { stdio: "ignore" });
237
+ return true;
238
+ } catch (error) {
239
+ return !(error instanceof Error && "status" in error && error.status === KEYCHAIN_ITEM_NOT_FOUND);
240
+ }
241
+ };
242
+ var liveMacStatePresence = {
243
+ keychainItem: keychainItemMayExist,
244
+ defaultsDomain: (domain) => commandSucceeds("defaults", ["read", domain])
245
+ };
211
246
  var macLibraryState = (home = homedir()) => [
212
247
  join(home, "Library", "Application Support", "Pushary"),
213
248
  join(home, "Library", "Caches", "com.pushary.app"),
@@ -281,7 +316,7 @@ var removeDeveloperLeftovers = (guards2, domains, bundles) => {
281
316
  }
282
317
  return removed;
283
318
  };
284
- var removeMacAppState = (guards2, readServices, home) => {
319
+ var removeMacAppState = (guards2, readServices, home, present) => {
285
320
  let removed = 0;
286
321
  let failed = 0;
287
322
  let services;
@@ -291,7 +326,7 @@ var removeMacAppState = (guards2, readServices, home) => {
291
326
  return { removed, failed: 1 };
292
327
  }
293
328
  for (const service of services) {
294
- for (const account of MAC_KEYCHAIN_ACCOUNTS) {
329
+ for (const account of MAC_KEYCHAIN_ACCOUNTS.filter((account2) => present.keychainItem(service, account2))) {
295
330
  try {
296
331
  guards2.execFile(
297
332
  "security",
@@ -305,7 +340,7 @@ var removeMacAppState = (guards2, readServices, home) => {
305
340
  }
306
341
  }
307
342
  }
308
- for (const domain of MAC_DEFAULTS_DOMAINS) {
343
+ for (const domain of MAC_DEFAULTS_DOMAINS.filter(present.defaultsDomain)) {
309
344
  try {
310
345
  guards2.execFile("defaults", ["delete", domain], { stdio: "ignore", timeout: 1e4 }, `delete preferences ${domain}`);
311
346
  removed++;
@@ -425,6 +460,26 @@ var claudeBackupRewrites = (receipt, home = homedir4()) => claudeJsonBackups(hom
425
460
  ` }] : [];
426
461
  });
427
462
 
463
+ // src/cli/config-temp-leftovers.ts
464
+ import { lstatSync, readdirSync as readdirSync3 } from "fs";
465
+ import { join as join5 } from "path";
466
+ var MAC_APP_WRITE_TEMP = /^\..+\.pushary-[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/;
467
+ var PID_STAMPED_WRITE_TEMP = /^\.\d+-[^/]+\.pushary-tmp$/;
468
+ var CONFIG_TEMP_MIN_AGE_MS = 6e4;
469
+ var isLeakedConfigTempName = (name) => MAC_APP_WRITE_TEMP.test(name) || PID_STAMPED_WRITE_TEMP.test(name);
470
+ var leakedConfigTemps = (entries, nowMs) => entries.filter((entry) => entry.isFile && isLeakedConfigTempName(entry.name) && nowMs - entry.modifiedAtMs >= CONFIG_TEMP_MIN_AGE_MS).map((entry) => entry.name);
471
+ var directoryEntries = (directory) => {
472
+ try {
473
+ return readdirSync3(directory).flatMap((name) => {
474
+ const stats = lstatSync(join5(directory, name), { throwIfNoEntry: false });
475
+ return stats ? [{ name, isFile: stats.isFile(), modifiedAtMs: stats.mtimeMs }] : [];
476
+ });
477
+ } catch {
478
+ return [];
479
+ }
480
+ };
481
+ var configTempLeftovers = (directories, nowMs) => [...new Set(directories)].flatMap((directory) => leakedConfigTemps(directoryEntries(directory), nowMs).map((name) => join5(directory, name)));
482
+
428
483
  // src/app-owned-paths.ts
429
484
  var APP_OWNED_ENTRIES = [
430
485
  // PusharyPaths.bin: bridgeStub, bridgeCache
@@ -456,11 +511,12 @@ var macAppKeepsMcpEntry = (entryKey, keys) => {
456
511
 
457
512
  // bin/pushary-clean.ts
458
513
  exitOnHelpFlag("clean");
459
- var dim = (s) => `\x1B[2m${s}\x1B[0m`;
460
- var bold = (s) => `\x1B[1m${s}\x1B[0m`;
461
- var green = (s) => `\x1B[32m${s}\x1B[0m`;
462
- var yellow = (s) => `\x1B[33m${s}\x1B[0m`;
463
- var red = (s) => `\x1B[31m${s}\x1B[0m`;
514
+ var paint = ansiPainter(() => useColor());
515
+ var dim = paint("\x1B[2m");
516
+ var bold = paint("\x1B[1m");
517
+ var green = paint("\x1B[32m");
518
+ var yellow = paint("\x1B[33m");
519
+ var red = paint("\x1B[31m");
464
520
  var check = green("\u2713");
465
521
  var skip = yellow("\u2013");
466
522
  var cross = red("\u2717");
@@ -471,19 +527,20 @@ var CLAUDE_SETTINGS_LOCAL = claudeSettingsLocal();
471
527
  var CLAUDE_JSON = claudeJson();
472
528
  var CLAUDE_MCP_RECEIPT = claudeMcpReceipt();
473
529
  var HERMES_CONFIG_RECEIPT = hermesConfigReceipt();
530
+ var HERMES_CONFIG_FILE = hermesConfig();
474
531
  var SKILL_DIR = claudeSkillDir();
475
532
  var CURSOR_MCP = cursorUserMcp();
476
533
  var CURSOR_PLUGIN_DIR = cursorPluginDir();
477
534
  var CURSOR_USER_HOOKS = cursorUserHooks();
478
535
  var VSCODE_PLUGIN_DIR = vscodePluginDir();
479
536
  var PUSHARY_DIR = pusharyDir();
480
- var SHELL_FILES = [".zshrc", ".zprofile", ".bashrc", ".bash_profile"].map((f) => join5(homedir5(), f));
537
+ var SHELL_FILES = [".zshrc", ".zprofile", ".bashrc", ".bash_profile"].map((f) => join6(homedir5(), f));
481
538
  var PRESENCE_BY_RESOLUTION = {
482
539
  bundle: "present",
483
540
  missing: "gone",
484
541
  "no-stub": "absent"
485
542
  };
486
- var macAppPresence = () => PRESENCE_BY_RESOLUTION[resolveBridgeStub(join5(PUSHARY_DIR, "bin", HOOK_LOCATOR_BINARY), liveBridgeProbe()).kind];
543
+ var macAppPresence = () => PRESENCE_BY_RESOLUTION[resolveBridgeStub(join6(PUSHARY_DIR, "bin", HOOK_LOCATOR_BINARY), liveBridgeProbe()).kind];
487
544
  var removalScope = (keepMcpServer, keepAppWiring) => ({
488
545
  keepAppWiring,
489
546
  keepMcpServer
@@ -512,7 +569,7 @@ var cursorPluginLeftovers = () => {
512
569
  const parent = dirname(CURSOR_PLUGIN_DIR);
513
570
  const backupPrefix = `${CURSOR_PLUGIN_DIR.split("/").pop()}.pushary-backup-`;
514
571
  try {
515
- return readdirSync3(parent).filter((name) => name.startsWith(backupPrefix) || name.startsWith(CURSOR_PLUGIN_STAGING)).map((name) => join5(parent, name));
572
+ return readdirSync4(parent).filter((name) => name.startsWith(backupPrefix) || name.startsWith(CURSOR_PLUGIN_STAGING)).map((name) => join6(parent, name));
516
573
  } catch {
517
574
  return [];
518
575
  }
@@ -533,7 +590,7 @@ var guardedInstructionBlockRemoval = (path) => {
533
590
  };
534
591
  var guardedAliasRemoval = () => {
535
592
  if (!dryRun) return removeClaudeAlias();
536
- const shells = CANDIDATE_RCS.map((name) => join5(homedir5(), name)).filter((path) => existsSync6(path) && readFileSync4(path, "utf-8").includes("pushary claude"));
593
+ const shells = CANDIDATE_RCS.map((name) => join6(homedir5(), name)).filter((path) => existsSync6(path) && readFileSync4(path, "utf-8").includes("pushary claude"));
537
594
  for (const path of shells) wouldNote("rewrite", path);
538
595
  return shells;
539
596
  };
@@ -577,6 +634,25 @@ var removeFxToolsRule = () => {
577
634
  const { settings, removed } = withoutPusharyToolsAllowed(read.settings);
578
635
  if (removed) writeFxText(path, fxSettingsText(settings), "fx auto-allowed Pushary tools");
579
636
  };
637
+ var FX_QUESTION_RULE_KEPT = {
638
+ "not-ours": "no setup record says Pushary added it, so it may be yours; left as it is",
639
+ "changed-after-setup": "changed after setup; left as it is"
640
+ };
641
+ var readFxQuestionRuleReceipt = () => {
642
+ const receipt = readJson(fxQuestionRuleReceipt());
643
+ return isFxQuestionRuleReceipt(receipt) ? receipt : null;
644
+ };
645
+ var removeFxQuestionRule = () => {
646
+ const path = fxSettings();
647
+ const read = readFxFile(path, readFxSettings);
648
+ if (read.kind === "refused" || read.kind === "unreadable") return;
649
+ if (read.kind === "settings") {
650
+ const { settings, outcome } = withoutQuestionsRoutedToPushary(read.settings, readFxQuestionRuleReceipt());
651
+ if (outcome === "removed") writeFxText(path, fxSettingsText(settings), "fx question rule");
652
+ else if (outcome !== "absent") console.log(` ${skip} fx question rule ${dim(`(${FX_QUESTION_TOOL} in ${path}: ${FX_QUESTION_RULE_KEPT[outcome]})`)}`);
653
+ }
654
+ if (existsSync6(fxQuestionRuleReceipt())) guardedRemove(fxQuestionRuleReceipt(), { force: true });
655
+ };
580
656
  var removeFxInstructions = () => {
581
657
  if (guardedInstructionBlockRemoval(fxAgentsMd())) {
582
658
  console.log(` ${check} fx instructions ${dim(did("removed"))}`);
@@ -591,21 +667,9 @@ var removeCursorUserHook = (scope) => {
591
667
  return "failed";
592
668
  }
593
669
  if (!parsed2 || typeof parsed2 !== "object") return "failed";
594
- const hooks = parsed2.hooks ?? {};
595
- let removedAny = false;
596
- for (const event of CURSOR_GATE_EVENTS) {
597
- const existing = Array.isArray(hooks[event]) ? hooks[event] : [];
598
- const others = existing.filter((h) => {
599
- const command = String(h.command ?? "");
600
- return pusharyHookExecutable(command) === null || isProtectedByScope(command, scope);
601
- });
602
- if (others.length === existing.length) continue;
603
- removedAny = true;
604
- if (others.length === 0) delete hooks[event];
605
- else hooks[event] = others;
606
- }
607
- if (!removedAny) return "absent";
608
- parsed2.hooks = hooks;
670
+ const removal = withoutPusharyCursorHooks(parsed2.hooks ?? {}, scope);
671
+ if (removal.removed === 0) return "absent";
672
+ parsed2.hooks = removal.hooks;
609
673
  try {
610
674
  writeJson(CURSOR_USER_HOOKS, parsed2);
611
675
  } catch {
@@ -614,15 +678,7 @@ var removeCursorUserHook = (scope) => {
614
678
  if (dryRun) return "removed";
615
679
  try {
616
680
  const after = JSON.parse(readFileSync4(CURSOR_USER_HOOKS, "utf-8"));
617
- const afterHooks = after?.hooks ?? {};
618
- const stillThere = CURSOR_GATE_EVENTS.some((event) => {
619
- const entries = afterHooks[event];
620
- return Array.isArray(entries) && entries.some((h) => {
621
- const command = String(h?.command ?? "");
622
- return pusharyHookExecutable(command) !== null && !isProtectedByScope(command, scope);
623
- });
624
- });
625
- if (stillThere) return "failed";
681
+ if (withoutPusharyCursorHooks(after?.hooks ?? {}, scope).removed > 0) return "failed";
626
682
  } catch {
627
683
  return "failed";
628
684
  }
@@ -647,13 +703,23 @@ var cleanSettingsFile = (path, label, scope) => {
647
703
  ` ${skip} ${label} ${dim(wouldHaveChanged ? "(kept: written by the Mac app)" : "(no pushary entries)")}`
648
704
  );
649
705
  };
706
+ var agentConfigDirectories = () => [
707
+ homedir5(),
708
+ dirname(CLAUDE_SETTINGS),
709
+ dirname(codexConfigToml()),
710
+ dirname(geminiSettings()),
711
+ dirname(CURSOR_USER_HOOKS),
712
+ openCodeConfigDir(),
713
+ fxConfigDir(),
714
+ ...vscodeSettingsTargets(existsSync6).map((settings) => dirname(settings))
715
+ ];
650
716
  var restoreTakeoverReceipts = () => {
651
717
  const targets = [
652
718
  ["claude_code", CLAUDE_SETTINGS, CLAUDE_JSON, "mcpServers", "json"],
653
719
  ["codex", codexHooksJson(), codexConfigToml(), "mcp_servers", "toml"],
654
720
  ["gemini_cli", geminiSettings(), geminiSettings(), "mcpServers", "json"],
655
721
  ["cursor", CURSOR_USER_HOOKS, null, null, null],
656
- ["vscode", join5(VSCODE_PLUGIN_DIR, "hooks", "hooks.json"), vscodePluginMcp(), "mcpServers", "json"]
722
+ ["vscode", join6(VSCODE_PLUGIN_DIR, "hooks", "hooks.json"), vscodePluginMcp(), "mcpServers", "json"]
657
723
  ];
658
724
  for (const [agent, hookFile, mcpFile, mcpKey, mcpFormat] of targets) {
659
725
  const receiptPath = hookTakeoverReceipt(agent);
@@ -1027,10 +1093,10 @@ var main = async () => {
1027
1093
  } else {
1028
1094
  guardedRemove(openCodePlugin, { force: true });
1029
1095
  console.log(` ${check} OpenCode plugin ${dim(did("removed"))}`);
1030
- const sibling = join5(openCodePluginDir(), OPENCODE_PLUGIN_SIBLING);
1096
+ const sibling = join6(openCodePluginDir(), OPENCODE_PLUGIN_SIBLING);
1031
1097
  const remaining = (() => {
1032
1098
  try {
1033
- return readdirSync3(openCodePluginDir()).filter((name) => name !== OPENCODE_PLUGIN_SIBLING);
1099
+ return readdirSync4(openCodePluginDir()).filter((name) => name !== OPENCODE_PLUGIN_SIBLING);
1034
1100
  } catch {
1035
1101
  return [];
1036
1102
  }
@@ -1054,23 +1120,40 @@ var main = async () => {
1054
1120
  } else {
1055
1121
  console.log(` ${skip} OpenCode MCP ${dim("(not found)")}`);
1056
1122
  }
1123
+ if (keepShared) {
1124
+ console.log(` ${skip} OpenCode AGENTS.md ${dim("(kept: the Mac app uses it)")}`);
1125
+ } else if (guardedInstructionBlockRemoval(openCodeInstructionsFile())) {
1126
+ console.log(` ${check} OpenCode AGENTS.md ${dim("(removed Pushary block)")}`);
1127
+ } else {
1128
+ console.log(` ${skip} OpenCode AGENTS.md ${dim("(no pushary block)")}`);
1129
+ }
1057
1130
  removeFxMcpServer();
1058
1131
  removeFxToolsRule();
1132
+ removeFxQuestionRule();
1059
1133
  removeFxInstructions();
1060
1134
  const hermesPython = resolveHermesPython();
1061
1135
  if (hermesPython) {
1062
- const configUpdated = dryRun ? (wouldNote("run ", "hermes plugin config restore"), true) : runHermesPythonScript(hermesPython, HERMES_CONFIG_SCRIPT, "clean", HERMES_CONFIG_RECEIPT);
1063
- if (!configUpdated) {
1136
+ const configRun = runHermesConfigScript(hermesPython, dryRun ? "clean-preview" : "clean", HERMES_CONFIG_RECEIPT);
1137
+ if (configRun === "failed") {
1064
1138
  incompleteClean = true;
1065
1139
  console.log(` ${skip} Hermes config ${dim("(could not update config.yaml)")}`);
1066
1140
  } else {
1067
- console.log(` ${check} Hermes config ${dim("(setup-owned changes restored)")}`);
1068
- try {
1069
- guards.execFile(hermesPython, ["-m", "pip", "uninstall", "-y", HERMES_PIP_PACKAGE], { stdio: "pipe", timeout: 6e4 }, `pip uninstall ${HERMES_PIP_PACKAGE}`);
1070
- console.log(` ${check} Hermes plugin ${dim("(pip uninstalled)")}`);
1071
- } catch {
1072
- incompleteClean = true;
1073
- console.log(` ${skip} Hermes plugin ${dim("(could not uninstall; setup receipt kept for retry)")}`);
1141
+ if (configRun === "changed") {
1142
+ if (dryRun) wouldNote("rewrite", HERMES_CONFIG_FILE);
1143
+ console.log(` ${check} Hermes config ${dim(did("removed"))} ${dim("(Pushary settings)")}`);
1144
+ } else {
1145
+ console.log(` ${skip} Hermes config ${dim("(no Pushary settings)")}`);
1146
+ }
1147
+ if (readHermesStatus(hermesPython)?.pluginInstalled === false) {
1148
+ console.log(` ${skip} Hermes plugin ${dim("(not installed)")}`);
1149
+ } else {
1150
+ try {
1151
+ guards.execFile(hermesPython, ["-m", "pip", "uninstall", "-y", HERMES_PIP_PACKAGE], { stdio: "pipe", timeout: 6e4 }, `pip uninstall ${HERMES_PIP_PACKAGE}`);
1152
+ console.log(` ${check} Hermes plugin ${dim(did("uninstalled"))}`);
1153
+ } catch {
1154
+ incompleteClean = true;
1155
+ console.log(` ${skip} Hermes plugin ${dim("(could not uninstall; setup receipt kept for retry)")}`);
1156
+ }
1074
1157
  }
1075
1158
  }
1076
1159
  } else if (existsSync6(HERMES_CONFIG_RECEIPT)) {
@@ -1117,15 +1200,20 @@ var main = async () => {
1117
1200
  } else {
1118
1201
  console.log(` ${skip} claude alias ${dim("(not set)")}`);
1119
1202
  }
1203
+ const leakedTemps = configTempLeftovers(agentConfigDirectories(), Date.now());
1204
+ for (const temp of leakedTemps) guardedRemove(temp, { force: true });
1205
+ if (leakedTemps.length > 0) {
1206
+ console.log(` ${check} Leftover temp files ${dim(`(${dryRun ? "would remove" : "removed"} ${leakedTemps.length} left by an interrupted config write)`)}`);
1207
+ }
1120
1208
  if (existsSync6(PUSHARY_DIR)) {
1121
1209
  let removed = 0;
1122
1210
  const kept = [];
1123
- for (const entry of readdirSync3(PUSHARY_DIR)) {
1211
+ for (const entry of readdirSync4(PUSHARY_DIR)) {
1124
1212
  if (keepShared && isAppOwned(entry) || entry === "setup" && (keepShared || incompleteClean)) {
1125
1213
  kept.push(entry);
1126
1214
  continue;
1127
1215
  }
1128
- guardedRemove(join5(PUSHARY_DIR, entry), { force: true });
1216
+ guardedRemove(join6(PUSHARY_DIR, entry), { force: true });
1129
1217
  removed++;
1130
1218
  }
1131
1219
  if (removed > 0) {
@@ -1142,10 +1230,10 @@ var main = async () => {
1142
1230
  }
1143
1231
  try {
1144
1232
  let swept = 0;
1145
- for (const f of readdirSync3(tmpdir())) {
1233
+ for (const f of readdirSync4(tmpdir())) {
1146
1234
  if (!f.startsWith("pushary-")) continue;
1147
1235
  try {
1148
- guardedRemove(join5(tmpdir(), f), { force: true });
1236
+ guardedRemove(join6(tmpdir(), f), { force: true });
1149
1237
  swept++;
1150
1238
  } catch {
1151
1239
  }
@@ -1164,26 +1252,30 @@ var main = async () => {
1164
1252
  if (leftovers > 0) {
1165
1253
  console.log(` ${check} Developer leftovers ${dim(did("removed"))} ${dim(`(${leftovers} leaked test preferences and stale app registrations)`)}`);
1166
1254
  }
1167
- const { removed, failed } = process.platform === "darwin" ? removeMacAppState(guards, storedPusharyKeychainServices, homedir5()) : { removed: 0, failed: 0 };
1255
+ const { removed, failed } = process.platform === "darwin" ? removeMacAppState(guards, storedPusharyKeychainServices, homedir5(), liveMacStatePresence) : { removed: 0, failed: 0 };
1168
1256
  if (failed > 0) {
1169
1257
  incompleteClean = true;
1170
1258
  console.log(` ${cross} Mac keychain ${dim(`(${failed} operations failed; unlock your keychain and re-run)`)}`);
1171
1259
  }
1172
1260
  if (removed > 0) {
1173
- console.log(` ${check} Mac app state ${dim(did("removed"))} ${dim(`(${removed} keychain items, preferences and caches)`)}`);
1261
+ console.log(` ${check} Mac app state ${dim(did("removed"))} ${dim(`(${removed} across the keychain, preferences and caches)`)}`);
1174
1262
  } else if (failed === 0) {
1175
1263
  console.log(` ${skip} Mac app state ${dim("(nothing of ours in the keychain, preferences or caches)")}`);
1176
1264
  }
1177
1265
  }
1178
- try {
1179
- if (dryRun) {
1180
- wouldNote("run ", "npm uninstall -g @pushary/agent-hooks");
1181
- } else {
1182
- execNpm("uninstall -g --no-workspaces @pushary/agent-hooks", { stdio: "ignore", timeout: 3e4 });
1183
- }
1184
- console.log(` ${check} Global package ${dim(did("uninstalled"))}`);
1185
- } catch {
1266
+ if (!npmIsOnPath()) {
1267
+ console.log(` ${skip} Global package ${dim(`(npm not found; remove ${AGENT_HOOKS_PACKAGE} with the tool that installed it)`)}`);
1268
+ } else if (globalPackageState(AGENT_HOOKS_PACKAGE) === "absent") {
1186
1269
  console.log(` ${skip} Global package ${dim("(not installed)")}`);
1270
+ } else {
1271
+ try {
1272
+ if (dryRun) wouldNote("run ", `npm uninstall -g ${AGENT_HOOKS_PACKAGE}`);
1273
+ else execNpm(`uninstall -g --no-workspaces ${AGENT_HOOKS_PACKAGE}`, { stdio: "ignore", timeout: 3e4 });
1274
+ console.log(` ${check} Global package ${dim(did("uninstalled"))}`);
1275
+ } catch {
1276
+ incompleteClean = true;
1277
+ console.log(` ${cross} Global package ${dim(`(npm uninstall failed; run npm uninstall -g ${AGENT_HOOKS_PACKAGE})`)}`);
1278
+ }
1187
1279
  }
1188
1280
  console.log();
1189
1281
  if (incompleteClean) {
@@ -1,24 +1,24 @@
1
1
  #!/usr/bin/env node
2
- import "../chunk-JXUAXO74.js";
2
+ import "../chunk-YNJ2H2FD.js";
3
3
  import {
4
4
  LiveTranscriptRelay,
5
5
  liveSessionSleep,
6
6
  postLiveSession,
7
7
  postLiveSessionUntilAccepted,
8
8
  startLiveSessionHeartbeat
9
- } from "../chunk-SQRWHALT.js";
9
+ } from "../chunk-WXIVUIXA.js";
10
10
  import {
11
11
  SESSION_IDLE_TIMEOUT_MS,
12
12
  describeIdleWindow,
13
13
  idleDeadlinePassed,
14
14
  startProcessOwnership,
15
15
  withSpawnProcessOwnership
16
- } from "../chunk-LEZFOTMI.js";
17
- import "../chunk-BH2SKSSK.js";
18
- import "../chunk-KXMZMZD3.js";
16
+ } from "../chunk-PWNQGITG.js";
17
+ import "../chunk-R7ZETVNR.js";
18
+ import "../chunk-QSZ37ROP.js";
19
19
  import {
20
20
  transcriptsEnabled
21
- } from "../chunk-B76WVEDX.js";
21
+ } from "../chunk-Q7CDBJXU.js";
22
22
  import {
23
23
  spawnClaude
24
24
  } from "../chunk-XHKBHWLX.js";
@@ -27,38 +27,39 @@ import {
27
27
  isDecisionStopped,
28
28
  isWaitForAnswerResponse,
29
29
  withdrawQuestion
30
- } from "../chunk-EGKXSQCY.js";
30
+ } from "../chunk-2XOHXZRC.js";
31
31
  import {
32
32
  writeDegraded
33
- } from "../chunk-V6QRSU2G.js";
33
+ } from "../chunk-6QZK4O36.js";
34
34
  import "../chunk-POFBE6ZY.js";
35
- import "../chunk-UOAQ6QMP.js";
35
+ import "../chunk-VSGKQ3HI.js";
36
36
  import {
37
37
  callMcpTool
38
- } from "../chunk-JNXVOU6Y.js";
39
- import "../chunk-KW2RRR7D.js";
38
+ } from "../chunk-D4OGEWLH.js";
39
+ import "../chunk-VQDJ6KB3.js";
40
+ import "../chunk-UFNBKYWT.js";
40
41
  import {
41
42
  getMachineId
42
- } from "../chunk-XNCMT7YY.js";
43
+ } from "../chunk-HOIGXMI7.js";
43
44
  import "../chunk-7QLSKOSU.js";
44
45
  import "../chunk-KZERVKTD.js";
45
- import "../chunk-ROQK7IN3.js";
46
+ import "../chunk-LI3C2IQY.js";
46
47
  import {
47
48
  resolveBinary
48
- } from "../chunk-DNJUSFBL.js";
49
+ } from "../chunk-NYBZJ44G.js";
49
50
  import "../chunk-T7E75EKA.js";
50
51
  import {
51
52
  getApiKey,
52
53
  getBaseUrl
53
- } from "../chunk-V4AQBAVG.js";
54
- import "../chunk-B3UXMSMW.js";
54
+ } from "../chunk-SJN64NJX.js";
55
+ import "../chunk-65RN6ZCO.js";
55
56
  import {
56
57
  elicitationContent,
57
58
  parseAgentQuestion,
58
59
  parseAgentQuestionAnswers,
59
60
  planElicitationAsk,
60
61
  readElicitationFields
61
- } from "../chunk-YROGUPOZ.js";
62
+ } from "../chunk-WWTLAZQA.js";
62
63
 
63
64
  // bin/pushary-codex-bridge.ts
64
65
  import { existsSync } from "fs";