@pushary/agent-hooks 1.9.50 → 1.9.52

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 (120) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +9 -1
  3. package/dist/api-K6ZROHYB.js +55 -0
  4. package/dist/bin/pushary-bell-hook.js +28 -25
  5. package/dist/bin/pushary-bell.js +13 -11
  6. package/dist/bin/pushary-claude.js +37 -33
  7. package/dist/bin/pushary-clean.js +68 -42
  8. package/dist/bin/pushary-codex-bridge.js +23 -20
  9. package/dist/bin/pushary-codex-hook.js +36 -32
  10. package/dist/bin/pushary-codex-session.js +17 -616
  11. package/dist/bin/pushary-codex.js +15 -12
  12. package/dist/bin/pushary-connect.js +31 -28
  13. package/dist/bin/pushary-cowork.js +7 -6
  14. package/dist/bin/pushary-daemon.js +57 -52
  15. package/dist/bin/pushary-disconnect.js +29 -26
  16. package/dist/bin/pushary-doctor.js +58 -53
  17. package/dist/bin/pushary-elicitation-hook.js +29 -26
  18. package/dist/bin/pushary-gemini-bridge.js +17 -15
  19. package/dist/bin/pushary-gemini-hook.js +33 -29
  20. package/dist/bin/pushary-hook.js +34 -31
  21. package/dist/bin/pushary-login.js +19 -16
  22. package/dist/bin/pushary-logout.js +30 -27
  23. package/dist/bin/pushary-mcp.js +16 -9
  24. package/dist/bin/pushary-mode.js +16 -14
  25. package/dist/bin/pushary-notification-hook.js +27 -24
  26. package/dist/bin/pushary-opencode-hook.js +32 -28
  27. package/dist/bin/pushary-permission-denied-hook.js +32 -29
  28. package/dist/bin/pushary-permission-hook.js +31 -28
  29. package/dist/bin/pushary-post-hook.js +27 -24
  30. package/dist/bin/pushary-prompt-hook.js +27 -24
  31. package/dist/bin/pushary-session-end-hook.js +27 -24
  32. package/dist/bin/pushary-session-start-hook.js +34 -29
  33. package/dist/bin/pushary-setup.js +195 -138
  34. package/dist/bin/pushary-stats.js +8 -7
  35. package/dist/bin/pushary-status.js +35 -32
  36. package/dist/bin/pushary-stop-hook.js +27 -24
  37. package/dist/bin/pushary-stopfailure-hook.js +27 -24
  38. package/dist/bin/pushary-suggestions.js +16 -14
  39. package/dist/bin/pushary-transcript-register.js +19 -17
  40. package/dist/bin/pushary-transcripts.js +10 -9
  41. package/dist/bin/pushary-upgrade.js +76 -46
  42. package/dist/bin/pushary-wait.js +16 -14
  43. package/dist/bin/pushary.js +10 -8
  44. package/dist/{chunk-GBKSCDEK.js → chunk-2LEH5IGX.js} +17 -4
  45. package/dist/chunk-36NGFHE4.js +72 -0
  46. package/dist/{chunk-B7LV6W7U.js → chunk-3RPN7AAT.js} +1 -1
  47. package/dist/{chunk-GDDXGBTM.js → chunk-46TC24ET.js} +2 -2
  48. package/dist/{chunk-KEAIIVW3.js → chunk-4QQEUJL4.js} +2 -2
  49. package/dist/{chunk-XNZB274I.js → chunk-5463UUO2.js} +1 -1
  50. package/dist/{chunk-FPKQGWAF.js → chunk-56ZTIY6D.js} +2 -2
  51. package/dist/{chunk-34AQAQKW.js → chunk-63IQRYVP.js} +4 -4
  52. package/dist/{chunk-25SYEAW4.js → chunk-6C4S3QYD.js} +3 -3
  53. package/dist/{chunk-4PCJ6DYK.js → chunk-6SWMKF5E.js} +2 -2
  54. package/dist/{chunk-Y7WD72J7.js → chunk-7CLLWDCP.js} +1 -1
  55. package/dist/{chunk-WLT6J3SB.js → chunk-ALZZVC3E.js} +2 -2
  56. package/dist/{chunk-ZMYLVFXC.js → chunk-BL3WAGIK.js} +14 -9
  57. package/dist/{chunk-PA54A437.js → chunk-BUXDR6US.js} +1 -1
  58. package/dist/{chunk-VUS6QGND.js → chunk-CQ5JGRML.js} +5 -1
  59. package/dist/{chunk-IF2UPWD2.js → chunk-DHJSBK63.js} +1 -1
  60. package/dist/chunk-DMJFW4KL.js +729 -0
  61. package/dist/{chunk-ABMEBN2R.js → chunk-EK7SZJ4K.js} +6 -4
  62. package/dist/{chunk-VCZN7NAB.js → chunk-EPOD7QHT.js} +7 -5
  63. package/dist/{chunk-KIO2MZQC.js → chunk-FCMWUYIE.js} +5 -3
  64. package/dist/{chunk-YTYXFA5M.js → chunk-FI73DGNB.js} +1 -1
  65. package/dist/{chunk-JGNYCRB2.js → chunk-FV34HT35.js} +1 -1
  66. package/dist/{chunk-KK2DIUVV.js → chunk-GCN73COS.js} +1 -1
  67. package/dist/{chunk-KBGKWB5T.js → chunk-H57DXSHR.js} +4 -2
  68. package/dist/{chunk-SALUTWPX.js → chunk-IHUFRAHB.js} +4 -4
  69. package/dist/chunk-JBT3ZSJS.js +92 -0
  70. package/dist/{chunk-5Q2FRMPC.js → chunk-JOWF4Y4P.js} +4 -4
  71. package/dist/{chunk-EP6S6VY3.js → chunk-JPABKXK6.js} +6 -6
  72. package/dist/{chunk-LLRYP5TR.js → chunk-K23WMLPY.js} +5 -5
  73. package/dist/{chunk-34RXPM5U.js → chunk-L5YTS2BP.js} +3 -3
  74. package/dist/{chunk-SE4JFMLW.js → chunk-LD4MWJMD.js} +8 -6
  75. package/dist/{chunk-OR5F63C2.js → chunk-LF3TLC7B.js} +2 -168
  76. package/dist/{chunk-XTVEW2NG.js → chunk-LIESRXK5.js} +1 -1
  77. package/dist/{chunk-ZOKMGBPR.js → chunk-MC4VY5LK.js} +16 -5
  78. package/dist/{chunk-K73CBZKW.js → chunk-MHQB62K5.js} +4 -4
  79. package/dist/{chunk-DH4BWFU7.js → chunk-MTKV4RUQ.js} +82 -16
  80. package/dist/{chunk-Y74IJ2IO.js → chunk-N77BH7H2.js} +10 -4
  81. package/dist/{chunk-ZTTCYHOM.js → chunk-NECZKPJN.js} +31 -6
  82. package/dist/{chunk-TGCIFEDE.js → chunk-NELH25J7.js} +13 -11
  83. package/dist/{chunk-HXRH7ZCK.js → chunk-NHVEQLQC.js} +2 -2
  84. package/dist/{chunk-OW4DNSQ6.js → chunk-NSY2V7XU.js} +1 -1
  85. package/dist/chunk-OHSHDQZF.js +271 -0
  86. package/dist/{chunk-ZYYQJSIO.js → chunk-OML4YFBN.js} +44 -462
  87. package/dist/{chunk-X3RCIOIH.js → chunk-ONCWYACA.js} +1 -1
  88. package/dist/{chunk-LZYJMSOY.js → chunk-P2546BBI.js} +3 -3
  89. package/dist/{chunk-WEY5ZHDB.js → chunk-Q7OXI6VS.js} +5 -5
  90. package/dist/{chunk-APASKZ2I.js → chunk-QKU46TK5.js} +5 -3
  91. package/dist/chunk-QTOLNRET.js +169 -0
  92. package/dist/{chunk-TYTIDEBW.js → chunk-RH6KR6EH.js} +5 -5
  93. package/dist/{chunk-7RMSB4A2.js → chunk-RL7EOD6I.js} +87 -24
  94. package/dist/{chunk-BOVSUH4N.js → chunk-S6RNS4UL.js} +2 -2
  95. package/dist/{chunk-LY3OJFBW.js → chunk-T6RIKJUO.js} +2 -1
  96. package/dist/{chunk-YVO4HIHX.js → chunk-U2L42GVI.js} +12 -10
  97. package/dist/{chunk-BXK6ZJVJ.js → chunk-UVT6B6XN.js} +2 -2
  98. package/dist/{chunk-UCF3EZZL.js → chunk-VQPSWD3A.js} +13 -13
  99. package/dist/{chunk-XH3F66VD.js → chunk-VYBH6D4X.js} +3 -3
  100. package/dist/chunk-XCEN33UP.js +7 -0
  101. package/dist/{chunk-GTGXQ7FJ.js → chunk-XDCXTDHH.js} +11 -11
  102. package/dist/{chunk-OZLGTMIY.js → chunk-XSUJ2PQY.js} +2 -2
  103. package/dist/chunk-XUW2DRAQ.js +427 -0
  104. package/dist/{chunk-UHVD7BSV.js → chunk-XZRLFBEA.js} +6 -6
  105. package/dist/{chunk-AWMMABVB.js → chunk-ZMPR436Z.js} +52 -138
  106. package/dist/{chunk-PXUNPXOX.js → chunk-ZOP3I2GQ.js} +3 -3
  107. package/dist/codex-app-cards-switch-OUQ3DUWF.js +52 -0
  108. package/dist/codex-desktop-launch-EIFLPLB7.js +27 -0
  109. package/dist/codex-session-launch-KLH2FSSJ.js +331 -0
  110. package/dist/config-HX6ZNOIL.js +14 -0
  111. package/dist/{global-upgrade-AIUSS2YH.js → global-upgrade-AZN3BPI3.js} +8 -6
  112. package/dist/identity-AQIMUWYN.js +15 -0
  113. package/dist/live-capabilities-4IIFAMHU.js +53 -0
  114. package/dist/{paths-RO34TYNM.js → paths-X4IPV2WJ.js} +4 -2
  115. package/dist/{reapply-KTNPP4XE.js → reapply-CXODG53B.js} +27 -21
  116. package/dist/src/index.d.ts +3 -3
  117. package/dist/src/index.js +22 -19
  118. package/dist/{upgrade-lock-5UAGXIW7.js → upgrade-lock-AHISGKER.js} +5 -3
  119. package/dist/usage-ZC6BKIE3.js +10 -0
  120. package/package.json +1 -1
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  MCP_BRIDGE_BINARY
3
- } from "./chunk-GDDXGBTM.js";
3
+ } from "./chunk-46TC24ET.js";
4
4
  import {
5
5
  KEY_FILE_MODE
6
- } from "./chunk-XH3F66VD.js";
6
+ } from "./chunk-VYBH6D4X.js";
7
7
  import {
8
8
  NpmInstallError,
9
9
  NpmMissingError,
10
10
  NpmPermissionError
11
- } from "./chunk-ZYYQJSIO.js";
11
+ } from "./chunk-XUW2DRAQ.js";
12
12
  import {
13
13
  readJsonSafe,
14
14
  writeFileAtomic,
@@ -16,13 +16,13 @@ import {
16
16
  } from "./chunk-AQFEP65J.js";
17
17
  import {
18
18
  NPX_LATEST_COMMAND
19
- } from "./chunk-ZOKMGBPR.js";
19
+ } from "./chunk-MC4VY5LK.js";
20
20
  import {
21
21
  readSetupAgentFailures
22
- } from "./chunk-OR5F63C2.js";
22
+ } from "./chunk-LF3TLC7B.js";
23
23
 
24
24
  // src/instruction-file.ts
25
- import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync } from "fs";
25
+ import { accessSync, constants, existsSync, readFileSync, statSync, writeFileSync, mkdirSync, rmSync } from "fs";
26
26
  import { dirname } from "path";
27
27
  var PUSHARY_BEGIN = "<!-- BEGIN PUSHARY (managed by @pushary/agent-hooks; do not edit this block) -->";
28
28
  var PUSHARY_END = "<!-- END PUSHARY -->";
@@ -44,6 +44,9 @@ You have Pushary MCP tools that reach the user on their phone. Use them proactiv
44
44
 
45
45
  Pass \`agentName\` as "${label} - <project folder name>" so the user knows which session is asking. If a question times out, follow \`handoffAction\` when present, otherwise \`nextAction\`: keep waiting with the same correlationId while pending. A poll ending is not question expiry. Cancel only for an explicit handoff or when the answer is no longer needed. If cancellation returns \`handoffAction: "stop"\`, stop. Otherwise, if cancellation returns false, poll once for 1 second and honor the answer that won the race.`;
46
46
  var SHARED_AGENTS_MD_LABEL = "<your agent's name, such as Codex or Hermes>";
47
+ var CODEX_INSTRUCTIONS_LABEL = "Codex";
48
+ var GEMINI_INSTRUCTIONS_LABEL = "Gemini";
49
+ var OPENCODE_INSTRUCTIONS_LABEL = "OpenCode";
47
50
  var renderAgentInstructions = (label) => instructionBody(label);
48
51
  var KEYLESS_FALLBACK_LINE = "This repo uses Pushary phone approvals. Your teammates get agent questions on their lock screens; you do not have a key yet, so questions will fall back to the terminal. Get your own key (3-day trial): https://pushary.com/sign-up?utm_source=agents-md&utm_medium=teammate";
49
52
  var renderProjectAgentInstructions = (label) => `${instructionBody(label)}
@@ -52,6 +55,19 @@ If this environment has no Pushary API key (no PUSHARY_API_KEY and no key in ~/.
52
55
  var wrap = (body) => `${PUSHARY_BEGIN}
53
56
  ${body}
54
57
  ${PUSHARY_END}`;
58
+ var withInstructionBlockAppended = (existing, body) => {
59
+ const prefix = existing.trim() ? existing.replace(/\s*$/, "") + "\n\n" : "";
60
+ return prefix + wrap(body) + "\n";
61
+ };
62
+ var managedBlockRange = (text) => {
63
+ const start = text.indexOf(PUSHARY_BEGIN);
64
+ const end = text.indexOf(PUSHARY_END);
65
+ return start !== -1 && end > start ? { start, end: end + PUSHARY_END.length } : null;
66
+ };
67
+ var withInstructionBlockReplaced = (existing, body) => {
68
+ const range = managedBlockRange(existing);
69
+ return range ? existing.slice(0, range.start) + wrap(body) + existing.slice(range.end) : null;
70
+ };
55
71
  var writeInstructionBlock = (filePath, body) => {
56
72
  const dir = dirname(filePath);
57
73
  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
@@ -60,17 +76,53 @@ var writeInstructionBlock = (filePath, body) => {
60
76
  existing = readFileSync(filePath, "utf-8");
61
77
  } catch {
62
78
  }
63
- const block = wrap(body);
64
- const start = existing.indexOf(PUSHARY_BEGIN);
65
- const end = existing.indexOf(PUSHARY_END);
66
- let next;
67
- if (start !== -1 && end !== -1 && end > start) {
68
- next = existing.slice(0, start) + block + existing.slice(end + PUSHARY_END.length);
69
- } else {
70
- const prefix = existing.trim() ? existing.replace(/\s*$/, "") + "\n\n" : "";
71
- next = prefix + block + "\n";
79
+ writeFileSync(filePath, withInstructionBlockReplaced(existing, body) ?? withInstructionBlockAppended(existing, body), "utf-8");
80
+ };
81
+ var occurrencesOf = (marker, text) => text.split(marker).length - 1;
82
+ var soleManagedBlock = (text) => {
83
+ const begins = occurrencesOf(PUSHARY_BEGIN, text);
84
+ const ends = occurrencesOf(PUSHARY_END, text);
85
+ if (begins === 0 && ends === 0) return { kind: "none" };
86
+ const range = managedBlockRange(text);
87
+ return begins === 1 && ends === 1 && range ? { kind: "one", range } : { kind: "ambiguous" };
88
+ };
89
+ var CRLF = "\r\n";
90
+ var withLineEndingsOf = (sample, block) => sample.includes(CRLF) ? block.replaceAll("\n", CRLF) : block;
91
+ var readUtf8 = (filePath) => {
92
+ try {
93
+ const bytes = readFileSync(filePath);
94
+ const text = bytes.toString("utf-8");
95
+ return Buffer.from(text, "utf-8").equals(bytes) ? { kind: "text", text } : { kind: "not_utf8" };
96
+ } catch {
97
+ return { kind: "unreadable" };
98
+ }
99
+ };
100
+ var isWritable = (filePath) => {
101
+ try {
102
+ accessSync(filePath, constants.W_OK);
103
+ return true;
104
+ } catch {
105
+ return false;
106
+ }
107
+ };
108
+ var refreshInstructionBlock = (filePath, body) => {
109
+ if (!existsSync(filePath)) return "absent";
110
+ const read = readUtf8(filePath);
111
+ if (read.kind !== "text") return read.kind;
112
+ const block = soleManagedBlock(read.text);
113
+ if (block.kind === "none") return "absent";
114
+ if (block.kind === "ambiguous") return "ambiguous_markers";
115
+ const existing = read.text.slice(block.range.start, block.range.end);
116
+ const fresh = withLineEndingsOf(existing, wrap(body));
117
+ if (existing === fresh) return "current";
118
+ if (!isWritable(filePath)) return "read_only";
119
+ try {
120
+ const refreshed = read.text.slice(0, block.range.start) + fresh + read.text.slice(block.range.end);
121
+ writeFileAtomic(filePath, refreshed, statSync(filePath).mode & 511);
122
+ return "refreshed";
123
+ } catch {
124
+ return "write_failed";
72
125
  }
73
- writeFileSync(filePath, next, "utf-8");
74
126
  };
75
127
  var removeInstructionBlock = (filePath) => {
76
128
  let existing = "";
@@ -550,6 +602,7 @@ var agentFailureWire = (failures) => readSetupAgentFailures(failures);
550
602
 
551
603
  // src/fx-lifecycle.ts
552
604
  import { existsSync as existsSync3 } from "fs";
605
+ import { join } from "path";
553
606
  var fxRetryHint = () => `Fix it, then run ${retryAgentCommand("fx")}.`;
554
607
  var readFxProfileForSetup = (filePath) => {
555
608
  const read = readFxFile(filePath, readFxProfile);
@@ -571,6 +624,13 @@ var writeFxProfile = (filePath, profile) => {
571
624
  }
572
625
  writeFileAtomic(filePath, rendered.text, KEY_FILE_MODE);
573
626
  };
627
+ var macAppFxBridge = (pusharyDir) => join(pusharyDir, "bin", MCP_BRIDGE_BINARY);
628
+ var fxServerHolder = (profilePath, appBridge) => {
629
+ const read = readFxFile(profilePath, readFxProfile);
630
+ const entry = read.kind === "profile" ? fxPusharyEntryOf(read.profile) : void 0;
631
+ if (!isFxPusharyEntry(entry)) return "none";
632
+ return fxBridgeTargetOf(entry) === appBridge ? "app" : "cli";
633
+ };
574
634
  var fxSettingsReadRefusal = (filePath, read) => {
575
635
  if (read.kind === "unreadable") return `${filePath} could not be read`;
576
636
  if (read.kind === "refused") return `${filePath} ${FX_SETTINGS_REFUSALS[read.reason]}`;
@@ -665,9 +725,13 @@ var planFxRemoval = (profilePath, settingsPath, receiptPath) => {
665
725
 
666
726
  export {
667
727
  SHARED_AGENTS_MD_LABEL,
728
+ CODEX_INSTRUCTIONS_LABEL,
729
+ GEMINI_INSTRUCTIONS_LABEL,
730
+ OPENCODE_INSTRUCTIONS_LABEL,
668
731
  renderAgentInstructions,
669
732
  renderProjectAgentInstructions,
670
733
  writeInstructionBlock,
734
+ refreshInstructionBlock,
671
735
  removeInstructionBlock,
672
736
  hasInstructionBlock,
673
737
  FX_PUSHARY_TOOLS_RULE,
@@ -691,6 +755,8 @@ export {
691
755
  agentFailureWire,
692
756
  readFxProfileForSetup,
693
757
  writeFxProfile,
758
+ macAppFxBridge,
759
+ fxServerHolder,
694
760
  configureFxSettings,
695
761
  inspectFxInstallation,
696
762
  planFxRemoval
@@ -3,19 +3,20 @@ import {
3
3
  addGeminiMcpServer,
4
4
  removeGeminiMcpServer,
5
5
  supportedClaudeEvents
6
- } from "./chunk-25SYEAW4.js";
6
+ } from "./chunk-6C4S3QYD.js";
7
7
  import {
8
8
  CLAUDE_CODE_AGENT,
9
9
  compatibleToolLookup
10
- } from "./chunk-YVO4HIHX.js";
10
+ } from "./chunk-U2L42GVI.js";
11
11
  import {
12
12
  guardBinary,
13
13
  guardBinaryRefusing,
14
14
  holdBudgetOf,
15
15
  isProtectedByScope,
16
16
  registerHookEntry
17
- } from "./chunk-ZYYQJSIO.js";
17
+ } from "./chunk-OML4YFBN.js";
18
18
  import {
19
+ HOOK_COMPATIBLE_PROFILES,
19
20
  HOOK_LOCATOR_BINARY,
20
21
  PHONE_ANSWERED_TOOLS,
21
22
  compatibleTargetFiles,
@@ -25,7 +26,7 @@ import {
25
26
  pusharyMissingReason,
26
27
  refusalOutput,
27
28
  withHookHoldBudget
28
- } from "./chunk-OR5F63C2.js";
29
+ } from "./chunk-LF3TLC7B.js";
29
30
 
30
31
  // src/claude-config.ts
31
32
  import { join } from "path";
@@ -280,6 +281,10 @@ var compatibleDocuments = (profile, home) => {
280
281
  }
281
282
  return documents;
282
283
  };
284
+ var compatibleRecord = (of) => HOOK_COMPATIBLE_PROFILES.reduce(
285
+ (record, profile) => ({ ...record, [profile.agentType]: of(profile) }),
286
+ {}
287
+ );
283
288
  var compatibleTargetPaths = (profile, home) => compatibleTargetFiles(profile).map((file) => compatibleFilePath(file, home));
284
289
  var compatibleConfigFile = (profile, home) => compatibleFilePath(profile.configFile, home);
285
290
  var compatibleMcpFile = (profile, home) => profile.mcp ? compatibleFilePath(profile.mcp.file, home) : null;
@@ -489,6 +494,7 @@ export {
489
494
  grokHome,
490
495
  compatibleFilePath,
491
496
  compatibleDocuments,
497
+ compatibleRecord,
492
498
  compatibleTargetPaths,
493
499
  compatibleConfigFile,
494
500
  compatibleMcpFile,
@@ -4,7 +4,7 @@ import {
4
4
  forkFinishWithUpgradeLock,
5
5
  installWithUpgradeLock,
6
6
  releaseAutoUpdateLock
7
- } from "./chunk-KBGKWB5T.js";
7
+ } from "./chunk-H57DXSHR.js";
8
8
  import {
9
9
  describeAutoUpdateCheck,
10
10
  globalInstallLocation,
@@ -14,23 +14,25 @@ import {
14
14
  readAutoUpdateState,
15
15
  updateAutoUpdateState,
16
16
  upgradeEntryFor
17
- } from "./chunk-APASKZ2I.js";
17
+ } from "./chunk-QKU46TK5.js";
18
18
  import {
19
19
  EXIT
20
20
  } from "./chunk-KZERVKTD.js";
21
21
  import {
22
22
  autoUpdateLock,
23
23
  autoUpdateLog,
24
- autoUpdateState,
24
+ autoUpdateState
25
+ } from "./chunk-OML4YFBN.js";
26
+ import {
25
27
  execNpm,
26
28
  fetchLatestPublishedVersion,
27
29
  npmErrorMessage,
28
30
  readGlobalCliInstallAt,
29
31
  readGlobalPrefix
30
- } from "./chunk-ZYYQJSIO.js";
32
+ } from "./chunk-XUW2DRAQ.js";
31
33
  import {
32
34
  NPX_LATEST_COMMAND
33
- } from "./chunk-ZOKMGBPR.js";
35
+ } from "./chunk-MC4VY5LK.js";
34
36
  import {
35
37
  commandsPackage,
36
38
  globalUpgradeEntry,
@@ -39,7 +41,7 @@ import {
39
41
  isSameMajorVersion,
40
42
  ownPackageRoot,
41
43
  packageVersionAt
42
- } from "./chunk-OR5F63C2.js";
44
+ } from "./chunk-QTOLNRET.js";
43
45
 
44
46
  // src/global-upgrade.ts
45
47
  import { existsSync } from "fs";
@@ -50,6 +52,26 @@ import { dirname } from "path";
50
52
 
51
53
  // src/upgrade-finish.ts
52
54
  var FINISHED_UPGRADE = { kind: "finished" };
55
+ var refreshedPartsOf = (agent) => [
56
+ ...agent.result.hooks ? ["hooks"] : [],
57
+ ...agent.result.mcp ? ["MCP key"] : [],
58
+ ...agent.instructions?.outcome === "refreshed" ? ["instructions"] : []
59
+ ];
60
+ var wasRefreshed = (agent) => refreshedPartsOf(agent).length > 0;
61
+ var INSTRUCTIONS_LEFT_BECAUSE = {
62
+ refreshed: null,
63
+ current: null,
64
+ absent: null,
65
+ read_only: "the file is read-only",
66
+ ambiguous_markers: "its Pushary markers do not form exactly one block",
67
+ not_utf8: "the file is not UTF-8 text",
68
+ unreadable: "the file could not be read",
69
+ write_failed: "the file could not be written"
70
+ };
71
+ var instructionsLeftNoteOf = (agent) => {
72
+ const reason = agent.instructions ? INSTRUCTIONS_LEFT_BECAUSE[agent.instructions.outcome] : null;
73
+ return agent.instructions && reason ? `${agent.instructions.file}: ${reason}` : null;
74
+ };
53
75
  var RETRYABLE_UPGRADE_FINISH = { kind: "retryable" };
54
76
  var SETTLED_UPGRADE_FINISH = { kind: "settled" };
55
77
  var controlWaitsOnThePerson = (readings) => readings.controlPolicy === "legacy" || readings.controlMode === "on" && readings.controlPolicy === "unsupported";
@@ -273,6 +295,9 @@ var upgradeInstalledPackage = async (subject, effects) => {
273
295
  };
274
296
 
275
297
  export {
298
+ refreshedPartsOf,
299
+ wasRefreshed,
300
+ instructionsLeftNoteOf,
276
301
  upgradeFinishOutcome,
277
302
  upgradeFinishExitCode,
278
303
  FINISH_UPGRADE_FLAG,
@@ -4,19 +4,19 @@ import {
4
4
  outcomeOfFailedAsk,
5
5
  reportMachineDenial,
6
6
  storedWaitDeadline
7
- } from "./chunk-EP6S6VY3.js";
7
+ } from "./chunk-JPABKXK6.js";
8
8
  import {
9
9
  isGatingMoment,
10
10
  recordKeylessMoment
11
- } from "./chunk-Y7WD72J7.js";
11
+ } from "./chunk-7CLLWDCP.js";
12
12
  import {
13
13
  isDeferAnswer,
14
14
  oncePerSession
15
- } from "./chunk-IF2UPWD2.js";
15
+ } from "./chunk-DHJSBK63.js";
16
16
  import {
17
17
  activeHookSource,
18
18
  activeIdentity
19
- } from "./chunk-Y74IJ2IO.js";
19
+ } from "./chunk-N77BH7H2.js";
20
20
  import {
21
21
  DEFAULT_SESSION,
22
22
  UNNAMED_ACTION,
@@ -40,7 +40,10 @@ import {
40
40
  reportEvent,
41
41
  scopePathFor,
42
42
  settleQuestionsForToolUse
43
- } from "./chunk-YVO4HIHX.js";
43
+ } from "./chunk-U2L42GVI.js";
44
+ import {
45
+ repoKeyFor
46
+ } from "./chunk-JBT3ZSJS.js";
44
47
  import {
45
48
  askUser,
46
49
  cancelQuestion,
@@ -49,22 +52,21 @@ import {
49
52
  isDecisionStopped,
50
53
  isLocalQuestionHandoff,
51
54
  pollForAnswer,
52
- repoKeyFor,
53
55
  requestGate,
54
56
  sendNotification,
55
57
  waitForQuestion,
56
58
  waitsForThePhone
57
- } from "./chunk-AWMMABVB.js";
59
+ } from "./chunk-ZMPR436Z.js";
58
60
  import {
59
61
  getMachineId
60
- } from "./chunk-LY3OJFBW.js";
62
+ } from "./chunk-T6RIKJUO.js";
61
63
  import {
62
64
  getApiKey,
63
65
  getBaseUrl
64
- } from "./chunk-VUS6QGND.js";
66
+ } from "./chunk-CQ5JGRML.js";
65
67
  import {
66
68
  NPX_LATEST_COMMAND
67
- } from "./chunk-ZOKMGBPR.js";
69
+ } from "./chunk-MC4VY5LK.js";
68
70
  import {
69
71
  AGENT_QUESTION_STRATEGY,
70
72
  AGENT_QUESTION_TOOL,
@@ -109,7 +111,7 @@ import {
109
111
  resolveGate,
110
112
  timeoutActionWithoutLocalPrompt,
111
113
  unansweredRefusalReason
112
- } from "./chunk-OR5F63C2.js";
114
+ } from "./chunk-LF3TLC7B.js";
113
115
 
114
116
  // src/claude-permission-rules.ts
115
117
  import { readFileSync, statSync } from "fs";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  CODEX_HOOK_STATUS
3
- } from "./chunk-KIO2MZQC.js";
3
+ } from "./chunk-FCMWUYIE.js";
4
4
  import {
5
5
  NPX_LATEST_COMMAND
6
- } from "./chunk-ZOKMGBPR.js";
6
+ } from "./chunk-MC4VY5LK.js";
7
7
 
8
8
  // src/setup/codex-trust.ts
9
9
  var CODEX_TRUST_TELEMETRY = {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  HOOK_HOLD_BUDGET_ENV,
3
3
  hookHoldBudgetProof
4
- } from "./chunk-OR5F63C2.js";
4
+ } from "./chunk-LF3TLC7B.js";
5
5
 
6
6
  // src/hold-budget.ts
7
7
  var takeHookHoldBudget = (args = process.argv.slice(2), env = process.env) => {
@@ -0,0 +1,271 @@
1
+ import {
2
+ codexPassThroughScript,
3
+ desktopEngine,
4
+ desktopProxyScript,
5
+ installedCodexApp,
6
+ shellQuoted
7
+ } from "./chunk-DMJFW4KL.js";
8
+ import {
9
+ writeHuman
10
+ } from "./chunk-QCGNGEGE.js";
11
+ import {
12
+ xml
13
+ } from "./chunk-BL3WAGIK.js";
14
+ import {
15
+ CODEX_APP_LAUNCH_VARIABLE
16
+ } from "./chunk-36NGFHE4.js";
17
+ import {
18
+ writeFileAtomic
19
+ } from "./chunk-AQFEP65J.js";
20
+
21
+ // src/codex-app-cards-switch.ts
22
+ import { execFileSync } from "child_process";
23
+ import { existsSync, mkdirSync, readFileSync, rmSync } from "fs";
24
+ import { homedir } from "os";
25
+ import { join } from "path";
26
+ var CODEX_APP_CARDS_LOGIN_ITEM = "com.pushary.codex-app-cards";
27
+ var CODEX_APP_CARDS_DIRECTORY = "codex-app";
28
+ var LAUNCHCTL = "/bin/launchctl";
29
+ var LAUNCHER_NAME = "codex";
30
+ var RECEIPT_NAME = "turned-on.json";
31
+ var PRIVATE_DIRECTORY_MODE = 448;
32
+ var PRIVATE_PROGRAM_MODE = 448;
33
+ var PRIVATE_FILE_MODE = 384;
34
+ var LOGIN_ITEM_DIRECTORY_MODE = 493;
35
+ var LOGIN_ITEM_MODE = 420;
36
+ var MAC_APP_HELPER = "/Contents/Helpers/pushary-native-transcripts";
37
+ var TEMPORARY_NPX_FOLDER = "/_npx/";
38
+ var codexAppCardsPaths = (homeDir, uid) => {
39
+ const launcherDirectory = join(homeDir, ".pushary", CODEX_APP_CARDS_DIRECTORY);
40
+ const loginItemDirectory = join(homeDir, "Library", "LaunchAgents");
41
+ return {
42
+ launcherDirectory,
43
+ launcherPath: join(launcherDirectory, LAUNCHER_NAME),
44
+ receiptPath: join(launcherDirectory, RECEIPT_NAME),
45
+ loginItemDirectory,
46
+ loginItemPath: join(loginItemDirectory, `${CODEX_APP_CARDS_LOGIN_ITEM}.plist`),
47
+ loginItemTarget: `gui/${uid}/${CODEX_APP_CARDS_LOGIN_ITEM}`
48
+ };
49
+ };
50
+ var codexAppCardsLoginScript = (launcherPath, engine) => [
51
+ `if [ -x ${shellQuoted(launcherPath)} ] && [ -x ${shellQuoted(engine)} ]`,
52
+ `&& [ -z "$(${LAUNCHCTL} getenv ${CODEX_APP_LAUNCH_VARIABLE})" ];`,
53
+ `then ${LAUNCHCTL} setenv ${CODEX_APP_LAUNCH_VARIABLE} ${shellQuoted(launcherPath)}; fi`
54
+ ].join(" ");
55
+ var codexAppCardsLoginItem = (launcherPath, engine) => `<?xml version="1.0" encoding="UTF-8"?>
56
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
57
+ <plist version="1.0">
58
+ <dict>
59
+ <key>Label</key>
60
+ <string>${CODEX_APP_CARDS_LOGIN_ITEM}</string>
61
+ <key>ProgramArguments</key>
62
+ <array>
63
+ <string>/bin/sh</string>
64
+ <string>-c</string>
65
+ <string>${xml(codexAppCardsLoginScript(launcherPath, engine))}</string>
66
+ </array>
67
+ <key>RunAtLoad</key>
68
+ <true/>
69
+ </dict>
70
+ </plist>
71
+ `;
72
+ var isAString = (value) => typeof value === "string";
73
+ var codexAppCardsReceiptFrom = (contents) => {
74
+ if (contents === null) return null;
75
+ let parsed;
76
+ try {
77
+ parsed = JSON.parse(contents);
78
+ } catch {
79
+ return null;
80
+ }
81
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return null;
82
+ const { entry, app, engine } = parsed;
83
+ return Array.isArray(entry) && entry.length > 0 && entry.every(isAString) && isAString(app) && isAString(engine) ? { entry, app, engine } : null;
84
+ };
85
+ var codexAppCardsInstallation = (input) => {
86
+ const paths = codexAppCardsPaths(input.homeDir, input.uid);
87
+ return {
88
+ paths,
89
+ launcherScript: desktopProxyScript(input.entry, input.app, input.engine, { turnsItselfOffWithoutTheEngine: true }),
90
+ loginItem: codexAppCardsLoginItem(paths.launcherPath, input.engine),
91
+ receipt: { entry: input.entry, app: input.app, engine: input.engine }
92
+ };
93
+ };
94
+ var isAbsolutePath = (value) => value.startsWith("/");
95
+ var whatTheLauncherCannotRun = (receipt, machine) => {
96
+ if (receipt === null) return null;
97
+ if (!machine.exists(receipt.engine)) return { kind: "on_but_the_codex_engine_moved", engine: receipt.engine };
98
+ const missing = receipt.entry.filter(isAbsolutePath).find((path) => !machine.exists(path));
99
+ return missing === void 0 ? null : { kind: "on_but_pushary_is_missing", missing };
100
+ };
101
+ var codexAppCardsStatus = (paths, machine) => {
102
+ const value = machine.launchVariable();
103
+ if (value.length > 0 && value !== paths.launcherPath) return { kind: "another_program_owns_the_launch", value };
104
+ const launcherIsThere = machine.exists(paths.launcherPath);
105
+ const setForThisLogin = value === paths.launcherPath && launcherIsThere;
106
+ const setAtEveryLogin = launcherIsThere && machine.exists(paths.loginItemPath);
107
+ if (!setForThisLogin && !setAtEveryLogin) return { kind: "off" };
108
+ const cannotRun = whatTheLauncherCannotRun(codexAppCardsReceiptFrom(machine.readFile(paths.receiptPath)), machine);
109
+ if (cannotRun) return cannotRun;
110
+ if (setForThisLogin && setAtEveryLogin) return { kind: "on" };
111
+ return setForThisLogin ? { kind: "on_until_logout" } : { kind: "on_after_next_login" };
112
+ };
113
+ var turnCodexAppCardsOn = (installation, machine) => {
114
+ const { paths } = installation;
115
+ const value = machine.launchVariable();
116
+ if (value.length > 0 && value !== paths.launcherPath) return { kind: "another_program_owns_the_launch", value };
117
+ machine.makeDirectory(paths.launcherDirectory, PRIVATE_DIRECTORY_MODE);
118
+ machine.writeFile(paths.launcherPath, installation.launcherScript, PRIVATE_PROGRAM_MODE);
119
+ machine.writeFile(paths.receiptPath, `${JSON.stringify(installation.receipt, null, 2)}
120
+ `, PRIVATE_FILE_MODE);
121
+ machine.makeDirectory(paths.loginItemDirectory, LOGIN_ITEM_DIRECTORY_MODE);
122
+ machine.writeFile(paths.loginItemPath, installation.loginItem, LOGIN_ITEM_MODE);
123
+ machine.setLaunchVariable(paths.launcherPath);
124
+ return { kind: "on" };
125
+ };
126
+ var leaveOnlyThePathToTheEngine = (paths, machine) => {
127
+ const receipt = codexAppCardsReceiptFrom(machine.readFile(paths.receiptPath));
128
+ const launcher = machine.readFile(paths.launcherPath);
129
+ if (receipt === null || launcher === null) return;
130
+ const onlyThePathToTheEngine = codexPassThroughScript(receipt.engine);
131
+ if (launcher !== onlyThePathToTheEngine) machine.writeFile(paths.launcherPath, onlyThePathToTheEngine, PRIVATE_PROGRAM_MODE);
132
+ };
133
+ var turnCodexAppCardsOff = (paths, machine) => {
134
+ const value = machine.launchVariable();
135
+ const ours = value === paths.launcherPath;
136
+ const loginItemIsThere = machine.exists(paths.loginItemPath);
137
+ leaveOnlyThePathToTheEngine(paths, machine);
138
+ if (ours) machine.unsetLaunchVariable();
139
+ if (loginItemIsThere) {
140
+ machine.unloadLoginItem(paths.loginItemTarget);
141
+ machine.remove(paths.loginItemPath);
142
+ }
143
+ return { wasOn: ours || loginItemIsThere, launchLeftToAnotherProgram: value.length > 0 && !ours ? value : null };
144
+ };
145
+ var turnedOnByTheMacApp = (receipt) => receipt !== null && receipt.entry[0].endsWith(MAC_APP_HELPER);
146
+ var removeCodexAppCards = (request, machine) => {
147
+ 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";
151
+ if (request.dryRun) return "removed";
152
+ turnCodexAppCardsOff(paths, machine);
153
+ machine.remove(paths.launcherDirectory);
154
+ return "removed";
155
+ };
156
+ var launchctl = (args) => execFileSync(LAUNCHCTL, [...args], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
157
+ var launchctlIgnoringFailure = (args) => {
158
+ try {
159
+ return launchctl(args);
160
+ } catch {
161
+ return "";
162
+ }
163
+ };
164
+ var fileContents = (path) => {
165
+ try {
166
+ return readFileSync(path, "utf8");
167
+ } catch {
168
+ return null;
169
+ }
170
+ };
171
+ var thisMacsCodexAppCardsMachine = () => ({
172
+ launchVariable: () => launchctlIgnoringFailure(["getenv", CODEX_APP_LAUNCH_VARIABLE]).trim(),
173
+ setLaunchVariable: (value) => {
174
+ launchctl(["setenv", CODEX_APP_LAUNCH_VARIABLE, value]);
175
+ },
176
+ unsetLaunchVariable: () => {
177
+ launchctl(["unsetenv", CODEX_APP_LAUNCH_VARIABLE]);
178
+ },
179
+ unloadLoginItem: (target) => {
180
+ launchctlIgnoringFailure(["bootout", target]);
181
+ },
182
+ exists: existsSync,
183
+ readFile: fileContents,
184
+ makeDirectory: (path, mode) => {
185
+ mkdirSync(path, { recursive: true, mode });
186
+ },
187
+ writeFile: (path, contents, mode) => {
188
+ writeFileAtomic(path, contents, mode);
189
+ },
190
+ remove: (path) => {
191
+ rmSync(path, { recursive: true, force: true });
192
+ }
193
+ });
194
+ var removeCodexAppCardsFromThisMac = (request) => removeCodexAppCards(request, thisMacsCodexAppCardsMachine());
195
+ var USAGE = "Usage: pushary codex --app-cards on [path/to/Codex.app] | off | status";
196
+ var TAKES_EFFECT_AFTER_REOPENING = "Quit Codex and open it again.";
197
+ var TURN_THEM_ON_AGAIN = "Run the same command with on to repair it.";
198
+ var runsFromATemporaryFolder = (entry) => entry.some((part) => part.includes(TEMPORARY_NPX_FOLDER));
199
+ var ownedByAnotherProgram = (value) => `Another program already starts the Codex app through ${value}. Pushary did not change it.`;
200
+ var codexAppCardsStatusLine = (status) => {
201
+ switch (status.kind) {
202
+ case "on":
203
+ return "Codex app cards are on.";
204
+ case "off":
205
+ return "Codex app cards are off.";
206
+ case "on_until_logout":
207
+ return "Codex app cards are on until you log out. Turn them on again to keep them on.";
208
+ case "on_after_next_login":
209
+ return "Codex app cards start the next time you log in. Turn them on again to start now.";
210
+ case "on_but_pushary_is_missing":
211
+ return `Codex app cards are on, but no card can reach Pushary: ${status.missing} is gone. Codex itself works. ${TURN_THEM_ON_AGAIN}`;
212
+ case "on_but_the_codex_engine_moved":
213
+ return `Codex app cards are on, but the Codex engine is no longer at ${status.engine}. ${TURN_THEM_ON_AGAIN}`;
214
+ case "another_program_owns_the_launch":
215
+ return ownedByAnotherProgram(status.value);
216
+ }
217
+ };
218
+ var codexAppCardsCommand = async (args, entry, readAccount, machine, say) => {
219
+ const [action, chosenApp, ...rest] = args;
220
+ const uid = process.getuid?.();
221
+ if (uid === void 0) throw new Error("Codex app cards need macOS");
222
+ const paths = codexAppCardsPaths(homedir(), uid);
223
+ if (action === "status" && chosenApp === void 0) {
224
+ say(codexAppCardsStatusLine(codexAppCardsStatus(paths, machine)));
225
+ return 0;
226
+ }
227
+ if (action === "off" && chosenApp === void 0) {
228
+ const turnedOff = turnCodexAppCardsOff(paths, machine);
229
+ say(turnedOff.wasOn ? `Codex app cards are off. ${TAKES_EFFECT_AFTER_REOPENING}` : "Codex app cards were already off.");
230
+ if (turnedOff.launchLeftToAnotherProgram) say(ownedByAnotherProgram(turnedOff.launchLeftToAnotherProgram));
231
+ return 0;
232
+ }
233
+ if (action !== "on" || rest.length > 0) throw new Error(USAGE);
234
+ if (!await readAccount()) throw new Error("Connect Pushary before turning Codex app cards on");
235
+ const app = installedCodexApp(chosenApp);
236
+ const engine = await desktopEngine(app);
237
+ const turnedOn = turnCodexAppCardsOn(codexAppCardsInstallation({ homeDir: homedir(), uid, entry, app, engine }), machine);
238
+ if (turnedOn.kind === "another_program_owns_the_launch") {
239
+ say(ownedByAnotherProgram(turnedOn.value));
240
+ return 1;
241
+ }
242
+ say(`Codex app cards are on. ${TAKES_EFFECT_AFTER_REOPENING}`);
243
+ say("From then on, when Codex asks to use an app on this Mac, the question also reaches Pushary. Everything else in Codex stays as it is.");
244
+ say("Turn them off by running the same command with off.");
245
+ if (runsFromATemporaryFolder(entry)) say("This copy of Pushary runs from a temporary npx folder. If that folder is cleared, the cards stop reaching Pushary and Codex keeps working. Install Pushary with npm install -g pushary and turn them on again to make it last.");
246
+ return 0;
247
+ };
248
+ var sayToThePerson = (line) => {
249
+ writeHuman(`${line}
250
+ `);
251
+ };
252
+ var codexAppCardsCommandOnThisMac = (args, entry, readAccount) => codexAppCardsCommand(args, entry, readAccount, thisMacsCodexAppCardsMachine(), sayToThePerson);
253
+
254
+ export {
255
+ CODEX_APP_CARDS_LOGIN_ITEM,
256
+ CODEX_APP_CARDS_DIRECTORY,
257
+ codexAppCardsPaths,
258
+ codexAppCardsLoginScript,
259
+ codexAppCardsLoginItem,
260
+ codexAppCardsReceiptFrom,
261
+ codexAppCardsInstallation,
262
+ codexAppCardsStatus,
263
+ turnCodexAppCardsOn,
264
+ turnCodexAppCardsOff,
265
+ removeCodexAppCards,
266
+ removeCodexAppCardsFromThisMac,
267
+ runsFromATemporaryFolder,
268
+ codexAppCardsStatusLine,
269
+ codexAppCardsCommand,
270
+ codexAppCardsCommandOnThisMac
271
+ };