@pushary/agent-hooks 1.4.0 → 1.4.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 +6 -0
  2. package/dist/bin/pushary-bell-hook.js +18 -18
  3. package/dist/bin/pushary-bell.js +6 -6
  4. package/dist/bin/pushary-claude.js +18 -18
  5. package/dist/bin/pushary-clean.js +154 -137
  6. package/dist/bin/pushary-codex-bridge.js +10 -10
  7. package/dist/bin/pushary-codex-hook.js +22 -22
  8. package/dist/bin/pushary-codex.js +6 -6
  9. package/dist/bin/pushary-connect.js +6 -6
  10. package/dist/bin/pushary-cowork.js +3 -3
  11. package/dist/bin/pushary-daemon.js +22 -22
  12. package/dist/bin/pushary-disconnect.js +10 -10
  13. package/dist/bin/pushary-doctor.js +20 -20
  14. package/dist/bin/pushary-elicitation-hook.js +17 -17
  15. package/dist/bin/pushary-gemini-bridge.js +9 -9
  16. package/dist/bin/pushary-gemini-hook.js +19 -19
  17. package/dist/bin/pushary-hook.js +23 -23
  18. package/dist/bin/pushary-login.js +7 -7
  19. package/dist/bin/pushary-logout.js +4 -4
  20. package/dist/bin/pushary-mode.js +3 -3
  21. package/dist/bin/pushary-notification-hook.js +20 -20
  22. package/dist/bin/pushary-opencode-hook.js +19 -19
  23. package/dist/bin/pushary-permission-denied-hook.js +24 -24
  24. package/dist/bin/pushary-permission-hook.js +23 -23
  25. package/dist/bin/pushary-post-hook.js +20 -20
  26. package/dist/bin/pushary-prompt-hook.js +20 -20
  27. package/dist/bin/pushary-session-end-hook.js +20 -20
  28. package/dist/bin/pushary-session-start-hook.js +22 -22
  29. package/dist/bin/pushary-setup.js +26 -26
  30. package/dist/bin/pushary-stats.js +2 -2
  31. package/dist/bin/pushary-status.js +10 -10
  32. package/dist/bin/pushary-stop-hook.js +20 -20
  33. package/dist/bin/pushary-stopfailure-hook.js +20 -20
  34. package/dist/bin/pushary-transcript-register.js +16 -16
  35. package/dist/bin/pushary-transcripts.js +4 -4
  36. package/dist/bin/pushary-upgrade.js +14 -14
  37. package/dist/bin/pushary-wait.js +3 -3
  38. package/dist/{chunk-S3CLZSV3.js → chunk-2GMI6JH6.js} +5 -5
  39. package/dist/{chunk-NBCTKC4Z.js → chunk-37VLIYLI.js} +4 -4
  40. package/dist/{chunk-RGZY77CD.js → chunk-3BPB2HYZ.js} +3 -3
  41. package/dist/{chunk-RQM5SMMR.js → chunk-3T52B2OF.js} +1 -1
  42. package/dist/{chunk-O5L2OJBB.js → chunk-3UA6FPRC.js} +3 -3
  43. package/dist/{chunk-2TOTCUJC.js → chunk-43JKGLZZ.js} +2 -2
  44. package/dist/{chunk-ZIGGEKZW.js → chunk-4FN6VV56.js} +2 -2
  45. package/dist/{chunk-JCWCTBYH.js → chunk-ALFT7H5B.js} +3 -3
  46. package/dist/{chunk-VENQSVKA.js → chunk-BZBUPZC6.js} +1 -1
  47. package/dist/{chunk-S3EUZZJB.js → chunk-CRNAXFQ6.js} +1 -1
  48. package/dist/{chunk-GS5EI2YL.js → chunk-D7ERHWYB.js} +1 -1
  49. package/dist/{chunk-A7XIL2WD.js → chunk-ED5TA2FJ.js} +3 -3
  50. package/dist/{chunk-7IEB2GV4.js → chunk-FVKFDTN6.js} +1 -0
  51. package/dist/{chunk-43Z3RLS5.js → chunk-GOFDGTEI.js} +6 -6
  52. package/dist/{chunk-XJWMPQ6X.js → chunk-HK3IXIQJ.js} +1 -1
  53. package/dist/{chunk-HGN6VZTY.js → chunk-HQLAZWJJ.js} +5 -5
  54. package/dist/{chunk-UIN3RD2U.js → chunk-I6HRQOMT.js} +4 -4
  55. package/dist/{chunk-7PQZYCEP.js → chunk-JOVWYVSR.js} +1 -1
  56. package/dist/{chunk-P4JVVJ2D.js → chunk-K6I5M2ME.js} +1 -1
  57. package/dist/{chunk-UTYTPDWN.js → chunk-KEMEBTCJ.js} +4 -4
  58. package/dist/{chunk-GLPWCQ6V.js → chunk-KI36MAT6.js} +2 -2
  59. package/dist/{chunk-IF46POXX.js → chunk-LNGYW6G4.js} +4 -4
  60. package/dist/{chunk-SGZ3IAWF.js → chunk-LUT2EZLG.js} +1 -1
  61. package/dist/{chunk-YYRZPEMA.js → chunk-LYXX5NSB.js} +1 -1
  62. package/dist/{chunk-BYAXXBNO.js → chunk-MN3XOVRK.js} +1 -1
  63. package/dist/{chunk-GIXLZFEY.js → chunk-PHHGHHOW.js} +1 -1
  64. package/dist/{chunk-D4TNSUDY.js → chunk-QBS6LGEK.js} +1 -1
  65. package/dist/{chunk-5MSBI6NP.js → chunk-R3AMKNIW.js} +1 -1
  66. package/dist/{chunk-U4FB623J.js → chunk-S3EP4B35.js} +2 -2
  67. package/dist/{chunk-UCGQEAKZ.js → chunk-SAF6NNXY.js} +1 -1
  68. package/dist/{chunk-H25UB3CG.js → chunk-SKXLIVFM.js} +1 -1
  69. package/dist/{chunk-5F5QQMCA.js → chunk-SWFF5U2N.js} +1 -1
  70. package/dist/{chunk-O6RN46OS.js → chunk-TF4IOINR.js} +3 -3
  71. package/dist/{chunk-NYHNLMQO.js → chunk-TI3ZWXZG.js} +1 -1
  72. package/dist/{chunk-ESLLVHDY.js → chunk-TNS3YLFE.js} +6 -6
  73. package/dist/{chunk-Q4UAMWXK.js → chunk-VYUDGQM7.js} +1 -1
  74. package/dist/{chunk-KZIXHLPQ.js → chunk-WEO5JCB4.js} +1 -1
  75. package/dist/{chunk-5IBVIMWT.js → chunk-WIOXWUUH.js} +3 -3
  76. package/dist/{reapply-B3S2LRMT.js → reapply-BAWDJTG7.js} +8 -8
  77. package/dist/src/index.js +12 -12
  78. package/package.json +1 -1
@@ -7,14 +7,14 @@ import {
7
7
  createGuards,
8
8
  resolveHermesPython,
9
9
  runHermesPythonScript
10
- } from "../chunk-NBCTKC4Z.js";
10
+ } from "../chunk-37VLIYLI.js";
11
11
  import "../chunk-P32LPT2L.js";
12
12
  import {
13
13
  removeInstructionBlock,
14
14
  shortenHome,
15
15
  unregisterPluginLocation,
16
16
  vscodeSettingsTargets
17
- } from "../chunk-O5L2OJBB.js";
17
+ } from "../chunk-3UA6FPRC.js";
18
18
  import {
19
19
  OPENCODE_PLUGIN_SIBLING,
20
20
  OPENCODE_PLUGIN_SIBLING_CONTENTS,
@@ -24,7 +24,7 @@ import {
24
24
  openCodePluginDir,
25
25
  openCodePluginFile,
26
26
  removeOpenCodeMcpServer
27
- } from "../chunk-Q4UAMWXK.js";
27
+ } from "../chunk-VYUDGQM7.js";
28
28
  import {
29
29
  compatibleConfigFile,
30
30
  compatibleInstructionsFile,
@@ -32,40 +32,40 @@ import {
32
32
  compatiblePermissionRuleFile,
33
33
  removeCompatibleHooks,
34
34
  removeCompatibleMcpServer
35
- } from "../chunk-HGN6VZTY.js";
35
+ } from "../chunk-HQLAZWJJ.js";
36
36
  import {
37
37
  isClaudeMcpSnapshot,
38
38
  removeClaudeMcpServers,
39
39
  removePusharySettings,
40
40
  removePusharyToolPermissions,
41
41
  restoreClaudeMcpServer
42
- } from "../chunk-5IBVIMWT.js";
42
+ } from "../chunk-WIOXWUUH.js";
43
43
  import {
44
44
  hookOwnerOf,
45
45
  isHookTakeoverReceipt,
46
46
  restoreHookTakeover,
47
47
  restoreMcpServer
48
- } from "../chunk-UTYTPDWN.js";
49
- import "../chunk-5MSBI6NP.js";
48
+ } from "../chunk-KEMEBTCJ.js";
49
+ import "../chunk-R3AMKNIW.js";
50
50
  import {
51
51
  liveBridgeProbe,
52
52
  resolveBridgeStub
53
- } from "../chunk-YYRZPEMA.js";
53
+ } from "../chunk-LYXX5NSB.js";
54
54
  import {
55
55
  pusharyHookExecutable
56
- } from "../chunk-O6RN46OS.js";
56
+ } from "../chunk-TF4IOINR.js";
57
57
  import {
58
58
  disableDaemonService
59
- } from "../chunk-RGZY77CD.js";
59
+ } from "../chunk-3BPB2HYZ.js";
60
60
  import {
61
61
  removeGeminiSettings
62
- } from "../chunk-A7XIL2WD.js";
63
- import "../chunk-7PQZYCEP.js";
62
+ } from "../chunk-ED5TA2FJ.js";
63
+ import "../chunk-JOVWYVSR.js";
64
64
  import "../chunk-XHKBHWLX.js";
65
- import "../chunk-IF46POXX.js";
66
- import "../chunk-KZIXHLPQ.js";
65
+ import "../chunk-LNGYW6G4.js";
66
+ import "../chunk-WEO5JCB4.js";
67
67
  import "../chunk-LGXUGYUH.js";
68
- import "../chunk-RQM5SMMR.js";
68
+ import "../chunk-3T52B2OF.js";
69
69
  import {
70
70
  bridgeAgentKey,
71
71
  claudeJson,
@@ -94,7 +94,7 @@ import {
94
94
  restoreCodexHookTrust,
95
95
  vscodePluginDir,
96
96
  vscodePluginMcp
97
- } from "../chunk-UCGQEAKZ.js";
97
+ } from "../chunk-SAF6NNXY.js";
98
98
  import {
99
99
  exitOnHelpFlag
100
100
  } from "../chunk-TWWLVOPB.js";
@@ -107,14 +107,14 @@ import {
107
107
  CANDIDATE_RCS,
108
108
  isDisabledExport,
109
109
  removeClaudeAlias
110
- } from "../chunk-NYHNLMQO.js";
110
+ } from "../chunk-TI3ZWXZG.js";
111
111
  import "../chunk-EYRGBYZG.js";
112
112
  import "../chunk-SAF6HGAA.js";
113
113
  import "../chunk-7QLSKOSU.js";
114
114
  import {
115
115
  EXIT
116
116
  } from "../chunk-KZERVKTD.js";
117
- import "../chunk-P4JVVJ2D.js";
117
+ import "../chunk-K6I5M2ME.js";
118
118
  import "../chunk-T7E75EKA.js";
119
119
  import "../chunk-2UMNXADU.js";
120
120
  import {
@@ -123,18 +123,19 @@ import {
123
123
  HOOK_LOCATOR_BINARY,
124
124
  SUPPORT_DISCORD,
125
125
  SUPPORT_EMAIL,
126
- isValidApiKey
127
- } from "../chunk-7IEB2GV4.js";
126
+ isValidApiKey,
127
+ redactSecrets
128
+ } from "../chunk-FVKFDTN6.js";
128
129
 
129
130
  // bin/pushary-clean.ts
130
- import { existsSync as existsSync5, readFileSync as readFileSync4, copyFileSync, readdirSync as readdirSync3 } from "fs";
131
+ import { existsSync as existsSync6, readFileSync as readFileSync4, copyFileSync, readdirSync as readdirSync3 } from "fs";
131
132
  import { dirname, join as join5 } from "path";
132
133
  import { homedir as homedir5, tmpdir } from "os";
133
134
  import { confirm } from "@inquirer/prompts";
134
135
  import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
135
136
 
136
137
  // src/cli/mac-leftovers.ts
137
- import { execSync } from "child_process";
138
+ import { execSync, execFileSync } from "child_process";
138
139
  import { existsSync } from "fs";
139
140
  import { homedir } from "os";
140
141
  import { join } from "path";
@@ -209,21 +210,16 @@ var pusharyKeychainServices = (dump) => {
209
210
  return [...found];
210
211
  };
211
212
  var storedPusharyKeychainServices = () => {
212
- try {
213
- const dump = execSync("security dump-keychain", {
214
- encoding: "utf-8",
215
- timeout: 3e4,
216
- maxBuffer: 64 * 1024 * 1024,
217
- stdio: ["ignore", "pipe", "ignore"]
218
- });
219
- const stored = pusharyKeychainServices(dump);
220
- return stored.includes(MAC_KEYCHAIN_SERVICE) ? stored : [MAC_KEYCHAIN_SERVICE, ...stored];
221
- } catch {
222
- return [MAC_KEYCHAIN_SERVICE];
223
- }
213
+ const dump = execFileSync("security", ["dump-keychain"], {
214
+ encoding: "utf-8",
215
+ timeout: 3e4,
216
+ maxBuffer: 64 * 1024 * 1024,
217
+ stdio: ["ignore", "pipe", "ignore"]
218
+ });
219
+ const stored = pusharyKeychainServices(dump);
220
+ return stored.includes(MAC_KEYCHAIN_SERVICE) ? stored : [MAC_KEYCHAIN_SERVICE, ...stored];
224
221
  };
225
222
  var MAC_APP_BUNDLE_ID = "com.pushary.app";
226
- var QUIT_MAC_APP = `osascript -e 'tell application id "${MAC_APP_BUNDLE_ID}" to quit'`;
227
223
  var runningMacAppPIDs = () => {
228
224
  if (process.platform !== "darwin") return [];
229
225
  try {
@@ -245,8 +241,83 @@ var waitForMacAppExit = (attempts = 20, everyMs = 250) => {
245
241
  return runningMacAppPIDs().length === 0;
246
242
  };
247
243
 
244
+ // src/cli/clean-mac.ts
245
+ import { existsSync as existsSync2 } from "fs";
246
+ var removeDeveloperLeftovers = (guards2, domains, bundles) => {
247
+ let removed = 0;
248
+ for (const domain of domains) {
249
+ try {
250
+ guards2.execFile("defaults", ["delete", domain], { stdio: "ignore", timeout: 1e4 }, `delete preferences ${domain}`);
251
+ removed++;
252
+ } catch {
253
+ continue;
254
+ }
255
+ }
256
+ for (const bundle of bundles) {
257
+ try {
258
+ guards2.execFile(LSREGISTER, ["-u", bundle], { stdio: "ignore", timeout: 2e4 }, `unregister ${bundle}`);
259
+ removed++;
260
+ } catch {
261
+ continue;
262
+ }
263
+ }
264
+ return removed;
265
+ };
266
+ var removeMacAppState = (guards2, readServices, home) => {
267
+ let removed = 0;
268
+ let failed = 0;
269
+ let services;
270
+ try {
271
+ services = readServices();
272
+ } catch {
273
+ return { removed, failed: 1 };
274
+ }
275
+ for (const service of services) {
276
+ for (const account of MAC_KEYCHAIN_ACCOUNTS) {
277
+ try {
278
+ guards2.execFile(
279
+ "security",
280
+ ["delete-generic-password", "-s", service, "-a", account],
281
+ { stdio: "ignore" },
282
+ `remove keychain item ${service} (${account})`
283
+ );
284
+ removed++;
285
+ } catch (error) {
286
+ if (!(error instanceof Error && "status" in error && error.status === 44)) failed++;
287
+ }
288
+ }
289
+ }
290
+ for (const domain of MAC_DEFAULTS_DOMAINS) {
291
+ try {
292
+ guards2.execFile("defaults", ["delete", domain], { stdio: "ignore", timeout: 1e4 }, `delete preferences ${domain}`);
293
+ removed++;
294
+ } catch {
295
+ continue;
296
+ }
297
+ }
298
+ for (const path of macLibraryState(home)) {
299
+ if (!existsSync2(path)) continue;
300
+ guards2.remove(path, { force: true });
301
+ removed++;
302
+ }
303
+ return { removed, failed };
304
+ };
305
+ var quitMacApp = (guards2, state) => {
306
+ if (state.platform !== "darwin" || state.running().length === 0) return "not-running";
307
+ try {
308
+ guards2.execFile(
309
+ "osascript",
310
+ ["-e", `tell application id "${MAC_APP_BUNDLE_ID}" to quit`],
311
+ { stdio: "ignore", timeout: 3e4 },
312
+ "quit Pushary"
313
+ );
314
+ } catch {
315
+ }
316
+ return state.dryRun || state.waitForExit() ? "quit" : "running";
317
+ };
318
+
248
319
  // src/cli/editor-extension.ts
249
- import { existsSync as existsSync2, readFileSync, readdirSync } from "fs";
320
+ import { existsSync as existsSync3, readFileSync, readdirSync } from "fs";
250
321
  import { homedir as homedir2 } from "os";
251
322
  import { join as join2 } from "path";
252
323
  var EDITOR_EXTENSION_ID = "pushary.pushary";
@@ -273,13 +344,13 @@ var recordWithoutUs = (directory) => {
273
344
  return void 0;
274
345
  }
275
346
  };
276
- var editorExtensionRemovals = (home = homedir2()) => EDITOR_EXTENSION_DIRS.map((relative) => join2(home, relative)).filter(existsSync2).map((directory) => {
347
+ var editorExtensionRemovals = (home = homedir2()) => EDITOR_EXTENSION_DIRS.map((relative) => join2(home, relative)).filter(existsSync3).map((directory) => {
277
348
  const folders = readdirSync(directory).filter((name) => name.startsWith(`${EDITOR_EXTENSION_ID}-`)).map((name) => join2(directory, name));
278
349
  return { directory, folders, record: recordWithoutUs(directory) };
279
350
  }).filter((removal) => removal.folders.length > 0 || removal.record !== void 0);
280
351
 
281
352
  // src/cli/skills-store.ts
282
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
353
+ import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
283
354
  import { homedir as homedir3 } from "os";
284
355
  import { join as join3 } from "path";
285
356
  var SKILLS_STORE_DIR = ".agents";
@@ -287,9 +358,12 @@ var LOCK_FILE = ".skill-lock.json";
287
358
  var lockWithoutUs = (path) => {
288
359
  try {
289
360
  const lock = JSON.parse(readFileSync2(path, "utf-8"));
290
- const entry = lock.skills?.[PUSHARY_SKILL_NAME];
291
- if (entry?.source !== PUSHARY_SKILL_SOURCE) return void 0;
292
- const { [PUSHARY_SKILL_NAME]: _ours, ...skills } = lock.skills ?? {};
361
+ if (!lock || typeof lock !== "object" || Array.isArray(lock) || !("skills" in lock)) return void 0;
362
+ const entries = lock.skills;
363
+ if (!entries || typeof entries !== "object" || Array.isArray(entries) || !(PUSHARY_SKILL_NAME in entries)) return void 0;
364
+ const entry = entries[PUSHARY_SKILL_NAME];
365
+ if (!entry || typeof entry !== "object" || !("source" in entry) || entry.source !== PUSHARY_SKILL_SOURCE) return void 0;
366
+ const { [PUSHARY_SKILL_NAME]: _ours, ...skills } = entries;
293
367
  return { path, contents: `${JSON.stringify({ ...lock, skills }, null, 2)}
294
368
  ` };
295
369
  } catch {
@@ -299,22 +373,23 @@ var lockWithoutUs = (path) => {
299
373
  var skillsStoreRemoval = (home = homedir3()) => {
300
374
  const store = join3(home, SKILLS_STORE_DIR);
301
375
  const skillDir = join3(store, "skills", PUSHARY_SKILL_NAME);
376
+ const lock = lockWithoutUs(join3(store, LOCK_FILE));
302
377
  return {
303
- skillDir: existsSync3(skillDir) ? skillDir : void 0,
304
- lock: lockWithoutUs(join3(store, LOCK_FILE))
378
+ skillDir: lock && existsSync4(skillDir) ? skillDir : void 0,
379
+ lock
305
380
  };
306
381
  };
307
382
 
308
383
  // src/cli/claude-backups.ts
309
- import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
384
+ import { existsSync as existsSync5, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
310
385
  import { homedir as homedir4 } from "os";
311
386
  import { join as join4 } from "path";
312
387
  var BACKUP_PREFIX = ".claude.json.backup";
313
388
  var claudeJsonBackups = (home = homedir4()) => {
314
389
  const rollingDir = join4(home, ".claude", "backups");
315
390
  const legacy = join4(home, BACKUP_PREFIX);
316
- const rolling = existsSync4(rollingDir) ? readdirSync2(rollingDir).filter((name) => name.startsWith(BACKUP_PREFIX)).sort().map((name) => join4(rollingDir, name)) : [];
317
- return existsSync4(legacy) ? [...rolling, legacy] : rolling;
391
+ const rolling = existsSync5(rollingDir) ? readdirSync2(rollingDir).filter((name) => name.startsWith(BACKUP_PREFIX)).sort().map((name) => join4(rollingDir, name)) : [];
392
+ return existsSync5(legacy) ? [...rolling, legacy] : rolling;
318
393
  };
319
394
  var parsed = (path) => {
320
395
  try {
@@ -414,69 +489,6 @@ var wouldNote = (action, path) => {
414
489
  var guards = createGuards(() => dryRun, wouldNote);
415
490
  var guardedWrite = (path, contents) => guards.write(path, contents);
416
491
  var guardedRemove = (path, options) => guards.remove(path, options);
417
- var guardedExec = (command, options, describe) => guards.exec(command, options ?? {}, describe);
418
- var removeDeveloperLeftovers = () => {
419
- if (process.platform !== "darwin") return 0;
420
- let removed = 0;
421
- for (const domain of leakedTestDefaultsDomains()) {
422
- const command = `defaults delete ${JSON.stringify(domain)}`;
423
- try {
424
- guardedExec(command, { stdio: "ignore", timeout: 1e4 }, command);
425
- removed++;
426
- } catch {
427
- continue;
428
- }
429
- }
430
- for (const bundle of registeredPusharyBundles()) {
431
- const command = `${LSREGISTER} -u ${JSON.stringify(bundle)}`;
432
- try {
433
- guardedExec(command, { stdio: "ignore", timeout: 2e4 }, command);
434
- removed++;
435
- } catch {
436
- continue;
437
- }
438
- }
439
- return removed;
440
- };
441
- var removeMacAppState = () => {
442
- if (process.platform !== "darwin") return 0;
443
- let removed = 0;
444
- for (const service of storedPusharyKeychainServices()) {
445
- for (const account of MAC_KEYCHAIN_ACCOUNTS) {
446
- const command = `security delete-generic-password -s ${JSON.stringify(service)} -a ${account}`;
447
- try {
448
- guardedExec(command, { stdio: "ignore", timeout: 1e4 }, command);
449
- removed++;
450
- } catch {
451
- continue;
452
- }
453
- }
454
- }
455
- for (const domain of MAC_DEFAULTS_DOMAINS) {
456
- const command = `defaults delete ${JSON.stringify(domain)}`;
457
- try {
458
- guardedExec(command, { stdio: "ignore", timeout: 1e4 }, command);
459
- removed++;
460
- } catch {
461
- continue;
462
- }
463
- }
464
- for (const path of macLibraryState(homedir5())) {
465
- if (!existsSync5(path)) continue;
466
- guardedRemove(path, { force: true });
467
- removed++;
468
- }
469
- return removed;
470
- };
471
- var quitMacApp = () => {
472
- if (process.platform !== "darwin") return "not-running";
473
- if (runningMacAppPIDs().length === 0) return "not-running";
474
- try {
475
- guardedExec(QUIT_MAC_APP, { stdio: "ignore", timeout: 3e4 }, QUIT_MAC_APP);
476
- } catch {
477
- }
478
- return dryRun || waitForMacAppExit() ? "quit" : "running";
479
- };
480
492
  var CURSOR_PLUGIN_STAGING = ".pushary-staging-";
481
493
  var cursorPluginLeftovers = () => {
482
494
  const parent = dirname(CURSOR_PLUGIN_DIR);
@@ -496,14 +508,14 @@ var guardedDaemonRemoval = async () => {
496
508
  };
497
509
  var guardedInstructionBlockRemoval = (path) => {
498
510
  if (!dryRun) return removeInstructionBlock(path);
499
- if (!existsSync5(path)) return false;
511
+ if (!existsSync6(path)) return false;
500
512
  const hasBlock = readFileSync4(path, "utf-8").includes("pushary");
501
513
  if (hasBlock) wouldNote("rewrite", path);
502
514
  return hasBlock;
503
515
  };
504
516
  var guardedAliasRemoval = () => {
505
517
  if (!dryRun) return removeClaudeAlias();
506
- const shells = CANDIDATE_RCS.map((name) => join5(homedir5(), name)).filter((path) => existsSync5(path) && readFileSync4(path, "utf-8").includes("pushary claude"));
518
+ const shells = CANDIDATE_RCS.map((name) => join5(homedir5(), name)).filter((path) => existsSync6(path) && readFileSync4(path, "utf-8").includes("pushary claude"));
507
519
  for (const path of shells) wouldNote("rewrite", path);
508
520
  return shells;
509
521
  };
@@ -511,7 +523,7 @@ var writeJson = (path, data) => {
511
523
  guardedWrite(path, JSON.stringify(data, null, 2) + "\n");
512
524
  };
513
525
  var removeCursorUserHook = (scope) => {
514
- if (!existsSync5(CURSOR_USER_HOOKS)) return "absent";
526
+ if (!existsSync6(CURSOR_USER_HOOKS)) return "absent";
515
527
  let parsed2;
516
528
  try {
517
529
  parsed2 = JSON.parse(readFileSync4(CURSOR_USER_HOOKS, "utf-8"));
@@ -585,11 +597,11 @@ var restoreTakeoverReceipts = () => {
585
597
  ];
586
598
  for (const [agent, hookFile, mcpFile, mcpKey, mcpFormat] of targets) {
587
599
  const receiptPath = hookTakeoverReceipt(agent);
588
- if (!existsSync5(receiptPath)) continue;
600
+ if (!existsSync6(receiptPath)) continue;
589
601
  try {
590
602
  const receipt = readJson(receiptPath);
591
603
  if (!isHookTakeoverReceipt(receipt) || receipt.agent !== agent) throw new Error("invalid receipt");
592
- const document = existsSync5(hookFile) ? JSON.parse(readFileSync4(hookFile, "utf-8")) : {};
604
+ const document = existsSync6(hookFile) ? JSON.parse(readFileSync4(hookFile, "utf-8")) : {};
593
605
  if (!document || typeof document !== "object" || Array.isArray(document)) throw new Error("invalid hooks file");
594
606
  const appAlreadyOwns = hookOwnerOf(document) === "app";
595
607
  const cliPositions = agent === "codex" ? codexHookPositions(document) : {};
@@ -600,7 +612,7 @@ var restoreTakeoverReceipts = () => {
600
612
  if (mcpFile === hookFile) {
601
613
  mcpDocument = document;
602
614
  } else {
603
- const raw = existsSync5(mcpFile) ? readFileSync4(mcpFile, "utf-8") : "";
615
+ const raw = existsSync6(mcpFile) ? readFileSync4(mcpFile, "utf-8") : "";
604
616
  mcpDocument = raw.trim() ? mcpFormat === "toml" ? parseTOML(raw) : JSON.parse(raw) : {};
605
617
  }
606
618
  mcpChanged = restoreMcpServer(mcpDocument, mcpKey, receipt.mcpServer);
@@ -610,7 +622,7 @@ var restoreTakeoverReceipts = () => {
610
622
  if (!appAlreadyOwns && agent === "codex") {
611
623
  if (!mcpDocument) {
612
624
  const configPath = codexConfigToml();
613
- const raw = existsSync5(configPath) ? readFileSync4(configPath, "utf-8") : "";
625
+ const raw = existsSync6(configPath) ? readFileSync4(configPath, "utf-8") : "";
614
626
  mcpDocument = raw.trim() ? parseTOML(raw) : {};
615
627
  }
616
628
  codexConfig = mcpDocument;
@@ -679,18 +691,19 @@ var main = async () => {
679
691
  console.log(` ${dim("Removing the Mac app's wiring and state as well.")}`);
680
692
  }
681
693
  if (everything) {
682
- const quit = quitMacApp();
694
+ const quit = quitMacApp(guards, { platform: process.platform, dryRun, running: runningMacAppPIDs, waitForExit: waitForMacAppExit });
683
695
  if (quit === "quit") {
684
696
  console.log(` ${check} Pushary ${dim(did("quit"))} ${dim("(running, and its watcher puts back what this removes)")}`);
685
697
  } else if (quit === "running") {
686
698
  incompleteClean = true;
687
699
  console.log(` ${cross} Pushary ${dim("would not quit, and it puts back what this removes")}`);
688
700
  console.log(` ${dim("Quit it from the notch menu, then re-run.")}`);
701
+ process.exit(EXIT.FAILED);
689
702
  }
690
703
  }
691
704
  if (presence !== "absent") console.log();
692
705
  const restoredByTakeover = new Set(
693
- ["claude_code", "codex", "gemini_cli"].filter((agent) => existsSync5(hookTakeoverReceipt(agent)))
706
+ ["claude_code", "codex", "gemini_cli"].filter((agent) => existsSync6(hookTakeoverReceipt(agent)))
694
707
  );
695
708
  if (keepShared) restoreTakeoverReceipts();
696
709
  const sharedMcpKeys = {
@@ -718,7 +731,7 @@ var main = async () => {
718
731
  const claudeHadPusharyEntry = claudeHasPusharyEntry();
719
732
  const rawReceipt = readJson(CLAUDE_MCP_RECEIPT);
720
733
  const receipt = isClaudeMcpSnapshot(rawReceipt) ? rawReceipt : null;
721
- const receiptUnreadable = existsSync5(CLAUDE_MCP_RECEIPT) && !receipt;
734
+ const receiptUnreadable = existsSync6(CLAUDE_MCP_RECEIPT) && !receipt;
722
735
  if (keepClaudeMcp) {
723
736
  console.log(` ${skip} Claude Code MCP servers ${dim("(kept: the Mac app uses it)")}`);
724
737
  } else if (claudeJson2) {
@@ -733,7 +746,7 @@ var main = async () => {
733
746
  if (receipt && !keepShared) incompleteClean = true;
734
747
  console.log(` ${skip} Claude Code MCP servers ${dim(receipt ? "(changed after setup; left unchanged)" : "(no pushary entries)")}`);
735
748
  }
736
- } else if (existsSync5(CLAUDE_MCP_RECEIPT)) {
749
+ } else if (existsSync6(CLAUDE_MCP_RECEIPT)) {
737
750
  incompleteClean = true;
738
751
  console.log(` ${skip} Claude Code MCP servers ${dim("(config missing; setup receipt kept for retry)")}`);
739
752
  } else {
@@ -777,7 +790,7 @@ var main = async () => {
777
790
  }
778
791
  if (cursorGate === "failed") {
779
792
  console.log(` ${skip} Cursor plugin ${dim("(kept: removing it now would block matched commands)")}`);
780
- } else if (existsSync5(CURSOR_PLUGIN_DIR)) {
793
+ } else if (existsSync6(CURSOR_PLUGIN_DIR)) {
781
794
  guardedRemove(CURSOR_PLUGIN_DIR);
782
795
  console.log(` ${check} Cursor plugin ${dim("(removed from ~/.cursor/plugins/local)")}`);
783
796
  } else {
@@ -793,9 +806,9 @@ var main = async () => {
793
806
  if (keepShared) {
794
807
  console.log(` ${skip} VS Code plugin ${dim("(kept: the Mac app writes the same plugin directory)")}`);
795
808
  }
796
- for (const settingsPath of keepShared ? [] : vscodeSettingsTargets(existsSync5)) {
809
+ for (const settingsPath of keepShared ? [] : vscodeSettingsTargets(existsSync6)) {
797
810
  const label = `VS Code plugin ${dim(`(${shortenHome(settingsPath)})`)}`;
798
- if (!existsSync5(settingsPath)) {
811
+ if (!existsSync6(settingsPath)) {
799
812
  console.log(` ${skip} ${label} ${dim("(no settings.json)")}`);
800
813
  continue;
801
814
  }
@@ -809,7 +822,7 @@ var main = async () => {
809
822
  console.log(` ${skip} ${label} ${dim("(no pushary entry)")}`);
810
823
  }
811
824
  }
812
- if (!keepShared && existsSync5(VSCODE_PLUGIN_DIR)) {
825
+ if (!keepShared && existsSync6(VSCODE_PLUGIN_DIR)) {
813
826
  guardedRemove(VSCODE_PLUGIN_DIR);
814
827
  console.log(` ${check} VS Code plugin files ${dim(did("removed"))}`);
815
828
  }
@@ -828,7 +841,7 @@ var main = async () => {
828
841
  }
829
842
  if (keepShared) {
830
843
  console.log(` ${skip} Skill directory ${dim("(kept: the Mac app uses it)")}`);
831
- } else if (existsSync5(SKILL_DIR)) {
844
+ } else if (existsSync6(SKILL_DIR)) {
832
845
  guardedRemove(SKILL_DIR);
833
846
  console.log(` ${check} Skill directory ${dim(did("removed"))}`);
834
847
  } else {
@@ -888,7 +901,7 @@ var main = async () => {
888
901
  const codexSkillDir2 = codexSkillDir();
889
902
  if (keepShared) {
890
903
  console.log(` ${skip} Codex skill directory ${dim("(kept: the Mac app uses it)")}`);
891
- } else if (existsSync5(codexSkillDir2)) {
904
+ } else if (existsSync6(codexSkillDir2)) {
892
905
  guardedRemove(codexSkillDir2);
893
906
  console.log(` ${check} Codex skill directory ${dim(did("removed"))}`);
894
907
  } else {
@@ -944,7 +957,7 @@ var main = async () => {
944
957
  console.log(` ${skip} Gemini GEMINI.md ${dim("(no pushary block)")}`);
945
958
  }
946
959
  const openCodePlugin = openCodePluginFile();
947
- const openCodePluginContents = existsSync5(openCodePlugin) ? readFileSync4(openCodePlugin, "utf-8") : null;
960
+ const openCodePluginContents = existsSync6(openCodePlugin) ? readFileSync4(openCodePlugin, "utf-8") : null;
948
961
  if (openCodePluginContents === null) {
949
962
  console.log(` ${skip} OpenCode plugin ${dim("(not installed)")}`);
950
963
  } else if (!isOpenCodePluginOurs(openCodePluginContents)) {
@@ -962,7 +975,7 @@ var main = async () => {
962
975
  return [];
963
976
  }
964
977
  })();
965
- const siblingIsOurs = existsSync5(sibling) && readFileSync4(sibling, "utf-8") === OPENCODE_PLUGIN_SIBLING_CONTENTS;
978
+ const siblingIsOurs = existsSync6(sibling) && readFileSync4(sibling, "utf-8") === OPENCODE_PLUGIN_SIBLING_CONTENTS;
966
979
  if (siblingIsOurs && !hasForeignPlugins(remaining)) {
967
980
  guardedRemove(sibling, { force: true });
968
981
  console.log(` ${check} OpenCode plugin sibling ${dim(did("removed"))}`);
@@ -990,14 +1003,14 @@ var main = async () => {
990
1003
  } else {
991
1004
  console.log(` ${check} Hermes config ${dim("(setup-owned changes restored)")}`);
992
1005
  try {
993
- guardedExec(`"${hermesPython}" -m pip uninstall -y ${HERMES_PIP_PACKAGE}`, { stdio: "pipe", timeout: 6e4 }, `pip uninstall ${HERMES_PIP_PACKAGE}`);
1006
+ guards.execFile(hermesPython, ["-m", "pip", "uninstall", "-y", HERMES_PIP_PACKAGE], { stdio: "pipe", timeout: 6e4 }, `pip uninstall ${HERMES_PIP_PACKAGE}`);
994
1007
  console.log(` ${check} Hermes plugin ${dim("(pip uninstalled)")}`);
995
1008
  } catch {
996
1009
  incompleteClean = true;
997
1010
  console.log(` ${skip} Hermes plugin ${dim("(could not uninstall; setup receipt kept for retry)")}`);
998
1011
  }
999
1012
  }
1000
- } else if (existsSync5(HERMES_CONFIG_RECEIPT)) {
1013
+ } else if (existsSync6(HERMES_CONFIG_RECEIPT)) {
1001
1014
  incompleteClean = true;
1002
1015
  console.log(` ${skip} Hermes ${dim("(runtime not found; setup receipt kept for retry)")}`);
1003
1016
  } else {
@@ -1025,10 +1038,10 @@ var main = async () => {
1025
1038
  if ((line.match(/pk_[A-Za-z0-9_]+\.[A-Za-z0-9_]+/g) ?? []).some(isValidApiKey)) {
1026
1039
  incompleteClean = true;
1027
1040
  console.log(` ${cross} ${name} ${dim("still sets PUSHARY_API_KEY, in a form this command will not rewrite:")}`);
1028
- console.log(` ${dim(line.trim())}`);
1041
+ console.log(` ${dim(redactSecrets(line.trim()))}`);
1029
1042
  console.log(` ${dim("Remove it yourself. A setup run would sign this machine in as that account.")}`);
1030
1043
  } else {
1031
- console.log(` ${skip} ${name} ${dim(`left a line referencing PUSHARY_API_KEY: ${line.trim()}`)}`);
1044
+ console.log(` ${skip} ${name} ${dim(`left a line referencing PUSHARY_API_KEY: ${redactSecrets(line.trim())}`)}`);
1032
1045
  }
1033
1046
  }
1034
1047
  }
@@ -1041,7 +1054,7 @@ var main = async () => {
1041
1054
  } else {
1042
1055
  console.log(` ${skip} claude alias ${dim("(not set)")}`);
1043
1056
  }
1044
- if (existsSync5(PUSHARY_DIR)) {
1057
+ if (existsSync6(PUSHARY_DIR)) {
1045
1058
  let removed = 0;
1046
1059
  const kept = [];
1047
1060
  for (const entry of readdirSync3(PUSHARY_DIR)) {
@@ -1084,14 +1097,18 @@ var main = async () => {
1084
1097
  if (store.skillDir || store.lock) {
1085
1098
  console.log(` ${check} skills.sh registration ${dim(did("removed"))} ${dim("(~/.agents)")}`);
1086
1099
  }
1087
- const leftovers = removeDeveloperLeftovers();
1100
+ const leftovers = process.platform === "darwin" ? removeDeveloperLeftovers(guards, leakedTestDefaultsDomains(), registeredPusharyBundles()) : 0;
1088
1101
  if (leftovers > 0) {
1089
1102
  console.log(` ${check} Developer leftovers ${dim(did("removed"))} ${dim(`(${leftovers} leaked test preferences and stale app registrations)`)}`);
1090
1103
  }
1091
- const removed = removeMacAppState();
1104
+ const { removed, failed } = process.platform === "darwin" ? removeMacAppState(guards, storedPusharyKeychainServices, homedir5()) : { removed: 0, failed: 0 };
1105
+ if (failed > 0) {
1106
+ incompleteClean = true;
1107
+ console.log(` ${cross} Mac keychain ${dim(`(${failed} operations failed; unlock your keychain and re-run)`)}`);
1108
+ }
1092
1109
  if (removed > 0) {
1093
1110
  console.log(` ${check} Mac app state ${dim(did("removed"))} ${dim(`(${removed} keychain items, preferences and caches)`)}`);
1094
- } else {
1111
+ } else if (failed === 0) {
1095
1112
  console.log(` ${skip} Mac app state ${dim("(nothing of ours in the keychain, preferences or caches)")}`);
1096
1113
  }
1097
1114
  }
@@ -1112,7 +1129,7 @@ var main = async () => {
1112
1129
  console.log(` ${dim("Still stuck? Send this output to")} ${SUPPORT_EMAIL} ${dim("or")} ${SUPPORT_DISCORD}`);
1113
1130
  } else if (everything) {
1114
1131
  console.log(` ${green(bold("Clean complete. Nothing of ours is left in any agent config."))}`);
1115
- const bundle = installedPusharyBundles().find(existsSync5);
1132
+ const bundle = installedPusharyBundles().find(existsSync6);
1116
1133
  if (bundle) {
1117
1134
  console.log(` ${dim("The app itself is still installed. Drag")} ${bundle} ${dim("to the Trash to finish.")}`);
1118
1135
  }
@@ -1,24 +1,24 @@
1
1
  #!/usr/bin/env node
2
- import "../chunk-GLPWCQ6V.js";
2
+ import "../chunk-KI36MAT6.js";
3
3
  import {
4
4
  LiveTranscriptRelay,
5
5
  liveSessionSleep,
6
6
  postLiveSession,
7
7
  postLiveSessionUntilAccepted,
8
8
  startLiveSessionHeartbeat
9
- } from "../chunk-H25UB3CG.js";
9
+ } from "../chunk-SKXLIVFM.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-GIXLZFEY.js";
17
- import "../chunk-S3EUZZJB.js";
16
+ } from "../chunk-PHHGHHOW.js";
17
+ import "../chunk-CRNAXFQ6.js";
18
18
  import "../chunk-EQRS3SGM.js";
19
19
  import {
20
20
  transcriptsEnabled
21
- } from "../chunk-BYAXXBNO.js";
21
+ } from "../chunk-MN3XOVRK.js";
22
22
  import {
23
23
  spawnClaude
24
24
  } from "../chunk-XHKBHWLX.js";
@@ -28,18 +28,18 @@ import {
28
28
  } from "../chunk-LGXUGYUH.js";
29
29
  import {
30
30
  getMachineId
31
- } from "../chunk-RQM5SMMR.js";
31
+ } from "../chunk-3T52B2OF.js";
32
32
  import {
33
33
  resolveBinary
34
- } from "../chunk-UCGQEAKZ.js";
35
- import "../chunk-NYHNLMQO.js";
34
+ } from "../chunk-SAF6NNXY.js";
35
+ import "../chunk-TI3ZWXZG.js";
36
36
  import {
37
37
  callMcpTool
38
38
  } from "../chunk-EYRGBYZG.js";
39
39
  import "../chunk-SAF6HGAA.js";
40
40
  import "../chunk-7QLSKOSU.js";
41
41
  import "../chunk-KZERVKTD.js";
42
- import "../chunk-P4JVVJ2D.js";
42
+ import "../chunk-K6I5M2ME.js";
43
43
  import "../chunk-T7E75EKA.js";
44
44
  import {
45
45
  getApiKey,
@@ -48,7 +48,7 @@ import {
48
48
  import {
49
49
  parseAgentQuestion,
50
50
  parseAgentQuestionAnswers
51
- } from "../chunk-7IEB2GV4.js";
51
+ } from "../chunk-FVKFDTN6.js";
52
52
 
53
53
  // bin/pushary-codex-bridge.ts
54
54
  import { existsSync } from "fs";