@pushary/agent-hooks 1.9.53 → 1.9.54

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.54
4
+
5
+ - For a switch the Pushary Mac app turns on, the login item that keeps Codex app cards on after a restart now runs Pushary's own program and not a shell line, so macOS treats it as part of Pushary and not as a separate `sh` item. A switch turned on with `pushary codex --app-cards on` keeps the login item it has, unchanged.
6
+
3
7
  ## 1.9.53
4
8
 
5
9
  - `pushary codex --app-cards status --json` prints the switch's state as one line of JSON for a program to read: the state, the Codex app found on this Mac, whether the Mac app turned the switch on, and whether it was turned off on purpose. The Pushary Mac app uses it for its new Settings switch, which is on by default there.
@@ -25,7 +29,7 @@
25
29
  - New, off by default: `pushary codex --app-cards on` makes the Codex app start through the same pass-through every time you open it, including after a restart, with no terminal to keep open. `pushary codex --app-cards off` undoes it and `status` says where it stands, including when Pushary or the Codex engine is no longer where the launcher expects. It writes a launcher under `~/.pushary/codex-app`, a login item, and the `CODEX_CLI_PATH` setting for your login session, and leaves that setting alone if another program already owns it. `off` replaces the launcher with one that only runs Codex's engine and leaves that file in place, because the Codex app records its path in `~/.codex/config.toml` and an open Codex keeps using it; `pushary clean` removes it, after which Codex should be reopened.
26
30
  - The launcher steps aside by itself: it hands every engine command except the app's own protocol straight to Codex's engine, starts the engine itself when Pushary is missing, broken, never starts it, or the launcher cannot write beside itself, and turns its own setting off if a Codex update moves the engine. If the launcher is stopped, Pushary stops the engine within a few seconds.
27
31
  - The pass-through holds at most 64 KiB of the app's input and inspects at most 256 KiB of a line from the engine, loads the code that talks to Pushary only when a card appears, does nothing while idle except check every two seconds that its launcher is still running, lets the engine finish its own shutdown when Codex quits, and keeps copying if anything in it fails. The first time Computer Use asks in a way this version does not know, it says so once in Codex's own log.
28
- - Setup: a Mac that has the Codex app and no Codex CLI gets native hooks again. The current Codex app keeps its engine behind a small script with its version in a file beside it; setup looked for the version inside the script, found none, and treated Codex as too old for hooks. Setup now reads that file, finds the engine where the app keeps it now, and never takes Pushary's own launcher for Codex.
32
+ - Setup on a Mac that has the Codex app and no Codex CLI: setup never takes Pushary's own launcher for Codex, and it finds the app's engine where the current Codex app keeps it when Codex's settings file does not name one. Before, the first would have skipped native hooks and the second reported Codex as not found. Correction: this entry first said such a Mac got no hooks at all since the Codex app changed its layout. That was wrong. When Codex's settings file names the app's own engine, as it does after Codex has started normally, setup already found it and installed hooks.
29
33
  - `pushary codex` is experimental and no longer appears in `pushary --help`. It still runs when typed, and `pushary codex --help` describes it.
30
34
 
31
35
  ## 1.9.50
@@ -1,15 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CODEX_APP_CARDS_DIRECTORY,
4
+ LSREGISTER,
5
+ MAC_APP_BUNDLE_ID,
6
+ MAC_DEFAULTS_DOMAINS,
7
+ MAC_KEYCHAIN_ACCOUNTS,
4
8
  codexAppCardsFolderStaysOnThisMac,
5
- removeCodexAppCardsFromThisMac
6
- } from "../chunk-SUIB4O3S.js";
9
+ developerDefaults,
10
+ installedPusharyBundles,
11
+ liveMacStatePresence,
12
+ registeredPusharyBundles,
13
+ removeCodexAppCardsFromThisMac,
14
+ runningMacAppPIDs,
15
+ storedMacAppState,
16
+ storedPusharyKeychainServices,
17
+ waitForMacAppExit
18
+ } from "../chunk-ZWOWEXCV.js";
7
19
  import {
8
20
  PUSHARY_SKILL_NAME,
9
21
  PUSHARY_SKILL_SOURCE,
10
22
  createGuards
11
23
  } from "../chunk-EUW7JL2K.js";
12
- import "../chunk-ABGN5RN2.js";
24
+ import "../chunk-T5L5NWT3.js";
13
25
  import "../chunk-XCEN33UP.js";
14
26
  import {
15
27
  describeCliKeyRevocation,
@@ -109,7 +121,7 @@ import {
109
121
  removeClaudeAlias,
110
122
  shellProfileCandidates
111
123
  } from "../chunk-VYBH6D4X.js";
112
- import "../chunk-36NGFHE4.js";
124
+ import "../chunk-E46NE7FB.js";
113
125
  import "../chunk-U2L42GVI.js";
114
126
  import "../chunk-3RPN7AAT.js";
115
127
  import "../chunk-JBT3ZSJS.js";
@@ -186,194 +198,14 @@ import {
186
198
  } from "../chunk-LF3TLC7B.js";
187
199
 
188
200
  // bin/pushary-clean.ts
189
- import { existsSync as existsSync6, readFileSync as readFileSync4, copyFileSync, readdirSync as readdirSync5 } from "fs";
190
- import { dirname, join as join6 } from "path";
191
- import { homedir as homedir5, tmpdir } from "os";
201
+ import { existsSync as existsSync5, readFileSync as readFileSync4, copyFileSync, readdirSync as readdirSync4 } from "fs";
202
+ import { dirname, join as join5 } from "path";
203
+ import { homedir as homedir4, tmpdir } from "os";
192
204
  import { confirm } from "@inquirer/prompts";
193
205
  import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
194
206
 
195
- // src/cli/mac-leftovers.ts
196
- import { execSync, execFileSync } from "child_process";
197
- import { existsSync, readdirSync } from "fs";
198
- import { homedir } from "os";
199
- import { isAbsolute, join } from "path";
200
- var MAC_APP_BUNDLE = "/Applications/Pushary.app";
201
- var MAC_APP_BUNDLE_ID = "com.pushary.app";
202
- var installedPusharyBundles = (home = homedir()) => [MAC_APP_BUNDLE, join(home, "Applications", "Pushary.app")];
203
- var LSREGISTER = "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister";
204
- var TEST_DEFAULTS_PREFIXES = [
205
- "com.pushary.mac.tests.",
206
- "com.pushary.tests.",
207
- "pushary.tests.",
208
- "pushary.quiet-mode-test.",
209
- "pushary.drafts.test.",
210
- "pushary-optin-",
211
- "pushary-completion-test-",
212
- "pushary-updates-only-"
213
- ];
214
- var UUID = "[0-9A-Fa-f]{8}(?:-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12}";
215
- var UNPREFIXED_TEST_DEFAULTS_DOMAIN = new RegExp(`^(?:owner-mode|fx-model)-${UUID}$`);
216
- var DEVELOPER_BUILD_DEFAULTS_DOMAIN = "PusharyMac";
217
- var isDeveloperDefaultsDomain = (domain) => domain === DEVELOPER_BUILD_DEFAULTS_DOMAIN || UNPREFIXED_TEST_DEFAULTS_DOMAIN.test(domain) || TEST_DEFAULTS_PREFIXES.some((prefix) => domain.startsWith(prefix));
218
- var PREFERENCES_FILE_EXTENSION = ".plist";
219
- var preferencesDirectory = (home) => join(home, "Library", "Preferences");
220
- var preferencesFile = (home, domain) => join(preferencesDirectory(home), `${domain}${PREFERENCES_FILE_EXTENSION}`);
221
- var namesIn = (directory) => {
222
- try {
223
- return readdirSync(directory);
224
- } catch {
225
- return [];
226
- }
227
- };
228
- var developerDefaults = (home = homedir()) => namesIn(preferencesDirectory(home)).filter((name) => name.endsWith(PREFERENCES_FILE_EXTENSION)).map((name) => name.slice(0, -PREFERENCES_FILE_EXTENSION.length)).filter(isDeveloperDefaultsDomain).map((domain) => ({ domain, file: preferencesFile(home, domain) }));
229
- var BUNDLE_NAME = "Pushary.app";
230
- var DUMP_RECORD_SEPARATOR = /^-{20,}$/m;
231
- var DUMP_PATH_LINES = /^[ \t]*path:[ \t]+(.+?)(?: \(0x[0-9a-f]+\))?[ \t]*$/gm;
232
- var DUMP_IDENTIFIER_LINES = /^[ \t]*identifier:[ \t]+(\S+)/gm;
233
- var capturedIn = (text, lines) => [...text.matchAll(lines)].flatMap((match) => match[1] === void 0 ? [] : [match[1]]);
234
- var appCopyNamedByRecord = (record) => {
235
- const paths = capturedIn(record, DUMP_PATH_LINES);
236
- const identifiers = capturedIn(record, DUMP_IDENTIFIER_LINES);
237
- const namesOneAppCopy = paths.length === 1 && identifiers.length === 1 && identifiers[0] === MAC_APP_BUNDLE_ID;
238
- return namesOneAppCopy ? paths : [];
239
- };
240
- var isAtOrInside = (path, bundle) => path === bundle || path.startsWith(`${bundle}/`);
241
- var isUnderBundleNamedPushary = (path) => path.split("/").includes(BUNDLE_NAME);
242
- var bundlesInLaunchServicesDump = (dump) => {
243
- const appCopies = dump.split(DUMP_RECORD_SEPARATOR).flatMap(appCopyNamedByRecord);
244
- const isOurs = (path) => isUnderBundleNamedPushary(path) || appCopies.some((copy) => isAtOrInside(path, copy));
245
- return [...new Set(capturedIn(dump, DUMP_PATH_LINES).filter(isOurs))];
246
- };
247
- var outsideInstalledBundles = (registered, installed) => registered.filter((path) => !installed.some((bundle) => isAtOrInside(path, bundle)));
248
- var registeredPusharyBundles = (installed = installedPusharyBundles()) => {
249
- if (!existsSync(LSREGISTER)) return [];
250
- try {
251
- const dump = execSync(`${LSREGISTER} -dump`, {
252
- encoding: "utf-8",
253
- timeout: 6e4,
254
- maxBuffer: 256 * 1024 * 1024
255
- });
256
- return outsideInstalledBundles(bundlesInLaunchServicesDump(dump), installed);
257
- } catch {
258
- return [];
259
- }
260
- };
261
- var MAC_KEYCHAIN_SERVICE = "com.pushary.app.mac";
262
- var MAC_KEYCHAIN_ACCOUNTS = [
263
- "pushary.site-api-key",
264
- "pushary.site-id",
265
- "pushary.partner-enrollments",
266
- "pushary.partner-device-key",
267
- "clerk.device-token",
268
- "clerk.session-id",
269
- "clerkDeviceToken",
270
- "cachedClient",
271
- "cachedClientServerDate",
272
- "cachedEnvironment"
273
- ];
274
- var MAC_DEFAULTS_DOMAINS = ["com.pushary.app", "pushary-bridge", "pushary.render"];
275
- var PRESENCE_PROBE_TIMEOUT_MS = 1e4;
276
- var commandSucceeds = (file, args) => {
277
- try {
278
- execFileSync(file, args, { stdio: "ignore", timeout: PRESENCE_PROBE_TIMEOUT_MS });
279
- return true;
280
- } catch {
281
- return false;
282
- }
283
- };
284
- var KEYCHAIN_ITEM_NOT_FOUND = 44;
285
- var keychainItemMayExist = (service, account) => {
286
- try {
287
- execFileSync("security", ["find-generic-password", "-s", service, "-a", account], { stdio: "ignore" });
288
- return true;
289
- } catch (error) {
290
- return !(error instanceof Error && "status" in error && error.status === KEYCHAIN_ITEM_NOT_FOUND);
291
- }
292
- };
293
- var liveMacStatePresence = {
294
- keychainItem: keychainItemMayExist,
295
- defaultsDomain: (domain) => commandSucceeds("defaults", ["read", domain])
296
- };
297
- var macLibraryState = (home = homedir()) => [
298
- join(home, "Library", "Application Support", "Pushary"),
299
- join(home, "Library", "Caches", "com.pushary.app"),
300
- join(home, "Library", "Caches", "com.pushary.app.sparkle"),
301
- join(home, "Library", "Saved Application State", "com.pushary.app.savedState"),
302
- join(home, "Library", "Caches", "pushary-bridge"),
303
- join(home, "Library", "HTTPStorages", "com.pushary.app"),
304
- join(home, "Library", "HTTPStorages", "com.pushary.app.binarycookies"),
305
- join(home, "Library", "HTTPStorages", "pushary-bridge"),
306
- ...MAC_DEFAULTS_DOMAINS.map((domain) => preferencesFile(home, domain))
307
- ];
308
- var USER_CACHE_ENTRIES = [MAC_APP_BUNDLE_ID, "pushary-bridge", "PusharyBridge"];
309
- var macUserCacheState = (reportedUserCacheDirectory) => {
310
- const directory = reportedUserCacheDirectory.trim();
311
- return isAbsolute(directory) ? USER_CACHE_ENTRIES.map((entry) => join(directory, entry)) : [];
312
- };
313
- var UNKNOWN_USER_CACHE_DIRECTORY = "";
314
- var reportedDarwinUserCacheDirectory = () => {
315
- try {
316
- return execFileSync("getconf", ["DARWIN_USER_CACHE_DIR"], {
317
- encoding: "utf-8",
318
- timeout: PRESENCE_PROBE_TIMEOUT_MS,
319
- stdio: ["ignore", "pipe", "ignore"]
320
- });
321
- } catch {
322
- return UNKNOWN_USER_CACHE_DIRECTORY;
323
- }
324
- };
325
- var CRASH_REPORTER_ENTRY = new RegExp(`^(?:Pushary|PusharyMac|pushary-bridge)_${UUID}\\.plist$`);
326
- var crashReporterEntries = (home = homedir()) => {
327
- const directory = join(home, "Library", "Application Support", "CrashReporter");
328
- return namesIn(directory).filter((name) => CRASH_REPORTER_ENTRY.test(name)).map((name) => join(directory, name));
329
- };
330
- var storedMacAppState = (home = homedir()) => [
331
- ...macLibraryState(home),
332
- ...macUserCacheState(reportedDarwinUserCacheDirectory()),
333
- ...crashReporterEntries(home)
334
- ];
335
- var DUMP_SERVICE_LINE = /^\s*"svce"<blob>="(.+)"\s*$/;
336
- var pusharyKeychainServices = (dump) => {
337
- const found = /* @__PURE__ */ new Set();
338
- for (const line of dump.split("\n")) {
339
- const service = DUMP_SERVICE_LINE.exec(line)?.[1];
340
- if (service?.startsWith(MAC_KEYCHAIN_SERVICE)) found.add(service);
341
- }
342
- return [...found];
343
- };
344
- var storedPusharyKeychainServices = () => {
345
- const dump = execFileSync("security", ["dump-keychain"], {
346
- encoding: "utf-8",
347
- timeout: 3e4,
348
- maxBuffer: 64 * 1024 * 1024,
349
- stdio: ["ignore", "pipe", "ignore"]
350
- });
351
- const stored = pusharyKeychainServices(dump);
352
- return stored.includes(MAC_KEYCHAIN_SERVICE) ? stored : [MAC_KEYCHAIN_SERVICE, ...stored];
353
- };
354
- var runningMacAppPIDs = () => {
355
- if (process.platform !== "darwin") return [];
356
- try {
357
- return execSync('pgrep -f "Pushary.app/Contents/MacOS/Pushary"', {
358
- encoding: "utf-8",
359
- timeout: 1e4,
360
- stdio: ["ignore", "pipe", "ignore"]
361
- }).split("\n").map((line) => Number(line.trim())).filter((pid) => Number.isInteger(pid) && pid > 0);
362
- } catch {
363
- return [];
364
- }
365
- };
366
- var waitForMacAppExit = (attempts = 20, everyMs = 250) => {
367
- const idle = new Int32Array(new SharedArrayBuffer(4));
368
- for (let attempt = 0; attempt < attempts; attempt++) {
369
- if (runningMacAppPIDs().length === 0) return true;
370
- Atomics.wait(idle, 0, 0, everyMs);
371
- }
372
- return runningMacAppPIDs().length === 0;
373
- };
374
-
375
207
  // src/cli/clean-mac.ts
376
- import { existsSync as existsSync2 } from "fs";
208
+ import { existsSync } from "fs";
377
209
  var deleteDefaultsDomain = (guards2, domain) => {
378
210
  try {
379
211
  guards2.execFile("defaults", ["delete", domain], { stdio: "ignore", timeout: 1e4 }, `delete preferences ${domain}`);
@@ -433,7 +265,7 @@ var removeMacAppState = (guards2, readServices, statePaths, present) => {
433
265
  if (deleteDefaultsDomain(guards2, domain)) removed++;
434
266
  }
435
267
  for (const path of statePaths) {
436
- if (!existsSync2(path)) continue;
268
+ if (!existsSync(path)) continue;
437
269
  try {
438
270
  guards2.remove(path, { force: true });
439
271
  removed++;
@@ -458,13 +290,13 @@ var quitMacApp = (guards2, state) => {
458
290
  };
459
291
 
460
292
  // src/cli/editor-extension.ts
461
- import { existsSync as existsSync3, readFileSync, readdirSync as readdirSync2 } from "fs";
462
- import { homedir as homedir2 } from "os";
463
- import { join as join2 } from "path";
293
+ import { existsSync as existsSync2, readFileSync, readdirSync } from "fs";
294
+ import { homedir } from "os";
295
+ import { join } from "path";
464
296
  var EDITOR_EXTENSION_ID = "pushary.pushary";
465
297
  var EDITOR_EXTENSION_DIRS = [
466
- join2(".cursor", "extensions"),
467
- join2(".vscode", "extensions")
298
+ join(".cursor", "extensions"),
299
+ join(".vscode", "extensions")
468
300
  ];
469
301
  var EXTENSIONS_JSON = "extensions.json";
470
302
  var isOurEntry = (entry) => {
@@ -475,7 +307,7 @@ var isOurEntry = (entry) => {
475
307
  return typeof id === "string" && id.toLowerCase() === EDITOR_EXTENSION_ID;
476
308
  };
477
309
  var recordWithoutUs = (directory) => {
478
- const path = join2(directory, EXTENSIONS_JSON);
310
+ const path = join(directory, EXTENSIONS_JSON);
479
311
  try {
480
312
  const entries = JSON.parse(readFileSync(path, "utf-8"));
481
313
  if (!Array.isArray(entries)) return void 0;
@@ -485,15 +317,15 @@ var recordWithoutUs = (directory) => {
485
317
  return void 0;
486
318
  }
487
319
  };
488
- var editorExtensionRemovals = (home = homedir2()) => EDITOR_EXTENSION_DIRS.map((relative) => join2(home, relative)).filter(existsSync3).map((directory) => {
489
- const folders = readdirSync2(directory).filter((name) => name.startsWith(`${EDITOR_EXTENSION_ID}-`)).map((name) => join2(directory, name));
320
+ var editorExtensionRemovals = (home = homedir()) => EDITOR_EXTENSION_DIRS.map((relative) => join(home, relative)).filter(existsSync2).map((directory) => {
321
+ const folders = readdirSync(directory).filter((name) => name.startsWith(`${EDITOR_EXTENSION_ID}-`)).map((name) => join(directory, name));
490
322
  return { directory, folders, record: recordWithoutUs(directory) };
491
323
  }).filter((removal) => removal.folders.length > 0 || removal.record !== void 0);
492
324
 
493
325
  // src/cli/skills-store.ts
494
- import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
495
- import { homedir as homedir3 } from "os";
496
- import { join as join3 } from "path";
326
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
327
+ import { homedir as homedir2 } from "os";
328
+ import { join as join2 } from "path";
497
329
  var SKILLS_STORE_DIR = ".agents";
498
330
  var LOCK_FILE = ".skill-lock.json";
499
331
  var lockWithoutUs = (path) => {
@@ -511,26 +343,26 @@ var lockWithoutUs = (path) => {
511
343
  return void 0;
512
344
  }
513
345
  };
514
- var skillsStoreRemoval = (home = homedir3()) => {
515
- const store = join3(home, SKILLS_STORE_DIR);
516
- const skillDir = join3(store, "skills", PUSHARY_SKILL_NAME);
517
- const lock = lockWithoutUs(join3(store, LOCK_FILE));
346
+ var skillsStoreRemoval = (home = homedir2()) => {
347
+ const store = join2(home, SKILLS_STORE_DIR);
348
+ const skillDir = join2(store, "skills", PUSHARY_SKILL_NAME);
349
+ const lock = lockWithoutUs(join2(store, LOCK_FILE));
518
350
  return {
519
- skillDir: lock && existsSync4(skillDir) ? skillDir : void 0,
351
+ skillDir: lock && existsSync3(skillDir) ? skillDir : void 0,
520
352
  lock
521
353
  };
522
354
  };
523
355
 
524
356
  // src/cli/claude-backups.ts
525
- import { existsSync as existsSync5, readFileSync as readFileSync3, readdirSync as readdirSync3 } from "fs";
526
- import { homedir as homedir4 } from "os";
527
- import { join as join4 } from "path";
357
+ import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
358
+ import { homedir as homedir3 } from "os";
359
+ import { join as join3 } from "path";
528
360
  var BACKUP_PREFIX = ".claude.json.backup";
529
- var claudeJsonBackups = (home = homedir4()) => {
530
- const rollingDir = join4(home, ".claude", "backups");
531
- const legacy = join4(home, BACKUP_PREFIX);
532
- const rolling = existsSync5(rollingDir) ? readdirSync3(rollingDir).filter((name) => name.startsWith(BACKUP_PREFIX)).sort().map((name) => join4(rollingDir, name)) : [];
533
- return existsSync5(legacy) ? [...rolling, legacy] : rolling;
361
+ var claudeJsonBackups = (home = homedir3()) => {
362
+ const rollingDir = join3(home, ".claude", "backups");
363
+ const legacy = join3(home, BACKUP_PREFIX);
364
+ const rolling = existsSync4(rollingDir) ? readdirSync2(rollingDir).filter((name) => name.startsWith(BACKUP_PREFIX)).sort().map((name) => join3(rollingDir, name)) : [];
365
+ return existsSync4(legacy) ? [...rolling, legacy] : rolling;
534
366
  };
535
367
  var parsed = (path) => {
536
368
  try {
@@ -540,7 +372,7 @@ var parsed = (path) => {
540
372
  return null;
541
373
  }
542
374
  };
543
- var claudeBackupRewrites = (receipt, home = homedir4()) => claudeJsonBackups(home).flatMap((path) => {
375
+ var claudeBackupRewrites = (receipt, home = homedir3()) => claudeJsonBackups(home).flatMap((path) => {
544
376
  const backup = parsed(path);
545
377
  if (!backup) return [];
546
378
  const changed = receipt ? restoreClaudeMcpServer(backup, receipt) : removeClaudeMcpServers(backup);
@@ -586,8 +418,8 @@ var removeGlobalCliPackages = (guards2, request) => {
586
418
  };
587
419
 
588
420
  // src/cli/config-temp-leftovers.ts
589
- import { lstatSync, readdirSync as readdirSync4 } from "fs";
590
- import { join as join5 } from "path";
421
+ import { lstatSync, readdirSync as readdirSync3 } from "fs";
422
+ import { join as join4 } from "path";
591
423
  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}$/;
592
424
  var PID_STAMPED_WRITE_TEMP = /^\.\d+-[^/]+\.pushary-tmp$/;
593
425
  var CONFIG_TEMP_MIN_AGE_MS = 6e4;
@@ -595,15 +427,15 @@ var isLeakedConfigTempName = (name) => MAC_APP_WRITE_TEMP.test(name) || PID_STAM
595
427
  var leakedConfigTemps = (entries, nowMs) => entries.filter((entry) => entry.isFile && isLeakedConfigTempName(entry.name) && nowMs - entry.modifiedAtMs >= CONFIG_TEMP_MIN_AGE_MS).map((entry) => entry.name);
596
428
  var directoryEntries = (directory) => {
597
429
  try {
598
- return readdirSync4(directory).flatMap((name) => {
599
- const stats = lstatSync(join5(directory, name), { throwIfNoEntry: false });
430
+ return readdirSync3(directory).flatMap((name) => {
431
+ const stats = lstatSync(join4(directory, name), { throwIfNoEntry: false });
600
432
  return stats ? [{ name, isFile: stats.isFile(), modifiedAtMs: stats.mtimeMs }] : [];
601
433
  });
602
434
  } catch {
603
435
  return [];
604
436
  }
605
437
  };
606
- var configTempLeftovers = (directories, nowMs) => [...new Set(directories)].flatMap((directory) => leakedConfigTemps(directoryEntries(directory), nowMs).map((name) => join5(directory, name)));
438
+ var configTempLeftovers = (directories, nowMs) => [...new Set(directories)].flatMap((directory) => leakedConfigTemps(directoryEntries(directory), nowMs).map((name) => join4(directory, name)));
607
439
 
608
440
  // src/app-owned-paths.ts
609
441
  var APP_OWNED_ENTRIES = [
@@ -700,13 +532,13 @@ var CURSOR_PLUGIN_DIR = cursorPluginDir();
700
532
  var CURSOR_USER_HOOKS = cursorUserHooks();
701
533
  var VSCODE_PLUGIN_DIR = vscodePluginDir();
702
534
  var PUSHARY_DIR = pusharyDir();
703
- var SHELL_FILES = [".zshrc", ".zprofile", ".bashrc", ".bash_profile"].map((f) => join6(homedir5(), f));
535
+ var SHELL_FILES = [".zshrc", ".zprofile", ".bashrc", ".bash_profile"].map((f) => join5(homedir4(), f));
704
536
  var PRESENCE_BY_RESOLUTION = {
705
537
  bundle: "present",
706
538
  missing: "gone",
707
539
  "no-stub": "absent"
708
540
  };
709
- var macAppPresence = () => PRESENCE_BY_RESOLUTION[resolveBridgeStub(join6(PUSHARY_DIR, "bin", HOOK_LOCATOR_BINARY), liveBridgeProbe()).kind];
541
+ var macAppPresence = () => PRESENCE_BY_RESOLUTION[resolveBridgeStub(join5(PUSHARY_DIR, "bin", HOOK_LOCATOR_BINARY), liveBridgeProbe()).kind];
710
542
  var removalScope = (keepMcpServer, keepAppWiring) => ({
711
543
  keepAppWiring,
712
544
  keepMcpServer
@@ -741,7 +573,7 @@ var guardedRemove = (path, options) => guards.remove(path, options);
741
573
  var cursorPluginLeftovers = () => {
742
574
  const parent = dirname(CURSOR_PLUGIN_DIR);
743
575
  try {
744
- return readdirSync5(parent).filter(isCursorPluginLeftover).map((name) => join6(parent, name));
576
+ return readdirSync4(parent).filter(isCursorPluginLeftover).map((name) => join5(parent, name));
745
577
  } catch {
746
578
  return [];
747
579
  }
@@ -755,14 +587,14 @@ var guardedDaemonRemoval = async () => {
755
587
  };
756
588
  var guardedInstructionBlockRemoval = (path) => {
757
589
  if (!dryRun) return removeInstructionBlock(path);
758
- if (!existsSync6(path)) return false;
590
+ if (!existsSync5(path)) return false;
759
591
  const hasBlock = readFileSync4(path, "utf-8").includes("pushary");
760
592
  if (hasBlock) wouldNote("rewrite", path);
761
593
  return hasBlock;
762
594
  };
763
595
  var guardedAliasRemoval = () => {
764
596
  if (!dryRun) return removeClaudeAlias();
765
- const shells = CANDIDATE_RCS.map((name) => join6(homedir5(), name)).filter((path) => existsSync6(path) && readFileSync4(path, "utf-8").includes("pushary claude"));
597
+ const shells = CANDIDATE_RCS.map((name) => join5(homedir4(), name)).filter((path) => existsSync5(path) && readFileSync4(path, "utf-8").includes("pushary claude"));
766
598
  for (const path of shells) wouldNote("rewrite", path);
767
599
  return shells;
768
600
  };
@@ -787,7 +619,7 @@ var removeFxInstructions = () => {
787
619
  }
788
620
  };
789
621
  var removeCursorUserHook = (scope) => {
790
- if (!existsSync6(CURSOR_USER_HOOKS)) return "absent";
622
+ if (!existsSync5(CURSOR_USER_HOOKS)) return "absent";
791
623
  let parsed2;
792
624
  try {
793
625
  parsed2 = JSON.parse(readFileSync4(CURSOR_USER_HOOKS, "utf-8"));
@@ -832,14 +664,14 @@ var cleanSettingsFile = (path, label, scope) => {
832
664
  );
833
665
  };
834
666
  var agentConfigDirectories = () => [
835
- homedir5(),
667
+ homedir4(),
836
668
  dirname(CLAUDE_SETTINGS),
837
669
  dirname(codexConfigToml()),
838
670
  dirname(geminiSettings()),
839
671
  dirname(CURSOR_USER_HOOKS),
840
672
  openCodeConfigDir(),
841
673
  fxConfigDir(),
842
- ...vscodeSettingsTargets(existsSync6).map((settings) => dirname(settings))
674
+ ...vscodeSettingsTargets(existsSync5).map((settings) => dirname(settings))
843
675
  ];
844
676
  var restoreTakeoverReceipts = () => {
845
677
  const targets = [
@@ -847,15 +679,15 @@ var restoreTakeoverReceipts = () => {
847
679
  ["codex", codexHooksJson(), codexConfigToml(), "mcp_servers", "toml"],
848
680
  ["gemini_cli", geminiSettings(), geminiSettings(), "mcpServers", "json"],
849
681
  ["cursor", CURSOR_USER_HOOKS, null, null, null],
850
- ["vscode", join6(VSCODE_PLUGIN_DIR, "hooks", "hooks.json"), vscodePluginMcp(), "mcpServers", "json"]
682
+ ["vscode", join5(VSCODE_PLUGIN_DIR, "hooks", "hooks.json"), vscodePluginMcp(), "mcpServers", "json"]
851
683
  ];
852
684
  for (const [agent, hookFile, mcpFile, mcpKey, mcpFormat] of targets) {
853
685
  const receiptPath = hookTakeoverReceipt(agent);
854
- if (!existsSync6(receiptPath)) continue;
686
+ if (!existsSync5(receiptPath)) continue;
855
687
  try {
856
688
  const receipt = readJson(receiptPath);
857
689
  if (!isHookTakeoverReceipt(receipt) || receipt.agent !== agent) throw new Error("invalid receipt");
858
- const document = existsSync6(hookFile) ? JSON.parse(readFileSync4(hookFile, "utf-8")) : {};
690
+ const document = existsSync5(hookFile) ? JSON.parse(readFileSync4(hookFile, "utf-8")) : {};
859
691
  if (!document || typeof document !== "object" || Array.isArray(document)) throw new Error("invalid hooks file");
860
692
  const appAlreadyOwns = hookOwnerOf(document) === "app";
861
693
  const cliPositions = agent === "codex" ? codexHookPositions(document) : {};
@@ -866,7 +698,7 @@ var restoreTakeoverReceipts = () => {
866
698
  if (mcpFile === hookFile) {
867
699
  mcpDocument = document;
868
700
  } else {
869
- const raw = existsSync6(mcpFile) ? readFileSync4(mcpFile, "utf-8") : "";
701
+ const raw = existsSync5(mcpFile) ? readFileSync4(mcpFile, "utf-8") : "";
870
702
  mcpDocument = raw.trim() ? mcpFormat === "toml" ? parseTOML(raw) : JSON.parse(raw) : {};
871
703
  }
872
704
  mcpChanged = restoreMcpServer(mcpDocument, mcpKey, receipt.mcpServer);
@@ -876,7 +708,7 @@ var restoreTakeoverReceipts = () => {
876
708
  if (!appAlreadyOwns && agent === "codex") {
877
709
  if (!mcpDocument) {
878
710
  const configPath = codexConfigToml();
879
- const raw = existsSync6(configPath) ? readFileSync4(configPath, "utf-8") : "";
711
+ const raw = existsSync5(configPath) ? readFileSync4(configPath, "utf-8") : "";
880
712
  mcpDocument = raw.trim() ? parseTOML(raw) : {};
881
713
  }
882
714
  codexConfig = mcpDocument;
@@ -972,7 +804,7 @@ var main = async () => {
972
804
  }
973
805
  if (presence !== "absent") console.log();
974
806
  const restoredByTakeover = new Set(
975
- ["claude_code", "codex", "gemini_cli"].filter((agent) => existsSync6(hookTakeoverReceipt(agent)))
807
+ ["claude_code", "codex", "gemini_cli"].filter((agent) => existsSync5(hookTakeoverReceipt(agent)))
976
808
  );
977
809
  if (keepShared) restoreTakeoverReceipts();
978
810
  const sharedMcpKeys = {
@@ -998,7 +830,7 @@ var main = async () => {
998
830
  let macAppKeepsCodexAppCards = false;
999
831
  if (uid !== void 0) {
1000
832
  try {
1001
- const removal = { homeDir: homedir5(), uid, keepWhatTheMacAppTurnedOn: keepShared, dryRun };
833
+ const removal = { homeDir: homedir4(), uid, keepWhatTheMacAppTurnedOn: keepShared, dryRun };
1002
834
  const appCards = removeCodexAppCardsFromThisMac(removal);
1003
835
  macAppKeepsCodexAppCards = codexAppCardsFolderStaysOnThisMac(removal);
1004
836
  if (appCards === "removed") console.log(` ${check} Codex app cards ${dim(did("removed"))} ${dim("(quit Codex and open it again)")}`);
@@ -1015,7 +847,7 @@ var main = async () => {
1015
847
  const claudeHadPusharyEntry = claudeHasPusharyEntry();
1016
848
  const rawReceipt = readJson(CLAUDE_MCP_RECEIPT);
1017
849
  const receipt = isClaudeMcpSnapshot(rawReceipt) ? rawReceipt : null;
1018
- const receiptUnreadable = existsSync6(CLAUDE_MCP_RECEIPT) && !receipt;
850
+ const receiptUnreadable = existsSync5(CLAUDE_MCP_RECEIPT) && !receipt;
1019
851
  if (keepClaudeMcp) {
1020
852
  console.log(` ${skip} Claude Code MCP servers ${dim("(kept: the Mac app uses it)")}`);
1021
853
  } else if (claudeJson2) {
@@ -1030,7 +862,7 @@ var main = async () => {
1030
862
  if (receipt && !keepShared) incompleteClean = true;
1031
863
  console.log(` ${skip} Claude Code MCP servers ${dim(receipt ? "(changed after setup; left unchanged)" : "(no pushary entries)")}`);
1032
864
  }
1033
- } else if (existsSync6(CLAUDE_MCP_RECEIPT)) {
865
+ } else if (existsSync5(CLAUDE_MCP_RECEIPT)) {
1034
866
  incompleteClean = true;
1035
867
  console.log(` ${skip} Claude Code MCP servers ${dim("(config missing; setup receipt kept for retry)")}`);
1036
868
  } else {
@@ -1074,7 +906,7 @@ var main = async () => {
1074
906
  }
1075
907
  if (cursorGate === "failed") {
1076
908
  console.log(` ${skip} Cursor plugin ${dim("(kept: removing it now would block matched commands)")}`);
1077
- } else if (existsSync6(CURSOR_PLUGIN_DIR)) {
909
+ } else if (existsSync5(CURSOR_PLUGIN_DIR)) {
1078
910
  guardedRemove(CURSOR_PLUGIN_DIR);
1079
911
  console.log(` ${check} Cursor plugin ${dim("(removed from ~/.cursor/plugins/local)")}`);
1080
912
  } else {
@@ -1090,9 +922,9 @@ var main = async () => {
1090
922
  if (keepShared) {
1091
923
  console.log(` ${skip} VS Code plugin ${dim("(kept: the Mac app writes the same plugin directory)")}`);
1092
924
  }
1093
- for (const settingsPath of keepShared ? [] : vscodeSettingsTargets(existsSync6)) {
925
+ for (const settingsPath of keepShared ? [] : vscodeSettingsTargets(existsSync5)) {
1094
926
  const label = `VS Code plugin ${dim(`(${shortenHome(settingsPath)})`)}`;
1095
- if (!existsSync6(settingsPath)) {
927
+ if (!existsSync5(settingsPath)) {
1096
928
  console.log(` ${skip} ${label} ${dim("(no settings.json)")}`);
1097
929
  continue;
1098
930
  }
@@ -1106,7 +938,7 @@ var main = async () => {
1106
938
  console.log(` ${skip} ${label} ${dim("(no pushary entry)")}`);
1107
939
  }
1108
940
  }
1109
- if (!keepShared && existsSync6(VSCODE_PLUGIN_DIR)) {
941
+ if (!keepShared && existsSync5(VSCODE_PLUGIN_DIR)) {
1110
942
  guardedRemove(VSCODE_PLUGIN_DIR);
1111
943
  console.log(` ${check} VS Code plugin files ${dim(did("removed"))}`);
1112
944
  }
@@ -1125,7 +957,7 @@ var main = async () => {
1125
957
  }
1126
958
  if (keepShared) {
1127
959
  console.log(` ${skip} Skill directory ${dim("(kept: the Mac app uses it)")}`);
1128
- } else if (existsSync6(SKILL_DIR)) {
960
+ } else if (existsSync5(SKILL_DIR)) {
1129
961
  guardedRemove(SKILL_DIR);
1130
962
  console.log(` ${check} Skill directory ${dim(did("removed"))}`);
1131
963
  } else {
@@ -1185,7 +1017,7 @@ var main = async () => {
1185
1017
  const codexSkillDir2 = codexSkillDir();
1186
1018
  if (keepShared) {
1187
1019
  console.log(` ${skip} Codex skill directory ${dim("(kept: the Mac app uses it)")}`);
1188
- } else if (existsSync6(codexSkillDir2)) {
1020
+ } else if (existsSync5(codexSkillDir2)) {
1189
1021
  guardedRemove(codexSkillDir2);
1190
1022
  console.log(` ${check} Codex skill directory ${dim(did("removed"))}`);
1191
1023
  } else {
@@ -1238,7 +1070,7 @@ var main = async () => {
1238
1070
  console.log(` ${skip} Gemini GEMINI.md ${dim("(no pushary block)")}`);
1239
1071
  }
1240
1072
  const openCodePlugin = openCodePluginFile();
1241
- const openCodePluginContents = existsSync6(openCodePlugin) ? readFileSync4(openCodePlugin, "utf-8") : null;
1073
+ const openCodePluginContents = existsSync5(openCodePlugin) ? readFileSync4(openCodePlugin, "utf-8") : null;
1242
1074
  if (openCodePluginContents === null) {
1243
1075
  console.log(` ${skip} OpenCode plugin ${dim("(not installed)")}`);
1244
1076
  } else if (!isOpenCodePluginOurs(openCodePluginContents)) {
@@ -1248,15 +1080,15 @@ var main = async () => {
1248
1080
  } else {
1249
1081
  guardedRemove(openCodePlugin, { force: true });
1250
1082
  console.log(` ${check} OpenCode plugin ${dim(did("removed"))}`);
1251
- const sibling = join6(openCodePluginDir(), OPENCODE_PLUGIN_SIBLING);
1083
+ const sibling = join5(openCodePluginDir(), OPENCODE_PLUGIN_SIBLING);
1252
1084
  const remaining = (() => {
1253
1085
  try {
1254
- return readdirSync5(openCodePluginDir()).filter((name) => name !== OPENCODE_PLUGIN_SIBLING);
1086
+ return readdirSync4(openCodePluginDir()).filter((name) => name !== OPENCODE_PLUGIN_SIBLING);
1255
1087
  } catch {
1256
1088
  return [];
1257
1089
  }
1258
1090
  })();
1259
- const siblingIsOurs = existsSync6(sibling) && readFileSync4(sibling, "utf-8") === OPENCODE_PLUGIN_SIBLING_CONTENTS;
1091
+ const siblingIsOurs = existsSync5(sibling) && readFileSync4(sibling, "utf-8") === OPENCODE_PLUGIN_SIBLING_CONTENTS;
1260
1092
  if (siblingIsOurs && !hasForeignPlugins(remaining)) {
1261
1093
  guardedRemove(sibling, { force: true });
1262
1094
  console.log(` ${check} OpenCode plugin sibling ${dim(did("removed"))}`);
@@ -1309,7 +1141,7 @@ var main = async () => {
1309
1141
  }
1310
1142
  }
1311
1143
  }
1312
- } else if (existsSync6(HERMES_CONFIG_RECEIPT)) {
1144
+ } else if (existsSync5(HERMES_CONFIG_RECEIPT)) {
1313
1145
  incompleteClean = true;
1314
1146
  console.log(` ${skip} Hermes ${dim("(runtime not found; setup receipt kept for retry)")}`);
1315
1147
  } else {
@@ -1358,15 +1190,15 @@ var main = async () => {
1358
1190
  if (leakedTemps.length > 0) {
1359
1191
  console.log(` ${check} Leftover temp files ${dim(`(${dryRun ? "would remove" : "removed"} ${leakedTemps.length} left by an interrupted config write)`)}`);
1360
1192
  }
1361
- if (existsSync6(PUSHARY_DIR)) {
1193
+ if (existsSync5(PUSHARY_DIR)) {
1362
1194
  let removed = 0;
1363
1195
  const kept = [];
1364
- for (const entry of readdirSync5(PUSHARY_DIR)) {
1196
+ for (const entry of readdirSync4(PUSHARY_DIR)) {
1365
1197
  if (keepShared && isAppOwned(entry) || entry === "setup" && (keepShared || incompleteClean) || entry === CODEX_APP_CARDS_DIRECTORY && macAppKeepsCodexAppCards) {
1366
1198
  kept.push(entry);
1367
1199
  continue;
1368
1200
  }
1369
- guardedRemove(join6(PUSHARY_DIR, entry), { force: true });
1201
+ guardedRemove(join5(PUSHARY_DIR, entry), { force: true });
1370
1202
  removed++;
1371
1203
  }
1372
1204
  if (removed > 0) {
@@ -1383,10 +1215,10 @@ var main = async () => {
1383
1215
  }
1384
1216
  try {
1385
1217
  let swept = 0;
1386
- for (const f of readdirSync5(tmpdir())) {
1218
+ for (const f of readdirSync4(tmpdir())) {
1387
1219
  if (!f.startsWith("pushary-")) continue;
1388
1220
  try {
1389
- guardedRemove(join6(tmpdir(), f), { force: true });
1221
+ guardedRemove(join5(tmpdir(), f), { force: true });
1390
1222
  swept++;
1391
1223
  } catch {
1392
1224
  }
@@ -1440,7 +1272,7 @@ var main = async () => {
1440
1272
  console.log(` ${dim("Still stuck? Send this output to")} ${SUPPORT_EMAIL} ${dim("or")} ${SUPPORT_DISCORD}`);
1441
1273
  } else if (everything) {
1442
1274
  console.log(` ${green(bold("Clean complete. Nothing of ours is left in any agent config."))}`);
1443
- const bundle = installedPusharyBundles().find(existsSync6);
1275
+ const bundle = installedPusharyBundles().find(existsSync5);
1444
1276
  if (bundle) {
1445
1277
  console.log(` ${dim("The app itself is still installed. Drag")} ${bundle} ${dim("to the Trash to finish.")}`);
1446
1278
  }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  letCodexRunWithoutPushary
4
- } from "../chunk-36NGFHE4.js";
4
+ } from "../chunk-E46NE7FB.js";
5
5
 
6
6
  // bin/pushary-codex-session.ts
7
7
  var args = process.argv.slice(2);
@@ -16,7 +16,7 @@ var desktopAccount = async () => {
16
16
  return null;
17
17
  }
18
18
  };
19
- var desktopLaunch = await import("../codex-desktop-launch-I2D6QATK.js").catch(() => null);
19
+ var desktopLaunch = await import("../codex-desktop-launch-RIBIFXSF.js").catch(() => null);
20
20
  if (desktopLaunch === null && appBehindTheProxy !== void 0) {
21
21
  process.exitCode = await letCodexRunWithoutPushary(appBehindTheProxy, args.slice(3));
22
22
  } else {
@@ -24,7 +24,7 @@ if (desktopLaunch === null && appBehindTheProxy !== void 0) {
24
24
  const stop = () => abort.abort();
25
25
  if (!args[0]?.startsWith("--desktop")) for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) process.on(signal, stop);
26
26
  try {
27
- const { codexDesktopCommand } = desktopLaunch ?? await import("../codex-desktop-launch-I2D6QATK.js");
27
+ const { codexDesktopCommand } = desktopLaunch ?? await import("../codex-desktop-launch-RIBIFXSF.js");
28
28
  const desktop = await codexDesktopCommand(args, [process.execPath, ...process.execArgv, process.argv[1], "codex"], desktopAccount);
29
29
  if (desktop !== null) process.exitCode = desktop;
30
30
  else {
@@ -55,7 +55,7 @@ import {
55
55
  } from "../chunk-EUW7JL2K.js";
56
56
  import {
57
57
  codexEngineBehindLauncher
58
- } from "../chunk-ABGN5RN2.js";
58
+ } from "../chunk-T5L5NWT3.js";
59
59
  import "../chunk-XCEN33UP.js";
60
60
  import {
61
61
  CURSOR_PLUGIN_BACKUP_INFIX,
@@ -244,7 +244,7 @@ import {
244
244
  CODEX_ENGINE_ENTRYPOINT,
245
245
  CODEX_ENGINE_MANIFEST,
246
246
  codexEngineInside
247
- } from "../chunk-36NGFHE4.js";
247
+ } from "../chunk-E46NE7FB.js";
248
248
  import {
249
249
  reportEvent
250
250
  } from "../chunk-U2L42GVI.js";
@@ -4,6 +4,7 @@ import { rmSync } from "fs";
4
4
  import { join } from "path";
5
5
  var CODEX_APP_LAUNCH_VARIABLE = "CODEX_CLI_PATH";
6
6
  var CODEX_ENGINE_PENDING_VARIABLE = "PUSHARY_CODEX_ENGINE_PENDING";
7
+ var CODEX_APP_LAUNCH_AT_LOGIN_VERB = "codex-app-launch-at-login";
7
8
  var CODEX_ENGINE_DIRECTORY = "Contents/Resources/codex-cli";
8
9
  var CODEX_ENGINE_ENTRYPOINT = "bin/codex";
9
10
  var CODEX_ENGINE_MANIFEST = "codex-package.json";
@@ -60,6 +61,7 @@ var letCodexRunWithoutPushary = (app, engineArgs) => {
60
61
  export {
61
62
  CODEX_APP_LAUNCH_VARIABLE,
62
63
  CODEX_ENGINE_PENDING_VARIABLE,
64
+ CODEX_APP_LAUNCH_AT_LOGIN_VERB,
63
65
  CODEX_ENGINE_DIRECTORY,
64
66
  CODEX_ENGINE_ENTRYPOINT,
65
67
  CODEX_ENGINE_MANIFEST,
@@ -12,7 +12,7 @@ import {
12
12
  launcherIsGone,
13
13
  launcherWaitingOnThisProcess,
14
14
  tellTheLauncherTheEngineStarted
15
- } from "./chunk-36NGFHE4.js";
15
+ } from "./chunk-E46NE7FB.js";
16
16
 
17
17
  // src/codex-desktop-launch.ts
18
18
  import { spawn as spawn2, execFileSync } from "child_process";
@@ -695,7 +695,7 @@ var codexDesktopCommand = async (args, entry, readAccount) => {
695
695
  return runCodexDesktopProxy(engine2, args.slice(3), readAccount, { watchesForCards: layoutIsKnown });
696
696
  }
697
697
  if (args[0] === APP_CARDS_FLAG) {
698
- const { codexAppCardsCommandOnThisMac } = await import("./codex-app-cards-switch-RENOSSDD.js");
698
+ const { codexAppCardsCommandOnThisMac } = await import("./codex-app-cards-switch-P4RVJNRV.js");
699
699
  return codexAppCardsCommandOnThisMac(args.slice(1), entry, readAccount);
700
700
  }
701
701
  if (args.length > 2) throw new Error("Usage: pushary codex --desktop [path/to/Codex.app]");
@@ -6,7 +6,7 @@ import {
6
6
  everyProgramFileIsThere,
7
7
  installedCodexApp,
8
8
  shellQuoted
9
- } from "./chunk-ABGN5RN2.js";
9
+ } from "./chunk-T5L5NWT3.js";
10
10
  import {
11
11
  writeHuman
12
12
  } from "./chunk-QCGNGEGE.js";
@@ -14,17 +14,200 @@ import {
14
14
  xml
15
15
  } from "./chunk-BL3WAGIK.js";
16
16
  import {
17
+ CODEX_APP_LAUNCH_AT_LOGIN_VERB,
17
18
  CODEX_APP_LAUNCH_VARIABLE
18
- } from "./chunk-36NGFHE4.js";
19
+ } from "./chunk-E46NE7FB.js";
19
20
  import {
20
21
  writeFileAtomic
21
22
  } from "./chunk-AQFEP65J.js";
22
23
 
23
24
  // src/codex-app-cards-switch.ts
24
- import { execFileSync } from "child_process";
25
- import { existsSync, mkdirSync, readFileSync, rmSync } from "fs";
25
+ import { execFileSync as execFileSync2 } from "child_process";
26
+ import { existsSync as existsSync2, mkdirSync, readFileSync, rmSync } from "fs";
27
+ import { homedir as homedir2 } from "os";
28
+ import { join as join2 } from "path";
29
+
30
+ // src/cli/mac-leftovers.ts
31
+ import { execSync, execFileSync } from "child_process";
32
+ import { existsSync, readdirSync } from "fs";
26
33
  import { homedir } from "os";
27
- import { join } from "path";
34
+ import { isAbsolute, join } from "path";
35
+ var MAC_APP_BUNDLE = "/Applications/Pushary.app";
36
+ var MAC_APP_BUNDLE_ID = "com.pushary.app";
37
+ var installedPusharyBundles = (home = homedir()) => [MAC_APP_BUNDLE, join(home, "Applications", "Pushary.app")];
38
+ var LSREGISTER = "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister";
39
+ var TEST_DEFAULTS_PREFIXES = [
40
+ "com.pushary.mac.tests.",
41
+ "com.pushary.tests.",
42
+ "pushary.tests.",
43
+ "pushary.quiet-mode-test.",
44
+ "pushary.drafts.test.",
45
+ "pushary-optin-",
46
+ "pushary-completion-test-",
47
+ "pushary-updates-only-"
48
+ ];
49
+ var UUID = "[0-9A-Fa-f]{8}(?:-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12}";
50
+ var UNPREFIXED_TEST_DEFAULTS_DOMAIN = new RegExp(`^(?:owner-mode|fx-model)-${UUID}$`);
51
+ var DEVELOPER_BUILD_DEFAULTS_DOMAIN = "PusharyMac";
52
+ var isDeveloperDefaultsDomain = (domain) => domain === DEVELOPER_BUILD_DEFAULTS_DOMAIN || UNPREFIXED_TEST_DEFAULTS_DOMAIN.test(domain) || TEST_DEFAULTS_PREFIXES.some((prefix) => domain.startsWith(prefix));
53
+ var PREFERENCES_FILE_EXTENSION = ".plist";
54
+ var preferencesDirectory = (home) => join(home, "Library", "Preferences");
55
+ var preferencesFile = (home, domain) => join(preferencesDirectory(home), `${domain}${PREFERENCES_FILE_EXTENSION}`);
56
+ var namesIn = (directory) => {
57
+ try {
58
+ return readdirSync(directory);
59
+ } catch {
60
+ return [];
61
+ }
62
+ };
63
+ var developerDefaults = (home = homedir()) => namesIn(preferencesDirectory(home)).filter((name) => name.endsWith(PREFERENCES_FILE_EXTENSION)).map((name) => name.slice(0, -PREFERENCES_FILE_EXTENSION.length)).filter(isDeveloperDefaultsDomain).map((domain) => ({ domain, file: preferencesFile(home, domain) }));
64
+ var BUNDLE_NAME = "Pushary.app";
65
+ var DUMP_RECORD_SEPARATOR = /^-{20,}$/m;
66
+ var DUMP_PATH_LINES = /^[ \t]*path:[ \t]+(.+?)(?: \(0x[0-9a-f]+\))?[ \t]*$/gm;
67
+ var DUMP_IDENTIFIER_LINES = /^[ \t]*identifier:[ \t]+(\S+)/gm;
68
+ var capturedIn = (text, lines) => [...text.matchAll(lines)].flatMap((match) => match[1] === void 0 ? [] : [match[1]]);
69
+ var appCopyNamedByRecord = (record) => {
70
+ const paths = capturedIn(record, DUMP_PATH_LINES);
71
+ const identifiers = capturedIn(record, DUMP_IDENTIFIER_LINES);
72
+ const namesOneAppCopy = paths.length === 1 && identifiers.length === 1 && identifiers[0] === MAC_APP_BUNDLE_ID;
73
+ return namesOneAppCopy ? paths : [];
74
+ };
75
+ var isAtOrInside = (path, bundle) => path === bundle || path.startsWith(`${bundle}/`);
76
+ var isUnderBundleNamedPushary = (path) => path.split("/").includes(BUNDLE_NAME);
77
+ var bundlesInLaunchServicesDump = (dump) => {
78
+ const appCopies = dump.split(DUMP_RECORD_SEPARATOR).flatMap(appCopyNamedByRecord);
79
+ const isOurs = (path) => isUnderBundleNamedPushary(path) || appCopies.some((copy) => isAtOrInside(path, copy));
80
+ return [...new Set(capturedIn(dump, DUMP_PATH_LINES).filter(isOurs))];
81
+ };
82
+ var outsideInstalledBundles = (registered, installed) => registered.filter((path) => !installed.some((bundle) => isAtOrInside(path, bundle)));
83
+ var registeredPusharyBundles = (installed = installedPusharyBundles()) => {
84
+ if (!existsSync(LSREGISTER)) return [];
85
+ try {
86
+ const dump = execSync(`${LSREGISTER} -dump`, {
87
+ encoding: "utf-8",
88
+ timeout: 6e4,
89
+ maxBuffer: 256 * 1024 * 1024
90
+ });
91
+ return outsideInstalledBundles(bundlesInLaunchServicesDump(dump), installed);
92
+ } catch {
93
+ return [];
94
+ }
95
+ };
96
+ var MAC_KEYCHAIN_SERVICE = "com.pushary.app.mac";
97
+ var MAC_KEYCHAIN_ACCOUNTS = [
98
+ "pushary.site-api-key",
99
+ "pushary.site-id",
100
+ "pushary.partner-enrollments",
101
+ "pushary.partner-device-key",
102
+ "clerk.device-token",
103
+ "clerk.session-id",
104
+ "clerkDeviceToken",
105
+ "cachedClient",
106
+ "cachedClientServerDate",
107
+ "cachedEnvironment"
108
+ ];
109
+ var MAC_DEFAULTS_DOMAINS = ["com.pushary.app", "pushary-bridge", "pushary.render"];
110
+ var PRESENCE_PROBE_TIMEOUT_MS = 1e4;
111
+ var commandSucceeds = (file, args) => {
112
+ try {
113
+ execFileSync(file, args, { stdio: "ignore", timeout: PRESENCE_PROBE_TIMEOUT_MS });
114
+ return true;
115
+ } catch {
116
+ return false;
117
+ }
118
+ };
119
+ var KEYCHAIN_ITEM_NOT_FOUND = 44;
120
+ var keychainItemMayExist = (service, account) => {
121
+ try {
122
+ execFileSync("security", ["find-generic-password", "-s", service, "-a", account], { stdio: "ignore" });
123
+ return true;
124
+ } catch (error) {
125
+ return !(error instanceof Error && "status" in error && error.status === KEYCHAIN_ITEM_NOT_FOUND);
126
+ }
127
+ };
128
+ var liveMacStatePresence = {
129
+ keychainItem: keychainItemMayExist,
130
+ defaultsDomain: (domain) => commandSucceeds("defaults", ["read", domain])
131
+ };
132
+ var macLibraryState = (home = homedir()) => [
133
+ join(home, "Library", "Application Support", "Pushary"),
134
+ join(home, "Library", "Caches", "com.pushary.app"),
135
+ join(home, "Library", "Caches", "com.pushary.app.sparkle"),
136
+ join(home, "Library", "Saved Application State", "com.pushary.app.savedState"),
137
+ join(home, "Library", "Caches", "pushary-bridge"),
138
+ join(home, "Library", "HTTPStorages", "com.pushary.app"),
139
+ join(home, "Library", "HTTPStorages", "com.pushary.app.binarycookies"),
140
+ join(home, "Library", "HTTPStorages", "pushary-bridge"),
141
+ ...MAC_DEFAULTS_DOMAINS.map((domain) => preferencesFile(home, domain))
142
+ ];
143
+ var USER_CACHE_ENTRIES = [MAC_APP_BUNDLE_ID, "pushary-bridge", "PusharyBridge"];
144
+ var macUserCacheState = (reportedUserCacheDirectory) => {
145
+ const directory = reportedUserCacheDirectory.trim();
146
+ return isAbsolute(directory) ? USER_CACHE_ENTRIES.map((entry) => join(directory, entry)) : [];
147
+ };
148
+ var UNKNOWN_USER_CACHE_DIRECTORY = "";
149
+ var reportedDarwinUserCacheDirectory = () => {
150
+ try {
151
+ return execFileSync("getconf", ["DARWIN_USER_CACHE_DIR"], {
152
+ encoding: "utf-8",
153
+ timeout: PRESENCE_PROBE_TIMEOUT_MS,
154
+ stdio: ["ignore", "pipe", "ignore"]
155
+ });
156
+ } catch {
157
+ return UNKNOWN_USER_CACHE_DIRECTORY;
158
+ }
159
+ };
160
+ var CRASH_REPORTER_ENTRY = new RegExp(`^(?:Pushary|PusharyMac|pushary-bridge)_${UUID}\\.plist$`);
161
+ var crashReporterEntries = (home = homedir()) => {
162
+ const directory = join(home, "Library", "Application Support", "CrashReporter");
163
+ return namesIn(directory).filter((name) => CRASH_REPORTER_ENTRY.test(name)).map((name) => join(directory, name));
164
+ };
165
+ var storedMacAppState = (home = homedir()) => [
166
+ ...macLibraryState(home),
167
+ ...macUserCacheState(reportedDarwinUserCacheDirectory()),
168
+ ...crashReporterEntries(home)
169
+ ];
170
+ var DUMP_SERVICE_LINE = /^\s*"svce"<blob>="(.+)"\s*$/;
171
+ var pusharyKeychainServices = (dump) => {
172
+ const found = /* @__PURE__ */ new Set();
173
+ for (const line of dump.split("\n")) {
174
+ const service = DUMP_SERVICE_LINE.exec(line)?.[1];
175
+ if (service?.startsWith(MAC_KEYCHAIN_SERVICE)) found.add(service);
176
+ }
177
+ return [...found];
178
+ };
179
+ var storedPusharyKeychainServices = () => {
180
+ const dump = execFileSync("security", ["dump-keychain"], {
181
+ encoding: "utf-8",
182
+ timeout: 3e4,
183
+ maxBuffer: 64 * 1024 * 1024,
184
+ stdio: ["ignore", "pipe", "ignore"]
185
+ });
186
+ const stored = pusharyKeychainServices(dump);
187
+ return stored.includes(MAC_KEYCHAIN_SERVICE) ? stored : [MAC_KEYCHAIN_SERVICE, ...stored];
188
+ };
189
+ var runningMacAppPIDs = () => {
190
+ if (process.platform !== "darwin") return [];
191
+ try {
192
+ return execSync('pgrep -f "Pushary.app/Contents/MacOS/Pushary"', {
193
+ encoding: "utf-8",
194
+ timeout: 1e4,
195
+ stdio: ["ignore", "pipe", "ignore"]
196
+ }).split("\n").map((line) => Number(line.trim())).filter((pid) => Number.isInteger(pid) && pid > 0);
197
+ } catch {
198
+ return [];
199
+ }
200
+ };
201
+ var waitForMacAppExit = (attempts = 20, everyMs = 250) => {
202
+ const idle = new Int32Array(new SharedArrayBuffer(4));
203
+ for (let attempt = 0; attempt < attempts; attempt++) {
204
+ if (runningMacAppPIDs().length === 0) return true;
205
+ Atomics.wait(idle, 0, 0, everyMs);
206
+ }
207
+ return runningMacAppPIDs().length === 0;
208
+ };
209
+
210
+ // src/codex-app-cards-switch.ts
28
211
  var CODEX_APP_CARDS_LOGIN_ITEM = "com.pushary.codex-app-cards";
29
212
  var CODEX_APP_CARDS_DIRECTORY = "codex-app";
30
213
  var LAUNCHCTL = "/bin/launchctl";
@@ -39,15 +222,15 @@ var LOGIN_ITEM_MODE = 420;
39
222
  var MAC_APP_HELPER = "/Contents/Helpers/pushary-native-transcripts";
40
223
  var TEMPORARY_NPX_FOLDER = "/_npx/";
41
224
  var codexAppCardsPaths = (homeDir, uid) => {
42
- const launcherDirectory = join(homeDir, ".pushary", CODEX_APP_CARDS_DIRECTORY);
43
- const loginItemDirectory = join(homeDir, "Library", "LaunchAgents");
225
+ const launcherDirectory = join2(homeDir, ".pushary", CODEX_APP_CARDS_DIRECTORY);
226
+ const loginItemDirectory = join2(homeDir, "Library", "LaunchAgents");
44
227
  return {
45
228
  launcherDirectory,
46
- launcherPath: join(launcherDirectory, LAUNCHER_NAME),
47
- receiptPath: join(launcherDirectory, RECEIPT_NAME),
48
- turnedOffPath: join(launcherDirectory, TURNED_OFF_NAME),
229
+ launcherPath: join2(launcherDirectory, LAUNCHER_NAME),
230
+ receiptPath: join2(launcherDirectory, RECEIPT_NAME),
231
+ turnedOffPath: join2(launcherDirectory, TURNED_OFF_NAME),
49
232
  loginItemDirectory,
50
- loginItemPath: join(loginItemDirectory, `${CODEX_APP_CARDS_LOGIN_ITEM}.plist`),
233
+ loginItemPath: join2(loginItemDirectory, `${CODEX_APP_CARDS_LOGIN_ITEM}.plist`),
51
234
  loginItemTarget: `gui/${uid}/${CODEX_APP_CARDS_LOGIN_ITEM}`
52
235
  };
53
236
  };
@@ -56,17 +239,23 @@ var codexAppCardsLoginScript = (launcherPath, engine, entry) => [
56
239
  `&& [ -z "$(${LAUNCHCTL} getenv ${CODEX_APP_LAUNCH_VARIABLE})" ];`,
57
240
  `then ${LAUNCHCTL} setenv ${CODEX_APP_LAUNCH_VARIABLE} ${shellQuoted(launcherPath)}; fi`
58
241
  ].join(" ");
242
+ var isTheMacAppsHelper = (entry) => entry.length > 0 && entry[0].endsWith(MAC_APP_HELPER);
243
+ var loginItemProgram = (launcherPath, engine, entry) => isTheMacAppsHelper(entry) ? [entry[0], CODEX_APP_LAUNCH_AT_LOGIN_VERB] : ["/bin/sh", "-c", codexAppCardsLoginScript(launcherPath, engine, entry)];
244
+ var LISTED_UNDER_THE_MAC_APP = ` <key>AssociatedBundleIdentifiers</key>
245
+ <array>
246
+ <string>${MAC_APP_BUNDLE_ID}</string>
247
+ </array>
248
+ `;
249
+ var propertyListString = (value) => ` <string>${xml(value)}</string>`;
59
250
  var codexAppCardsLoginItem = (launcherPath, engine, entry) => `<?xml version="1.0" encoding="UTF-8"?>
60
251
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
61
252
  <plist version="1.0">
62
253
  <dict>
63
254
  <key>Label</key>
64
255
  <string>${CODEX_APP_CARDS_LOGIN_ITEM}</string>
65
- <key>ProgramArguments</key>
256
+ ${isTheMacAppsHelper(entry) ? LISTED_UNDER_THE_MAC_APP : ""} <key>ProgramArguments</key>
66
257
  <array>
67
- <string>/bin/sh</string>
68
- <string>-c</string>
69
- <string>${xml(codexAppCardsLoginScript(launcherPath, engine, entry))}</string>
258
+ ${loginItemProgram(launcherPath, engine, entry).map(propertyListString).join("\n")}
70
259
  </array>
71
260
  <key>RunAtLoad</key>
72
261
  <true/>
@@ -128,6 +317,13 @@ var turnCodexAppCardsOn = (installation, machine) => {
128
317
  machine.setLaunchVariable(paths.launcherPath);
129
318
  return { kind: "on" };
130
319
  };
320
+ var setCodexAppLaunchAtLogin = (paths, machine) => {
321
+ const isTurnedOn = machine.exists(paths.launcherPath) && machine.exists(paths.loginItemPath);
322
+ const cannotRun = whatTheLauncherCannotRun(codexAppCardsReceiptFrom(machine.readFile(paths.receiptPath)), machine);
323
+ if (!isTurnedOn || cannotRun !== null || machine.launchVariable().length > 0) return "left_as_it_is";
324
+ machine.setLaunchVariable(paths.launcherPath);
325
+ return "set";
326
+ };
131
327
  var leaveOnlyThePathToTheEngine = (paths, machine) => {
132
328
  const receipt = codexAppCardsReceiptFrom(machine.readFile(paths.receiptPath));
133
329
  const launcher = machine.readFile(paths.launcherPath);
@@ -152,7 +348,6 @@ var rememberCodexAppCardsWereTurnedOff = (paths, machine) => {
152
348
  machine.makeDirectory(paths.launcherDirectory, PRIVATE_DIRECTORY_MODE);
153
349
  machine.writeFile(paths.turnedOffPath, "", PRIVATE_FILE_MODE);
154
350
  };
155
- var isTheMacAppsHelper = (entry) => entry.length > 0 && entry[0].endsWith(MAC_APP_HELPER);
156
351
  var turnedOnByTheMacApp = (receipt) => receipt !== null && isTheMacAppsHelper(receipt.entry);
157
352
  var codexAppCardsReport = (paths, machine) => ({
158
353
  status: codexAppCardsStatus(paths, machine),
@@ -181,7 +376,7 @@ var removeCodexAppCards = (request, machine) => {
181
376
  if (keepsTheOff) rememberCodexAppCardsWereTurnedOff(paths, machine);
182
377
  return "removed";
183
378
  };
184
- var launchctl = (args) => execFileSync(LAUNCHCTL, [...args], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
379
+ var launchctl = (args) => execFileSync2(LAUNCHCTL, [...args], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
185
380
  var launchctlIgnoringFailure = (args) => {
186
381
  try {
187
382
  return launchctl(args);
@@ -208,7 +403,7 @@ var thisMacsCodexAppCardsMachine = () => ({
208
403
  unloadLoginItem: (target) => {
209
404
  launchctlIgnoringFailure(["bootout", target]);
210
405
  },
211
- exists: existsSync,
406
+ exists: existsSync2,
212
407
  readFile: fileContents,
213
408
  makeDirectory: (path, mode) => {
214
409
  mkdirSync(path, { recursive: true, mode });
@@ -222,6 +417,11 @@ var thisMacsCodexAppCardsMachine = () => ({
222
417
  });
223
418
  var removeCodexAppCardsFromThisMac = (request) => removeCodexAppCards(request, thisMacsCodexAppCardsMachine());
224
419
  var codexAppCardsFolderStaysOnThisMac = (request) => codexAppCardsFolderStays(request, thisMacsCodexAppCardsMachine());
420
+ var setCodexAppLaunchAtLoginOnThisMac = () => {
421
+ const uid = process.getuid?.();
422
+ if (uid === void 0) return;
423
+ setCodexAppLaunchAtLogin(codexAppCardsPaths(homedir2(), uid), thisMacsCodexAppCardsMachine());
424
+ };
225
425
  var USAGE = "Usage: pushary codex --app-cards on [path/to/Codex.app] | off | status [--json]";
226
426
  var AS_JSON = "--json";
227
427
  var TAKES_EFFECT_AFTER_REOPENING = "Quit Codex and open it again.";
@@ -250,7 +450,7 @@ var codexAppCardsCommand = async (args, entry, readAccount, machine, say) => {
250
450
  const [action, chosenApp, ...rest] = args;
251
451
  const uid = process.getuid?.();
252
452
  if (uid === void 0) throw new Error("Codex app cards need macOS");
253
- const paths = codexAppCardsPaths(homedir(), uid);
453
+ const paths = codexAppCardsPaths(homedir2(), uid);
254
454
  if (action === "status" && chosenApp === AS_JSON && rest.length === 0) {
255
455
  say(JSON.stringify(codexAppCardsReport(paths, machine)));
256
456
  return 0;
@@ -270,7 +470,7 @@ var codexAppCardsCommand = async (args, entry, readAccount, machine, say) => {
270
470
  if (!await readAccount()) throw new Error("Connect Pushary before turning Codex app cards on");
271
471
  const app = installedCodexApp(chosenApp);
272
472
  const engine = await desktopEngine(app);
273
- const turnedOn = turnCodexAppCardsOn(codexAppCardsInstallation({ homeDir: homedir(), uid, entry, app, engine }), machine);
473
+ const turnedOn = turnCodexAppCardsOn(codexAppCardsInstallation({ homeDir: homedir2(), uid, entry, app, engine }), machine);
274
474
  if (turnedOn.kind === "another_program_owns_the_launch") {
275
475
  say(ownedByAnotherProgram(turnedOn.value));
276
476
  return 1;
@@ -288,6 +488,18 @@ var sayToThePerson = (line) => {
288
488
  var codexAppCardsCommandOnThisMac = (args, entry, readAccount) => codexAppCardsCommand(args, entry, readAccount, thisMacsCodexAppCardsMachine(), sayToThePerson);
289
489
 
290
490
  export {
491
+ MAC_APP_BUNDLE_ID,
492
+ installedPusharyBundles,
493
+ LSREGISTER,
494
+ developerDefaults,
495
+ registeredPusharyBundles,
496
+ MAC_KEYCHAIN_ACCOUNTS,
497
+ MAC_DEFAULTS_DOMAINS,
498
+ liveMacStatePresence,
499
+ storedMacAppState,
500
+ storedPusharyKeychainServices,
501
+ runningMacAppPIDs,
502
+ waitForMacAppExit,
291
503
  CODEX_APP_CARDS_LOGIN_ITEM,
292
504
  CODEX_APP_CARDS_DIRECTORY,
293
505
  codexAppCardsPaths,
@@ -297,6 +509,7 @@ export {
297
509
  codexAppCardsInstallation,
298
510
  codexAppCardsStatus,
299
511
  turnCodexAppCardsOn,
512
+ setCodexAppLaunchAtLogin,
300
513
  turnCodexAppCardsOff,
301
514
  rememberCodexAppCardsWereTurnedOff,
302
515
  codexAppCardsReport,
@@ -304,6 +517,7 @@ export {
304
517
  removeCodexAppCards,
305
518
  removeCodexAppCardsFromThisMac,
306
519
  codexAppCardsFolderStaysOnThisMac,
520
+ setCodexAppLaunchAtLoginOnThisMac,
307
521
  runsFromATemporaryFolder,
308
522
  codexAppCardsStatusLine,
309
523
  codexAppCardsCommand,
@@ -17,16 +17,18 @@ import {
17
17
  removeCodexAppCards,
18
18
  removeCodexAppCardsFromThisMac,
19
19
  runsFromATemporaryFolder,
20
+ setCodexAppLaunchAtLogin,
21
+ setCodexAppLaunchAtLoginOnThisMac,
20
22
  turnCodexAppCardsOff,
21
23
  turnCodexAppCardsOn
22
- } from "./chunk-SUIB4O3S.js";
23
- import "./chunk-ABGN5RN2.js";
24
+ } from "./chunk-ZWOWEXCV.js";
25
+ import "./chunk-T5L5NWT3.js";
24
26
  import "./chunk-XCEN33UP.js";
25
27
  import "./chunk-QCGNGEGE.js";
26
28
  import "./chunk-BL3WAGIK.js";
27
29
  import "./chunk-XHKBHWLX.js";
28
30
  import "./chunk-VYBH6D4X.js";
29
- import "./chunk-36NGFHE4.js";
31
+ import "./chunk-E46NE7FB.js";
30
32
  import "./chunk-T6RIKJUO.js";
31
33
  import "./chunk-4QQEUJL4.js";
32
34
  import "./chunk-OML4YFBN.js";
@@ -55,6 +57,8 @@ export {
55
57
  removeCodexAppCards,
56
58
  removeCodexAppCardsFromThisMac,
57
59
  runsFromATemporaryFolder,
60
+ setCodexAppLaunchAtLogin,
61
+ setCodexAppLaunchAtLoginOnThisMac,
58
62
  turnCodexAppCardsOff,
59
63
  turnCodexAppCardsOn
60
64
  };
@@ -10,11 +10,11 @@ import {
10
10
  installedCodexApp,
11
11
  shellQuoted,
12
12
  writeDesktopProxy
13
- } from "./chunk-ABGN5RN2.js";
13
+ } from "./chunk-T5L5NWT3.js";
14
14
  import "./chunk-XCEN33UP.js";
15
15
  import {
16
16
  CODEX_APP_LAUNCH_VARIABLE
17
- } from "./chunk-36NGFHE4.js";
17
+ } from "./chunk-E46NE7FB.js";
18
18
  export {
19
19
  CODEX_APP_LAUNCH_VARIABLE,
20
20
  codexAppOnThisMac,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushary/agent-hooks",
3
- "version": "1.9.53",
3
+ "version": "1.9.54",
4
4
  "description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
5
5
  "keywords": [
6
6
  "pushary",