pushary 1.9.52 → 1.9.53

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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.53
4
+
5
+ - `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.
6
+ - `pushary codex --app-cards off` is remembered. The Pushary Mac app turns the switch on by itself, and it leaves alone a switch you turned off with this command until you turn it on again. `pushary clean` keeps that record while the Mac app stays installed.
7
+ - The login item that keeps Codex app cards on after a restart now also checks that every file of Pushary's own program is still there. If Pushary was removed without turning the switch off, Codex starts the ordinary way from the next login. An existing login item gets the check the next time the switch is turned on.
8
+
3
9
  ## 1.9.52
4
10
 
5
11
  - `pushary upgrade` and the daily automatic update now refresh the Pushary instructions in each agent's instruction file: Codex, Gemini CLI, OpenCode, fx, Qwen Code, CodeBuddy and Grok. Before this release only `setup` wrote them, so a machine set up before 1.9.43 kept the old text after every update and its agents were never told about reminders. In fx a plain "remind me in 2 minutes" could fall back to a sleep timer that stops when fx closes.
@@ -1,14 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CODEX_APP_CARDS_DIRECTORY,
4
+ codexAppCardsFolderStaysOnThisMac,
4
5
  removeCodexAppCardsFromThisMac
5
- } from "../chunk-OHSHDQZF.js";
6
+ } from "../chunk-SUIB4O3S.js";
6
7
  import {
7
8
  PUSHARY_SKILL_NAME,
8
9
  PUSHARY_SKILL_SOURCE,
9
10
  createGuards
10
11
  } from "../chunk-EUW7JL2K.js";
11
- import "../chunk-DMJFW4KL.js";
12
+ import "../chunk-ABGN5RN2.js";
12
13
  import "../chunk-XCEN33UP.js";
13
14
  import {
14
15
  describeCliKeyRevocation,
@@ -997,10 +998,11 @@ var main = async () => {
997
998
  let macAppKeepsCodexAppCards = false;
998
999
  if (uid !== void 0) {
999
1000
  try {
1000
- const appCards = removeCodexAppCardsFromThisMac({ homeDir: homedir5(), uid, keepWhatTheMacAppTurnedOn: keepShared, dryRun });
1001
- macAppKeepsCodexAppCards = appCards === "kept_for_the_mac_app";
1001
+ const removal = { homeDir: homedir5(), uid, keepWhatTheMacAppTurnedOn: keepShared, dryRun };
1002
+ const appCards = removeCodexAppCardsFromThisMac(removal);
1003
+ macAppKeepsCodexAppCards = codexAppCardsFolderStaysOnThisMac(removal);
1002
1004
  if (appCards === "removed") console.log(` ${check} Codex app cards ${dim(did("removed"))} ${dim("(quit Codex and open it again)")}`);
1003
- if (macAppKeepsCodexAppCards) console.log(` ${skip} Codex app cards ${dim("(turned on by the Mac app; left on)")}`);
1005
+ if (appCards === "kept_for_the_mac_app") console.log(` ${skip} Codex app cards ${dim("(turned on by the Mac app; left on)")}`);
1004
1006
  } catch {
1005
1007
  incompleteClean = true;
1006
1008
  console.log(` ${cross} Codex app cards ${dim("(could not turn off; run pushary codex --app-cards off)")}`);
@@ -16,7 +16,7 @@ var desktopAccount = async () => {
16
16
  return null;
17
17
  }
18
18
  };
19
- var desktopLaunch = await import("../codex-desktop-launch-EIFLPLB7.js").catch(() => null);
19
+ var desktopLaunch = await import("../codex-desktop-launch-I2D6QATK.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-EIFLPLB7.js");
27
+ const { codexDesktopCommand } = desktopLaunch ?? await import("../codex-desktop-launch-I2D6QATK.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-DMJFW4KL.js";
58
+ } from "../chunk-ABGN5RN2.js";
59
59
  import "../chunk-XCEN33UP.js";
60
60
  import {
61
61
  CURSOR_PLUGIN_BACKUP_INFIX,
@@ -670,7 +670,8 @@ var engineWhateverTheLayout = async (app) => {
670
670
  return { engine, layoutIsKnown: false };
671
671
  }
672
672
  };
673
- var installedCodexApp = (chosen) => resolve(chosen ?? INSTALLED_CODEX_APPS.find((candidate) => existsSync(join(candidate, CODEX_ENGINE_DIRECTORY, CODEX_ENGINE_MANIFEST))) ?? INSTALLED_CODEX_APPS[1]);
673
+ var codexAppOnThisMac = () => INSTALLED_CODEX_APPS.find((candidate) => existsSync(join(candidate, CODEX_ENGINE_DIRECTORY, CODEX_ENGINE_MANIFEST))) ?? null;
674
+ var installedCodexApp = (chosen) => resolve(chosen ?? codexAppOnThisMac() ?? INSTALLED_CODEX_APPS[1]);
674
675
  var desktopExecutable = (app) => {
675
676
  const plist = join(app, "Contents/Info.plist");
676
677
  const read = (key) => execFileSync("/usr/bin/plutil", ["-extract", key, "raw", plist], { encoding: "utf8" }).trim();
@@ -694,7 +695,7 @@ var codexDesktopCommand = async (args, entry, readAccount) => {
694
695
  return runCodexDesktopProxy(engine2, args.slice(3), readAccount, { watchesForCards: layoutIsKnown });
695
696
  }
696
697
  if (args[0] === APP_CARDS_FLAG) {
697
- const { codexAppCardsCommandOnThisMac } = await import("./codex-app-cards-switch-OUQ3DUWF.js");
698
+ const { codexAppCardsCommandOnThisMac } = await import("./codex-app-cards-switch-RENOSSDD.js");
698
699
  return codexAppCardsCommandOnThisMac(args.slice(1), entry, readAccount);
699
700
  }
700
701
  if (args.length > 2) throw new Error("Usage: pushary codex --desktop [path/to/Codex.app]");
@@ -719,11 +720,13 @@ var codexDesktopCommand = async (args, entry, readAccount) => {
719
720
  export {
720
721
  shellQuoted,
721
722
  desktopEngineFromManifest,
723
+ everyProgramFileIsThere,
722
724
  desktopProxyScript,
723
725
  codexPassThroughScript,
724
726
  codexEngineBehindLauncher,
725
727
  writeDesktopProxy,
726
728
  desktopEngine,
729
+ codexAppOnThisMac,
727
730
  installedCodexApp,
728
731
  codexDesktopCommand
729
732
  };
@@ -1,10 +1,12 @@
1
1
  import {
2
+ codexAppOnThisMac,
2
3
  codexPassThroughScript,
3
4
  desktopEngine,
4
5
  desktopProxyScript,
6
+ everyProgramFileIsThere,
5
7
  installedCodexApp,
6
8
  shellQuoted
7
- } from "./chunk-DMJFW4KL.js";
9
+ } from "./chunk-ABGN5RN2.js";
8
10
  import {
9
11
  writeHuman
10
12
  } from "./chunk-QCGNGEGE.js";
@@ -28,6 +30,7 @@ var CODEX_APP_CARDS_DIRECTORY = "codex-app";
28
30
  var LAUNCHCTL = "/bin/launchctl";
29
31
  var LAUNCHER_NAME = "codex";
30
32
  var RECEIPT_NAME = "turned-on.json";
33
+ var TURNED_OFF_NAME = "turned-off";
31
34
  var PRIVATE_DIRECTORY_MODE = 448;
32
35
  var PRIVATE_PROGRAM_MODE = 448;
33
36
  var PRIVATE_FILE_MODE = 384;
@@ -42,17 +45,18 @@ var codexAppCardsPaths = (homeDir, uid) => {
42
45
  launcherDirectory,
43
46
  launcherPath: join(launcherDirectory, LAUNCHER_NAME),
44
47
  receiptPath: join(launcherDirectory, RECEIPT_NAME),
48
+ turnedOffPath: join(launcherDirectory, TURNED_OFF_NAME),
45
49
  loginItemDirectory,
46
50
  loginItemPath: join(loginItemDirectory, `${CODEX_APP_CARDS_LOGIN_ITEM}.plist`),
47
51
  loginItemTarget: `gui/${uid}/${CODEX_APP_CARDS_LOGIN_ITEM}`
48
52
  };
49
53
  };
50
- var codexAppCardsLoginScript = (launcherPath, engine) => [
51
- `if [ -x ${shellQuoted(launcherPath)} ] && [ -x ${shellQuoted(engine)} ]`,
54
+ var codexAppCardsLoginScript = (launcherPath, engine, entry) => [
55
+ `if [ -x ${shellQuoted(launcherPath)} ] && [ -x ${shellQuoted(engine)} ] && ${everyProgramFileIsThere(entry)}`,
52
56
  `&& [ -z "$(${LAUNCHCTL} getenv ${CODEX_APP_LAUNCH_VARIABLE})" ];`,
53
57
  `then ${LAUNCHCTL} setenv ${CODEX_APP_LAUNCH_VARIABLE} ${shellQuoted(launcherPath)}; fi`
54
58
  ].join(" ");
55
- var codexAppCardsLoginItem = (launcherPath, engine) => `<?xml version="1.0" encoding="UTF-8"?>
59
+ var codexAppCardsLoginItem = (launcherPath, engine, entry) => `<?xml version="1.0" encoding="UTF-8"?>
56
60
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
57
61
  <plist version="1.0">
58
62
  <dict>
@@ -62,7 +66,7 @@ var codexAppCardsLoginItem = (launcherPath, engine) => `<?xml version="1.0" enco
62
66
  <array>
63
67
  <string>/bin/sh</string>
64
68
  <string>-c</string>
65
- <string>${xml(codexAppCardsLoginScript(launcherPath, engine))}</string>
69
+ <string>${xml(codexAppCardsLoginScript(launcherPath, engine, entry))}</string>
66
70
  </array>
67
71
  <key>RunAtLoad</key>
68
72
  <true/>
@@ -87,7 +91,7 @@ var codexAppCardsInstallation = (input) => {
87
91
  return {
88
92
  paths,
89
93
  launcherScript: desktopProxyScript(input.entry, input.app, input.engine, { turnsItselfOffWithoutTheEngine: true }),
90
- loginItem: codexAppCardsLoginItem(paths.launcherPath, input.engine),
94
+ loginItem: codexAppCardsLoginItem(paths.launcherPath, input.engine, input.entry),
91
95
  receipt: { entry: input.entry, app: input.app, engine: input.engine }
92
96
  };
93
97
  };
@@ -118,6 +122,7 @@ var turnCodexAppCardsOn = (installation, machine) => {
118
122
  machine.writeFile(paths.launcherPath, installation.launcherScript, PRIVATE_PROGRAM_MODE);
119
123
  machine.writeFile(paths.receiptPath, `${JSON.stringify(installation.receipt, null, 2)}
120
124
  `, PRIVATE_FILE_MODE);
125
+ if (machine.exists(paths.turnedOffPath)) machine.remove(paths.turnedOffPath);
121
126
  machine.makeDirectory(paths.loginItemDirectory, LOGIN_ITEM_DIRECTORY_MODE);
122
127
  machine.writeFile(paths.loginItemPath, installation.loginItem, LOGIN_ITEM_MODE);
123
128
  machine.setLaunchVariable(paths.launcherPath);
@@ -142,15 +147,38 @@ var turnCodexAppCardsOff = (paths, machine) => {
142
147
  }
143
148
  return { wasOn: ours || loginItemIsThere, launchLeftToAnotherProgram: value.length > 0 && !ours ? value : null };
144
149
  };
145
- var turnedOnByTheMacApp = (receipt) => receipt !== null && receipt.entry[0].endsWith(MAC_APP_HELPER);
150
+ var rememberCodexAppCardsWereTurnedOff = (paths, machine) => {
151
+ if (machine.exists(paths.turnedOffPath)) return;
152
+ machine.makeDirectory(paths.launcherDirectory, PRIVATE_DIRECTORY_MODE);
153
+ machine.writeFile(paths.turnedOffPath, "", PRIVATE_FILE_MODE);
154
+ };
155
+ var isTheMacAppsHelper = (entry) => entry.length > 0 && entry[0].endsWith(MAC_APP_HELPER);
156
+ var turnedOnByTheMacApp = (receipt) => receipt !== null && isTheMacAppsHelper(receipt.entry);
157
+ var codexAppCardsReport = (paths, machine) => ({
158
+ status: codexAppCardsStatus(paths, machine),
159
+ codexApp: machine.codexApp(),
160
+ turnedOnByTheMacApp: turnedOnByTheMacApp(codexAppCardsReceiptFrom(machine.readFile(paths.receiptPath))),
161
+ turnedOffOnPurpose: machine.exists(paths.turnedOffPath)
162
+ });
163
+ var isKeptOnForTheMacApp = (request, paths, machine) => request.keepWhatTheMacAppTurnedOn && turnedOnByTheMacApp(codexAppCardsReceiptFrom(machine.readFile(paths.receiptPath))) && codexAppCardsStatus(paths, machine).kind !== "off";
164
+ var isKeptOffForTheMacApp = (request, paths, machine) => request.keepWhatTheMacAppTurnedOn && machine.exists(paths.turnedOffPath);
165
+ var codexAppCardsFolderStays = (request, machine) => {
166
+ const paths = codexAppCardsPaths(request.homeDir, request.uid);
167
+ return isKeptOnForTheMacApp(request, paths, machine) || isKeptOffForTheMacApp(request, paths, machine);
168
+ };
169
+ var nothingIsTurnedOn = (paths, machine) => !machine.exists(paths.launcherPath) && !machine.exists(paths.loginItemPath) && machine.launchVariable() !== paths.launcherPath;
146
170
  var removeCodexAppCards = (request, machine) => {
147
171
  const paths = codexAppCardsPaths(request.homeDir, request.uid);
148
- if (!machine.exists(paths.launcherDirectory) && !machine.exists(paths.loginItemPath)) return "absent";
149
- const keptOnForTheMacApp = request.keepWhatTheMacAppTurnedOn && turnedOnByTheMacApp(codexAppCardsReceiptFrom(machine.readFile(paths.receiptPath))) && codexAppCardsStatus(paths, machine).kind !== "off";
150
- if (keptOnForTheMacApp) return "kept_for_the_mac_app";
172
+ const keepsTheOff = isKeptOffForTheMacApp(request, paths, machine);
173
+ if (nothingIsTurnedOn(paths, machine)) {
174
+ if (!request.dryRun && !keepsTheOff && machine.exists(paths.launcherDirectory)) machine.remove(paths.launcherDirectory);
175
+ return "absent";
176
+ }
177
+ if (isKeptOnForTheMacApp(request, paths, machine)) return "kept_for_the_mac_app";
151
178
  if (request.dryRun) return "removed";
152
179
  turnCodexAppCardsOff(paths, machine);
153
180
  machine.remove(paths.launcherDirectory);
181
+ if (keepsTheOff) rememberCodexAppCardsWereTurnedOff(paths, machine);
154
182
  return "removed";
155
183
  };
156
184
  var launchctl = (args) => execFileSync(LAUNCHCTL, [...args], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
@@ -169,6 +197,7 @@ var fileContents = (path) => {
169
197
  }
170
198
  };
171
199
  var thisMacsCodexAppCardsMachine = () => ({
200
+ codexApp: codexAppOnThisMac,
172
201
  launchVariable: () => launchctlIgnoringFailure(["getenv", CODEX_APP_LAUNCH_VARIABLE]).trim(),
173
202
  setLaunchVariable: (value) => {
174
203
  launchctl(["setenv", CODEX_APP_LAUNCH_VARIABLE, value]);
@@ -192,7 +221,9 @@ var thisMacsCodexAppCardsMachine = () => ({
192
221
  }
193
222
  });
194
223
  var removeCodexAppCardsFromThisMac = (request) => removeCodexAppCards(request, thisMacsCodexAppCardsMachine());
195
- var USAGE = "Usage: pushary codex --app-cards on [path/to/Codex.app] | off | status";
224
+ var codexAppCardsFolderStaysOnThisMac = (request) => codexAppCardsFolderStays(request, thisMacsCodexAppCardsMachine());
225
+ var USAGE = "Usage: pushary codex --app-cards on [path/to/Codex.app] | off | status [--json]";
226
+ var AS_JSON = "--json";
196
227
  var TAKES_EFFECT_AFTER_REOPENING = "Quit Codex and open it again.";
197
228
  var TURN_THEM_ON_AGAIN = "Run the same command with on to repair it.";
198
229
  var runsFromATemporaryFolder = (entry) => entry.some((part) => part.includes(TEMPORARY_NPX_FOLDER));
@@ -220,17 +251,22 @@ var codexAppCardsCommand = async (args, entry, readAccount, machine, say) => {
220
251
  const uid = process.getuid?.();
221
252
  if (uid === void 0) throw new Error("Codex app cards need macOS");
222
253
  const paths = codexAppCardsPaths(homedir(), uid);
254
+ if (action === "status" && chosenApp === AS_JSON && rest.length === 0) {
255
+ say(JSON.stringify(codexAppCardsReport(paths, machine)));
256
+ return 0;
257
+ }
223
258
  if (action === "status" && chosenApp === void 0) {
224
259
  say(codexAppCardsStatusLine(codexAppCardsStatus(paths, machine)));
225
260
  return 0;
226
261
  }
227
262
  if (action === "off" && chosenApp === void 0) {
228
263
  const turnedOff = turnCodexAppCardsOff(paths, machine);
264
+ if (!isTheMacAppsHelper(entry)) rememberCodexAppCardsWereTurnedOff(paths, machine);
229
265
  say(turnedOff.wasOn ? `Codex app cards are off. ${TAKES_EFFECT_AFTER_REOPENING}` : "Codex app cards were already off.");
230
266
  if (turnedOff.launchLeftToAnotherProgram) say(ownedByAnotherProgram(turnedOff.launchLeftToAnotherProgram));
231
267
  return 0;
232
268
  }
233
- if (action !== "on" || rest.length > 0) throw new Error(USAGE);
269
+ if (action !== "on" || rest.length > 0 || chosenApp?.startsWith("--")) throw new Error(USAGE);
234
270
  if (!await readAccount()) throw new Error("Connect Pushary before turning Codex app cards on");
235
271
  const app = installedCodexApp(chosenApp);
236
272
  const engine = await desktopEngine(app);
@@ -262,8 +298,12 @@ export {
262
298
  codexAppCardsStatus,
263
299
  turnCodexAppCardsOn,
264
300
  turnCodexAppCardsOff,
301
+ rememberCodexAppCardsWereTurnedOff,
302
+ codexAppCardsReport,
303
+ codexAppCardsFolderStays,
265
304
  removeCodexAppCards,
266
305
  removeCodexAppCardsFromThisMac,
306
+ codexAppCardsFolderStaysOnThisMac,
267
307
  runsFromATemporaryFolder,
268
308
  codexAppCardsStatusLine,
269
309
  codexAppCardsCommand,
@@ -3,20 +3,24 @@ import {
3
3
  CODEX_APP_CARDS_LOGIN_ITEM,
4
4
  codexAppCardsCommand,
5
5
  codexAppCardsCommandOnThisMac,
6
+ codexAppCardsFolderStays,
7
+ codexAppCardsFolderStaysOnThisMac,
6
8
  codexAppCardsInstallation,
7
9
  codexAppCardsLoginItem,
8
10
  codexAppCardsLoginScript,
9
11
  codexAppCardsPaths,
10
12
  codexAppCardsReceiptFrom,
13
+ codexAppCardsReport,
11
14
  codexAppCardsStatus,
12
15
  codexAppCardsStatusLine,
16
+ rememberCodexAppCardsWereTurnedOff,
13
17
  removeCodexAppCards,
14
18
  removeCodexAppCardsFromThisMac,
15
19
  runsFromATemporaryFolder,
16
20
  turnCodexAppCardsOff,
17
21
  turnCodexAppCardsOn
18
- } from "./chunk-OHSHDQZF.js";
19
- import "./chunk-DMJFW4KL.js";
22
+ } from "./chunk-SUIB4O3S.js";
23
+ import "./chunk-ABGN5RN2.js";
20
24
  import "./chunk-XCEN33UP.js";
21
25
  import "./chunk-QCGNGEGE.js";
22
26
  import "./chunk-BL3WAGIK.js";
@@ -37,13 +41,17 @@ export {
37
41
  CODEX_APP_CARDS_LOGIN_ITEM,
38
42
  codexAppCardsCommand,
39
43
  codexAppCardsCommandOnThisMac,
44
+ codexAppCardsFolderStays,
45
+ codexAppCardsFolderStaysOnThisMac,
40
46
  codexAppCardsInstallation,
41
47
  codexAppCardsLoginItem,
42
48
  codexAppCardsLoginScript,
43
49
  codexAppCardsPaths,
44
50
  codexAppCardsReceiptFrom,
51
+ codexAppCardsReport,
45
52
  codexAppCardsStatus,
46
53
  codexAppCardsStatusLine,
54
+ rememberCodexAppCardsWereTurnedOff,
47
55
  removeCodexAppCards,
48
56
  removeCodexAppCardsFromThisMac,
49
57
  runsFromATemporaryFolder,
@@ -1,26 +1,30 @@
1
1
  import {
2
+ codexAppOnThisMac,
2
3
  codexDesktopCommand,
3
4
  codexEngineBehindLauncher,
4
5
  codexPassThroughScript,
5
6
  desktopEngine,
6
7
  desktopEngineFromManifest,
7
8
  desktopProxyScript,
9
+ everyProgramFileIsThere,
8
10
  installedCodexApp,
9
11
  shellQuoted,
10
12
  writeDesktopProxy
11
- } from "./chunk-DMJFW4KL.js";
13
+ } from "./chunk-ABGN5RN2.js";
12
14
  import "./chunk-XCEN33UP.js";
13
15
  import {
14
16
  CODEX_APP_LAUNCH_VARIABLE
15
17
  } from "./chunk-36NGFHE4.js";
16
18
  export {
17
19
  CODEX_APP_LAUNCH_VARIABLE,
20
+ codexAppOnThisMac,
18
21
  codexDesktopCommand,
19
22
  codexEngineBehindLauncher,
20
23
  codexPassThroughScript,
21
24
  desktopEngine,
22
25
  desktopEngineFromManifest,
23
26
  desktopProxyScript,
27
+ everyProgramFileIsThere,
24
28
  installedCodexApp,
25
29
  shellQuoted,
26
30
  writeDesktopProxy
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pushary",
3
- "version": "1.9.52",
3
+ "version": "1.9.53",
4
4
  "description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
5
5
  "keywords": [
6
6
  "pushary",