@pushary/agent-hooks 1.7.1 → 1.7.3
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 +21 -0
- package/data/cursor-plugin/CHANGELOG.md +1 -0
- package/data/cursor-plugin/scripts/pushary-gate.mjs +3 -3
- package/data/cursor-plugin/scripts/pushary-gate.test.mjs +23 -1
- package/data/vscode-plugin/CHANGELOG.md +1 -0
- package/data/vscode-plugin/scripts/pushary-gate.mjs +3 -3
- package/dist/bin/pushary-bell-hook.js +23 -23
- package/dist/bin/pushary-bell.js +10 -10
- package/dist/bin/pushary-claude.js +48 -37
- package/dist/bin/pushary-clean.js +107 -60
- package/dist/bin/pushary-codex-bridge.js +18 -17
- package/dist/bin/pushary-codex-hook.js +53 -39
- package/dist/bin/pushary-codex.js +14 -12
- package/dist/bin/pushary-connect.js +16 -16
- package/dist/bin/pushary-cowork.js +5 -5
- package/dist/bin/pushary-daemon.js +27 -27
- package/dist/bin/pushary-disconnect.js +19 -17
- package/dist/bin/pushary-doctor.js +63 -35
- package/dist/bin/pushary-elicitation-hook.js +35 -26
- package/dist/bin/pushary-gemini-bridge.js +12 -12
- package/dist/bin/pushary-gemini-hook.js +47 -32
- package/dist/bin/pushary-hook.js +34 -32
- package/dist/bin/pushary-login.js +16 -16
- package/dist/bin/pushary-logout.js +8 -8
- package/dist/bin/pushary-mcp.js +9 -8
- package/dist/bin/pushary-mode.js +10 -10
- package/dist/bin/pushary-notification-hook.js +29 -27
- package/dist/bin/pushary-opencode-hook.js +46 -32
- package/dist/bin/pushary-permission-denied-hook.js +34 -32
- package/dist/bin/pushary-permission-hook.js +33 -31
- package/dist/bin/pushary-post-hook.js +29 -27
- package/dist/bin/pushary-prompt-hook.js +29 -27
- package/dist/bin/pushary-session-end-hook.js +29 -27
- package/dist/bin/pushary-session-start-hook.js +33 -31
- package/dist/bin/pushary-setup.js +69 -56
- package/dist/bin/pushary-stats.js +5 -5
- package/dist/bin/pushary-status.js +19 -19
- package/dist/bin/pushary-stop-hook.js +29 -27
- package/dist/bin/pushary-stopfailure-hook.js +29 -27
- package/dist/bin/pushary-suggestions.js +5 -5
- package/dist/bin/pushary-transcript-register.js +19 -19
- package/dist/bin/pushary-transcripts.js +7 -7
- package/dist/bin/pushary-upgrade.js +20 -20
- package/dist/bin/pushary-wait.js +10 -10
- package/dist/bin/pushary.js +6 -6
- package/dist/{chunk-MWVCDP64.js → chunk-3EUBQARL.js} +1 -1
- package/dist/{chunk-3QORH5EJ.js → chunk-5GB22QYL.js} +6 -4
- package/dist/chunk-5OP5MQI7.js +45 -0
- package/dist/{chunk-6PV2JQ64.js → chunk-5S2VBSJI.js} +2 -2
- package/dist/{chunk-UPKP67TA.js → chunk-62CVUUNU.js} +2 -2
- package/dist/{chunk-42XR73I2.js → chunk-62VT3BPH.js} +35 -35
- package/dist/chunk-6JQFIHZC.js +99 -0
- package/dist/{chunk-2FU43B5Q.js → chunk-7OA34PNW.js} +2 -2
- package/dist/{chunk-7GI6QC3M.js → chunk-7RUJKCR4.js} +2 -2
- package/dist/{chunk-H6JV44TE.js → chunk-AWVNAYGD.js} +1 -1
- package/dist/{chunk-XMN37YJH.js → chunk-BGBLLHZ4.js} +1 -1
- package/dist/{chunk-VCMFKZON.js → chunk-BIH2Y2HP.js} +2 -2
- package/dist/{chunk-YZKS3ME3.js → chunk-D6OODZCM.js} +2 -2
- package/dist/{chunk-JTQDP4ZL.js → chunk-DUQO4C4I.js} +3 -3
- package/dist/{chunk-3QE3BHBW.js → chunk-EADXTSHE.js} +2 -2
- package/dist/{chunk-43SSQCWO.js → chunk-EEEJ2JIL.js} +3 -3
- package/dist/{chunk-4C4NRDIC.js → chunk-EUGNVLMG.js} +1 -1
- package/dist/{chunk-WSC53O7I.js → chunk-G3OMOTJ4.js} +3 -3
- package/dist/{chunk-XFNVG3OV.js → chunk-G4GLCLKK.js} +44 -9
- package/dist/{chunk-62TEPRWQ.js → chunk-G62JL2NT.js} +1 -1
- package/dist/{chunk-QPR33SHS.js → chunk-G6RRVJOG.js} +6 -6
- package/dist/{chunk-Y6GKOZBT.js → chunk-IPSRMLCJ.js} +1 -1
- package/dist/{chunk-MCNS4725.js → chunk-IRZG3HEU.js} +1 -1
- package/dist/{chunk-55RO62FV.js → chunk-IWJKSIB4.js} +1 -1
- package/dist/{chunk-NID4UZDN.js → chunk-KEL5MXRL.js} +1 -1
- package/dist/{chunk-BYVB3RX3.js → chunk-KJXUIPS4.js} +2 -2
- package/dist/{chunk-SNWNA3MQ.js → chunk-LHC45YUC.js} +1 -1
- package/dist/{chunk-XPTCPU6V.js → chunk-LPNJLKBQ.js} +1 -1
- package/dist/{chunk-WZWXBTRF.js → chunk-MIXWMA73.js} +3 -3
- package/dist/{chunk-454KMJHF.js → chunk-MZBRL5H5.js} +34 -1
- package/dist/{chunk-KSNAAMU5.js → chunk-N5MZH5A6.js} +4 -4
- package/dist/chunk-N6IOSZOE.js +185 -0
- package/dist/{chunk-XPMOCJHN.js → chunk-NOI3XTCY.js} +1 -1
- package/dist/{chunk-NAAZCNKI.js → chunk-O3JDWNLU.js} +351 -37
- package/dist/{chunk-7GYGVQBU.js → chunk-OTNOANMX.js} +8 -8
- package/dist/{chunk-P5CBNSYL.js → chunk-OVC5QXN5.js} +1 -1
- package/dist/{chunk-O5JD7UI5.js → chunk-P2VIBGXA.js} +3 -3
- package/dist/{chunk-3T35OE7C.js → chunk-PRNFSORD.js} +4 -4
- package/dist/{chunk-OAL44FM2.js → chunk-R6OYCUNK.js} +1 -1
- package/dist/{chunk-6SJQ442W.js → chunk-RLW3JWDY.js} +2 -2
- package/dist/{chunk-SVEMF2VO.js → chunk-TCVMK6GI.js} +4 -4
- package/dist/{chunk-O5PRIYFZ.js → chunk-U4TMAANR.js} +3 -0
- package/dist/{chunk-WM3U2RUK.js → chunk-U6RVDUJ5.js} +75 -232
- package/dist/{chunk-KBLIVEFJ.js → chunk-UOQRM7JQ.js} +5 -5
- package/dist/{chunk-NQFGVAT6.js → chunk-VE7TXLR4.js} +19 -2
- package/dist/{chunk-IGBDOZUO.js → chunk-VKVSRCBO.js} +1 -1
- package/dist/{chunk-ZEMSCGDD.js → chunk-VYPJHGG6.js} +8 -3
- package/dist/{chunk-YQN7S57T.js → chunk-WGMW7OXW.js} +6 -6
- package/dist/{chunk-OTZHT34O.js → chunk-WPX67AKT.js} +1 -1
- package/dist/{chunk-XDASEYRS.js → chunk-WTJM7PSL.js} +3 -3
- package/dist/{chunk-Q7QRR6YL.js → chunk-Y4ZH64UK.js} +2 -2
- package/dist/{chunk-ZIIYTQHC.js → chunk-YC27PROF.js} +12 -4
- package/dist/{chunk-AHWJHLG5.js → chunk-YPUBA2FL.js} +7 -5
- package/dist/{chunk-EIZW73P5.js → chunk-YYCTF4Q5.js} +1 -1
- package/dist/{chunk-AAGLDXH4.js → chunk-ZKJ34T2F.js} +5 -5
- package/dist/{reapply-66GQIBXN.js → reapply-PH5T4BGR.js} +9 -9
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +22 -20
- package/package.json +2 -1
- package/dist/chunk-JMBG47WV.js +0 -336
- package/dist/chunk-YHG74UFF.js +0 -12
|
@@ -1,15 +1,322 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MCP_BRIDGE_BINARY
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7OA34PNW.js";
|
|
4
4
|
import {
|
|
5
5
|
openCodeConfigDirFrom
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-KEL5MXRL.js";
|
|
7
7
|
import {
|
|
8
|
-
codexHomeFrom
|
|
9
|
-
|
|
8
|
+
codexHomeFrom,
|
|
9
|
+
resolvePathBinary
|
|
10
|
+
} from "./chunk-MZBRL5H5.js";
|
|
10
11
|
import {
|
|
11
12
|
HOOK_COMPATIBLE_PROFILES
|
|
12
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-G4GLCLKK.js";
|
|
14
|
+
|
|
15
|
+
// src/hermes-config.ts
|
|
16
|
+
import { execFileSync } from "child_process";
|
|
17
|
+
import { existsSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
18
|
+
import { homedir, tmpdir } from "os";
|
|
19
|
+
import { join } from "path";
|
|
20
|
+
var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
21
|
+
var isSnapshot = (value) => isRecord(value) && typeof value.present === "boolean" && Object.hasOwn(value, "value");
|
|
22
|
+
var isHermesConfigReceipt = (value) => {
|
|
23
|
+
if (!isRecord(value)) return false;
|
|
24
|
+
return ["security", "approval", "transport", "fallback", "plugins", "enabled", "agent", "disabled"].every((key) => isSnapshot(value[key])) && typeof value.pushary_enabled === "boolean" && typeof value.clarify_disabled === "boolean";
|
|
25
|
+
};
|
|
26
|
+
var HERMES_PIP_PACKAGE = "hermes-plugin-pushary";
|
|
27
|
+
var HERMES_PLUGIN_NAME = "pushary";
|
|
28
|
+
var HERMES_CONFIG_SCRIPT = String.raw`
|
|
29
|
+
import copy, importlib.util, json, os, sys
|
|
30
|
+
from hermes_cli.config import load_config, save_config
|
|
31
|
+
|
|
32
|
+
PUSHARY_TRANSPORT = "pushary"
|
|
33
|
+
PUSHARY_FALLBACK = "builtin"
|
|
34
|
+
PUSHARY_PLUGIN = "pushary"
|
|
35
|
+
PUSHARY_PLUGIN_MODULE = "pushary_plugin"
|
|
36
|
+
QUESTION_TOOLSET = "clarify"
|
|
37
|
+
|
|
38
|
+
mode = sys.argv[1]
|
|
39
|
+
receipt_path = sys.argv[2] if len(sys.argv) > 2 else None
|
|
40
|
+
c = load_config()
|
|
41
|
+
original = copy.deepcopy(c)
|
|
42
|
+
|
|
43
|
+
def section(obj, key):
|
|
44
|
+
value = obj.get(key)
|
|
45
|
+
return value if isinstance(value, dict) else {}
|
|
46
|
+
|
|
47
|
+
def members(obj, key):
|
|
48
|
+
value = obj.get(key)
|
|
49
|
+
return value if isinstance(value, list) else []
|
|
50
|
+
|
|
51
|
+
if mode == "status":
|
|
52
|
+
print(json.dumps({
|
|
53
|
+
"plugin_installed": importlib.util.find_spec(PUSHARY_PLUGIN_MODULE) is not None,
|
|
54
|
+
"plugin_enabled": PUSHARY_PLUGIN in members(section(c, "plugins"), "enabled"),
|
|
55
|
+
"approvals_routed": section(section(c, "security"), "approval").get("transport") == PUSHARY_TRANSPORT,
|
|
56
|
+
"questions_routed": QUESTION_TOOLSET in members(section(c, "agent"), "disabled_toolsets"),
|
|
57
|
+
}))
|
|
58
|
+
sys.exit(0)
|
|
59
|
+
|
|
60
|
+
def recorded(snapshot, value):
|
|
61
|
+
return bool(snapshot.get("present")) and snapshot.get("value") == value
|
|
62
|
+
|
|
63
|
+
def pop_if(obj, key, value):
|
|
64
|
+
if obj.get(key) == value:
|
|
65
|
+
obj.pop(key, None)
|
|
66
|
+
|
|
67
|
+
def snap(obj, key):
|
|
68
|
+
return {"present": key in obj, "value": obj.get(key)}
|
|
69
|
+
|
|
70
|
+
restore_conflicts = []
|
|
71
|
+
|
|
72
|
+
def restore(obj, key, before, ours):
|
|
73
|
+
if before.get("present") and before.get("value") == ours:
|
|
74
|
+
return
|
|
75
|
+
if before.get("present"):
|
|
76
|
+
if key in obj and obj.get(key) == before.get("value"):
|
|
77
|
+
return
|
|
78
|
+
elif key not in obj:
|
|
79
|
+
return
|
|
80
|
+
if obj.get(key) != ours:
|
|
81
|
+
restore_conflicts.append(key)
|
|
82
|
+
return
|
|
83
|
+
if before.get("present"):
|
|
84
|
+
obj[key] = before.get("value")
|
|
85
|
+
else:
|
|
86
|
+
obj.pop(key, None)
|
|
87
|
+
|
|
88
|
+
def restore_container(obj, key, before, current, changed):
|
|
89
|
+
raw = obj.get(key)
|
|
90
|
+
if isinstance(before.get("value"), dict):
|
|
91
|
+
if not isinstance(raw, dict):
|
|
92
|
+
if changed:
|
|
93
|
+
restore_conflicts.append(key)
|
|
94
|
+
return
|
|
95
|
+
if current or before.get("present"):
|
|
96
|
+
obj[key] = current
|
|
97
|
+
else:
|
|
98
|
+
obj.pop(key, None)
|
|
99
|
+
elif isinstance(raw, dict) and current:
|
|
100
|
+
restore_conflicts.append(key)
|
|
101
|
+
else:
|
|
102
|
+
restore(obj, key, before, {})
|
|
103
|
+
|
|
104
|
+
def restore_list_member(obj, key, before, ours, ours_before):
|
|
105
|
+
raw = obj.get(key)
|
|
106
|
+
if isinstance(before.get("value"), list):
|
|
107
|
+
if ours_before:
|
|
108
|
+
return
|
|
109
|
+
if not isinstance(raw, list):
|
|
110
|
+
restore_conflicts.append(key)
|
|
111
|
+
return
|
|
112
|
+
remaining = [item for item in raw if item != ours]
|
|
113
|
+
if remaining or before.get("present"):
|
|
114
|
+
obj[key] = remaining
|
|
115
|
+
else:
|
|
116
|
+
obj.pop(key, None)
|
|
117
|
+
return
|
|
118
|
+
if before.get("present") and raw == before.get("value"):
|
|
119
|
+
return
|
|
120
|
+
if not before.get("present") and key not in obj:
|
|
121
|
+
return
|
|
122
|
+
if not isinstance(raw, list):
|
|
123
|
+
restore_conflicts.append(key)
|
|
124
|
+
return
|
|
125
|
+
remaining = [item for item in raw if item != ours]
|
|
126
|
+
if remaining:
|
|
127
|
+
restore_conflicts.append(key)
|
|
128
|
+
else:
|
|
129
|
+
restore(obj, key, before, raw)
|
|
130
|
+
|
|
131
|
+
def valid_snapshot(value):
|
|
132
|
+
return isinstance(value, dict) and isinstance(value.get("present"), bool) and "value" in value
|
|
133
|
+
|
|
134
|
+
def valid_receipt(value):
|
|
135
|
+
snapshots = ["security", "approval", "transport", "fallback", "plugins", "enabled", "agent", "disabled"]
|
|
136
|
+
return (isinstance(value, dict)
|
|
137
|
+
and all(valid_snapshot(value.get(key)) for key in snapshots)
|
|
138
|
+
and isinstance(value.get("pushary_enabled"), bool)
|
|
139
|
+
and isinstance(value.get("clarify_disabled"), bool))
|
|
140
|
+
|
|
141
|
+
if mode == "setup":
|
|
142
|
+
security_before = snap(c, "security")
|
|
143
|
+
s = section(c, "security")
|
|
144
|
+
approval_before = snap(s, "approval")
|
|
145
|
+
ap = section(s, "approval")
|
|
146
|
+
plugins_before = snap(c, "plugins")
|
|
147
|
+
p = section(c, "plugins")
|
|
148
|
+
agent_before = snap(c, "agent")
|
|
149
|
+
a = section(c, "agent")
|
|
150
|
+
enabled = members(p, "enabled")
|
|
151
|
+
disabled = members(a, "disabled_toolsets")
|
|
152
|
+
receipt = {
|
|
153
|
+
"security": security_before,
|
|
154
|
+
"approval": approval_before,
|
|
155
|
+
"transport": snap(ap, "transport"),
|
|
156
|
+
"fallback": snap(ap, "transport_fallback"),
|
|
157
|
+
"plugins": plugins_before,
|
|
158
|
+
"enabled": snap(p, "enabled"),
|
|
159
|
+
"pushary_enabled": PUSHARY_PLUGIN in enabled,
|
|
160
|
+
"agent": agent_before,
|
|
161
|
+
"disabled": snap(a, "disabled_toolsets"),
|
|
162
|
+
"clarify_disabled": QUESTION_TOOLSET in disabled,
|
|
163
|
+
}
|
|
164
|
+
if os.path.exists(receipt_path):
|
|
165
|
+
with open(receipt_path, encoding="utf-8") as handle:
|
|
166
|
+
existing_receipt = json.load(handle)
|
|
167
|
+
if not valid_receipt(existing_receipt):
|
|
168
|
+
raise ValueError("invalid Pushary Hermes setup receipt")
|
|
169
|
+
else:
|
|
170
|
+
os.makedirs(os.path.dirname(receipt_path), exist_ok=True)
|
|
171
|
+
temp = receipt_path + ".tmp"
|
|
172
|
+
with open(temp, "x", encoding="utf-8") as handle:
|
|
173
|
+
json.dump(receipt, handle)
|
|
174
|
+
os.chmod(temp, 0o600)
|
|
175
|
+
os.replace(temp, receipt_path)
|
|
176
|
+
ap["transport"] = PUSHARY_TRANSPORT
|
|
177
|
+
ap["transport_fallback"] = PUSHARY_FALLBACK
|
|
178
|
+
s["approval"] = ap
|
|
179
|
+
c["security"] = s
|
|
180
|
+
p["enabled"] = enabled if PUSHARY_PLUGIN in enabled else enabled + [PUSHARY_PLUGIN]
|
|
181
|
+
c["plugins"] = p
|
|
182
|
+
a["disabled_toolsets"] = disabled if QUESTION_TOOLSET in disabled else disabled + [QUESTION_TOOLSET]
|
|
183
|
+
c["agent"] = a
|
|
184
|
+
else:
|
|
185
|
+
receipt_exists = os.path.exists(receipt_path)
|
|
186
|
+
try:
|
|
187
|
+
with open(receipt_path, encoding="utf-8") as handle:
|
|
188
|
+
receipt = json.load(handle)
|
|
189
|
+
except (OSError, ValueError):
|
|
190
|
+
if receipt_exists:
|
|
191
|
+
raise
|
|
192
|
+
receipt = None
|
|
193
|
+
s = section(c, "security")
|
|
194
|
+
ap = section(s, "approval")
|
|
195
|
+
if receipt:
|
|
196
|
+
if not valid_receipt(receipt):
|
|
197
|
+
raise ValueError("invalid Pushary Hermes setup receipt")
|
|
198
|
+
approval_changed = (not receipt["transport"].get("present")
|
|
199
|
+
or receipt["transport"].get("value") != PUSHARY_TRANSPORT
|
|
200
|
+
or not receipt["fallback"].get("present")
|
|
201
|
+
or receipt["fallback"].get("value") != PUSHARY_FALLBACK)
|
|
202
|
+
plugins_changed = not (isinstance(receipt["enabled"].get("value"), list)
|
|
203
|
+
and receipt["pushary_enabled"])
|
|
204
|
+
agent_changed = not (isinstance(receipt["disabled"].get("value"), list)
|
|
205
|
+
and receipt["clarify_disabled"])
|
|
206
|
+
transport_left_over = recorded(receipt["transport"], PUSHARY_TRANSPORT)
|
|
207
|
+
if transport_left_over:
|
|
208
|
+
pop_if(ap, "transport", PUSHARY_TRANSPORT)
|
|
209
|
+
else:
|
|
210
|
+
restore(ap, "transport", receipt["transport"], PUSHARY_TRANSPORT)
|
|
211
|
+
if transport_left_over and recorded(receipt["fallback"], PUSHARY_FALLBACK):
|
|
212
|
+
pop_if(ap, "transport_fallback", PUSHARY_FALLBACK)
|
|
213
|
+
else:
|
|
214
|
+
restore(ap, "transport_fallback", receipt["fallback"], PUSHARY_FALLBACK)
|
|
215
|
+
else:
|
|
216
|
+
pop_if(ap, "transport", PUSHARY_TRANSPORT)
|
|
217
|
+
pop_if(ap, "transport_fallback", PUSHARY_FALLBACK)
|
|
218
|
+
if receipt:
|
|
219
|
+
restore_container(s, "approval", receipt["approval"], ap, approval_changed)
|
|
220
|
+
restore_container(c, "security", receipt["security"], s, approval_changed)
|
|
221
|
+
else:
|
|
222
|
+
if ap: s["approval"] = ap
|
|
223
|
+
else: s.pop("approval", None)
|
|
224
|
+
if s: c["security"] = s
|
|
225
|
+
else: c.pop("security", None)
|
|
226
|
+
|
|
227
|
+
p = section(c, "plugins")
|
|
228
|
+
if receipt:
|
|
229
|
+
restore_list_member(p, "enabled", receipt["enabled"], PUSHARY_PLUGIN, False)
|
|
230
|
+
restore_container(c, "plugins", receipt["plugins"], p, plugins_changed)
|
|
231
|
+
else:
|
|
232
|
+
enabled = [item for item in members(p, "enabled") if item != PUSHARY_PLUGIN]
|
|
233
|
+
if enabled: p["enabled"] = enabled
|
|
234
|
+
else: p.pop("enabled", None)
|
|
235
|
+
if p: c["plugins"] = p
|
|
236
|
+
else: c.pop("plugins", None)
|
|
237
|
+
|
|
238
|
+
a = section(c, "agent")
|
|
239
|
+
if receipt:
|
|
240
|
+
clarify_was_users = receipt["clarify_disabled"] and not recorded(receipt["transport"], PUSHARY_TRANSPORT)
|
|
241
|
+
restore_list_member(a, "disabled_toolsets", receipt["disabled"], QUESTION_TOOLSET, clarify_was_users)
|
|
242
|
+
restore_container(c, "agent", receipt["agent"], a, agent_changed)
|
|
243
|
+
else:
|
|
244
|
+
disabled = [item for item in members(a, "disabled_toolsets") if item != QUESTION_TOOLSET]
|
|
245
|
+
if disabled: a["disabled_toolsets"] = disabled
|
|
246
|
+
else: a.pop("disabled_toolsets", None)
|
|
247
|
+
if a: c["agent"] = a
|
|
248
|
+
else: c.pop("agent", None)
|
|
249
|
+
|
|
250
|
+
if receipt and restore_conflicts:
|
|
251
|
+
raise ValueError("Hermes config changed after Pushary setup")
|
|
252
|
+
|
|
253
|
+
changed = c != original
|
|
254
|
+
if changed and mode != "clean-preview":
|
|
255
|
+
save_config(c)
|
|
256
|
+
print(json.dumps({"changed": changed}))
|
|
257
|
+
`;
|
|
258
|
+
var resolveHermesPython = () => {
|
|
259
|
+
const launcher = resolvePathBinary("hermes");
|
|
260
|
+
if (launcher && process.platform !== "win32") {
|
|
261
|
+
try {
|
|
262
|
+
const shebang = readFileSync(launcher, "utf-8").split("\n", 1)[0];
|
|
263
|
+
const interpreter = shebang?.startsWith("#!") ? shebang.slice(2).trim().split(/\s+/)[0] : void 0;
|
|
264
|
+
if (interpreter && /python/i.test(interpreter) && existsSync(interpreter)) return interpreter;
|
|
265
|
+
} catch {
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const root = join(homedir(), ".hermes", "hermes-agent", "venv");
|
|
269
|
+
const candidates = process.platform === "win32" ? [join(root, "Scripts", "python.exe"), join(root, "Scripts", "python3.exe")] : [join(root, "bin", "python3"), join(root, "bin", "python")];
|
|
270
|
+
return candidates.find(existsSync) ?? null;
|
|
271
|
+
};
|
|
272
|
+
var HERMES_SCRIPT_TIMEOUT_MS = 15e3;
|
|
273
|
+
var runPythonScript = (python, script, args) => {
|
|
274
|
+
const path = join(tmpdir(), `pushary-hermes-${process.pid}-${Date.now()}.py`);
|
|
275
|
+
try {
|
|
276
|
+
writeFileSync(path, script, { encoding: "utf-8", mode: 384 });
|
|
277
|
+
return execFileSync(python, [path, ...args], {
|
|
278
|
+
env: { ...process.env },
|
|
279
|
+
encoding: "utf-8",
|
|
280
|
+
stdio: "pipe",
|
|
281
|
+
timeout: HERMES_SCRIPT_TIMEOUT_MS
|
|
282
|
+
});
|
|
283
|
+
} catch {
|
|
284
|
+
return null;
|
|
285
|
+
} finally {
|
|
286
|
+
try {
|
|
287
|
+
rmSync(path, { force: true });
|
|
288
|
+
} catch {
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
var lastReport = (stdout) => {
|
|
293
|
+
const line = stdout.trim().split("\n").at(-1) ?? "";
|
|
294
|
+
try {
|
|
295
|
+
return JSON.parse(line);
|
|
296
|
+
} catch {
|
|
297
|
+
return void 0;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
var configRunFrom = (stdout) => {
|
|
301
|
+
const report = stdout === null ? void 0 : lastReport(stdout);
|
|
302
|
+
if (!isRecord(report) || typeof report.changed !== "boolean") return "failed";
|
|
303
|
+
return report.changed ? "changed" : "unchanged";
|
|
304
|
+
};
|
|
305
|
+
var runHermesConfigScript = (python, mode, receiptPath) => configRunFrom(runPythonScript(python, HERMES_CONFIG_SCRIPT, [mode, receiptPath]));
|
|
306
|
+
var HERMES_STATUS_FIELDS = ["plugin_installed", "plugin_enabled", "approvals_routed", "questions_routed"];
|
|
307
|
+
var isHermesStatusReport = (value) => isRecord(value) && HERMES_STATUS_FIELDS.every((field) => typeof value[field] === "boolean");
|
|
308
|
+
var hermesWiredByPushary = (status, setupRecorded) => setupRecorded || status.pluginEnabled || status.approvalsRouted;
|
|
309
|
+
var readHermesStatus = (python) => {
|
|
310
|
+
const stdout = runPythonScript(python, HERMES_CONFIG_SCRIPT, ["status"]);
|
|
311
|
+
const report = stdout === null ? void 0 : lastReport(stdout);
|
|
312
|
+
if (!isHermesStatusReport(report)) return null;
|
|
313
|
+
return {
|
|
314
|
+
pluginInstalled: report.plugin_installed,
|
|
315
|
+
pluginEnabled: report.plugin_enabled,
|
|
316
|
+
approvalsRouted: report.approvals_routed,
|
|
317
|
+
questionsRouted: report.questions_routed
|
|
318
|
+
};
|
|
319
|
+
};
|
|
13
320
|
|
|
14
321
|
// src/fx-config.ts
|
|
15
322
|
var FX_SERVER_NAME = "pushary";
|
|
@@ -347,13 +654,13 @@ var workspaceShowsQuestionTool = (workspace) => {
|
|
|
347
654
|
var workspacesShowingQuestionTool = (settings) => Object.entries(asRecord(settings[WORKSPACES_KEY]) ?? {}).filter(([, workspace]) => workspaceShowsQuestionTool(workspace)).map(([path]) => path);
|
|
348
655
|
|
|
349
656
|
// src/fx-files.ts
|
|
350
|
-
import { existsSync, lstatSync, readFileSync, realpathSync } from "fs";
|
|
657
|
+
import { existsSync as existsSync2, lstatSync, readFileSync as readFileSync2, realpathSync } from "fs";
|
|
351
658
|
import { relative, isAbsolute } from "path";
|
|
352
659
|
var readFxFile = (path, read) => {
|
|
353
|
-
if (!
|
|
660
|
+
if (!existsSync2(path)) return { kind: "missing" };
|
|
354
661
|
let text;
|
|
355
662
|
try {
|
|
356
|
-
text =
|
|
663
|
+
text = readFileSync2(path, "utf-8");
|
|
357
664
|
} catch {
|
|
358
665
|
return { kind: "unreadable" };
|
|
359
666
|
}
|
|
@@ -374,8 +681,8 @@ var fxIgnoresInstructionsFile = (path, fxDir) => {
|
|
|
374
681
|
};
|
|
375
682
|
|
|
376
683
|
// src/vscode-config.ts
|
|
377
|
-
import { homedir } from "os";
|
|
378
|
-
import { join } from "path";
|
|
684
|
+
import { homedir as homedir2 } from "os";
|
|
685
|
+
import { join as join2 } from "path";
|
|
379
686
|
var PLUGIN_LOCATIONS_KEY = "chat.pluginLocations";
|
|
380
687
|
var blankJsonComments = (text) => {
|
|
381
688
|
let out = "";
|
|
@@ -505,13 +812,13 @@ var pluginLocationSnippet = (pluginDir) => `"${PLUGIN_LOCATIONS_KEY}": {
|
|
|
505
812
|
}`;
|
|
506
813
|
var VSCODE_PRODUCTS = ["Code", "Code - Insiders"];
|
|
507
814
|
var settingsRoot = (home, platform) => {
|
|
508
|
-
if (platform === "darwin") return
|
|
509
|
-
if (platform === "win32") return process.env.APPDATA?.trim() ||
|
|
510
|
-
return process.env.XDG_CONFIG_HOME?.trim() ||
|
|
815
|
+
if (platform === "darwin") return join2(home, "Library", "Application Support");
|
|
816
|
+
if (platform === "win32") return process.env.APPDATA?.trim() || join2(home, "AppData", "Roaming");
|
|
817
|
+
return process.env.XDG_CONFIG_HOME?.trim() || join2(home, ".config");
|
|
511
818
|
};
|
|
512
|
-
var vscodeSettingsCandidates = (home =
|
|
819
|
+
var vscodeSettingsCandidates = (home = homedir2(), platform = process.platform) => {
|
|
513
820
|
const root = settingsRoot(home, platform);
|
|
514
|
-
return VSCODE_PRODUCTS.map((product) =>
|
|
821
|
+
return VSCODE_PRODUCTS.map((product) => join2(root, product, "User", "settings.json"));
|
|
515
822
|
};
|
|
516
823
|
var vscodeSettingsTargets = (exists, home, platform) => {
|
|
517
824
|
const candidates = vscodeSettingsCandidates(home, platform);
|
|
@@ -521,9 +828,9 @@ var vscodeSettingsTargets = (exists, home, platform) => {
|
|
|
521
828
|
|
|
522
829
|
// src/setup/detect.ts
|
|
523
830
|
import { execSync } from "child_process";
|
|
524
|
-
import { existsSync as
|
|
525
|
-
import { homedir as
|
|
526
|
-
import { dirname, join as
|
|
831
|
+
import { existsSync as existsSync3 } from "fs";
|
|
832
|
+
import { homedir as homedir3 } from "os";
|
|
833
|
+
import { dirname, join as join3 } from "path";
|
|
527
834
|
var whichCommand = () => process.platform === "win32" ? "where" : "which";
|
|
528
835
|
var binaryOnPath = (binary) => {
|
|
529
836
|
try {
|
|
@@ -533,7 +840,7 @@ var binaryOnPath = (binary) => {
|
|
|
533
840
|
return false;
|
|
534
841
|
}
|
|
535
842
|
};
|
|
536
|
-
var defaultDeps = { onPath: binaryOnPath, exists:
|
|
843
|
+
var defaultDeps = { onPath: binaryOnPath, exists: existsSync3 };
|
|
537
844
|
var detectAgent = (probe, deps = defaultDeps) => {
|
|
538
845
|
const checked = [];
|
|
539
846
|
if (probe.binary) {
|
|
@@ -555,12 +862,12 @@ var detectAgent = (probe, deps = defaultDeps) => {
|
|
|
555
862
|
}
|
|
556
863
|
return { kind: "not-found", checked };
|
|
557
864
|
};
|
|
558
|
-
var agentProbes = (home =
|
|
865
|
+
var agentProbes = (home = homedir3()) => ({
|
|
559
866
|
claude_code: {
|
|
560
867
|
binary: "claude",
|
|
561
868
|
// The native installer puts it here, outside a default non-login PATH.
|
|
562
|
-
paths: [
|
|
563
|
-
configMarkers: [
|
|
869
|
+
paths: [join3(home, ".local", "bin", "claude")],
|
|
870
|
+
configMarkers: [join3(home, ".claude")]
|
|
564
871
|
},
|
|
565
872
|
codex: {
|
|
566
873
|
binary: "codex",
|
|
@@ -570,25 +877,25 @@ var agentProbes = (home = homedir2()) => ({
|
|
|
570
877
|
gemini_cli: {
|
|
571
878
|
binary: "gemini",
|
|
572
879
|
paths: [],
|
|
573
|
-
configMarkers: [
|
|
880
|
+
configMarkers: [join3(home, ".gemini")]
|
|
574
881
|
},
|
|
575
882
|
hermes: {
|
|
576
883
|
binary: "hermes",
|
|
577
884
|
paths: [],
|
|
578
|
-
configMarkers: [
|
|
885
|
+
configMarkers: [join3(home, ".hermes")]
|
|
579
886
|
},
|
|
580
887
|
cursor: {
|
|
581
888
|
// GUI editor. `cursor` on PATH only exists if the user ran "Install 'cursor'
|
|
582
889
|
// command in PATH" from the command palette, which most never do.
|
|
583
890
|
binary: "cursor",
|
|
584
|
-
paths: process.platform === "darwin" ? ["/Applications/Cursor.app"] : process.platform === "win32" ? [
|
|
585
|
-
configMarkers: [
|
|
891
|
+
paths: process.platform === "darwin" ? ["/Applications/Cursor.app"] : process.platform === "win32" ? [join3(process.env.LOCALAPPDATA ?? join3(home, "AppData", "Local"), "Programs", "cursor")] : ["/usr/share/cursor", join3(home, ".local", "share", "cursor")],
|
|
892
|
+
configMarkers: [join3(home, ".cursor")]
|
|
586
893
|
},
|
|
587
894
|
vscode: {
|
|
588
895
|
// Like Cursor, a GUI editor: `code` on PATH only exists if the user ran
|
|
589
896
|
// "Shell Command: Install 'code' command in PATH", which on macOS is opt-in.
|
|
590
897
|
binary: "code",
|
|
591
|
-
paths: process.platform === "darwin" ? ["/Applications/Visual Studio Code.app"] : process.platform === "win32" ? [
|
|
898
|
+
paths: process.platform === "darwin" ? ["/Applications/Visual Studio Code.app"] : process.platform === "win32" ? [join3(process.env.LOCALAPPDATA ?? join3(home, "AppData", "Local"), "Programs", "Microsoft VS Code")] : ["/usr/share/code", join3(home, ".local", "share", "code")],
|
|
592
899
|
// The settings directory rather than ~/.vscode, because the settings
|
|
593
900
|
// directory is what this installer actually writes to. Insiders counts:
|
|
594
901
|
// someone running only Insiders still has VS Code.
|
|
@@ -604,7 +911,7 @@ var agentProbes = (home = homedir2()) => ({
|
|
|
604
911
|
},
|
|
605
912
|
fx: {
|
|
606
913
|
binary: null,
|
|
607
|
-
paths: [
|
|
914
|
+
paths: [join3(home, ".fx", "settings.json"), join3(home, ".fx", "sessions"), join3(home, ".fx", "history.jsonl")],
|
|
608
915
|
configMarkers: []
|
|
609
916
|
},
|
|
610
917
|
...compatibleProbes(),
|
|
@@ -628,7 +935,7 @@ var detectAllAgents = (deps = defaultDeps, home) => {
|
|
|
628
935
|
}));
|
|
629
936
|
};
|
|
630
937
|
var isDetected = (result) => result.kind === "installed";
|
|
631
|
-
var shortenHome = (path, home =
|
|
938
|
+
var shortenHome = (path, home = homedir3()) => home && path.startsWith(home) ? `~${path.slice(home.length)}` : path;
|
|
632
939
|
var describeDetection = (result, home) => {
|
|
633
940
|
if (result.kind !== "installed") return null;
|
|
634
941
|
const evidence = shortenHome(result.evidence, home);
|
|
@@ -636,7 +943,7 @@ var describeDetection = (result, home) => {
|
|
|
636
943
|
};
|
|
637
944
|
|
|
638
945
|
// src/instruction-file.ts
|
|
639
|
-
import { existsSync as
|
|
946
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync, rmSync as rmSync2 } from "fs";
|
|
640
947
|
import { dirname as dirname2 } from "path";
|
|
641
948
|
var PUSHARY_BEGIN = "<!-- BEGIN PUSHARY (managed by @pushary/agent-hooks; do not edit this block) -->";
|
|
642
949
|
var PUSHARY_END = "<!-- END PUSHARY -->";
|
|
@@ -666,10 +973,10 @@ ${body}
|
|
|
666
973
|
${PUSHARY_END}`;
|
|
667
974
|
var writeInstructionBlock = (filePath, body) => {
|
|
668
975
|
const dir = dirname2(filePath);
|
|
669
|
-
if (!
|
|
976
|
+
if (!existsSync4(dir)) mkdirSync(dir, { recursive: true });
|
|
670
977
|
let existing = "";
|
|
671
978
|
try {
|
|
672
|
-
existing =
|
|
979
|
+
existing = readFileSync3(filePath, "utf-8");
|
|
673
980
|
} catch {
|
|
674
981
|
}
|
|
675
982
|
const block = wrap(body);
|
|
@@ -682,12 +989,12 @@ var writeInstructionBlock = (filePath, body) => {
|
|
|
682
989
|
const prefix = existing.trim() ? existing.replace(/\s*$/, "") + "\n\n" : "";
|
|
683
990
|
next = prefix + block + "\n";
|
|
684
991
|
}
|
|
685
|
-
|
|
992
|
+
writeFileSync2(filePath, next, "utf-8");
|
|
686
993
|
};
|
|
687
994
|
var removeInstructionBlock = (filePath) => {
|
|
688
995
|
let existing = "";
|
|
689
996
|
try {
|
|
690
|
-
existing =
|
|
997
|
+
existing = readFileSync3(filePath, "utf-8");
|
|
691
998
|
} catch {
|
|
692
999
|
return false;
|
|
693
1000
|
}
|
|
@@ -696,21 +1003,28 @@ var removeInstructionBlock = (filePath) => {
|
|
|
696
1003
|
if (start === -1 || end === -1 || end < start) return false;
|
|
697
1004
|
const remaining = (existing.slice(0, start) + existing.slice(end + PUSHARY_END.length)).trim();
|
|
698
1005
|
if (remaining === "") {
|
|
699
|
-
|
|
1006
|
+
rmSync2(filePath, { force: true });
|
|
700
1007
|
} else {
|
|
701
|
-
|
|
1008
|
+
writeFileSync2(filePath, remaining + "\n", "utf-8");
|
|
702
1009
|
}
|
|
703
1010
|
return true;
|
|
704
1011
|
};
|
|
705
1012
|
var hasInstructionBlock = (filePath) => {
|
|
706
1013
|
try {
|
|
707
|
-
return
|
|
1014
|
+
return readFileSync3(filePath, "utf-8").includes(PUSHARY_BEGIN);
|
|
708
1015
|
} catch {
|
|
709
1016
|
return false;
|
|
710
1017
|
}
|
|
711
1018
|
};
|
|
712
1019
|
|
|
713
1020
|
export {
|
|
1021
|
+
isHermesConfigReceipt,
|
|
1022
|
+
HERMES_PIP_PACKAGE,
|
|
1023
|
+
HERMES_PLUGIN_NAME,
|
|
1024
|
+
resolveHermesPython,
|
|
1025
|
+
runHermesConfigScript,
|
|
1026
|
+
hermesWiredByPushary,
|
|
1027
|
+
readHermesStatus,
|
|
714
1028
|
FX_PUSHARY_TOOLS_RULE,
|
|
715
1029
|
FX_TOOL_DISCOVERY_NOTE,
|
|
716
1030
|
FX_PROFILE_REFUSALS,
|
|
@@ -6,38 +6,38 @@ import {
|
|
|
6
6
|
} from "./chunk-SGZJ5LYH.js";
|
|
7
7
|
import {
|
|
8
8
|
hookOwnerOf
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-TCVMK6GI.js";
|
|
10
10
|
import {
|
|
11
11
|
ensureDaemonRunning
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ZKJ34T2F.js";
|
|
13
13
|
import {
|
|
14
14
|
buildTranscriptRecords,
|
|
15
15
|
decodePublicKey,
|
|
16
16
|
generateSessionKey,
|
|
17
17
|
wrapSessionKey
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-P2VIBGXA.js";
|
|
19
19
|
import {
|
|
20
20
|
fetchTranscriptRecipients,
|
|
21
21
|
uploadTranscriptRecords
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-WPX67AKT.js";
|
|
23
23
|
import {
|
|
24
24
|
transcriptEnvironmentPreference,
|
|
25
25
|
transcriptsEnabled
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-LPNJLKBQ.js";
|
|
27
27
|
import {
|
|
28
28
|
readTranscriptPreference
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-D6OODZCM.js";
|
|
30
30
|
import {
|
|
31
31
|
codexHome,
|
|
32
32
|
pusharyDir
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-MZBRL5H5.js";
|
|
34
34
|
import {
|
|
35
35
|
writeJsonAtomic
|
|
36
36
|
} from "./chunk-T7E75EKA.js";
|
|
37
37
|
import {
|
|
38
38
|
getApiKey,
|
|
39
39
|
getBaseUrl
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-R6OYCUNK.js";
|
|
41
41
|
|
|
42
42
|
// src/transcript-registration.ts
|
|
43
43
|
import { createHash } from "crypto";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./chunk-
|
|
2
|
+
redactSecretsFromContent
|
|
3
|
+
} from "./chunk-G4GLCLKK.js";
|
|
4
4
|
|
|
5
5
|
// src/crypto.ts
|
|
6
6
|
import nacl from "tweetnacl";
|
|
@@ -111,7 +111,7 @@ var INTERNAL_TYPES = /* @__PURE__ */ new Set([
|
|
|
111
111
|
"artifact-comment-monitor"
|
|
112
112
|
]);
|
|
113
113
|
var redactDeep = (value) => {
|
|
114
|
-
if (typeof value === "string") return
|
|
114
|
+
if (typeof value === "string") return redactSecretsFromContent(value);
|
|
115
115
|
if (Array.isArray(value)) return value.map(redactDeep);
|
|
116
116
|
if (value && typeof value === "object") {
|
|
117
117
|
const out = {};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createIo
|
|
3
|
+
} from "./chunk-U4TMAANR.js";
|
|
1
4
|
import {
|
|
2
5
|
describeKeyCheck,
|
|
3
6
|
keyCheckFromResponse
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
createIo
|
|
7
|
-
} from "./chunk-O5PRIYFZ.js";
|
|
7
|
+
} from "./chunk-EEEJ2JIL.js";
|
|
8
8
|
import {
|
|
9
9
|
EXIT
|
|
10
10
|
} from "./chunk-KZERVKTD.js";
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
codexHooksJsonIn,
|
|
7
7
|
isPusharyCodexCommand,
|
|
8
8
|
resolvePathBinary
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-MZBRL5H5.js";
|
|
10
10
|
import {
|
|
11
11
|
getPackageVersion
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-G4GLCLKK.js";
|
|
13
13
|
|
|
14
14
|
// src/codex-app-server.ts
|
|
15
15
|
import { existsSync, realpathSync } from "fs";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AGENT_CHOICES
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-BGBLLHZ4.js";
|
|
4
4
|
import {
|
|
5
5
|
isBridgeLocator
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-3EUBQARL.js";
|
|
7
7
|
import {
|
|
8
8
|
pusharyHookExecutable
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-WTJM7PSL.js";
|
|
10
10
|
import {
|
|
11
11
|
BELL_HOOK_BINARY
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-NOI3XTCY.js";
|
|
13
13
|
|
|
14
14
|
// src/setup/hook-ownership.ts
|
|
15
15
|
var commandsIn = (value) => {
|