@pushary/agent-hooks 1.9.62 → 1.9.64

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 (130) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +2 -2
  3. package/dist/{api-7HLZRIUV.js → api-HDLTZTVR.js} +10 -11
  4. package/dist/bin/pushary-bell-hook.js +27 -30
  5. package/dist/bin/pushary-bell.js +10 -11
  6. package/dist/bin/pushary-claude.js +29 -32
  7. package/dist/bin/pushary-clean.js +63 -42
  8. package/dist/bin/pushary-codex-bridge.js +22 -24
  9. package/dist/bin/pushary-codex-hook.js +33 -36
  10. package/dist/bin/pushary-codex-session.js +8 -8
  11. package/dist/bin/pushary-codex.js +13 -15
  12. package/dist/bin/pushary-connect.js +26 -29
  13. package/dist/bin/pushary-cowork.js +5 -5
  14. package/dist/bin/pushary-daemon.js +39 -41
  15. package/dist/bin/pushary-disconnect.js +60 -40
  16. package/dist/bin/pushary-doctor.js +89 -46
  17. package/dist/bin/pushary-elicitation-hook.js +28 -31
  18. package/dist/bin/pushary-gemini-bridge.js +16 -18
  19. package/dist/bin/pushary-gemini-hook.js +30 -33
  20. package/dist/bin/pushary-hook.js +31 -34
  21. package/dist/bin/pushary-login.js +27 -16
  22. package/dist/bin/pushary-logout.js +26 -29
  23. package/dist/bin/pushary-mcp.js +11 -12
  24. package/dist/bin/pushary-mode.js +14 -15
  25. package/dist/bin/pushary-notification-hook.js +26 -29
  26. package/dist/bin/pushary-opencode-hook.js +29 -32
  27. package/dist/bin/pushary-permission-denied-hook.js +31 -34
  28. package/dist/bin/pushary-permission-hook.js +30 -33
  29. package/dist/bin/pushary-post-hook.js +26 -29
  30. package/dist/bin/pushary-prompt-hook.js +26 -29
  31. package/dist/bin/pushary-session-end-hook.js +28 -31
  32. package/dist/bin/pushary-session-start-hook.js +35 -37
  33. package/dist/bin/pushary-setup.js +361 -4412
  34. package/dist/bin/pushary-stats.js +5 -5
  35. package/dist/bin/pushary-status.js +32 -35
  36. package/dist/bin/pushary-stop-hook.js +26 -29
  37. package/dist/bin/pushary-stopfailure-hook.js +26 -29
  38. package/dist/bin/pushary-suggestions.js +14 -15
  39. package/dist/bin/pushary-transcript-register.js +18 -21
  40. package/dist/bin/pushary-transcripts.js +63 -11
  41. package/dist/bin/pushary-upgrade.js +41 -43
  42. package/dist/bin/pushary-wait.js +14 -15
  43. package/dist/bin/pushary.js +7 -8
  44. package/dist/{chunk-SJCPIYWJ.js → chunk-2CEVEMJE.js} +3 -3
  45. package/dist/{chunk-3YGUWPNZ.js → chunk-2EY4HGLG.js} +3 -3
  46. package/dist/{chunk-ESXGCZDA.js → chunk-2KID4FK4.js} +4 -4
  47. package/dist/{chunk-EO6CL4PD.js → chunk-2PKHGHMA.js} +2 -2
  48. package/dist/{chunk-PSCXEH42.js → chunk-2VADJ6JH.js} +2 -2
  49. package/dist/{chunk-GV43RXR2.js → chunk-2YXBCZ3Z.js} +1 -1
  50. package/dist/{chunk-7GU4PXE5.js → chunk-2Z7I7DHT.js} +1 -1
  51. package/dist/{chunk-4K6YZPZ3.js → chunk-3KXBRSL3.js} +1 -1
  52. package/dist/{chunk-YQK72JGV.js → chunk-42PD2MQH.js} +5 -5
  53. package/dist/{chunk-EUNSJKJJ.js → chunk-57PU5OBL.js} +21 -14
  54. package/dist/{chunk-5R23J52J.js → chunk-5NP3OJ5P.js} +7 -9
  55. package/dist/{chunk-UWCPY4RY.js → chunk-5TNGBDIE.js} +2 -2
  56. package/dist/{chunk-ZEDGKCCM.js → chunk-5TUDGSDC.js} +1 -1
  57. package/dist/{chunk-M7MEVILL.js → chunk-66FRMK7V.js} +4 -4
  58. package/dist/{chunk-3LBB7GVF.js → chunk-6HPLEGUP.js} +4 -4
  59. package/dist/{chunk-LCNN7UOE.js → chunk-6QPDBD7Q.js} +3 -57
  60. package/dist/{chunk-AFV3FQNG.js → chunk-7UBDBJTG.js} +4 -4
  61. package/dist/{chunk-RFCEVROB.js → chunk-A5KQXZR7.js} +3 -3
  62. package/dist/{chunk-G3ZDCYMU.js → chunk-ADRPW7KU.js} +2 -2
  63. package/dist/{chunk-OZRT64BB.js → chunk-AN7C3CHH.js} +1 -1
  64. package/dist/{chunk-6JAWNRDR.js → chunk-AQAPPSDV.js} +3 -3
  65. package/dist/{chunk-FG5HMJ7C.js → chunk-BAGBCSXA.js} +4 -2
  66. package/dist/{chunk-W3CBFLIX.js → chunk-BLAIETMP.js} +18 -4
  67. package/dist/{chunk-CFIQ3252.js → chunk-BSZIPIFA.js} +128 -26
  68. package/dist/{chunk-7EHZXZB2.js → chunk-CCNH4PJ2.js} +12 -12
  69. package/dist/{chunk-NZLQ6GMX.js → chunk-CJADXAJU.js} +9 -9
  70. package/dist/{chunk-TMHE5CVX.js → chunk-DCMRNIDM.js} +4 -4
  71. package/dist/{chunk-QW3FRUFB.js → chunk-DVYVGBPB.js} +1 -1
  72. package/dist/{chunk-RSNN2TPE.js → chunk-E23RKH3T.js} +9 -9
  73. package/dist/{chunk-ZJFJUAHS.js → chunk-E2LB6JNV.js} +6 -6
  74. package/dist/{chunk-HSRNWCXJ.js → chunk-EEM65CGJ.js} +3 -3
  75. package/dist/chunk-H4BKC2GN.js +1201 -0
  76. package/dist/{chunk-7NXB7OVX.js → chunk-HVOQUPSO.js} +1 -1
  77. package/dist/{chunk-R3CLBNST.js → chunk-IZTDX2MX.js} +3 -3
  78. package/dist/{chunk-RU37NSZH.js → chunk-JTOBQUIL.js} +3 -3
  79. package/dist/{chunk-W6MYFAOK.js → chunk-JX3DHGZX.js} +44 -32
  80. package/dist/{chunk-7NJ4TDUH.js → chunk-KA7JIMTG.js} +6 -6
  81. package/dist/chunk-KEPESIIR.js +4117 -0
  82. package/dist/{chunk-EA6574W2.js → chunk-KX3RMF6T.js} +12 -6
  83. package/dist/{chunk-BIUSODLS.js → chunk-LA7CKRZN.js} +2 -2
  84. package/dist/{chunk-A4CZPUQ6.js → chunk-LMC5UPL7.js} +1 -1
  85. package/dist/{chunk-EVZDYG7L.js → chunk-LV6DX4P6.js} +2 -2
  86. package/dist/{chunk-LWR5VKNC.js → chunk-MIPJ2VXP.js} +12 -14
  87. package/dist/{chunk-557ZE5EX.js → chunk-ML2Q6WWE.js} +37 -214
  88. package/dist/{chunk-FXECTHAG.js → chunk-MNKIR2ZB.js} +37 -4
  89. package/dist/{chunk-LILS32LF.js → chunk-MPPTIZ2G.js} +212 -254
  90. package/dist/{chunk-VUFHYMSP.js → chunk-MXPOLQZH.js} +1 -1
  91. package/dist/{chunk-MYEALNW6.js → chunk-NOH3EJFH.js} +1 -1
  92. package/dist/{chunk-GFAG72LR.js → chunk-NUEPJ5W6.js} +7 -3
  93. package/dist/chunk-NYV45Q25.js +111 -0
  94. package/dist/{chunk-NAZRRXZM.js → chunk-O7PCNYEY.js} +2 -2
  95. package/dist/{chunk-7E2ZN7XA.js → chunk-OQKSF5ST.js} +3 -5
  96. package/dist/{chunk-VF3IL56Q.js → chunk-PLMX3IHG.js} +3 -3
  97. package/dist/{chunk-F35YILEN.js → chunk-PMLQRB3D.js} +1 -1
  98. package/dist/{chunk-SJJYXMJP.js → chunk-Q6ID23SU.js} +6 -6
  99. package/dist/{chunk-SDOWT67G.js → chunk-QECRQWLV.js} +5 -5
  100. package/dist/{chunk-Q4WTIKM6.js → chunk-QNATBOUH.js} +3 -3
  101. package/dist/{chunk-QIPW7OVB.js → chunk-QPPBH5NY.js} +5 -5
  102. package/dist/{chunk-7ETELRQX.js → chunk-QSW3HAKI.js} +16 -5
  103. package/dist/{chunk-FVERRWDP.js → chunk-RY4EPMZX.js} +2 -2
  104. package/dist/{chunk-MURJ4WAL.js → chunk-SROWUG5W.js} +1 -1
  105. package/dist/{chunk-UUAVYIWJ.js → chunk-TJUJAK5L.js} +4 -2
  106. package/dist/{chunk-3IFCXMC6.js → chunk-TR3GP5MH.js} +1 -1
  107. package/dist/{chunk-FX7KDF47.js → chunk-VHKK3US3.js} +3 -3
  108. package/dist/{chunk-6HIYOY6I.js → chunk-VNRWQCGU.js} +6 -6
  109. package/dist/{chunk-67Q3Q5IO.js → chunk-XF3AWNMO.js} +6 -6
  110. package/dist/{chunk-44FNEAXK.js → chunk-XJIIU36L.js} +1 -1
  111. package/dist/{chunk-DFKEJARZ.js → chunk-Y64JGYTB.js} +1 -1
  112. package/dist/{chunk-FYS27SUS.js → chunk-YUDZCJYC.js} +10 -10
  113. package/dist/{codex-app-cards-switch-IIL7IPP6.js → codex-app-cards-switch-JQ6356VX.js} +11 -12
  114. package/dist/{codex-desktop-launch-XCLMYVBD.js → codex-desktop-launch-YUB2LOAG.js} +1 -1
  115. package/dist/{codex-session-launch-UMVALJ3A.js → codex-session-launch-UKMAORXS.js} +19 -21
  116. package/dist/{config-5N3GUJD5.js → config-YY54G3CC.js} +3 -3
  117. package/dist/{global-upgrade-5F4CSXED.js → global-upgrade-Y4USGPS2.js} +10 -12
  118. package/dist/{identity-7ULYW4RL.js → identity-W5CYL5RC.js} +4 -5
  119. package/dist/{live-capabilities-QTSFXA6T.js → live-capabilities-JRNNA5EP.js} +5 -7
  120. package/dist/{paths-HEMK2ALW.js → paths-4MEBINV3.js} +7 -3
  121. package/dist/reapply-ZN7C3CB3.js +63 -0
  122. package/dist/src/index.js +20 -23
  123. package/dist/{upgrade-lock-IAZC5644.js → upgrade-lock-QAWUV2DO.js} +4 -5
  124. package/dist/{usage-NEFDYSRT.js → usage-43C2DHDU.js} +3 -3
  125. package/package.json +1 -1
  126. package/dist/chunk-6ICPEJY5.js +0 -20
  127. package/dist/chunk-6YSEOXP5.js +0 -615
  128. package/dist/chunk-LL2KHEJH.js +0 -41
  129. package/dist/chunk-QENTGE75.js +0 -86
  130. package/dist/reapply-AMFKVYZV.js +0 -63
@@ -1,615 +0,0 @@
1
- import {
2
- quoteIfNeeded,
3
- shellDoubleQuoted
4
- } from "./chunk-CFIQ3252.js";
5
- import {
6
- CODEX_QUESTION_TOOLS,
7
- HOOK_BUDGETS,
8
- HOOK_LOCATOR_BINARY,
9
- withHookHoldBudget
10
- } from "./chunk-FXECTHAG.js";
11
-
12
- // src/setup/paths.ts
13
- import { createHash as createHash2 } from "crypto";
14
-
15
- // src/claude-config-paths.ts
16
- import { homedir } from "os";
17
- import { join, resolve } from "path";
18
- var claudeConfigDir = (home = homedir(), environment = process.env) => resolve(environment.CLAUDE_CONFIG_DIR || join(home, ".claude"));
19
- var claudeUserConfigFile = (home = homedir(), environment = process.env) => join(environment.CLAUDE_CONFIG_DIR ? claudeConfigDir(home, environment) : home, ".claude.json");
20
-
21
- // src/setup/paths.ts
22
- import { homedir as homedir3 } from "os";
23
- import { join as join3 } from "path";
24
-
25
- // src/codex-config.ts
26
- import { createHash } from "crypto";
27
- import { homedir as homedir2 } from "os";
28
- import { join as join2 } from "path";
29
-
30
- // src/registration-holder.ts
31
- var asRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
32
- var registeredCommands = (document) => {
33
- const hooks = asRecord(document?.hooks);
34
- if (!hooks) return [];
35
- const found = [];
36
- for (const [event, value] of Object.entries(hooks)) {
37
- if (!Array.isArray(value)) continue;
38
- for (const item of value) {
39
- const inner = asRecord(item)?.hooks;
40
- if (!Array.isArray(inner)) continue;
41
- for (const hook of inner) {
42
- const command = asRecord(hook)?.command;
43
- if (typeof command === "string") found.push({ event, command });
44
- }
45
- }
46
- }
47
- return found;
48
- };
49
- var wholeSegments = (command) => command.split(/[\s/\\"']+/).map((segment) => segment.replace(/\.(cmd|exe)$/i, ""));
50
- var namesLocator = (command) => wholeSegments(command).includes(HOOK_LOCATOR_BINARY);
51
- var namesCliBinary = (command, cliBinaries) => wholeSegments(command).some((segment) => cliBinaries.has(segment));
52
- var namesOurBinary = (command, cliBinaries) => namesLocator(command) || namesCliBinary(command, cliBinaries);
53
- var registrationHolderOf = (document, cliBinaries) => {
54
- const commands = registeredCommands(document);
55
- if (commands.some(({ command }) => namesLocator(command))) return "app";
56
- return commands.some(({ command }) => namesCliBinary(command, cliBinaries)) ? "cli" : "none";
57
- };
58
-
59
- // src/hook-command.ts
60
- var HOOK_SHELL = "/bin/sh -c";
61
- var holdBudgetOf = (hook) => hook.holds ? hook.timeout : void 0;
62
- var LOCATE = 'B=$(command -v "$0") || exit 0; [ -f "$B" ] || exit 0; [ -x "$B" ] || exit 0';
63
- var NODE_PRESENT = "command -v node >/dev/null 2>&1 || exit 0";
64
- var CURSOR_NO_OPINION = { permission: "deny", user_message: "Command denied via Pushary.", agent_message: "Pushary hook is unavailable. Repair the integration before retrying." };
65
- var CURSOR_NATIVE_PROMPT = { permission: "ask" };
66
- var CURSOR_NATIVE_PROMPT_EVENTS = ["beforeShellExecution", "beforeMCPExecution"];
67
- var hookEventIsOneOf = (events) => events.flatMap((event) => [`*\\"hook_event_name\\":\\"${event}\\"*`, `*\\"hook_event_name\\":\\ \\"${event}\\"*`]).join("|");
68
- var CURSOR_MISS = `{ E=$(cat); case "$E" in ${hookEventIsOneOf(CURSOR_NATIVE_PROMPT_EVENTS)}) printf %s ${shellDoubleQuoted(JSON.stringify(CURSOR_NATIVE_PROMPT))} ;; *) printf %s ${shellDoubleQuoted(JSON.stringify(CURSOR_NO_OPINION))} ;; esac; exit 0; }`;
69
- var HOOK_GUARD_SCRIPTS = {
70
- native_binary: `${LOCATE}; exec "$B" "$@"`,
71
- node_binary: `${LOCATE}; ${NODE_PRESENT}; exec "$B" "$@"`,
72
- node_script: `[ -f "$0" ] || exit 0; ${NODE_PRESENT}; exec node "$0" "$@"`,
73
- cursor_gate_script: `[ -f "$0" ] || ${CURSOR_MISS}; command -v node >/dev/null 2>&1 || ${CURSOR_MISS}; exec node "$0" "$@"`
74
- };
75
- var BINARY_GUARDS = {
76
- native: "native_binary",
77
- node: "node_binary"
78
- };
79
- var guardKindOf = (target) => {
80
- switch (target.kind) {
81
- case "node":
82
- return "node_script";
83
- case "cursor_gate":
84
- return "cursor_gate_script";
85
- case "binary":
86
- return BINARY_GUARDS[target.runtime];
87
- }
88
- };
89
- var targetPath = (target) => target.kind === "binary" ? target.path : target.script;
90
- var runsThroughNode = (target) => target.kind !== "binary";
91
- var guardHookCommand = (target, platform = process.platform) => {
92
- const path = quoteIfNeeded(targetPath(target), platform);
93
- if (platform === "win32") return runsThroughNode(target) ? `node ${path}` : path;
94
- return `${HOOK_SHELL} '${HOOK_GUARD_SCRIPTS[guardKindOf(target)]}' ${path}`;
95
- };
96
- var guardBinary = (path, platform) => guardHookCommand({ kind: "binary", path, runtime: "node" }, platform);
97
- var SILENT_MISS = "exit 0";
98
- var REFUSE = "R";
99
- var definesRefusal = (refusal) => `${REFUSE}() { printf %s ${shellDoubleQuoted(refusal)}; exit 0; }`;
100
- var guardBinaryRefusing = (path, refusal, platform = process.platform) => {
101
- if (platform === "win32") return guardBinary(path, platform);
102
- const script = `${definesRefusal(refusal)}; ${HOOK_GUARD_SCRIPTS.node_binary.replaceAll(SILENT_MISS, REFUSE)}`;
103
- return `${HOOK_SHELL} '${script}' ${quoteIfNeeded(path)}`;
104
- };
105
- var guardNodeScript = (script, platform) => guardHookCommand({ kind: "node", script }, platform);
106
- var guardCursorGate = (script, platform) => guardHookCommand({ kind: "cursor_gate", script }, platform);
107
- var guardedArgv = (target, args = [], platform = process.platform) => {
108
- const path = targetPath(target);
109
- if (platform === "win32") {
110
- return runsThroughNode(target) ? ["node", path, ...args] : [path, ...args];
111
- }
112
- const [shell, ...shellArgs] = HOOK_SHELL.split(/\s+/);
113
- return [shell, ...shellArgs, HOOK_GUARD_SCRIPTS[guardKindOf(target)], path, ...args];
114
- };
115
-
116
- // src/hook-entries.ts
117
- var registerHookEntry = (existing, isOurs, entry) => {
118
- const rewritten = [];
119
- let placed = false;
120
- for (const item of existing) {
121
- if (!isOurs(item)) {
122
- rewritten.push(item);
123
- continue;
124
- }
125
- if (placed) continue;
126
- rewritten.push(entry);
127
- placed = true;
128
- }
129
- if (!placed) rewritten.push(entry);
130
- return rewritten;
131
- };
132
-
133
- // src/removal-scope.ts
134
- var namesAppLocator = (command) => command.includes(HOOK_LOCATOR_BINARY);
135
- var isProtectedByScope = (command, scope) => scope?.keepAppWiring === true && namesAppLocator(command);
136
-
137
- // src/canonical-json.ts
138
- var canonicalJson = (value) => {
139
- if (value === null || typeof value !== "object") return JSON.stringify(value);
140
- if (Array.isArray(value)) return "[" + value.map(canonicalJson).join(",") + "]";
141
- const record = value;
142
- return "{" + Object.keys(record).sort().map((key) => JSON.stringify(key) + ":" + canonicalJson(record[key])).join(",") + "}";
143
- };
144
-
145
- // src/codex-config.ts
146
- var CODEX_HOOK_BINARY = "pushary-codex-hook";
147
- var codexHome = () => codexHomeFrom(homedir2());
148
- var codexHomeFrom = (home) => process.env.CODEX_HOME?.trim() || join2(home, ".codex");
149
- var codexConfigToml = () => join2(codexHome(), "config.toml");
150
- var codexHooksJsonIn = (home) => join2(home, "hooks.json");
151
- var codexHooksJson = () => codexHooksJsonIn(codexHome());
152
- var codexAgentsMd = () => join2(codexHome(), "AGENTS.md");
153
- var codexSkillDir = () => join2(codexHome(), "skills", "pushary");
154
- var CODEX_TOOL_CALL_MATCHER = "Bash|apply_patch|mcp__.*";
155
- var CODEX_PRE_TOOL_USE_MATCHER = [CODEX_TOOL_CALL_MATCHER, ...CODEX_QUESTION_TOOLS].join("|");
156
- var CODEX_HOOK_EVENTS = [
157
- { event: "PermissionRequest", delivery: "approval", timeout: HOOK_BUDGETS.codex.budgetSeconds, statusMessage: "Waiting for your phone" },
158
- { event: "PreToolUse", matcher: CODEX_PRE_TOOL_USE_MATCHER, delivery: "approval", timeout: HOOK_BUDGETS.codex.budgetSeconds, statusMessage: "Checking Pushary policy" },
159
- { event: "PostToolUse", matcher: CODEX_TOOL_CALL_MATCHER, delivery: "telemetry", timeout: 10 },
160
- { event: "UserPromptSubmit", delivery: "telemetry", timeout: 10 },
161
- { event: "Stop", delivery: "rescue", timeout: HOOK_BUDGETS.codex.budgetSeconds, holds: true },
162
- // `clear` alongside startup and resume, matching what we already do on Claude
163
- // Code. Codex names all three in its own SessionStart sources, and without it a
164
- // session the person started by clearing is one we never see begin.
165
- { event: "SessionStart", matcher: "startup|resume|clear", delivery: "telemetry", timeout: 10 },
166
- // Codex caps SessionEnd at 3s and defaults it to 1s, unlike every other event
167
- // here. It also runs synchronously whatever `async` says, so the handler must
168
- // fit the window rather than assume the 10s Claude Code allows.
169
- { event: "SessionEnd", delivery: "telemetry", timeout: 3 },
170
- // Observability only, and the four Codex names we were not registering at all.
171
- // Every one is in codex-cli 0.151.0's own `HookEventName` enum
172
- // (subagent_start, subagent_stop, pre_compact, post_compact), and we already
173
- // carry all four on Claude Code, so the island showed subagent and compaction
174
- // shape for one agent and not the other. None of them decides anything.
175
- { event: "SubagentStart", delivery: "telemetry", timeout: 5 },
176
- { event: "SubagentStop", delivery: "telemetry", timeout: 5 },
177
- { event: "PreCompact", matcher: "manual|auto", delivery: "telemetry", timeout: 5 },
178
- { event: "PostCompact", matcher: "manual|auto", delivery: "telemetry", timeout: 5 }
179
- ];
180
- var CODEX_REQUIRED_APPROVAL_EVENTS = CODEX_HOOK_EVENTS.filter((event) => event.delivery === "approval").map((event) => event.event);
181
- var CODEX_EVENT_KEY = {
182
- PermissionRequest: "permission_request",
183
- PreToolUse: "pre_tool_use",
184
- PostToolUse: "post_tool_use",
185
- UserPromptSubmit: "user_prompt_submit",
186
- Stop: "stop",
187
- SessionStart: "session_start",
188
- SessionEnd: "session_end",
189
- SubagentStart: "subagent_start",
190
- SubagentStop: "subagent_stop",
191
- PreCompact: "pre_compact",
192
- PostCompact: "post_compact"
193
- };
194
- var codexEventKeyOf = (event) => event.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
195
- var asRecord2 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
196
- var ensureRecord = (target, key) => {
197
- const existing = asRecord2(target[key]);
198
- if (existing) return existing;
199
- const created = {};
200
- target[key] = created;
201
- return created;
202
- };
203
- var CODEX_MCP_URL = "https://pushary.com/api/mcp/mcp";
204
- var CODEX_HTTP_ONLY_FIELDS = ["url", "http_headers", "env_http_headers", "http_headers_helper", "bearer_token", "bearer_token_env_var", "auth", "oauth", "oauth_resource"];
205
- var NATIVE_MCP_TRANSPORT_FIELDS = [...CODEX_HTTP_ONLY_FIELDS, "args", "env", "env_vars", "cwd"];
206
- var OLD_CLI_HTTP_FIELDS = /* @__PURE__ */ new Set(["url", "http_headers"]);
207
- var nativeCodexMcpCommand = () => join2(homedir2(), ".pushary", "bin", "pushary-mcp");
208
- var isNativeCodexMcpEntry = (entry, command) => {
209
- const server = asRecord2(entry);
210
- return server?.command === command && NATIVE_MCP_TRANSPORT_FIELDS.every((field) => !(field in server));
211
- };
212
- var carriesOnlyAnAuthorizationHeader = (headers) => {
213
- const record = asRecord2(headers);
214
- return record !== void 0 && Object.keys(record).length === 1 && typeof record.Authorization === "string";
215
- };
216
- var isOldCliMixedCodexMcpEntry = (entry, command) => {
217
- const server = asRecord2(entry);
218
- return server?.command === command && server.url === CODEX_MCP_URL && carriesOnlyAnAuthorizationHeader(server.http_headers) && NATIVE_MCP_TRANSPORT_FIELDS.every((field) => OLD_CLI_HTTP_FIELDS.has(field) || !(field in server));
219
- };
220
- var codexMcpMixesCommandWithHttp = (entry) => {
221
- const server = asRecord2(entry);
222
- return server !== void 0 && "command" in server && CODEX_HTTP_ONLY_FIELDS.some((field) => field in server);
223
- };
224
- var CODEX_RESTART_AFTER_TRANSPORT_CHANGE = "Fully quit and reopen Codex to load the updated Pushary configuration.";
225
- var codexMcpStartsCommand = (config) => {
226
- const pushary = asRecord2(asRecord2(config.mcp_servers)?.pushary);
227
- return pushary !== void 0 && "command" in pushary && pushary.enabled !== false;
228
- };
229
- var addCodexMcpServer = (config, apiKey, nativeOwnership = "preserve") => {
230
- const existing = asRecord2(asRecord2(config.mcp_servers)?.pushary);
231
- if (existing !== void 0 && "command" in existing) {
232
- const command = nativeCodexMcpCommand();
233
- if (!isOldCliMixedCodexMcpEntry(existing, command) && !isNativeCodexMcpEntry(existing, command)) {
234
- throw new Error("Pushary MCP has an unrecognized or mixed transport. Its configuration was left unchanged.");
235
- }
236
- if (nativeOwnership === "preserve") {
237
- for (const field of OLD_CLI_HTTP_FIELDS) delete existing[field];
238
- return "kept-native";
239
- }
240
- }
241
- const servers = ensureRecord(config, "mcp_servers");
242
- const pushary = ensureRecord(servers, "pushary");
243
- delete pushary.command;
244
- pushary.url = CODEX_MCP_URL;
245
- ensureRecord(pushary, "http_headers").Authorization = `Bearer ${apiKey}`;
246
- pushary.default_tools_approval_mode = "approve";
247
- delete pushary.bearer_token_env_var;
248
- delete pushary.tools;
249
- return "wrote-key";
250
- };
251
- var readCodexMcpAuth = (config) => {
252
- const pushary = asRecord2(asRecord2(config.mcp_servers)?.pushary);
253
- if (!pushary) return void 0;
254
- if ("command" in pushary) {
255
- return isNativeCodexMcpEntry(pushary, nativeCodexMcpCommand()) ? { method: "native" } : void 0;
256
- }
257
- const authorization = asRecord2(pushary.http_headers)?.Authorization;
258
- if (typeof authorization === "string" && authorization.startsWith("Bearer ")) {
259
- return { method: "embedded", key: authorization.slice("Bearer ".length).trim() };
260
- }
261
- if (typeof pushary.bearer_token_env_var === "string") {
262
- return { method: "env", envVar: pushary.bearer_token_env_var };
263
- }
264
- if (typeof pushary.bearer_token === "string") return { method: "legacy-bearer" };
265
- return void 0;
266
- };
267
- var isPusharyCodexCommand = (command) => command.includes(CODEX_HOOK_BINARY) || command.includes(HOOK_LOCATOR_BINARY);
268
- var isPusharyCommand = (hook, scope) => {
269
- const command = String(asRecord2(hook)?.command ?? "");
270
- if (isProtectedByScope(command, scope)) return false;
271
- return isPusharyCodexCommand(command);
272
- };
273
- var isPusharyCodexHook = (entry, scope) => {
274
- const hooks = asRecord2(entry)?.hooks;
275
- return Array.isArray(hooks) && hooks.some((hook) => isPusharyCommand(hook, scope));
276
- };
277
- var CODEX_CLI_BINARIES = /* @__PURE__ */ new Set([CODEX_HOOK_BINARY]);
278
- var codexRegistrationHolder = (hooksConfig) => registrationHolderOf(hooksConfig, CODEX_CLI_BINARIES);
279
- var addCodexHooks = (config, command) => {
280
- const hooks = ensureRecord(config, "hooks");
281
- for (const definition of CODEX_HOOK_EVENTS) {
282
- const existing = Array.isArray(hooks[definition.event]) ? hooks[definition.event] : [];
283
- hooks[definition.event] = registerHookEntry(existing, isPusharyCodexHook, {
284
- ...definition.matcher ? { matcher: definition.matcher } : {},
285
- hooks: [{
286
- type: "command",
287
- command: withHookHoldBudget(command, holdBudgetOf(definition)),
288
- timeout: definition.timeout,
289
- ...definition.statusMessage ? { statusMessage: definition.statusMessage } : {}
290
- }]
291
- });
292
- }
293
- };
294
- var removeCodexHooks = (config, scope) => {
295
- const hooks = asRecord2(config.hooks);
296
- if (!hooks) return false;
297
- let changed = false;
298
- for (const definition of CODEX_HOOK_EVENTS) {
299
- const entries = hooks[definition.event];
300
- if (!Array.isArray(entries)) continue;
301
- const filtered = entries.filter((entry) => !isPusharyCodexHook(entry, scope));
302
- if (filtered.length !== entries.length) {
303
- if (filtered.length === 0) {
304
- delete hooks[definition.event];
305
- } else {
306
- hooks[definition.event] = filtered;
307
- }
308
- changed = true;
309
- }
310
- }
311
- if (Object.keys(hooks).length === 0) delete config.hooks;
312
- return changed;
313
- };
314
- var hasCodexHooks = (config) => {
315
- const hooks = asRecord2(config.hooks);
316
- if (!hooks) return false;
317
- return CODEX_HOOK_EVENTS.some((definition) => {
318
- const entries = hooks[definition.event];
319
- return Array.isArray(entries) && entries.some((entry) => isPusharyCodexHook(entry));
320
- });
321
- };
322
- var missingCodexHookEvents = (config) => {
323
- const hooks = asRecord2(config.hooks);
324
- return CODEX_HOOK_EVENTS.filter((definition) => {
325
- const entries = hooks?.[definition.event];
326
- return !Array.isArray(entries) || !entries.some((entry) => isPusharyCodexHook(entry));
327
- }).map((definition) => definition.event);
328
- };
329
- var codexHookTrustHash = (definition, command) => {
330
- const hook = { command: withHookHoldBudget(command, holdBudgetOf(definition)), timeout: definition.timeout, type: "command" };
331
- if (definition.statusMessage) hook.statusMessage = definition.statusMessage;
332
- const entry = { hooks: [hook] };
333
- if (definition.matcher) entry.matcher = definition.matcher;
334
- return codexEntryTrustHash(CODEX_EVENT_KEY[definition.event], entry);
335
- };
336
- var codexEntryTrustHash = (eventKey, entry) => {
337
- const hooks = Array.isArray(entry.hooks) ? entry.hooks : [];
338
- const identity = {
339
- event_name: eventKey,
340
- hooks: hooks.map((hook) => ({ async: false, ...asRecord2(hook) }))
341
- };
342
- if (typeof entry.matcher === "string") identity.matcher = entry.matcher;
343
- return "sha256:" + createHash("sha256").update(canonicalJson(identity), "utf8").digest("hex");
344
- };
345
- var codexHookPositions = (hooksConfig) => {
346
- const hooks = asRecord2(hooksConfig?.hooks);
347
- const positions = {};
348
- for (const definition of CODEX_HOOK_EVENTS) {
349
- const entries = hooks?.[definition.event];
350
- if (!Array.isArray(entries)) continue;
351
- const entryIndex = entries.findIndex((entry) => isPusharyCodexHook(entry));
352
- if (entryIndex < 0) continue;
353
- const inner = asRecord2(entries[entryIndex])?.hooks;
354
- const hookIndex = Array.isArray(inner) ? inner.findIndex((hook) => isPusharyCommand(hook)) : -1;
355
- positions[definition.event] = [entryIndex, Math.max(hookIndex, 0)];
356
- }
357
- return positions;
358
- };
359
- var codexHookStateKey = (hooksJsonPath, event, position) => `${hooksJsonPath}:${CODEX_EVENT_KEY[event]}:${position[0]}:${position[1]}`;
360
- var codexVacatedIndexes = (hooksConfig) => {
361
- const hooks = asRecord2(hooksConfig?.hooks);
362
- const vacated = {};
363
- for (const definition of CODEX_HOOK_EVENTS) {
364
- const entries = hooks?.[definition.event];
365
- if (!Array.isArray(entries)) continue;
366
- const ours = entries.flatMap((entry, index) => isPusharyCodexHook(entry) ? [index] : []);
367
- if (ours.length > 1) vacated[definition.event] = ours[1];
368
- }
369
- return vacated;
370
- };
371
- var dropVacatedCodexHookTrust = (config, hooksJsonPath, vacated) => {
372
- const state = asRecord2(asRecord2(config.hooks)?.state);
373
- if (!state) return false;
374
- let changed = false;
375
- for (const [event, from] of Object.entries(vacated)) {
376
- const prefix = `${hooksJsonPath}:${CODEX_EVENT_KEY[event] ?? codexEventKeyOf(event)}:`;
377
- for (const key of Object.keys(state)) {
378
- if (!key.startsWith(prefix)) continue;
379
- const entryIndex = Number(key.slice(prefix.length).split(":")[0]);
380
- if (!Number.isInteger(entryIndex) || entryIndex < from) continue;
381
- delete state[key];
382
- changed = true;
383
- }
384
- }
385
- return changed;
386
- };
387
- var captureCodexHookTrust = (config, hooksJsonPath, positions) => {
388
- const state = asRecord2(asRecord2(config.hooks)?.state);
389
- if (!state) return {};
390
- const snapshot = {};
391
- for (const [event, position] of Object.entries(positions)) {
392
- const value = state[codexHookStateKey(hooksJsonPath, event, position)];
393
- if (value !== void 0) snapshot[event] = structuredClone(value);
394
- }
395
- return snapshot;
396
- };
397
- var restoreCodexHookTrust = (config, hooksJsonPath, positions, snapshot) => {
398
- const restorable = Object.entries(snapshot).filter(([event]) => positions[event] !== void 0);
399
- if (restorable.length === 0) return false;
400
- const state = ensureRecord(ensureRecord(config, "hooks"), "state");
401
- for (const [event, value] of restorable) {
402
- state[codexHookStateKey(hooksJsonPath, event, positions[event])] = structuredClone(value);
403
- }
404
- return true;
405
- };
406
- var codexTrustGaps = (config, hooksConfig, hooksJsonPath, command, positions) => {
407
- const state = asRecord2(asRecord2(config.hooks)?.state);
408
- const hooks = asRecord2(hooksConfig?.hooks);
409
- const gaps = [];
410
- for (const definition of CODEX_HOOK_EVENTS) {
411
- const position = positions[definition.event];
412
- if (!position) continue;
413
- const hookState = asRecord2(state?.[codexHookStateKey(hooksJsonPath, definition.event, position)]);
414
- if (definition.delivery === "approval" && hookState?.enabled === false) {
415
- gaps.push({ event: definition.event, kind: "disabled" });
416
- continue;
417
- }
418
- const stored = hookState?.trusted_hash;
419
- const eventKey = CODEX_EVENT_KEY[definition.event] ?? definition.event;
420
- const onDisk = asRecord2(
421
- asRecord2(hooks?.[definition.event]) ?? (Array.isArray(hooks?.[definition.event]) ? hooks[definition.event][position[0]] : void 0)
422
- );
423
- const handlers = onDisk?.hooks;
424
- const handler = Array.isArray(handlers) ? asRecord2(handlers[position[1]]) : void 0;
425
- if (definition.delivery === "approval" && handler?.async === true) {
426
- gaps.push({ event: definition.event, kind: "asynchronous" });
427
- continue;
428
- }
429
- const diskHash = onDisk ? codexEntryTrustHash(eventKey, onDisk) : void 0;
430
- if (stored !== void 0 && diskHash !== void 0 && stored === diskHash) {
431
- if (diskHash !== codexHookTrustHash(definition, command)) {
432
- gaps.push({ event: definition.event, kind: "stale" });
433
- }
434
- continue;
435
- }
436
- if (stored !== (diskHash ?? codexHookTrustHash(definition, command))) {
437
- gaps.push({ event: definition.event, kind: "untrusted" });
438
- }
439
- }
440
- return gaps;
441
- };
442
- var removeCodexMcpServer = (config) => {
443
- const servers = asRecord2(config.mcp_servers);
444
- if (!servers?.pushary) return false;
445
- delete servers.pushary;
446
- if (Object.keys(servers).length === 0) delete config.mcp_servers;
447
- return true;
448
- };
449
- var removeCodexHookTrust = (config, hooksJsonPath, positions) => {
450
- const state = asRecord2(asRecord2(config.hooks)?.state);
451
- if (!state) return false;
452
- let changed = false;
453
- for (const definition of CODEX_HOOK_EVENTS) {
454
- const position = positions[definition.event];
455
- if (!position) continue;
456
- const key = codexHookStateKey(hooksJsonPath, definition.event, position);
457
- if (key in state) {
458
- delete state[key];
459
- changed = true;
460
- }
461
- }
462
- if (changed && Object.keys(state).length === 0) {
463
- const hooks = asRecord2(config.hooks);
464
- if (hooks) {
465
- delete hooks.state;
466
- if (Object.keys(hooks).length === 0) delete config.hooks;
467
- }
468
- }
469
- return changed;
470
- };
471
- var removeCodexSettings = (config, hooksJsonPath, positions) => {
472
- const mcp = removeCodexMcpServer(config);
473
- const trust = removeCodexHookTrust(config, hooksJsonPath, positions);
474
- return mcp || trust;
475
- };
476
- var addCodexHookTrust = (config, hooksJsonPath, command, positions) => {
477
- const hooks = ensureRecord(config, "hooks");
478
- const state = ensureRecord(hooks, "state");
479
- for (const definition of CODEX_HOOK_EVENTS) {
480
- const position = positions[definition.event];
481
- if (!position) continue;
482
- const key = codexHookStateKey(hooksJsonPath, definition.event, position);
483
- const ours = codexHookTrustHash(definition, command);
484
- const existing = asRecord2(state[key]) ?? {};
485
- state[key] = { ...existing, trusted_hash: ours };
486
- for (const stale of staleTrustKeys(state, hooksJsonPath, definition.event, key, ours)) {
487
- delete state[stale];
488
- }
489
- }
490
- };
491
- var staleTrustKeys = (state, hooksJsonPath, event, currentKey, ourHash) => {
492
- const prefix = `${hooksJsonPath}:${CODEX_EVENT_KEY[event]}:`;
493
- return Object.keys(state).filter(
494
- (key) => key !== currentKey && key.startsWith(prefix) && asRecord2(state[key])?.trusted_hash === ourHash
495
- );
496
- };
497
-
498
- // src/setup/paths.ts
499
- var claudeSettings = (environment = process.env) => join3(claudeConfigDir(homedir3(), environment), "settings.json");
500
- var claudeJson = (environment = process.env) => claudeUserConfigFile(homedir3(), environment);
501
- var claudeSkillDir = (environment = process.env) => join3(claudeConfigDir(homedir3(), environment), "skills", "pushary");
502
- var cursorPluginDir = () => join3(homedir3(), ".cursor", "plugins", "local", "pushary");
503
- var cursorUserHooks = () => join3(homedir3(), ".cursor", "hooks.json");
504
- var cursorPluginMcp = () => join3(cursorPluginDir(), "mcp.json");
505
- var cursorPluginManifest = () => join3(cursorPluginDir(), ".cursor-plugin", "plugin.json");
506
- var cursorPluginRule = () => join3(cursorPluginDir(), "rules", "pushary.mdc");
507
- var cursorUserMcp = () => join3(homedir3(), ".cursor", "mcp.json");
508
- var vscodePluginDir = () => join3(homedir3(), ".pushary", "plugins", "vscode");
509
- var vscodePluginMcp = () => join3(vscodePluginDir(), ".mcp.json");
510
- var claudeSettingsLocal = () => join3(claudeConfigDir(), "settings.local.json");
511
- var pusharyDir = () => join3(homedir3(), ".pushary");
512
- var claudeSetupDir = () => process.env.CLAUDE_CONFIG_DIR ? join3(pusharyDir(), "setup", "claude-profiles", createHash2("sha256").update(claudeUserConfigFile()).digest("hex").slice(0, 32)) : join3(pusharyDir(), "setup");
513
- var claudeMcpReceipt = () => join3(claudeSetupDir(), "claude-mcp.json");
514
- var bridgeAgentKey = () => join3(pusharyDir(), "bridge-auth", "agent-key.json");
515
- var autoUpdateState = () => join3(pusharyDir(), "auto-update.json");
516
- var autoUpdateLock = () => join3(pusharyDir(), "auto-update.lock");
517
- var serviceOwedBackMark = () => join3(pusharyDir(), "service-owed-back");
518
- var autoUpdateLog = () => join3(pusharyDir(), "logs", "auto-update.log");
519
- var clientReportClaims = () => join3(pusharyDir(), "client-reports");
520
- var claudeRegistrationReceipt = () => join3(claudeSetupDir(), "claude-registration.json");
521
- var hermesConfig = () => join3(homedir3(), ".hermes", "config.yaml");
522
- var hermesConfigReceipt = () => join3(pusharyDir(), "setup", "hermes-config.json");
523
- var fxQuestionRuleReceipt = () => join3(pusharyDir(), "setup", "fx-question-rule.json");
524
- var hookTakeoverReceipt = (agent) => join3(agent === "claude_code" ? claudeSetupDir() : join3(pusharyDir(), "setup"), `hook-takeover-${agent}.json`);
525
- var codexSkillDir2 = () => join3(codexHome(), "skills", "pushary");
526
- var codexAgentsMd2 = () => join3(codexHome(), "AGENTS.md");
527
- var geminiSettings = () => join3(homedir3(), ".gemini", "settings.json");
528
- var geminiMd = () => join3(homedir3(), ".gemini", "GEMINI.md");
529
- var pusharyConfigFile = () => join3(homedir3(), ".pushary", "config.json");
530
- var fxConfigDir = () => join3(homedir3(), ".fx");
531
- var fxMcpProfile = () => join3(fxConfigDir(), "mcp.json");
532
- var fxSettings = () => join3(fxConfigDir(), "settings.json");
533
- var fxAgentsMd = () => join3(fxConfigDir(), "AGENTS.md");
534
-
535
- export {
536
- claudeConfigDir,
537
- claudeUserConfigFile,
538
- registeredCommands,
539
- namesOurBinary,
540
- registrationHolderOf,
541
- HOOK_SHELL,
542
- holdBudgetOf,
543
- guardBinary,
544
- guardBinaryRefusing,
545
- guardNodeScript,
546
- guardCursorGate,
547
- guardedArgv,
548
- registerHookEntry,
549
- isProtectedByScope,
550
- canonicalJson,
551
- CODEX_HOOK_BINARY,
552
- codexHome,
553
- codexHomeFrom,
554
- codexConfigToml,
555
- codexHooksJsonIn,
556
- codexHooksJson,
557
- codexAgentsMd,
558
- codexSkillDir,
559
- CODEX_HOOK_EVENTS,
560
- CODEX_REQUIRED_APPROVAL_EVENTS,
561
- codexMcpMixesCommandWithHttp,
562
- CODEX_RESTART_AFTER_TRANSPORT_CHANGE,
563
- codexMcpStartsCommand,
564
- addCodexMcpServer,
565
- readCodexMcpAuth,
566
- isPusharyCodexCommand,
567
- codexRegistrationHolder,
568
- addCodexHooks,
569
- removeCodexHooks,
570
- hasCodexHooks,
571
- missingCodexHookEvents,
572
- codexHookPositions,
573
- codexVacatedIndexes,
574
- dropVacatedCodexHookTrust,
575
- captureCodexHookTrust,
576
- restoreCodexHookTrust,
577
- codexTrustGaps,
578
- removeCodexHookTrust,
579
- removeCodexSettings,
580
- addCodexHookTrust,
581
- claudeSettings,
582
- claudeJson,
583
- claudeSkillDir,
584
- cursorPluginDir,
585
- cursorUserHooks,
586
- cursorPluginMcp,
587
- cursorPluginManifest,
588
- cursorPluginRule,
589
- cursorUserMcp,
590
- vscodePluginDir,
591
- vscodePluginMcp,
592
- claudeSettingsLocal,
593
- pusharyDir,
594
- claudeMcpReceipt,
595
- bridgeAgentKey,
596
- autoUpdateState,
597
- autoUpdateLock,
598
- serviceOwedBackMark,
599
- autoUpdateLog,
600
- clientReportClaims,
601
- claudeRegistrationReceipt,
602
- hermesConfig,
603
- hermesConfigReceipt,
604
- fxQuestionRuleReceipt,
605
- hookTakeoverReceipt,
606
- codexSkillDir2,
607
- codexAgentsMd2,
608
- geminiSettings,
609
- geminiMd,
610
- pusharyConfigFile,
611
- fxConfigDir,
612
- fxMcpProfile,
613
- fxSettings,
614
- fxAgentsMd
615
- };
@@ -1,41 +0,0 @@
1
- import {
2
- PRETOOLUSE_GATED_TOOLS
3
- } from "./chunk-FXECTHAG.js";
4
-
5
- // src/claude-tools.ts
6
- var POSTTOOLUSE_MIRROR_ONLY_TOOLS = ["TodoWrite", "Task", "WebFetch", "WebSearch"];
7
- var POSTTOOLUSE_MIRRORED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, ...POSTTOOLUSE_MIRROR_ONLY_TOOLS];
8
-
9
- // src/claude-notifications.ts
10
- var IDLE_PROMPT_NOTIFICATION = "idle_prompt";
11
- var NOTIFICATION_MATCHED_TYPES = [
12
- // Blocks. The agent, or one of its workers, is waiting on a person.
13
- "permission_prompt",
14
- "idle_prompt",
15
- "agent_needs_input",
16
- "worker_permission_prompt",
17
- // An MCP server asking the person for a value. The Elicitation hook answers it;
18
- // this is the feed row saying one is open.
19
- "elicitation_dialog",
20
- "elicitation_url_dialog",
21
- // Turn boundary.
22
- "agent_completed",
23
- // Quota. The island already reads plan usage, and these say when a limit hit,
24
- // went stale, or was turned off, which no polling of the usage endpoint reveals.
25
- "quota_auto_resume_fired",
26
- "quota_auto_resume_stale",
27
- "quota_auto_resume_disabled"
28
- ];
29
- var NOTIFICATION_PUSH_TYPES = /* @__PURE__ */ new Set([
30
- "idle_prompt",
31
- "agent_needs_input",
32
- "worker_permission_prompt"
33
- ]);
34
-
35
- export {
36
- POSTTOOLUSE_MIRROR_ONLY_TOOLS,
37
- POSTTOOLUSE_MIRRORED_TOOLS,
38
- IDLE_PROMPT_NOTIFICATION,
39
- NOTIFICATION_MATCHED_TYPES,
40
- NOTIFICATION_PUSH_TYPES
41
- };