@pushary/agent-hooks 1.4.0 → 1.4.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 (78) hide show
  1. package/CHANGELOG.md +15 -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 +159 -138
  6. package/dist/bin/pushary-codex-bridge.js +10 -10
  7. package/dist/bin/pushary-codex-hook.js +31 -26
  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 +53 -32
  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-VENQSVKA.js → chunk-25RTLTQD.js} +1 -1
  39. package/dist/{chunk-H25UB3CG.js → chunk-2V2IKOGJ.js} +1 -1
  40. package/dist/{chunk-BYAXXBNO.js → chunk-4BROEAKH.js} +1 -1
  41. package/dist/{chunk-UTYTPDWN.js → chunk-4ZDKSDVW.js} +4 -4
  42. package/dist/{chunk-2TOTCUJC.js → chunk-55KW4FLG.js} +2 -2
  43. package/dist/{chunk-S3CLZSV3.js → chunk-ACYIZ3KH.js} +5 -5
  44. package/dist/{chunk-RGZY77CD.js → chunk-BZ4GDOJX.js} +3 -3
  45. package/dist/{chunk-5MSBI6NP.js → chunk-DY4ILT6L.js} +1 -1
  46. package/dist/{chunk-Q4UAMWXK.js → chunk-F4UWL4NY.js} +1 -1
  47. package/dist/{chunk-NYHNLMQO.js → chunk-FU2DFEAZ.js} +1 -1
  48. package/dist/{chunk-IF46POXX.js → chunk-G653QPTR.js} +17 -13
  49. package/dist/{chunk-S3EUZZJB.js → chunk-GZ7E6VOB.js} +1 -1
  50. package/dist/{chunk-5IBVIMWT.js → chunk-II7PUMPB.js} +3 -3
  51. package/dist/{chunk-ZIGGEKZW.js → chunk-JVTOML54.js} +2 -2
  52. package/dist/{chunk-5F5QQMCA.js → chunk-LEAAERSQ.js} +1 -1
  53. package/dist/{chunk-A7XIL2WD.js → chunk-LPYCPFBZ.js} +3 -3
  54. package/dist/{chunk-XJWMPQ6X.js → chunk-M5CTUFF3.js} +1 -1
  55. package/dist/{chunk-O5L2OJBB.js → chunk-MUVTZNJW.js} +3 -3
  56. package/dist/{chunk-7PQZYCEP.js → chunk-MW6ZPC6R.js} +1 -1
  57. package/dist/{chunk-RQM5SMMR.js → chunk-NHTAHAIS.js} +1 -1
  58. package/dist/{chunk-GS5EI2YL.js → chunk-NOWZUGZW.js} +1 -1
  59. package/dist/{chunk-D4TNSUDY.js → chunk-NY6XQ6CA.js} +1 -1
  60. package/dist/{chunk-SGZ3IAWF.js → chunk-PC6DU5C4.js} +1 -1
  61. package/dist/{chunk-7IEB2GV4.js → chunk-SOUZBGYJ.js} +5 -0
  62. package/dist/{chunk-JCWCTBYH.js → chunk-SUWRZYQG.js} +56 -5
  63. package/dist/{chunk-U4FB623J.js → chunk-T5SZ4PML.js} +24 -10
  64. package/dist/{chunk-UCGQEAKZ.js → chunk-TRLFZKVG.js} +1 -1
  65. package/dist/{chunk-GLPWCQ6V.js → chunk-TYEO6T5J.js} +2 -2
  66. package/dist/{chunk-ESLLVHDY.js → chunk-UJBZIKSY.js} +6 -6
  67. package/dist/{chunk-P4JVVJ2D.js → chunk-UM5J3J4V.js} +1 -1
  68. package/dist/{chunk-HGN6VZTY.js → chunk-VIOL2DJS.js} +5 -5
  69. package/dist/{chunk-GIXLZFEY.js → chunk-VOMOZ4D5.js} +1 -1
  70. package/dist/{chunk-UIN3RD2U.js → chunk-VW66JEGU.js} +4 -4
  71. package/dist/{chunk-O6RN46OS.js → chunk-WPVHRUDT.js} +3 -3
  72. package/dist/{chunk-43Z3RLS5.js → chunk-XDP3UYH5.js} +16 -43
  73. package/dist/{chunk-NBCTKC4Z.js → chunk-Y3MM6PYN.js} +4 -4
  74. package/dist/{chunk-KZIXHLPQ.js → chunk-YXP3WPAI.js} +1 -1
  75. package/dist/{chunk-YYRZPEMA.js → chunk-ZVY25BMK.js} +1 -1
  76. package/dist/{reapply-B3S2LRMT.js → reapply-J527BCJG.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-Y3MM6PYN.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-MUVTZNJW.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-F4UWL4NY.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-VIOL2DJS.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-II7PUMPB.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-4ZDKSDVW.js";
49
+ import "../chunk-DY4ILT6L.js";
50
50
  import {
51
51
  liveBridgeProbe,
52
52
  resolveBridgeStub
53
- } from "../chunk-YYRZPEMA.js";
53
+ } from "../chunk-ZVY25BMK.js";
54
54
  import {
55
55
  pusharyHookExecutable
56
- } from "../chunk-O6RN46OS.js";
56
+ } from "../chunk-WPVHRUDT.js";
57
57
  import {
58
58
  disableDaemonService
59
- } from "../chunk-RGZY77CD.js";
59
+ } from "../chunk-BZ4GDOJX.js";
60
60
  import {
61
61
  removeGeminiSettings
62
- } from "../chunk-A7XIL2WD.js";
63
- import "../chunk-7PQZYCEP.js";
62
+ } from "../chunk-LPYCPFBZ.js";
63
+ import "../chunk-MW6ZPC6R.js";
64
64
  import "../chunk-XHKBHWLX.js";
65
- import "../chunk-IF46POXX.js";
66
- import "../chunk-KZIXHLPQ.js";
65
+ import "../chunk-G653QPTR.js";
66
+ import "../chunk-YXP3WPAI.js";
67
67
  import "../chunk-LGXUGYUH.js";
68
- import "../chunk-RQM5SMMR.js";
68
+ import "../chunk-NHTAHAIS.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-TRLFZKVG.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-FU2DFEAZ.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-UM5J3J4V.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-SOUZBGYJ.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";
@@ -186,7 +187,11 @@ var MAC_KEYCHAIN_ACCOUNTS = [
186
187
  "pushary.site-api-key",
187
188
  "pushary.site-id",
188
189
  "clerk.device-token",
189
- "clerk.session-id"
190
+ "clerk.session-id",
191
+ "clerkDeviceToken",
192
+ "cachedClient",
193
+ "cachedClientServerDate",
194
+ "cachedEnvironment"
190
195
  ];
191
196
  var MAC_DEFAULTS_DOMAINS = ["com.pushary.app", "pushary-bridge", "pushary.render"];
192
197
  var macLibraryState = (home = homedir()) => [
@@ -209,21 +214,16 @@ var pusharyKeychainServices = (dump) => {
209
214
  return [...found];
210
215
  };
211
216
  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
- }
217
+ const dump = execFileSync("security", ["dump-keychain"], {
218
+ encoding: "utf-8",
219
+ timeout: 3e4,
220
+ maxBuffer: 64 * 1024 * 1024,
221
+ stdio: ["ignore", "pipe", "ignore"]
222
+ });
223
+ const stored = pusharyKeychainServices(dump);
224
+ return stored.includes(MAC_KEYCHAIN_SERVICE) ? stored : [MAC_KEYCHAIN_SERVICE, ...stored];
224
225
  };
225
226
  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
227
  var runningMacAppPIDs = () => {
228
228
  if (process.platform !== "darwin") return [];
229
229
  try {
@@ -245,8 +245,83 @@ var waitForMacAppExit = (attempts = 20, everyMs = 250) => {
245
245
  return runningMacAppPIDs().length === 0;
246
246
  };
247
247
 
248
+ // src/cli/clean-mac.ts
249
+ import { existsSync as existsSync2 } from "fs";
250
+ var removeDeveloperLeftovers = (guards2, domains, bundles) => {
251
+ let removed = 0;
252
+ for (const domain of domains) {
253
+ try {
254
+ guards2.execFile("defaults", ["delete", domain], { stdio: "ignore", timeout: 1e4 }, `delete preferences ${domain}`);
255
+ removed++;
256
+ } catch {
257
+ continue;
258
+ }
259
+ }
260
+ for (const bundle of bundles) {
261
+ try {
262
+ guards2.execFile(LSREGISTER, ["-u", bundle], { stdio: "ignore", timeout: 2e4 }, `unregister ${bundle}`);
263
+ removed++;
264
+ } catch {
265
+ continue;
266
+ }
267
+ }
268
+ return removed;
269
+ };
270
+ var removeMacAppState = (guards2, readServices, home) => {
271
+ let removed = 0;
272
+ let failed = 0;
273
+ let services;
274
+ try {
275
+ services = readServices();
276
+ } catch {
277
+ return { removed, failed: 1 };
278
+ }
279
+ for (const service of services) {
280
+ for (const account of MAC_KEYCHAIN_ACCOUNTS) {
281
+ try {
282
+ guards2.execFile(
283
+ "security",
284
+ ["delete-generic-password", "-s", service, "-a", account],
285
+ { stdio: "ignore" },
286
+ `remove keychain item ${service} (${account})`
287
+ );
288
+ removed++;
289
+ } catch (error) {
290
+ if (!(error instanceof Error && "status" in error && error.status === 44)) failed++;
291
+ }
292
+ }
293
+ }
294
+ for (const domain of MAC_DEFAULTS_DOMAINS) {
295
+ try {
296
+ guards2.execFile("defaults", ["delete", domain], { stdio: "ignore", timeout: 1e4 }, `delete preferences ${domain}`);
297
+ removed++;
298
+ } catch {
299
+ continue;
300
+ }
301
+ }
302
+ for (const path of macLibraryState(home)) {
303
+ if (!existsSync2(path)) continue;
304
+ guards2.remove(path, { force: true });
305
+ removed++;
306
+ }
307
+ return { removed, failed };
308
+ };
309
+ var quitMacApp = (guards2, state) => {
310
+ if (state.platform !== "darwin" || state.running().length === 0) return "not-running";
311
+ try {
312
+ guards2.execFile(
313
+ "osascript",
314
+ ["-e", `tell application id "${MAC_APP_BUNDLE_ID}" to quit`],
315
+ { stdio: "ignore", timeout: 3e4 },
316
+ "quit Pushary"
317
+ );
318
+ } catch {
319
+ }
320
+ return state.dryRun || state.waitForExit() ? "quit" : "running";
321
+ };
322
+
248
323
  // src/cli/editor-extension.ts
249
- import { existsSync as existsSync2, readFileSync, readdirSync } from "fs";
324
+ import { existsSync as existsSync3, readFileSync, readdirSync } from "fs";
250
325
  import { homedir as homedir2 } from "os";
251
326
  import { join as join2 } from "path";
252
327
  var EDITOR_EXTENSION_ID = "pushary.pushary";
@@ -273,13 +348,13 @@ var recordWithoutUs = (directory) => {
273
348
  return void 0;
274
349
  }
275
350
  };
276
- var editorExtensionRemovals = (home = homedir2()) => EDITOR_EXTENSION_DIRS.map((relative) => join2(home, relative)).filter(existsSync2).map((directory) => {
351
+ var editorExtensionRemovals = (home = homedir2()) => EDITOR_EXTENSION_DIRS.map((relative) => join2(home, relative)).filter(existsSync3).map((directory) => {
277
352
  const folders = readdirSync(directory).filter((name) => name.startsWith(`${EDITOR_EXTENSION_ID}-`)).map((name) => join2(directory, name));
278
353
  return { directory, folders, record: recordWithoutUs(directory) };
279
354
  }).filter((removal) => removal.folders.length > 0 || removal.record !== void 0);
280
355
 
281
356
  // src/cli/skills-store.ts
282
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
357
+ import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
283
358
  import { homedir as homedir3 } from "os";
284
359
  import { join as join3 } from "path";
285
360
  var SKILLS_STORE_DIR = ".agents";
@@ -287,9 +362,12 @@ var LOCK_FILE = ".skill-lock.json";
287
362
  var lockWithoutUs = (path) => {
288
363
  try {
289
364
  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 ?? {};
365
+ if (!lock || typeof lock !== "object" || Array.isArray(lock) || !("skills" in lock)) return void 0;
366
+ const entries = lock.skills;
367
+ if (!entries || typeof entries !== "object" || Array.isArray(entries) || !(PUSHARY_SKILL_NAME in entries)) return void 0;
368
+ const entry = entries[PUSHARY_SKILL_NAME];
369
+ if (!entry || typeof entry !== "object" || !("source" in entry) || entry.source !== PUSHARY_SKILL_SOURCE) return void 0;
370
+ const { [PUSHARY_SKILL_NAME]: _ours, ...skills } = entries;
293
371
  return { path, contents: `${JSON.stringify({ ...lock, skills }, null, 2)}
294
372
  ` };
295
373
  } catch {
@@ -299,22 +377,23 @@ var lockWithoutUs = (path) => {
299
377
  var skillsStoreRemoval = (home = homedir3()) => {
300
378
  const store = join3(home, SKILLS_STORE_DIR);
301
379
  const skillDir = join3(store, "skills", PUSHARY_SKILL_NAME);
380
+ const lock = lockWithoutUs(join3(store, LOCK_FILE));
302
381
  return {
303
- skillDir: existsSync3(skillDir) ? skillDir : void 0,
304
- lock: lockWithoutUs(join3(store, LOCK_FILE))
382
+ skillDir: lock && existsSync4(skillDir) ? skillDir : void 0,
383
+ lock
305
384
  };
306
385
  };
307
386
 
308
387
  // src/cli/claude-backups.ts
309
- import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
388
+ import { existsSync as existsSync5, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
310
389
  import { homedir as homedir4 } from "os";
311
390
  import { join as join4 } from "path";
312
391
  var BACKUP_PREFIX = ".claude.json.backup";
313
392
  var claudeJsonBackups = (home = homedir4()) => {
314
393
  const rollingDir = join4(home, ".claude", "backups");
315
394
  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;
395
+ const rolling = existsSync5(rollingDir) ? readdirSync2(rollingDir).filter((name) => name.startsWith(BACKUP_PREFIX)).sort().map((name) => join4(rollingDir, name)) : [];
396
+ return existsSync5(legacy) ? [...rolling, legacy] : rolling;
318
397
  };
319
398
  var parsed = (path) => {
320
399
  try {
@@ -414,69 +493,6 @@ var wouldNote = (action, path) => {
414
493
  var guards = createGuards(() => dryRun, wouldNote);
415
494
  var guardedWrite = (path, contents) => guards.write(path, contents);
416
495
  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
496
  var CURSOR_PLUGIN_STAGING = ".pushary-staging-";
481
497
  var cursorPluginLeftovers = () => {
482
498
  const parent = dirname(CURSOR_PLUGIN_DIR);
@@ -496,14 +512,14 @@ var guardedDaemonRemoval = async () => {
496
512
  };
497
513
  var guardedInstructionBlockRemoval = (path) => {
498
514
  if (!dryRun) return removeInstructionBlock(path);
499
- if (!existsSync5(path)) return false;
515
+ if (!existsSync6(path)) return false;
500
516
  const hasBlock = readFileSync4(path, "utf-8").includes("pushary");
501
517
  if (hasBlock) wouldNote("rewrite", path);
502
518
  return hasBlock;
503
519
  };
504
520
  var guardedAliasRemoval = () => {
505
521
  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"));
522
+ const shells = CANDIDATE_RCS.map((name) => join5(homedir5(), name)).filter((path) => existsSync6(path) && readFileSync4(path, "utf-8").includes("pushary claude"));
507
523
  for (const path of shells) wouldNote("rewrite", path);
508
524
  return shells;
509
525
  };
@@ -511,7 +527,7 @@ var writeJson = (path, data) => {
511
527
  guardedWrite(path, JSON.stringify(data, null, 2) + "\n");
512
528
  };
513
529
  var removeCursorUserHook = (scope) => {
514
- if (!existsSync5(CURSOR_USER_HOOKS)) return "absent";
530
+ if (!existsSync6(CURSOR_USER_HOOKS)) return "absent";
515
531
  let parsed2;
516
532
  try {
517
533
  parsed2 = JSON.parse(readFileSync4(CURSOR_USER_HOOKS, "utf-8"));
@@ -585,11 +601,11 @@ var restoreTakeoverReceipts = () => {
585
601
  ];
586
602
  for (const [agent, hookFile, mcpFile, mcpKey, mcpFormat] of targets) {
587
603
  const receiptPath = hookTakeoverReceipt(agent);
588
- if (!existsSync5(receiptPath)) continue;
604
+ if (!existsSync6(receiptPath)) continue;
589
605
  try {
590
606
  const receipt = readJson(receiptPath);
591
607
  if (!isHookTakeoverReceipt(receipt) || receipt.agent !== agent) throw new Error("invalid receipt");
592
- const document = existsSync5(hookFile) ? JSON.parse(readFileSync4(hookFile, "utf-8")) : {};
608
+ const document = existsSync6(hookFile) ? JSON.parse(readFileSync4(hookFile, "utf-8")) : {};
593
609
  if (!document || typeof document !== "object" || Array.isArray(document)) throw new Error("invalid hooks file");
594
610
  const appAlreadyOwns = hookOwnerOf(document) === "app";
595
611
  const cliPositions = agent === "codex" ? codexHookPositions(document) : {};
@@ -600,7 +616,7 @@ var restoreTakeoverReceipts = () => {
600
616
  if (mcpFile === hookFile) {
601
617
  mcpDocument = document;
602
618
  } else {
603
- const raw = existsSync5(mcpFile) ? readFileSync4(mcpFile, "utf-8") : "";
619
+ const raw = existsSync6(mcpFile) ? readFileSync4(mcpFile, "utf-8") : "";
604
620
  mcpDocument = raw.trim() ? mcpFormat === "toml" ? parseTOML(raw) : JSON.parse(raw) : {};
605
621
  }
606
622
  mcpChanged = restoreMcpServer(mcpDocument, mcpKey, receipt.mcpServer);
@@ -610,7 +626,7 @@ var restoreTakeoverReceipts = () => {
610
626
  if (!appAlreadyOwns && agent === "codex") {
611
627
  if (!mcpDocument) {
612
628
  const configPath = codexConfigToml();
613
- const raw = existsSync5(configPath) ? readFileSync4(configPath, "utf-8") : "";
629
+ const raw = existsSync6(configPath) ? readFileSync4(configPath, "utf-8") : "";
614
630
  mcpDocument = raw.trim() ? parseTOML(raw) : {};
615
631
  }
616
632
  codexConfig = mcpDocument;
@@ -679,18 +695,19 @@ var main = async () => {
679
695
  console.log(` ${dim("Removing the Mac app's wiring and state as well.")}`);
680
696
  }
681
697
  if (everything) {
682
- const quit = quitMacApp();
698
+ const quit = quitMacApp(guards, { platform: process.platform, dryRun, running: runningMacAppPIDs, waitForExit: waitForMacAppExit });
683
699
  if (quit === "quit") {
684
700
  console.log(` ${check} Pushary ${dim(did("quit"))} ${dim("(running, and its watcher puts back what this removes)")}`);
685
701
  } else if (quit === "running") {
686
702
  incompleteClean = true;
687
703
  console.log(` ${cross} Pushary ${dim("would not quit, and it puts back what this removes")}`);
688
704
  console.log(` ${dim("Quit it from the notch menu, then re-run.")}`);
705
+ process.exit(EXIT.FAILED);
689
706
  }
690
707
  }
691
708
  if (presence !== "absent") console.log();
692
709
  const restoredByTakeover = new Set(
693
- ["claude_code", "codex", "gemini_cli"].filter((agent) => existsSync5(hookTakeoverReceipt(agent)))
710
+ ["claude_code", "codex", "gemini_cli"].filter((agent) => existsSync6(hookTakeoverReceipt(agent)))
694
711
  );
695
712
  if (keepShared) restoreTakeoverReceipts();
696
713
  const sharedMcpKeys = {
@@ -718,7 +735,7 @@ var main = async () => {
718
735
  const claudeHadPusharyEntry = claudeHasPusharyEntry();
719
736
  const rawReceipt = readJson(CLAUDE_MCP_RECEIPT);
720
737
  const receipt = isClaudeMcpSnapshot(rawReceipt) ? rawReceipt : null;
721
- const receiptUnreadable = existsSync5(CLAUDE_MCP_RECEIPT) && !receipt;
738
+ const receiptUnreadable = existsSync6(CLAUDE_MCP_RECEIPT) && !receipt;
722
739
  if (keepClaudeMcp) {
723
740
  console.log(` ${skip} Claude Code MCP servers ${dim("(kept: the Mac app uses it)")}`);
724
741
  } else if (claudeJson2) {
@@ -733,7 +750,7 @@ var main = async () => {
733
750
  if (receipt && !keepShared) incompleteClean = true;
734
751
  console.log(` ${skip} Claude Code MCP servers ${dim(receipt ? "(changed after setup; left unchanged)" : "(no pushary entries)")}`);
735
752
  }
736
- } else if (existsSync5(CLAUDE_MCP_RECEIPT)) {
753
+ } else if (existsSync6(CLAUDE_MCP_RECEIPT)) {
737
754
  incompleteClean = true;
738
755
  console.log(` ${skip} Claude Code MCP servers ${dim("(config missing; setup receipt kept for retry)")}`);
739
756
  } else {
@@ -777,7 +794,7 @@ var main = async () => {
777
794
  }
778
795
  if (cursorGate === "failed") {
779
796
  console.log(` ${skip} Cursor plugin ${dim("(kept: removing it now would block matched commands)")}`);
780
- } else if (existsSync5(CURSOR_PLUGIN_DIR)) {
797
+ } else if (existsSync6(CURSOR_PLUGIN_DIR)) {
781
798
  guardedRemove(CURSOR_PLUGIN_DIR);
782
799
  console.log(` ${check} Cursor plugin ${dim("(removed from ~/.cursor/plugins/local)")}`);
783
800
  } else {
@@ -793,9 +810,9 @@ var main = async () => {
793
810
  if (keepShared) {
794
811
  console.log(` ${skip} VS Code plugin ${dim("(kept: the Mac app writes the same plugin directory)")}`);
795
812
  }
796
- for (const settingsPath of keepShared ? [] : vscodeSettingsTargets(existsSync5)) {
813
+ for (const settingsPath of keepShared ? [] : vscodeSettingsTargets(existsSync6)) {
797
814
  const label = `VS Code plugin ${dim(`(${shortenHome(settingsPath)})`)}`;
798
- if (!existsSync5(settingsPath)) {
815
+ if (!existsSync6(settingsPath)) {
799
816
  console.log(` ${skip} ${label} ${dim("(no settings.json)")}`);
800
817
  continue;
801
818
  }
@@ -809,7 +826,7 @@ var main = async () => {
809
826
  console.log(` ${skip} ${label} ${dim("(no pushary entry)")}`);
810
827
  }
811
828
  }
812
- if (!keepShared && existsSync5(VSCODE_PLUGIN_DIR)) {
829
+ if (!keepShared && existsSync6(VSCODE_PLUGIN_DIR)) {
813
830
  guardedRemove(VSCODE_PLUGIN_DIR);
814
831
  console.log(` ${check} VS Code plugin files ${dim(did("removed"))}`);
815
832
  }
@@ -828,7 +845,7 @@ var main = async () => {
828
845
  }
829
846
  if (keepShared) {
830
847
  console.log(` ${skip} Skill directory ${dim("(kept: the Mac app uses it)")}`);
831
- } else if (existsSync5(SKILL_DIR)) {
848
+ } else if (existsSync6(SKILL_DIR)) {
832
849
  guardedRemove(SKILL_DIR);
833
850
  console.log(` ${check} Skill directory ${dim(did("removed"))}`);
834
851
  } else {
@@ -888,7 +905,7 @@ var main = async () => {
888
905
  const codexSkillDir2 = codexSkillDir();
889
906
  if (keepShared) {
890
907
  console.log(` ${skip} Codex skill directory ${dim("(kept: the Mac app uses it)")}`);
891
- } else if (existsSync5(codexSkillDir2)) {
908
+ } else if (existsSync6(codexSkillDir2)) {
892
909
  guardedRemove(codexSkillDir2);
893
910
  console.log(` ${check} Codex skill directory ${dim(did("removed"))}`);
894
911
  } else {
@@ -944,7 +961,7 @@ var main = async () => {
944
961
  console.log(` ${skip} Gemini GEMINI.md ${dim("(no pushary block)")}`);
945
962
  }
946
963
  const openCodePlugin = openCodePluginFile();
947
- const openCodePluginContents = existsSync5(openCodePlugin) ? readFileSync4(openCodePlugin, "utf-8") : null;
964
+ const openCodePluginContents = existsSync6(openCodePlugin) ? readFileSync4(openCodePlugin, "utf-8") : null;
948
965
  if (openCodePluginContents === null) {
949
966
  console.log(` ${skip} OpenCode plugin ${dim("(not installed)")}`);
950
967
  } else if (!isOpenCodePluginOurs(openCodePluginContents)) {
@@ -962,7 +979,7 @@ var main = async () => {
962
979
  return [];
963
980
  }
964
981
  })();
965
- const siblingIsOurs = existsSync5(sibling) && readFileSync4(sibling, "utf-8") === OPENCODE_PLUGIN_SIBLING_CONTENTS;
982
+ const siblingIsOurs = existsSync6(sibling) && readFileSync4(sibling, "utf-8") === OPENCODE_PLUGIN_SIBLING_CONTENTS;
966
983
  if (siblingIsOurs && !hasForeignPlugins(remaining)) {
967
984
  guardedRemove(sibling, { force: true });
968
985
  console.log(` ${check} OpenCode plugin sibling ${dim(did("removed"))}`);
@@ -990,14 +1007,14 @@ var main = async () => {
990
1007
  } else {
991
1008
  console.log(` ${check} Hermes config ${dim("(setup-owned changes restored)")}`);
992
1009
  try {
993
- guardedExec(`"${hermesPython}" -m pip uninstall -y ${HERMES_PIP_PACKAGE}`, { stdio: "pipe", timeout: 6e4 }, `pip uninstall ${HERMES_PIP_PACKAGE}`);
1010
+ guards.execFile(hermesPython, ["-m", "pip", "uninstall", "-y", HERMES_PIP_PACKAGE], { stdio: "pipe", timeout: 6e4 }, `pip uninstall ${HERMES_PIP_PACKAGE}`);
994
1011
  console.log(` ${check} Hermes plugin ${dim("(pip uninstalled)")}`);
995
1012
  } catch {
996
1013
  incompleteClean = true;
997
1014
  console.log(` ${skip} Hermes plugin ${dim("(could not uninstall; setup receipt kept for retry)")}`);
998
1015
  }
999
1016
  }
1000
- } else if (existsSync5(HERMES_CONFIG_RECEIPT)) {
1017
+ } else if (existsSync6(HERMES_CONFIG_RECEIPT)) {
1001
1018
  incompleteClean = true;
1002
1019
  console.log(` ${skip} Hermes ${dim("(runtime not found; setup receipt kept for retry)")}`);
1003
1020
  } else {
@@ -1025,10 +1042,10 @@ var main = async () => {
1025
1042
  if ((line.match(/pk_[A-Za-z0-9_]+\.[A-Za-z0-9_]+/g) ?? []).some(isValidApiKey)) {
1026
1043
  incompleteClean = true;
1027
1044
  console.log(` ${cross} ${name} ${dim("still sets PUSHARY_API_KEY, in a form this command will not rewrite:")}`);
1028
- console.log(` ${dim(line.trim())}`);
1045
+ console.log(` ${dim(redactSecrets(line.trim()))}`);
1029
1046
  console.log(` ${dim("Remove it yourself. A setup run would sign this machine in as that account.")}`);
1030
1047
  } else {
1031
- console.log(` ${skip} ${name} ${dim(`left a line referencing PUSHARY_API_KEY: ${line.trim()}`)}`);
1048
+ console.log(` ${skip} ${name} ${dim(`left a line referencing PUSHARY_API_KEY: ${redactSecrets(line.trim())}`)}`);
1032
1049
  }
1033
1050
  }
1034
1051
  }
@@ -1041,7 +1058,7 @@ var main = async () => {
1041
1058
  } else {
1042
1059
  console.log(` ${skip} claude alias ${dim("(not set)")}`);
1043
1060
  }
1044
- if (existsSync5(PUSHARY_DIR)) {
1061
+ if (existsSync6(PUSHARY_DIR)) {
1045
1062
  let removed = 0;
1046
1063
  const kept = [];
1047
1064
  for (const entry of readdirSync3(PUSHARY_DIR)) {
@@ -1084,14 +1101,18 @@ var main = async () => {
1084
1101
  if (store.skillDir || store.lock) {
1085
1102
  console.log(` ${check} skills.sh registration ${dim(did("removed"))} ${dim("(~/.agents)")}`);
1086
1103
  }
1087
- const leftovers = removeDeveloperLeftovers();
1104
+ const leftovers = process.platform === "darwin" ? removeDeveloperLeftovers(guards, leakedTestDefaultsDomains(), registeredPusharyBundles()) : 0;
1088
1105
  if (leftovers > 0) {
1089
1106
  console.log(` ${check} Developer leftovers ${dim(did("removed"))} ${dim(`(${leftovers} leaked test preferences and stale app registrations)`)}`);
1090
1107
  }
1091
- const removed = removeMacAppState();
1108
+ const { removed, failed } = process.platform === "darwin" ? removeMacAppState(guards, storedPusharyKeychainServices, homedir5()) : { removed: 0, failed: 0 };
1109
+ if (failed > 0) {
1110
+ incompleteClean = true;
1111
+ console.log(` ${cross} Mac keychain ${dim(`(${failed} operations failed; unlock your keychain and re-run)`)}`);
1112
+ }
1092
1113
  if (removed > 0) {
1093
1114
  console.log(` ${check} Mac app state ${dim(did("removed"))} ${dim(`(${removed} keychain items, preferences and caches)`)}`);
1094
- } else {
1115
+ } else if (failed === 0) {
1095
1116
  console.log(` ${skip} Mac app state ${dim("(nothing of ours in the keychain, preferences or caches)")}`);
1096
1117
  }
1097
1118
  }
@@ -1112,7 +1133,7 @@ var main = async () => {
1112
1133
  console.log(` ${dim("Still stuck? Send this output to")} ${SUPPORT_EMAIL} ${dim("or")} ${SUPPORT_DISCORD}`);
1113
1134
  } else if (everything) {
1114
1135
  console.log(` ${green(bold("Clean complete. Nothing of ours is left in any agent config."))}`);
1115
- const bundle = installedPusharyBundles().find(existsSync5);
1136
+ const bundle = installedPusharyBundles().find(existsSync6);
1116
1137
  if (bundle) {
1117
1138
  console.log(` ${dim("The app itself is still installed. Drag")} ${bundle} ${dim("to the Trash to finish.")}`);
1118
1139
  }
@@ -1,24 +1,24 @@
1
1
  #!/usr/bin/env node
2
- import "../chunk-GLPWCQ6V.js";
2
+ import "../chunk-TYEO6T5J.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-2V2IKOGJ.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-VOMOZ4D5.js";
17
+ import "../chunk-GZ7E6VOB.js";
18
18
  import "../chunk-EQRS3SGM.js";
19
19
  import {
20
20
  transcriptsEnabled
21
- } from "../chunk-BYAXXBNO.js";
21
+ } from "../chunk-4BROEAKH.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-NHTAHAIS.js";
32
32
  import {
33
33
  resolveBinary
34
- } from "../chunk-UCGQEAKZ.js";
35
- import "../chunk-NYHNLMQO.js";
34
+ } from "../chunk-TRLFZKVG.js";
35
+ import "../chunk-FU2DFEAZ.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-UM5J3J4V.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-SOUZBGYJ.js";
52
52
 
53
53
  // bin/pushary-codex-bridge.ts
54
54
  import { existsSync } from "fs";