@pushary/agent-hooks 0.89.5 → 0.89.7
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 +26 -0
- package/dist/bin/pushary-bell.js +1 -1
- package/dist/bin/pushary-claude.js +5 -5
- package/dist/bin/pushary-clean.js +128 -24
- package/dist/bin/pushary-codex-bridge.js +3 -3
- package/dist/bin/pushary-codex-hook.js +3 -3
- package/dist/bin/pushary-codex.js +3 -3
- package/dist/bin/pushary-daemon.js +47 -9
- package/dist/bin/pushary-disconnect.js +2 -2
- package/dist/bin/pushary-doctor.js +6 -6
- package/dist/bin/pushary-elicitation-hook.js +2 -2
- package/dist/bin/pushary-gemini-bridge.js +3 -3
- package/dist/bin/pushary-gemini-hook.js +3 -3
- package/dist/bin/pushary-hook.js +4 -4
- package/dist/bin/pushary-logout.js +1 -1
- package/dist/bin/pushary-notification-hook.js +3 -3
- package/dist/bin/pushary-opencode-hook.js +3 -3
- package/dist/bin/pushary-permission-denied-hook.js +4 -4
- package/dist/bin/pushary-permission-hook.js +4 -4
- package/dist/bin/pushary-post-hook.js +3 -3
- package/dist/bin/pushary-prompt-hook.js +3 -3
- package/dist/bin/pushary-session-end-hook.js +3 -3
- package/dist/bin/pushary-session-start-hook.js +3 -3
- package/dist/bin/pushary-setup.js +46 -16
- package/dist/bin/pushary-status.js +3 -3
- package/dist/bin/pushary-stop-hook.js +3 -3
- package/dist/bin/pushary-stopfailure-hook.js +3 -3
- package/dist/bin/pushary-upgrade.js +38 -198
- package/dist/{chunk-2HYPZLYY.js → chunk-2M66JVZM.js} +1 -1
- package/dist/chunk-2MEJBUOI.js +210 -0
- package/dist/{chunk-4ZHQNBDP.js → chunk-42TTFZLV.js} +1 -1
- package/dist/{chunk-MZBT2LXW.js → chunk-5YUVKPTS.js} +2 -2
- package/dist/{chunk-QH4AA7QV.js → chunk-A4O5ROZK.js} +1 -1
- package/dist/{chunk-OBI4YMCT.js → chunk-BAE45YLP.js} +2 -2
- package/dist/{chunk-NFI2K2ZQ.js → chunk-BPKMGE7L.js} +1 -1
- package/dist/{chunk-V37ZXMH3.js → chunk-GMI5QZLG.js} +15 -9
- package/dist/{chunk-475T3XIO.js → chunk-J2JZJZKB.js} +1 -1
- package/dist/{chunk-VP7SDXYG.js → chunk-TESGYWEM.js} +1 -1
- package/dist/{chunk-7TS2G4QG.js → chunk-VA7VUNRD.js} +22 -14
- package/dist/{chunk-TRQ46MXR.js → chunk-ZH7TWAYK.js} +8 -5
- package/dist/src/index.js +4 -4
- package/package.json +1 -1
|
@@ -1,28 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
addGeminiHooks,
|
|
9
|
-
addGeminiMcpServer,
|
|
10
|
-
addPusharyHooks,
|
|
11
|
-
addPusharyToolPermissions,
|
|
12
|
-
hasGeminiHooks
|
|
13
|
-
} from "../chunk-7TS2G4QG.js";
|
|
3
|
+
reapplyAllAgents
|
|
4
|
+
} from "../chunk-2MEJBUOI.js";
|
|
5
|
+
import "../chunk-J2JZJZKB.js";
|
|
6
|
+
import "../chunk-BAE45YLP.js";
|
|
7
|
+
import "../chunk-VA7VUNRD.js";
|
|
14
8
|
import "../chunk-ATBKJNWS.js";
|
|
15
|
-
import
|
|
16
|
-
guardBinary
|
|
17
|
-
} from "../chunk-AIGDBRIJ.js";
|
|
9
|
+
import "../chunk-AIGDBRIJ.js";
|
|
18
10
|
import {
|
|
19
11
|
daemonServiceManagerAvailable,
|
|
20
12
|
disableDaemonService,
|
|
21
13
|
ensureDaemonRunning,
|
|
22
14
|
hasDaemonServiceDefinition,
|
|
23
15
|
readDaemonStatus,
|
|
24
|
-
replaceDaemonService
|
|
25
|
-
|
|
16
|
+
replaceDaemonService,
|
|
17
|
+
stopDaemonService
|
|
18
|
+
} from "../chunk-ZH7TWAYK.js";
|
|
26
19
|
import {
|
|
27
20
|
detectProviderLiveCapabilities,
|
|
28
21
|
hasSpawnProvider,
|
|
@@ -34,25 +27,16 @@ import {
|
|
|
34
27
|
import {
|
|
35
28
|
execNpm,
|
|
36
29
|
npmErrorMessage,
|
|
37
|
-
resolveGlobalBinDir,
|
|
38
30
|
resolveGlobalBinary
|
|
39
31
|
} from "../chunk-PZA7G4CN.js";
|
|
40
|
-
import "../chunk-
|
|
32
|
+
import "../chunk-2M66JVZM.js";
|
|
41
33
|
import {
|
|
42
|
-
CODEX_HOOK_BINARY,
|
|
43
|
-
addCodexHookTrust,
|
|
44
|
-
addCodexHooks,
|
|
45
|
-
addCodexMcpServer,
|
|
46
34
|
claudeJson,
|
|
47
35
|
codexConfigToml,
|
|
48
|
-
codexHookPositions,
|
|
49
|
-
codexHooksJson,
|
|
50
36
|
cursorPluginDir,
|
|
51
37
|
geminiSettings,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
vscodePluginMcp
|
|
55
|
-
} from "../chunk-V37ZXMH3.js";
|
|
38
|
+
vscodePluginDir
|
|
39
|
+
} from "../chunk-GMI5QZLG.js";
|
|
56
40
|
import {
|
|
57
41
|
readControlMode
|
|
58
42
|
} from "../chunk-L3YUHEB6.js";
|
|
@@ -66,202 +50,49 @@ import {
|
|
|
66
50
|
} from "../chunk-DINDL2CF.js";
|
|
67
51
|
import "../chunk-OFRNZWC4.js";
|
|
68
52
|
import "../chunk-KZERVKTD.js";
|
|
69
|
-
import
|
|
70
|
-
readJsonSafe
|
|
71
|
-
} from "../chunk-6MTNS63X.js";
|
|
53
|
+
import "../chunk-6MTNS63X.js";
|
|
72
54
|
import {
|
|
73
55
|
getApiKey
|
|
74
56
|
} from "../chunk-2UMNXADU.js";
|
|
75
57
|
import "../chunk-L4C2JXJS.js";
|
|
76
58
|
|
|
77
59
|
// bin/pushary-upgrade.ts
|
|
78
|
-
import { existsSync
|
|
79
|
-
import { homedir as homedir2 } from "os";
|
|
80
|
-
import { join as join2 } from "path";
|
|
81
|
-
import { execFileSync } from "child_process";
|
|
82
|
-
|
|
83
|
-
// src/reapply.ts
|
|
84
|
-
import { join, dirname } from "path";
|
|
60
|
+
import { existsSync } from "fs";
|
|
85
61
|
import { homedir } from "os";
|
|
86
|
-
import {
|
|
87
|
-
import {
|
|
88
|
-
var CLAUDE_SETTINGS = join(homedir(), ".claude", "settings.json");
|
|
89
|
-
var CLAUDE_JSON = join(homedir(), ".claude.json");
|
|
90
|
-
var readJson = (filePath) => {
|
|
91
|
-
const result = readJsonSafe(filePath);
|
|
92
|
-
if (result.kind === "ok") return result.value;
|
|
93
|
-
if (result.kind === "missing") return {};
|
|
94
|
-
return null;
|
|
95
|
-
};
|
|
96
|
-
var writeJson = (filePath, data) => {
|
|
97
|
-
const dir = dirname(filePath);
|
|
98
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
99
|
-
writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
100
|
-
};
|
|
101
|
-
var hasPusharyClaudeHooks = (settings) => JSON.stringify(settings.hooks ?? {}).includes("pushary-hook");
|
|
102
|
-
var hasPusharyMcp = (claudeJson2) => !!claudeJson2.mcpServers?.pushary;
|
|
103
|
-
var reapplyClaudeSettings = (apiKey, paths = {}) => {
|
|
104
|
-
const settingsPath = paths.settingsPath ?? CLAUDE_SETTINGS;
|
|
105
|
-
const claudeJsonPath = paths.claudeJsonPath ?? CLAUDE_JSON;
|
|
106
|
-
const settings = readJson(settingsPath);
|
|
107
|
-
const claudeJson2 = readJson(claudeJsonPath);
|
|
108
|
-
const configured = settings != null && hasPusharyClaudeHooks(settings) || claudeJson2 != null && hasPusharyMcp(claudeJson2);
|
|
109
|
-
if (!configured) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
110
|
-
const settingsWritable = settings != null;
|
|
111
|
-
const claudeJsonWritable = claudeJson2 != null;
|
|
112
|
-
let hooks = false;
|
|
113
|
-
let mcp = false;
|
|
114
|
-
try {
|
|
115
|
-
if (!settingsWritable) throw new Error("settings.json could not be parsed");
|
|
116
|
-
const s = settings;
|
|
117
|
-
addPusharyToolPermissions(s);
|
|
118
|
-
addPusharyHooks(s, resolveGlobalBinDir("pushary-hook"), detectClaudeVersion());
|
|
119
|
-
writeJson(settingsPath, s);
|
|
120
|
-
hooks = true;
|
|
121
|
-
} catch {
|
|
122
|
-
}
|
|
123
|
-
if (apiKey) {
|
|
124
|
-
try {
|
|
125
|
-
if (!claudeJsonWritable) throw new Error(".claude.json could not be parsed");
|
|
126
|
-
const cj = claudeJson2;
|
|
127
|
-
addClaudeMcpServer(cj, apiKey);
|
|
128
|
-
writeJson(claudeJsonPath, cj);
|
|
129
|
-
mcp = true;
|
|
130
|
-
} catch {
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return { configured: true, reapplied: hooks || mcp, hooks, mcp };
|
|
134
|
-
};
|
|
135
|
-
var readToml = (filePath) => {
|
|
136
|
-
try {
|
|
137
|
-
const raw = readFileSync(filePath, "utf-8");
|
|
138
|
-
return raw.trim() === "" ? {} : parseTOML(raw);
|
|
139
|
-
} catch {
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
var reapplyCodexSettings = (apiKey, paths = {}) => {
|
|
144
|
-
const configPath = paths.configPath ?? codexConfigToml();
|
|
145
|
-
const hooksPath = paths.hooksPath ?? codexHooksJson();
|
|
146
|
-
const config = readToml(configPath);
|
|
147
|
-
const hooksConfig = readJson(hooksPath);
|
|
148
|
-
const configured = config != null && !!config.mcp_servers?.pushary || hooksConfig != null && hasCodexHooks(hooksConfig);
|
|
149
|
-
if (!configured) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
150
|
-
const command = guardBinary(resolveGlobalBinary(CODEX_HOOK_BINARY) ?? CODEX_HOOK_BINARY);
|
|
151
|
-
let hooks = false;
|
|
152
|
-
let mcp = false;
|
|
153
|
-
if (hooksConfig != null) {
|
|
154
|
-
try {
|
|
155
|
-
addCodexHooks(hooksConfig, command);
|
|
156
|
-
writeJson(hooksPath, hooksConfig);
|
|
157
|
-
hooks = true;
|
|
158
|
-
} catch {
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
if (config != null) {
|
|
162
|
-
try {
|
|
163
|
-
if (hooks) addCodexHookTrust(config, hooksPath, command, codexHookPositions(hooksConfig ?? void 0));
|
|
164
|
-
if (apiKey) {
|
|
165
|
-
addCodexMcpServer(config, apiKey);
|
|
166
|
-
mcp = true;
|
|
167
|
-
}
|
|
168
|
-
if (hooks || apiKey) writeFileSync(configPath, stringifyTOML(config), "utf-8");
|
|
169
|
-
} catch {
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return { configured: true, reapplied: hooks || mcp, hooks, mcp };
|
|
173
|
-
};
|
|
174
|
-
var reapplyGeminiSettings = (apiKey, paths = {}) => {
|
|
175
|
-
const settingsPath = paths.settingsPath ?? join(homedir(), ".gemini", "settings.json");
|
|
176
|
-
const settings = readJson(settingsPath);
|
|
177
|
-
if (settings == null) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
178
|
-
const configured = hasGeminiHooks(settings) || !!settings.mcpServers?.pushary;
|
|
179
|
-
if (!configured) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
180
|
-
let hooks = false;
|
|
181
|
-
let mcp = false;
|
|
182
|
-
try {
|
|
183
|
-
addGeminiHooks(settings, guardBinary(resolveGlobalBinary(GEMINI_HOOK_BINARY) ?? GEMINI_HOOK_BINARY));
|
|
184
|
-
hooks = true;
|
|
185
|
-
if (apiKey) {
|
|
186
|
-
addGeminiMcpServer(settings, apiKey);
|
|
187
|
-
mcp = true;
|
|
188
|
-
}
|
|
189
|
-
writeJson(settingsPath, settings);
|
|
190
|
-
} catch {
|
|
191
|
-
}
|
|
192
|
-
return { configured: true, reapplied: hooks || mcp, hooks, mcp };
|
|
193
|
-
};
|
|
194
|
-
var reapplyPluginMcp = (mcpPath, apiKey) => {
|
|
195
|
-
const mcpConfig = readJson(mcpPath);
|
|
196
|
-
if (mcpConfig == null) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
197
|
-
const servers = mcpConfig.mcpServers;
|
|
198
|
-
if (!servers?.pushary) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
199
|
-
if (!apiKey) return { configured: true, reapplied: false, hooks: false, mcp: false };
|
|
200
|
-
try {
|
|
201
|
-
addClaudeMcpServer(mcpConfig, apiKey);
|
|
202
|
-
writeJson(mcpPath, mcpConfig);
|
|
203
|
-
return { configured: true, reapplied: true, hooks: false, mcp: true };
|
|
204
|
-
} catch {
|
|
205
|
-
return { configured: true, reapplied: false, hooks: false, mcp: false };
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
var reapplyCursorPlugin = (apiKey, paths = {}) => reapplyPluginMcp(
|
|
209
|
-
paths.pluginMcpPath ?? join(homedir(), ".cursor", "plugins", "local", "pushary", "mcp.json"),
|
|
210
|
-
apiKey
|
|
211
|
-
);
|
|
212
|
-
var reapplyVsCodePlugin = (apiKey, paths = {}) => reapplyPluginMcp(paths.pluginMcpPath ?? vscodePluginMcp(), apiKey);
|
|
213
|
-
var reapplyAllAgents = (apiKey) => {
|
|
214
|
-
const runners = [
|
|
215
|
-
{ id: "claude", label: "Claude Code", run: () => reapplyClaudeSettings(apiKey) },
|
|
216
|
-
{ id: "codex", label: "Codex", run: () => reapplyCodexSettings(apiKey) },
|
|
217
|
-
{ id: "gemini", label: "Gemini CLI", run: () => reapplyGeminiSettings(apiKey) },
|
|
218
|
-
{ id: "cursor", label: "Cursor", run: () => reapplyCursorPlugin(apiKey) },
|
|
219
|
-
{ id: "vscode", label: "VS Code", run: () => reapplyVsCodePlugin(apiKey) }
|
|
220
|
-
];
|
|
221
|
-
const done = [];
|
|
222
|
-
for (const runner of runners) {
|
|
223
|
-
try {
|
|
224
|
-
const result = runner.run();
|
|
225
|
-
if (result.configured) done.push({ id: runner.id, label: runner.label, result });
|
|
226
|
-
} catch {
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
return done;
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
// bin/pushary-upgrade.ts
|
|
62
|
+
import { join } from "path";
|
|
63
|
+
import { execFileSync } from "child_process";
|
|
233
64
|
exitOnHelpFlag("upgrade");
|
|
234
65
|
var detectInstallModes = () => {
|
|
235
66
|
const candidates = [
|
|
236
67
|
{
|
|
237
68
|
label: "Cursor plugin",
|
|
238
69
|
upgrade: "updates itself through Cursor",
|
|
239
|
-
present:
|
|
70
|
+
present: existsSync(cursorPluginDir())
|
|
240
71
|
},
|
|
241
72
|
{
|
|
242
73
|
label: "VS Code plugin",
|
|
243
74
|
upgrade: "npx @pushary/agent-hooks@latest setup --agents vscode",
|
|
244
|
-
present:
|
|
75
|
+
present: existsSync(vscodePluginDir())
|
|
245
76
|
},
|
|
246
77
|
{
|
|
247
78
|
label: "Codex config",
|
|
248
79
|
upgrade: "npx @pushary/agent-hooks@latest setup --agents codex",
|
|
249
|
-
present:
|
|
80
|
+
present: existsSync(codexConfigToml())
|
|
250
81
|
},
|
|
251
82
|
{
|
|
252
83
|
label: "Claude Code config",
|
|
253
84
|
upgrade: "npx @pushary/agent-hooks@latest setup --agents claude_code",
|
|
254
|
-
present:
|
|
85
|
+
present: existsSync(claudeJson())
|
|
255
86
|
},
|
|
256
87
|
{
|
|
257
88
|
label: "Gemini config",
|
|
258
89
|
upgrade: "npx @pushary/agent-hooks@latest setup --agents gemini_cli",
|
|
259
|
-
present:
|
|
90
|
+
present: existsSync(geminiSettings())
|
|
260
91
|
},
|
|
261
92
|
{
|
|
262
93
|
label: "Hermes plugin (pip)",
|
|
263
94
|
upgrade: "npx @pushary/agent-hooks@latest setup --agents hermes",
|
|
264
|
-
present:
|
|
95
|
+
present: existsSync(join(homedir(), ".hermes"))
|
|
265
96
|
}
|
|
266
97
|
];
|
|
267
98
|
return candidates.filter((candidate) => candidate.present).map(({ label, upgrade }) => ({ label, upgrade }));
|
|
@@ -305,14 +136,23 @@ var finishUpgrade = async () => {
|
|
|
305
136
|
servicePresent: serviceWasPresent
|
|
306
137
|
});
|
|
307
138
|
let daemonReady = true;
|
|
139
|
+
let legacyStopFailure = null;
|
|
308
140
|
if (controlPolicy === "disabled" && serviceWasPresent) {
|
|
309
141
|
daemonReady = (await disableDaemonService()).kind === "ok";
|
|
310
|
-
} else if (
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
142
|
+
} else if (controlPolicy === "legacy") {
|
|
143
|
+
const stopped = await stopDaemonService();
|
|
144
|
+
legacyStopFailure = stopped.kind === "ok" ? null : stopped.detail;
|
|
145
|
+
daemonReady = false;
|
|
146
|
+
} else if (controlPolicy === "enabled") {
|
|
147
|
+
if (!apiKey) {
|
|
148
|
+
daemonReady = false;
|
|
149
|
+
} else {
|
|
150
|
+
const service = await replaceDaemonService();
|
|
151
|
+
const daemon = service.kind === "ok" ? await ensureDaemonRunning({ spawnDaemon: () => {
|
|
152
|
+
} }) : null;
|
|
153
|
+
daemonReady = service.kind === "ok" && (daemon?.kind === "running" || daemon?.kind === "started");
|
|
154
|
+
}
|
|
155
|
+
} else if (controlMode === "on" && controlPolicy === "unsupported") {
|
|
316
156
|
daemonReady = false;
|
|
317
157
|
}
|
|
318
158
|
console.log();
|
|
@@ -331,7 +171,7 @@ var finishUpgrade = async () => {
|
|
|
331
171
|
}
|
|
332
172
|
console.log();
|
|
333
173
|
if (!daemonReady) {
|
|
334
|
-
console.error(controlPolicy === "disabled" ? "Upgrade installed, but the disabled background service could not be fully removed. Re-run setup with --control off." : controlPolicy === "legacy" ?
|
|
174
|
+
console.error(controlPolicy === "disabled" ? "Upgrade installed, but the disabled background service could not be fully removed. Re-run setup with --control off." : controlPolicy === "legacy" ? legacyStopFailure ? `Upgrade installed, but the legacy background service could not be stopped: ${legacyStopFailure}. Run setup with --control off.` : "Upgrade installed and the legacy background service was stopped, but it cannot be safely adopted. Run setup with --control off, or restore its provider and native service manager." : controlPolicy === "enabled" && !apiKey ? "Upgrade installed, but phone-start could not be reconciled because no API key was readable. Re-run setup." : "Upgrade installed, but the background service did not start. Run: pushary daemon install");
|
|
335
175
|
process.exitCode = 1;
|
|
336
176
|
return;
|
|
337
177
|
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import {
|
|
2
|
+
detectClaudeVersion
|
|
3
|
+
} from "./chunk-J2JZJZKB.js";
|
|
4
|
+
import {
|
|
5
|
+
claudeWired,
|
|
6
|
+
codexWired,
|
|
7
|
+
geminiWired
|
|
8
|
+
} from "./chunk-BAE45YLP.js";
|
|
9
|
+
import {
|
|
10
|
+
GEMINI_HOOK_BINARY,
|
|
11
|
+
addClaudeMcpServer,
|
|
12
|
+
addGeminiHooks,
|
|
13
|
+
addGeminiMcpServer,
|
|
14
|
+
addPusharyHooks,
|
|
15
|
+
addPusharyToolPermissions,
|
|
16
|
+
hasGeminiHooks
|
|
17
|
+
} from "./chunk-VA7VUNRD.js";
|
|
18
|
+
import {
|
|
19
|
+
guardBinary
|
|
20
|
+
} from "./chunk-AIGDBRIJ.js";
|
|
21
|
+
import {
|
|
22
|
+
resolveGlobalBinDir,
|
|
23
|
+
resolveGlobalBinary
|
|
24
|
+
} from "./chunk-PZA7G4CN.js";
|
|
25
|
+
import {
|
|
26
|
+
CODEX_HOOK_BINARY,
|
|
27
|
+
addCodexHookTrust,
|
|
28
|
+
addCodexHooks,
|
|
29
|
+
addCodexMcpServer,
|
|
30
|
+
codexConfigToml,
|
|
31
|
+
codexHookPositions,
|
|
32
|
+
codexHooksJson,
|
|
33
|
+
hasCodexHooks,
|
|
34
|
+
vscodePluginMcp
|
|
35
|
+
} from "./chunk-GMI5QZLG.js";
|
|
36
|
+
import {
|
|
37
|
+
readJsonSafe
|
|
38
|
+
} from "./chunk-6MTNS63X.js";
|
|
39
|
+
|
|
40
|
+
// src/reapply.ts
|
|
41
|
+
import { join, dirname } from "path";
|
|
42
|
+
import { homedir } from "os";
|
|
43
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
44
|
+
import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
|
|
45
|
+
var CLAUDE_SETTINGS = join(homedir(), ".claude", "settings.json");
|
|
46
|
+
var CLAUDE_JSON = join(homedir(), ".claude.json");
|
|
47
|
+
var readJson = (filePath) => {
|
|
48
|
+
const result = readJsonSafe(filePath);
|
|
49
|
+
if (result.kind === "ok") return result.value;
|
|
50
|
+
if (result.kind === "missing") return {};
|
|
51
|
+
return null;
|
|
52
|
+
};
|
|
53
|
+
var writeJson = (filePath, data) => {
|
|
54
|
+
const dir = dirname(filePath);
|
|
55
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
56
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
57
|
+
};
|
|
58
|
+
var hasPusharyClaudeHooks = (settings) => JSON.stringify(settings.hooks ?? {}).includes("pushary-hook");
|
|
59
|
+
var hasPusharyMcp = (claudeJson) => !!claudeJson.mcpServers?.pushary;
|
|
60
|
+
var reapplyClaudeSettings = (apiKey, paths = {}) => {
|
|
61
|
+
const settingsPath = paths.settingsPath ?? CLAUDE_SETTINGS;
|
|
62
|
+
const claudeJsonPath = paths.claudeJsonPath ?? CLAUDE_JSON;
|
|
63
|
+
const settings = readJson(settingsPath);
|
|
64
|
+
const claudeJson = readJson(claudeJsonPath);
|
|
65
|
+
const configured = settings != null && hasPusharyClaudeHooks(settings) || claudeJson != null && hasPusharyMcp(claudeJson);
|
|
66
|
+
if (!configured) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
67
|
+
const settingsWritable = settings != null;
|
|
68
|
+
const claudeJsonWritable = claudeJson != null;
|
|
69
|
+
let hooks = false;
|
|
70
|
+
let mcp = false;
|
|
71
|
+
try {
|
|
72
|
+
if (!settingsWritable) throw new Error("settings.json could not be parsed");
|
|
73
|
+
const s = settings;
|
|
74
|
+
addPusharyToolPermissions(s);
|
|
75
|
+
addPusharyHooks(s, resolveGlobalBinDir("pushary-hook"), detectClaudeVersion());
|
|
76
|
+
writeJson(settingsPath, s);
|
|
77
|
+
hooks = true;
|
|
78
|
+
} catch {
|
|
79
|
+
}
|
|
80
|
+
if (apiKey) {
|
|
81
|
+
try {
|
|
82
|
+
if (!claudeJsonWritable) throw new Error(".claude.json could not be parsed");
|
|
83
|
+
const cj = claudeJson;
|
|
84
|
+
addClaudeMcpServer(cj, apiKey);
|
|
85
|
+
writeJson(claudeJsonPath, cj);
|
|
86
|
+
mcp = true;
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return { configured: true, reapplied: hooks || mcp, hooks, mcp };
|
|
91
|
+
};
|
|
92
|
+
var readToml = (filePath) => {
|
|
93
|
+
try {
|
|
94
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
95
|
+
return raw.trim() === "" ? {} : parseTOML(raw);
|
|
96
|
+
} catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
var inspectConfiguredManagedProviders = (paths = {}) => {
|
|
101
|
+
const providers = [];
|
|
102
|
+
const claudeSettings = readJson(paths.claudeSettingsPath ?? CLAUDE_SETTINGS);
|
|
103
|
+
const claudeJson = readJson(paths.claudeJsonPath ?? CLAUDE_JSON);
|
|
104
|
+
if (claudeWired({ claudeJson, settings: claudeSettings, skillExists: false })) {
|
|
105
|
+
providers.push("claude");
|
|
106
|
+
}
|
|
107
|
+
const codexConfig = readToml(paths.codexConfigPath ?? codexConfigToml());
|
|
108
|
+
const codexHooks = readJson(paths.codexHooksPath ?? codexHooksJson());
|
|
109
|
+
if (codexWired({ config: codexConfig, hooks: codexHooks, skillExists: false })) {
|
|
110
|
+
providers.push("codex");
|
|
111
|
+
}
|
|
112
|
+
const gemini = readJson(paths.geminiSettingsPath ?? join(homedir(), ".gemini", "settings.json"));
|
|
113
|
+
if (geminiWired({ settings: gemini })) {
|
|
114
|
+
providers.push("gemini");
|
|
115
|
+
}
|
|
116
|
+
return providers;
|
|
117
|
+
};
|
|
118
|
+
var reapplyCodexSettings = (apiKey, paths = {}) => {
|
|
119
|
+
const configPath = paths.configPath ?? codexConfigToml();
|
|
120
|
+
const hooksPath = paths.hooksPath ?? codexHooksJson();
|
|
121
|
+
const config = readToml(configPath);
|
|
122
|
+
const hooksConfig = readJson(hooksPath);
|
|
123
|
+
const configured = config != null && !!config.mcp_servers?.pushary || hooksConfig != null && hasCodexHooks(hooksConfig);
|
|
124
|
+
if (!configured) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
125
|
+
const command = guardBinary(resolveGlobalBinary(CODEX_HOOK_BINARY) ?? CODEX_HOOK_BINARY);
|
|
126
|
+
let hooks = false;
|
|
127
|
+
let mcp = false;
|
|
128
|
+
if (hooksConfig != null) {
|
|
129
|
+
try {
|
|
130
|
+
addCodexHooks(hooksConfig, command);
|
|
131
|
+
writeJson(hooksPath, hooksConfig);
|
|
132
|
+
hooks = true;
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (config != null) {
|
|
137
|
+
try {
|
|
138
|
+
if (hooks) addCodexHookTrust(config, hooksPath, command, codexHookPositions(hooksConfig ?? void 0));
|
|
139
|
+
if (apiKey) {
|
|
140
|
+
addCodexMcpServer(config, apiKey);
|
|
141
|
+
mcp = true;
|
|
142
|
+
}
|
|
143
|
+
if (hooks || apiKey) writeFileSync(configPath, stringifyTOML(config), "utf-8");
|
|
144
|
+
} catch {
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return { configured: true, reapplied: hooks || mcp, hooks, mcp };
|
|
148
|
+
};
|
|
149
|
+
var reapplyGeminiSettings = (apiKey, paths = {}) => {
|
|
150
|
+
const settingsPath = paths.settingsPath ?? join(homedir(), ".gemini", "settings.json");
|
|
151
|
+
const settings = readJson(settingsPath);
|
|
152
|
+
if (settings == null) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
153
|
+
const configured = hasGeminiHooks(settings) || !!settings.mcpServers?.pushary;
|
|
154
|
+
if (!configured) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
155
|
+
let hooks = false;
|
|
156
|
+
let mcp = false;
|
|
157
|
+
try {
|
|
158
|
+
addGeminiHooks(settings, guardBinary(resolveGlobalBinary(GEMINI_HOOK_BINARY) ?? GEMINI_HOOK_BINARY));
|
|
159
|
+
hooks = true;
|
|
160
|
+
if (apiKey) {
|
|
161
|
+
addGeminiMcpServer(settings, apiKey);
|
|
162
|
+
mcp = true;
|
|
163
|
+
}
|
|
164
|
+
writeJson(settingsPath, settings);
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
return { configured: true, reapplied: hooks || mcp, hooks, mcp };
|
|
168
|
+
};
|
|
169
|
+
var reapplyPluginMcp = (mcpPath, apiKey) => {
|
|
170
|
+
const mcpConfig = readJson(mcpPath);
|
|
171
|
+
if (mcpConfig == null) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
172
|
+
const servers = mcpConfig.mcpServers;
|
|
173
|
+
if (!servers?.pushary) return { configured: false, reapplied: false, hooks: false, mcp: false };
|
|
174
|
+
if (!apiKey) return { configured: true, reapplied: false, hooks: false, mcp: false };
|
|
175
|
+
try {
|
|
176
|
+
addClaudeMcpServer(mcpConfig, apiKey);
|
|
177
|
+
writeJson(mcpPath, mcpConfig);
|
|
178
|
+
return { configured: true, reapplied: true, hooks: false, mcp: true };
|
|
179
|
+
} catch {
|
|
180
|
+
return { configured: true, reapplied: false, hooks: false, mcp: false };
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
var reapplyCursorPlugin = (apiKey, paths = {}) => reapplyPluginMcp(
|
|
184
|
+
paths.pluginMcpPath ?? join(homedir(), ".cursor", "plugins", "local", "pushary", "mcp.json"),
|
|
185
|
+
apiKey
|
|
186
|
+
);
|
|
187
|
+
var reapplyVsCodePlugin = (apiKey, paths = {}) => reapplyPluginMcp(paths.pluginMcpPath ?? vscodePluginMcp(), apiKey);
|
|
188
|
+
var reapplyAllAgents = (apiKey) => {
|
|
189
|
+
const runners = [
|
|
190
|
+
{ id: "claude", label: "Claude Code", run: () => reapplyClaudeSettings(apiKey) },
|
|
191
|
+
{ id: "codex", label: "Codex", run: () => reapplyCodexSettings(apiKey) },
|
|
192
|
+
{ id: "gemini", label: "Gemini CLI", run: () => reapplyGeminiSettings(apiKey) },
|
|
193
|
+
{ id: "cursor", label: "Cursor", run: () => reapplyCursorPlugin(apiKey) },
|
|
194
|
+
{ id: "vscode", label: "VS Code", run: () => reapplyVsCodePlugin(apiKey) }
|
|
195
|
+
];
|
|
196
|
+
const done = [];
|
|
197
|
+
for (const runner of runners) {
|
|
198
|
+
try {
|
|
199
|
+
const result = runner.run();
|
|
200
|
+
if (result.configured) done.push({ id: runner.id, label: runner.label, result });
|
|
201
|
+
} catch {
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return done;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export {
|
|
208
|
+
inspectConfiguredManagedProviders,
|
|
209
|
+
reapplyAllAgents
|
|
210
|
+
};
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
readLastUserPrompt,
|
|
18
18
|
repoKeyFor,
|
|
19
19
|
throttlePass
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-BPKMGE7L.js";
|
|
21
21
|
import {
|
|
22
22
|
DEFAULT_SESSION,
|
|
23
23
|
askUser,
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
} from "./chunk-KOPUTJQC.js";
|
|
37
37
|
import {
|
|
38
38
|
getMachineId
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-2M66JVZM.js";
|
|
40
40
|
import {
|
|
41
41
|
getApiKey,
|
|
42
42
|
getBaseUrl
|
|
@@ -8,6 +8,10 @@ import { createHash } from "crypto";
|
|
|
8
8
|
import { homedir } from "os";
|
|
9
9
|
import { join } from "path";
|
|
10
10
|
|
|
11
|
+
// src/removal-scope.ts
|
|
12
|
+
var namesAppLocator = (command) => command.includes(HOOK_LOCATOR_BINARY);
|
|
13
|
+
var isProtectedByScope = (command, scope) => scope?.keepAppWiring === true && namesAppLocator(command);
|
|
14
|
+
|
|
11
15
|
// src/canonical-json.ts
|
|
12
16
|
var canonicalJson = (value) => {
|
|
13
17
|
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
@@ -77,13 +81,14 @@ var readCodexMcpAuth = (config) => {
|
|
|
77
81
|
if (typeof pushary.bearer_token === "string") return { method: "legacy-bearer" };
|
|
78
82
|
return void 0;
|
|
79
83
|
};
|
|
80
|
-
var isPusharyCommand = (hook) => {
|
|
84
|
+
var isPusharyCommand = (hook, scope) => {
|
|
81
85
|
const command = String(asRecord(hook)?.command ?? "");
|
|
86
|
+
if (isProtectedByScope(command, scope)) return false;
|
|
82
87
|
return command.includes(CODEX_HOOK_BINARY) || command.includes(HOOK_LOCATOR_BINARY);
|
|
83
88
|
};
|
|
84
|
-
var isPusharyCodexHook = (entry) => {
|
|
89
|
+
var isPusharyCodexHook = (entry, scope) => {
|
|
85
90
|
const hooks = asRecord(entry)?.hooks;
|
|
86
|
-
return Array.isArray(hooks) && hooks.some(isPusharyCommand);
|
|
91
|
+
return Array.isArray(hooks) && hooks.some((hook) => isPusharyCommand(hook, scope));
|
|
87
92
|
};
|
|
88
93
|
var addCodexHooks = (config, command) => {
|
|
89
94
|
const hooks = ensureRecord(config, "hooks");
|
|
@@ -102,14 +107,14 @@ var addCodexHooks = (config, command) => {
|
|
|
102
107
|
hooks[definition.event] = entries;
|
|
103
108
|
}
|
|
104
109
|
};
|
|
105
|
-
var removeCodexHooks = (config) => {
|
|
110
|
+
var removeCodexHooks = (config, scope) => {
|
|
106
111
|
const hooks = asRecord(config.hooks);
|
|
107
112
|
if (!hooks) return false;
|
|
108
113
|
let changed = false;
|
|
109
114
|
for (const definition of CODEX_HOOK_EVENTS) {
|
|
110
115
|
const entries = hooks[definition.event];
|
|
111
116
|
if (!Array.isArray(entries)) continue;
|
|
112
|
-
const filtered = entries.filter((entry) => !isPusharyCodexHook(entry));
|
|
117
|
+
const filtered = entries.filter((entry) => !isPusharyCodexHook(entry, scope));
|
|
113
118
|
if (filtered.length !== entries.length) {
|
|
114
119
|
if (filtered.length === 0) {
|
|
115
120
|
delete hooks[definition.event];
|
|
@@ -127,14 +132,14 @@ var hasCodexHooks = (config) => {
|
|
|
127
132
|
if (!hooks) return false;
|
|
128
133
|
return CODEX_HOOK_EVENTS.some((definition) => {
|
|
129
134
|
const entries = hooks[definition.event];
|
|
130
|
-
return Array.isArray(entries) && entries.some(isPusharyCodexHook);
|
|
135
|
+
return Array.isArray(entries) && entries.some((entry) => isPusharyCodexHook(entry));
|
|
131
136
|
});
|
|
132
137
|
};
|
|
133
138
|
var missingCodexHookEvents = (config) => {
|
|
134
139
|
const hooks = asRecord(config.hooks);
|
|
135
140
|
return CODEX_HOOK_EVENTS.filter((definition) => {
|
|
136
141
|
const entries = hooks?.[definition.event];
|
|
137
|
-
return !Array.isArray(entries) || !entries.some(isPusharyCodexHook);
|
|
142
|
+
return !Array.isArray(entries) || !entries.some((entry) => isPusharyCodexHook(entry));
|
|
138
143
|
}).map((definition) => definition.event);
|
|
139
144
|
};
|
|
140
145
|
var codexHookTrustHash = (definition, command) => {
|
|
@@ -176,10 +181,10 @@ var codexHookPositions = (hooksConfig) => {
|
|
|
176
181
|
for (const definition of CODEX_HOOK_EVENTS) {
|
|
177
182
|
const entries = hooks?.[definition.event];
|
|
178
183
|
if (!Array.isArray(entries)) continue;
|
|
179
|
-
const entryIndex = entries.findIndex(isPusharyCodexHook);
|
|
184
|
+
const entryIndex = entries.findIndex((entry) => isPusharyCodexHook(entry));
|
|
180
185
|
if (entryIndex < 0) continue;
|
|
181
186
|
const inner = asRecord(entries[entryIndex])?.hooks;
|
|
182
|
-
const hookIndex = Array.isArray(inner) ? inner.findIndex(isPusharyCommand) : -1;
|
|
187
|
+
const hookIndex = Array.isArray(inner) ? inner.findIndex((hook) => isPusharyCommand(hook)) : -1;
|
|
183
188
|
positions[definition.event] = [entryIndex, Math.max(hookIndex, 0)];
|
|
184
189
|
}
|
|
185
190
|
return positions;
|
|
@@ -270,6 +275,7 @@ var geminiMd = () => join2(homedir2(), ".gemini", "GEMINI.md");
|
|
|
270
275
|
var pusharyConfigFile = () => join2(homedir2(), ".pushary", "config.json");
|
|
271
276
|
|
|
272
277
|
export {
|
|
278
|
+
isProtectedByScope,
|
|
273
279
|
canonicalJson,
|
|
274
280
|
CODEX_HOOK_BINARY,
|
|
275
281
|
codexHome,
|