@pushary/agent-hooks 0.70.0 → 0.71.0

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,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.71.0
4
+
5
+ ### Setting up Codex no longer gets Codex deleted by macOS
6
+
7
+ Setup ran `codex --version` to decide whether your Codex was new enough for
8
+ native hooks. On macOS, executing a binary hands it to XProtect, and current
9
+ definitions false-positive on the Codex CLI: macOS killed it and moved it to the
10
+ Trash. Reading a version number destroyed the tool it was asking, mid-setup, and
11
+ the only thing you saw was "codex was not opened because it contains malware".
12
+
13
+ Setup no longer runs Codex, or any other agent's binary, to learn something about
14
+ it. The version now comes from the package manifest next to the binary, which
15
+ covers npm, bun, pnpm and yarn installs, and from `brew list` for the Homebrew
16
+ cask, which ships no manifest. Same result, nothing launched.
17
+
18
+ If your Codex was already quarantined, reinstall it: `npm install -g @openai/codex`
19
+ or `brew install --cask codex`.
20
+
3
21
  ## 0.70.0
4
22
 
5
23
  ### A key you name is the key you get
@@ -110,7 +110,7 @@ import {
110
110
  } from "../chunk-KZERVKTD.js";
111
111
 
112
112
  // bin/pushary-setup.ts
113
- import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync, rmSync, renameSync } from "fs";
113
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync, rmSync, renameSync, realpathSync } from "fs";
114
114
  import { join, dirname, basename } from "path";
115
115
  import { homedir, tmpdir } from "os";
116
116
  import { execSync as execSync2 } from "child_process";
@@ -198,6 +198,53 @@ var describeClosing = (facts) => {
198
198
  };
199
199
  };
200
200
 
201
+ // src/setup/codex-version.ts
202
+ var parseCodexVersion = (raw) => {
203
+ const match = raw.match(/(\d+)\.(\d+)\.(\d+)/);
204
+ if (!match) return null;
205
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
206
+ };
207
+ var compareCodexVersion = (a, b) => {
208
+ for (let i = 0; i < 3; i++) {
209
+ if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;
210
+ }
211
+ return 0;
212
+ };
213
+ var versionFromPackageManifest = (probe, binPath) => {
214
+ let dir = probe.dirname(binPath);
215
+ for (let depth = 0; depth < 4; depth++) {
216
+ const raw = probe.readFile(probe.join(dir, "package.json"));
217
+ if (raw) {
218
+ try {
219
+ const manifest = JSON.parse(raw);
220
+ if (typeof manifest.version === "string") {
221
+ const parsed = parseCodexVersion(manifest.version);
222
+ if (parsed) return parsed;
223
+ }
224
+ } catch {
225
+ }
226
+ }
227
+ const parent = probe.dirname(dir);
228
+ if (parent === dir) break;
229
+ dir = parent;
230
+ }
231
+ return null;
232
+ };
233
+ var readCodexVersion = (probe) => {
234
+ const onPath = probe.resolveOnPath();
235
+ if (onPath) {
236
+ const real = probe.realpath(onPath) ?? onPath;
237
+ const fromManifest = versionFromPackageManifest(probe, real);
238
+ if (fromManifest) return { kind: "known", version: fromManifest, source: "package manifest" };
239
+ }
240
+ const brew = probe.brewVersions();
241
+ if (brew) {
242
+ const parsed = parseCodexVersion(brew);
243
+ if (parsed) return { kind: "known", version: parsed, source: "homebrew" };
244
+ }
245
+ return { kind: "unknown" };
246
+ };
247
+
201
248
  // src/skills-cli.ts
202
249
  import { execSync } from "child_process";
203
250
  var installSkillViaSkillsCli = (agent) => {
@@ -641,26 +688,46 @@ var setupHermes = async (_apiKey) => {
641
688
  var CODEX_HOOKS_JSON = join(CODEX_HOME, "hooks.json");
642
689
  var CODEX_HOOKS_MIN_VERSION = [0, 122, 0];
643
690
  var CODEX_TRUST_VERIFIED_MAX = [0, 142, 2];
644
- var parseCodexVersion = (raw) => {
645
- const match = raw.match(/(\d+)\.(\d+)\.(\d+)/);
646
- if (!match) return null;
647
- return [Number(match[1]), Number(match[2]), Number(match[3])];
648
- };
649
- var compareCodexVersion = (a, b) => {
650
- for (let i = 0; i < 3; i++) {
651
- if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;
652
- }
653
- return 0;
654
- };
655
- var readCodexVersion = () => {
656
- try {
657
- return parseCodexVersion(execSync2("codex --version", { encoding: "utf-8", stdio: "pipe", timeout: 1e4 }));
658
- } catch {
659
- return null;
660
- }
661
- };
662
- var codexSupportsHooks = (version) => version !== null && compareCodexVersion(version, CODEX_HOOKS_MIN_VERSION) >= 0;
663
- var codexTrustAutoSupported = (version) => version !== null && codexSupportsHooks(version) && compareCodexVersion(version, CODEX_TRUST_VERIFIED_MAX) <= 0;
691
+ var detectCodexVersion = () => readCodexVersion({
692
+ resolveOnPath: () => {
693
+ const whichCmd = IS_WINDOWS ? "where" : "which";
694
+ try {
695
+ const found = execSync2(`${whichCmd} codex`, { encoding: "utf-8", stdio: "pipe", timeout: 5e3 }).split("\n")[0].trim();
696
+ return found || null;
697
+ } catch {
698
+ return null;
699
+ }
700
+ },
701
+ realpath: (path) => {
702
+ try {
703
+ return realpathSync(path);
704
+ } catch {
705
+ return null;
706
+ }
707
+ },
708
+ readFile: (path) => {
709
+ try {
710
+ return readFileSync(path, "utf-8");
711
+ } catch {
712
+ return null;
713
+ }
714
+ },
715
+ brewVersions: () => {
716
+ try {
717
+ return execSync2("brew list --versions codex", {
718
+ encoding: "utf-8",
719
+ stdio: "pipe",
720
+ timeout: 1e4
721
+ }).trim() || null;
722
+ } catch {
723
+ return null;
724
+ }
725
+ },
726
+ join,
727
+ dirname
728
+ });
729
+ var codexSupportsHooks = (result) => result.kind === "known" && compareCodexVersion(result.version, CODEX_HOOKS_MIN_VERSION) >= 0;
730
+ var codexTrustAutoSupported = (result) => result.kind === "known" && codexSupportsHooks(result) && compareCodexVersion(result.version, CODEX_TRUST_VERIFIED_MAX) <= 0;
664
731
  var removeCodexNotifyEntry = (codexConfig) => {
665
732
  let raw = "";
666
733
  try {
@@ -711,7 +778,7 @@ var setupCodex = async (apiKey) => {
711
778
  addCodexMcpServer(config, apiKey);
712
779
  writeFileAtomic(codexConfig, stringifyTOML(config), KEY_FILE_MODE);
713
780
  });
714
- const codexVersion = readCodexVersion();
781
+ const codexVersion = detectCodexVersion();
715
782
  const hooksSupported = codexSupportsHooks(codexVersion);
716
783
  const trustAuto = codexTrustAutoSupported(codexVersion);
717
784
  let trusted = false;
@@ -739,9 +806,16 @@ var setupCodex = async (apiKey) => {
739
806
  removeCodexNotifyEntry(codexConfig);
740
807
  });
741
808
  } else {
742
- console.log(` ${yellow("!")} This Codex version predates native hooks (needs ${CODEX_HOOKS_MIN_VERSION.join(".")}+).`);
743
- console.log(` ${dim("Installing the deprecated notify handler instead. Upgrade Codex and re-run setup")}`);
744
- console.log(` ${dim("to get policy enforcement, phone approvals, and session tracking.")}`);
809
+ if (codexVersion.kind === "known") {
810
+ console.log(` ${yellow("!")} This Codex version predates native hooks (needs ${CODEX_HOOKS_MIN_VERSION.join(".")}+).`);
811
+ console.log(` ${dim("Installing the deprecated notify handler instead. Upgrade Codex and re-run setup")}`);
812
+ console.log(` ${dim("to get policy enforcement, phone approvals, and session tracking.")}`);
813
+ } else {
814
+ console.log(` ${yellow("!")} Could not read your Codex version from its install, so hooks were skipped.`);
815
+ console.log(` ${dim("Deliberately not run: asking the binary its version is what macOS quarantines.")}`);
816
+ console.log(` ${dim(`Installing the notify handler, which works on every version. If Codex is ${CODEX_HOOKS_MIN_VERSION.join(".")}+,`)}`);
817
+ console.log(` ${dim("re-run setup after installing it through npm or Homebrew to get native hooks.")}`);
818
+ }
745
819
  await spinner("Adding notify handler for Codex events (deprecated)", async () => {
746
820
  addCodexNotifyEntry(codexConfig);
747
821
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushary/agent-hooks",
3
- "version": "0.70.0",
3
+ "version": "0.71.0",
4
4
  "description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
5
5
  "keywords": [
6
6
  "pushary",