@pushary/agent-hooks 0.60.0 → 0.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +161 -0
- package/README.md +52 -9
- package/dist/bin/pushary-claude.js +6 -6
- package/dist/bin/pushary-clean.js +83 -38
- package/dist/bin/pushary-codex-hook.js +6 -6
- package/dist/bin/pushary-codex.js +4 -4
- package/dist/bin/pushary-connect.d.ts +1 -0
- package/dist/bin/pushary-connect.js +92 -0
- package/dist/bin/pushary-daemon.js +42 -5
- package/dist/bin/pushary-doctor.js +246 -71
- package/dist/bin/pushary-gemini-hook.js +6 -6
- package/dist/bin/pushary-hook.js +10 -5
- package/dist/bin/pushary-login.d.ts +1 -0
- package/dist/bin/pushary-login.js +156 -0
- package/dist/bin/pushary-logout.d.ts +1 -0
- package/dist/bin/pushary-logout.js +144 -0
- package/dist/bin/pushary-mode.js +24 -13
- package/dist/bin/pushary-notification-hook.js +4 -4
- package/dist/bin/pushary-permission-denied-hook.js +5 -5
- package/dist/bin/pushary-permission-hook.js +5 -5
- package/dist/bin/pushary-post-hook.js +4 -4
- package/dist/bin/pushary-prompt-hook.js +4 -4
- package/dist/bin/pushary-session-end-hook.js +4 -4
- package/dist/bin/pushary-session-start-hook.js +4 -4
- package/dist/bin/pushary-setup.js +769 -518
- package/dist/bin/pushary-stats.js +6 -1
- package/dist/bin/pushary-status.d.ts +1 -0
- package/dist/bin/pushary-status.js +206 -0
- package/dist/bin/pushary-stop-hook.js +4 -4
- package/dist/bin/pushary-stopfailure-hook.js +4 -4
- package/dist/bin/pushary-suggestions.js +10 -5
- package/dist/bin/pushary-upgrade.js +184 -14
- package/dist/bin/pushary-wait.js +21 -12
- package/dist/bin/pushary.js +42 -60
- package/dist/chunk-247C4RE5.js +236 -0
- package/dist/{chunk-NKXSILEW.js → chunk-2UMNXADU.js} +18 -2
- package/dist/chunk-3EGEA4KH.js +44 -0
- package/dist/chunk-3O27ZSRE.js +569 -0
- package/dist/{chunk-BE5X3WXL.js → chunk-5SO3CEGJ.js} +5 -5
- package/dist/chunk-7QLSKOSU.js +19 -0
- package/dist/chunk-E2U35RLD.js +108 -0
- package/dist/chunk-ER657KRJ.js +168 -0
- package/dist/{chunk-WNRYRN2R.js → chunk-HIIBSYFJ.js} +5 -5
- package/dist/{chunk-DWED7BS3.js → chunk-HNTKTK5B.js} +1 -1
- package/dist/chunk-IIZZYUWK.js +18 -0
- package/dist/{chunk-J7JWI3KU.js → chunk-MUEW424A.js} +19 -1
- package/dist/chunk-N4DA4CJB.js +57 -0
- package/dist/chunk-N7XJ4L2W.js +79 -0
- package/dist/chunk-ONVEYEVR.js +44 -0
- package/dist/chunk-QHOVJXOT.js +255 -0
- package/dist/chunk-SP7OZXCQ.js +224 -0
- package/dist/chunk-TX7KBKT7.js +79 -0
- package/dist/chunk-UXXRRXUS.js +93 -0
- package/dist/chunk-YJ7YZRVV.js +217 -0
- package/dist/src/index.js +5 -5
- package/package.json +11 -4
- package/dist/chunk-BQLCELYC.js +0 -332
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
exitOnHelpFlag
|
|
4
|
+
} from "../chunk-IIZZYUWK.js";
|
|
5
|
+
import "../chunk-SP7OZXCQ.js";
|
|
2
6
|
import {
|
|
3
7
|
readLedgerSummary
|
|
4
8
|
} from "../chunk-WLGEY4UX.js";
|
|
5
9
|
import "../chunk-DQAN3JQP.js";
|
|
6
10
|
import {
|
|
7
11
|
getApiKey
|
|
8
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-2UMNXADU.js";
|
|
9
13
|
|
|
10
14
|
// bin/pushary-stats.ts
|
|
15
|
+
exitOnHelpFlag("stats");
|
|
11
16
|
var DAYS = 7;
|
|
12
17
|
var summary = readLedgerSummary(DAYS);
|
|
13
18
|
var connected = true;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
describeReach,
|
|
4
|
+
fetchChannels,
|
|
5
|
+
reachVerdict
|
|
6
|
+
} from "../chunk-3O27ZSRE.js";
|
|
7
|
+
import "../chunk-3EGEA4KH.js";
|
|
8
|
+
import {
|
|
9
|
+
readKeySource
|
|
10
|
+
} from "../chunk-247C4RE5.js";
|
|
11
|
+
import {
|
|
12
|
+
checkApiKey,
|
|
13
|
+
describeKeyCheck
|
|
14
|
+
} from "../chunk-YJ7YZRVV.js";
|
|
15
|
+
import {
|
|
16
|
+
createIo
|
|
17
|
+
} from "../chunk-TX7KBKT7.js";
|
|
18
|
+
import "../chunk-7QLSKOSU.js";
|
|
19
|
+
import "../chunk-BC3VCZ3E.js";
|
|
20
|
+
import {
|
|
21
|
+
exitOnHelpFlag
|
|
22
|
+
} from "../chunk-IIZZYUWK.js";
|
|
23
|
+
import {
|
|
24
|
+
EXIT
|
|
25
|
+
} from "../chunk-SP7OZXCQ.js";
|
|
26
|
+
import "../chunk-HNTKTK5B.js";
|
|
27
|
+
import "../chunk-DQAN3JQP.js";
|
|
28
|
+
import "../chunk-2UMNXADU.js";
|
|
29
|
+
|
|
30
|
+
// src/status.ts
|
|
31
|
+
var keySourceLine = (source) => {
|
|
32
|
+
if (source.kind === "none") {
|
|
33
|
+
return { label: "Key", value: "none found", ok: false };
|
|
34
|
+
}
|
|
35
|
+
const prefix = source.key ? source.key.split(".")[0] : "unknown";
|
|
36
|
+
const where = source.kind === "env" ? "$PUSHARY_API_KEY" : source.origin ?? "config file";
|
|
37
|
+
return { label: "Key", value: `${prefix} from ${where}`, ok: true };
|
|
38
|
+
};
|
|
39
|
+
var reachLine = (channels) => {
|
|
40
|
+
const verdict = reachVerdict(channels);
|
|
41
|
+
const line = describeReach(channels);
|
|
42
|
+
if (verdict.kind === "nobody") return { label: "Reachable", value: line, ok: false };
|
|
43
|
+
if (verdict.kind === "yours") {
|
|
44
|
+
const inPocket = (channels.yours?.phoneReachable ?? channels.phoneReachable) || channels.webPhone > 0;
|
|
45
|
+
return { label: "Reachable", value: line, ok: inPocket };
|
|
46
|
+
}
|
|
47
|
+
return { label: "Reachable", value: line, ok: false };
|
|
48
|
+
};
|
|
49
|
+
var siteLine = (channels) => {
|
|
50
|
+
const site = channels.site;
|
|
51
|
+
if (site === null || site.otherMembers === 0) return null;
|
|
52
|
+
const devices = site.appDevices + site.webActive;
|
|
53
|
+
return {
|
|
54
|
+
label: "Team",
|
|
55
|
+
value: `${devices} device${devices === 1 ? "" : "s"} across ${site.otherMembers + 1} members`,
|
|
56
|
+
ok: null
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
var buildStatusReport = (facts) => {
|
|
60
|
+
const lines = [keySourceLine(facts.source)];
|
|
61
|
+
if (facts.source.drift) {
|
|
62
|
+
lines.push({
|
|
63
|
+
label: "Key drift",
|
|
64
|
+
value: `$PUSHARY_API_KEY (${facts.source.drift.envPrefix}) differs from ${facts.source.drift.configPath} (${facts.source.drift.configPrefix}); the environment wins`,
|
|
65
|
+
ok: false
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (facts.source.kind === "none") {
|
|
69
|
+
return {
|
|
70
|
+
lines,
|
|
71
|
+
headline: "Not set up on this machine.",
|
|
72
|
+
next: ["Run `pushary setup` to connect an agent."],
|
|
73
|
+
exitCode: EXIT.NOT_CONFIGURED
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const check = facts.keyCheck;
|
|
77
|
+
if (check && check.kind !== "ok") {
|
|
78
|
+
const report = describeKeyCheck(check);
|
|
79
|
+
lines.push({ label: "Server", value: report.message, ok: check.kind === "unreachable" ? null : false });
|
|
80
|
+
return { lines, headline: report.message, next: [...report.next], exitCode: report.exitCode };
|
|
81
|
+
}
|
|
82
|
+
if (check?.kind === "ok") {
|
|
83
|
+
const id = check.identity;
|
|
84
|
+
lines.push({ label: "Site", value: `${id.siteName || id.siteSlug} (${id.siteSlug})`, ok: true });
|
|
85
|
+
lines.push({
|
|
86
|
+
label: "Plan",
|
|
87
|
+
value: id.plan === id.surfacePlan ? `${id.plan} \xB7 ${id.subscriptionStatus}` : `${id.plan} (from ${id.surfacePlan}) \xB7 ${id.subscriptionStatus}`,
|
|
88
|
+
ok: true
|
|
89
|
+
});
|
|
90
|
+
if (id.workspaceMembers > 1) {
|
|
91
|
+
lines.push({
|
|
92
|
+
label: "Workspace",
|
|
93
|
+
value: `${id.workspaceMembers} members \u2014 some devices below may not be yours`,
|
|
94
|
+
ok: null
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const channels = facts.channels?.kind === "ok" ? facts.channels.status : null;
|
|
99
|
+
if (channels) {
|
|
100
|
+
lines.push(reachLine(channels));
|
|
101
|
+
const site = siteLine(channels);
|
|
102
|
+
if (site) lines.push(site);
|
|
103
|
+
} else if (facts.channels && facts.channels.kind === "unreachable") {
|
|
104
|
+
lines.push({ label: "Reachable", value: `could not check (${facts.channels.detail})`, ok: null });
|
|
105
|
+
}
|
|
106
|
+
if (facts.source.drift) {
|
|
107
|
+
return {
|
|
108
|
+
lines,
|
|
109
|
+
headline: "Working, but two different keys are configured.",
|
|
110
|
+
next: [
|
|
111
|
+
"The shell export wins over the config file, and it may be the older one.",
|
|
112
|
+
"Run `pushary setup` to line them up, or open a new terminal."
|
|
113
|
+
],
|
|
114
|
+
exitCode: EXIT.PROBLEMS_FOUND
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (facts.channels && facts.channels.kind === "unreachable") {
|
|
118
|
+
return {
|
|
119
|
+
lines,
|
|
120
|
+
headline: "Key is fine; could not read which devices are connected.",
|
|
121
|
+
next: ["Run `pushary status` again in a minute."],
|
|
122
|
+
exitCode: EXIT.UNREACHABLE
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (channels) {
|
|
126
|
+
const verdict = reachVerdict(channels);
|
|
127
|
+
if (verdict.kind !== "yours") {
|
|
128
|
+
return {
|
|
129
|
+
lines,
|
|
130
|
+
headline: verdict.kind === "nobody" ? "Configured, but no device can receive an approval." : verdict.kind === "others" ? "Configured, but the only devices here are your teammates'." : "Configured, and nothing proves an approval reaches you.",
|
|
131
|
+
next: verdict.kind === "nobody" ? ["Run `pushary connect` to add your phone, or install the Pushary app."] : ["Run `pushary connect` to add your own phone.", "Or `pushary doctor --roundtrip` to prove one of these is yours."],
|
|
132
|
+
exitCode: EXIT.NO_DEVICE
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (!(channels.yours?.phoneReachable ?? channels.phoneReachable) && channels.webPhone === 0) {
|
|
136
|
+
return {
|
|
137
|
+
lines,
|
|
138
|
+
headline: "Configured, but nothing in your pocket can receive an approval.",
|
|
139
|
+
next: ["Run `pushary connect` and connect your phone, or install the Pushary app."],
|
|
140
|
+
exitCode: EXIT.NO_DEVICE
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
lines,
|
|
146
|
+
headline: "Ready.",
|
|
147
|
+
next: [],
|
|
148
|
+
exitCode: EXIT.OK
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
var statusJson = (facts, report) => ({
|
|
152
|
+
ok: report.exitCode === EXIT.OK,
|
|
153
|
+
headline: report.headline,
|
|
154
|
+
exitCode: report.exitCode,
|
|
155
|
+
keySource: facts.source.kind,
|
|
156
|
+
keyOrigin: facts.source.origin,
|
|
157
|
+
keyPrefix: facts.source.key ? facts.source.key.split(".")[0] : null,
|
|
158
|
+
drift: facts.source.drift ? {
|
|
159
|
+
env: facts.source.drift.envPrefix,
|
|
160
|
+
config: facts.source.drift.configPrefix,
|
|
161
|
+
configPath: facts.source.drift.configPath
|
|
162
|
+
} : null,
|
|
163
|
+
keyCheck: facts.keyCheck?.kind ?? null,
|
|
164
|
+
identity: facts.keyCheck?.kind === "ok" ? facts.keyCheck.identity : null,
|
|
165
|
+
channels: facts.channels?.kind === "ok" ? facts.channels.status : null,
|
|
166
|
+
channelsProbe: facts.channels?.kind ?? null
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// bin/pushary-status.ts
|
|
170
|
+
exitOnHelpFlag("status");
|
|
171
|
+
var { bold, dim, green, red, yellow } = createIo();
|
|
172
|
+
var args = process.argv.slice(2);
|
|
173
|
+
var json = args.includes("--json");
|
|
174
|
+
var main = async () => {
|
|
175
|
+
const source = readKeySource();
|
|
176
|
+
let keyCheck = null;
|
|
177
|
+
let channels = null;
|
|
178
|
+
if (source.key) {
|
|
179
|
+
keyCheck = await checkApiKey(source.key);
|
|
180
|
+
if (keyCheck.kind === "ok") channels = await fetchChannels(source.key);
|
|
181
|
+
}
|
|
182
|
+
const facts = { source, keyCheck, channels };
|
|
183
|
+
const report = buildStatusReport(facts);
|
|
184
|
+
if (json) {
|
|
185
|
+
process.stdout.write(`${JSON.stringify(statusJson(facts, report), null, 2)}
|
|
186
|
+
`);
|
|
187
|
+
process.exit(report.exitCode);
|
|
188
|
+
}
|
|
189
|
+
const width = Math.max(...report.lines.map((line) => line.label.length)) + 2;
|
|
190
|
+
console.log();
|
|
191
|
+
console.log(` ${bold("Pushary")}`);
|
|
192
|
+
console.log();
|
|
193
|
+
for (const line of report.lines) {
|
|
194
|
+
const icon = line.ok === true ? green("\u2713") : line.ok === false ? red("\u2717") : dim("\xB7");
|
|
195
|
+
console.log(` ${icon} ${line.label.padEnd(width)}${line.value}`);
|
|
196
|
+
}
|
|
197
|
+
console.log();
|
|
198
|
+
console.log(` ${report.exitCode === 0 ? green(bold(report.headline)) : yellow(bold(report.headline))}`);
|
|
199
|
+
for (const next of report.next) console.log(` ${dim(next)}`);
|
|
200
|
+
console.log();
|
|
201
|
+
process.exit(report.exitCode);
|
|
202
|
+
};
|
|
203
|
+
main().catch((err) => {
|
|
204
|
+
console.error(` ${yellow("!")} status failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
205
|
+
process.exit(1);
|
|
206
|
+
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handleStop
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-DWED7BS3.js";
|
|
4
|
+
} from "../chunk-HIIBSYFJ.js";
|
|
5
|
+
import "../chunk-HNTKTK5B.js";
|
|
7
6
|
import "../chunk-DQAN3JQP.js";
|
|
8
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-RN3NOEJF.js";
|
|
8
|
+
import "../chunk-2UMNXADU.js";
|
|
9
9
|
|
|
10
10
|
// bin/pushary-stop-hook.ts
|
|
11
11
|
var main = async () => {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handleStopFailure
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-DWED7BS3.js";
|
|
4
|
+
} from "../chunk-HIIBSYFJ.js";
|
|
5
|
+
import "../chunk-HNTKTK5B.js";
|
|
7
6
|
import "../chunk-DQAN3JQP.js";
|
|
8
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-RN3NOEJF.js";
|
|
8
|
+
import "../chunk-2UMNXADU.js";
|
|
9
9
|
|
|
10
10
|
// bin/pushary-stopfailure-hook.ts
|
|
11
11
|
var main = async () => {
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createIo
|
|
4
|
+
} from "../chunk-TX7KBKT7.js";
|
|
5
|
+
import {
|
|
6
|
+
exitOnHelpFlag
|
|
7
|
+
} from "../chunk-IIZZYUWK.js";
|
|
8
|
+
import "../chunk-SP7OZXCQ.js";
|
|
2
9
|
import {
|
|
3
10
|
getApiKey,
|
|
4
11
|
getBaseUrl
|
|
5
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-2UMNXADU.js";
|
|
6
13
|
|
|
7
14
|
// bin/pushary-suggestions.ts
|
|
8
|
-
|
|
9
|
-
var green = (
|
|
10
|
-
var cyan = (s) => `\x1B[36m${s}\x1B[0m`;
|
|
11
|
-
var red = (s) => `\x1B[31m${s}\x1B[0m`;
|
|
15
|
+
exitOnHelpFlag("suggestions");
|
|
16
|
+
var { dim, green, cyan, red } = createIo();
|
|
12
17
|
var errorMessage = async (res) => {
|
|
13
18
|
try {
|
|
14
19
|
const body = await res.json();
|
|
@@ -1,23 +1,50 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
execNpm,
|
|
4
|
-
npmErrorMessage,
|
|
5
|
-
resolveGlobalBinDir
|
|
6
|
-
} from "../chunk-J7JWI3KU.js";
|
|
7
2
|
import {
|
|
8
3
|
addClaudeMcpServer,
|
|
9
4
|
addPusharyHooks,
|
|
10
5
|
addPusharyToolPermissions
|
|
11
6
|
} from "../chunk-CAJZAFVS.js";
|
|
7
|
+
import {
|
|
8
|
+
GEMINI_HOOK_BINARY,
|
|
9
|
+
addGeminiHooks,
|
|
10
|
+
addGeminiMcpServer,
|
|
11
|
+
hasGeminiHooks
|
|
12
|
+
} from "../chunk-E2U35RLD.js";
|
|
13
|
+
import {
|
|
14
|
+
CODEX_HOOK_BINARY,
|
|
15
|
+
addCodexHookTrust,
|
|
16
|
+
addCodexHooks,
|
|
17
|
+
addCodexMcpServer,
|
|
18
|
+
codexConfigToml,
|
|
19
|
+
codexHooksJson,
|
|
20
|
+
hasCodexHooks
|
|
21
|
+
} from "../chunk-ER657KRJ.js";
|
|
22
|
+
import {
|
|
23
|
+
execNpm,
|
|
24
|
+
npmErrorMessage,
|
|
25
|
+
quoteIfNeeded,
|
|
26
|
+
resolveGlobalBinDir,
|
|
27
|
+
resolveGlobalBinary
|
|
28
|
+
} from "../chunk-MUEW424A.js";
|
|
29
|
+
import {
|
|
30
|
+
exitOnHelpFlag
|
|
31
|
+
} from "../chunk-IIZZYUWK.js";
|
|
32
|
+
import "../chunk-SP7OZXCQ.js";
|
|
12
33
|
import "../chunk-DQAN3JQP.js";
|
|
13
34
|
import {
|
|
14
35
|
getApiKey
|
|
15
|
-
} from "../chunk-
|
|
36
|
+
} from "../chunk-2UMNXADU.js";
|
|
37
|
+
|
|
38
|
+
// bin/pushary-upgrade.ts
|
|
39
|
+
import { existsSync as existsSync2 } from "fs";
|
|
40
|
+
import { homedir as homedir2 } from "os";
|
|
41
|
+
import { join as join2 } from "path";
|
|
16
42
|
|
|
17
43
|
// src/reapply.ts
|
|
18
44
|
import { join, dirname } from "path";
|
|
19
45
|
import { homedir } from "os";
|
|
20
46
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
47
|
+
import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
|
|
21
48
|
var CLAUDE_SETTINGS = join(homedir(), ".claude", "settings.json");
|
|
22
49
|
var CLAUDE_JSON = join(homedir(), ".claude.json");
|
|
23
50
|
var readJson = (filePath) => {
|
|
@@ -62,8 +89,130 @@ var reapplyClaudeSettings = (apiKey, paths = {}) => {
|
|
|
62
89
|
}
|
|
63
90
|
return { reapplied: hooks || mcp, hooks, mcp };
|
|
64
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 reapplyCodexSettings = (apiKey, paths = {}) => {
|
|
101
|
+
const configPath = paths.configPath ?? codexConfigToml();
|
|
102
|
+
const hooksPath = paths.hooksPath ?? codexHooksJson();
|
|
103
|
+
const config = readToml(configPath);
|
|
104
|
+
const hooksConfig = readJson(hooksPath);
|
|
105
|
+
const configured = config != null && !!config.mcp_servers?.pushary || hooksConfig != null && hasCodexHooks(hooksConfig);
|
|
106
|
+
if (!configured) return { reapplied: false, hooks: false, mcp: false };
|
|
107
|
+
const command = quoteIfNeeded(resolveGlobalBinary(CODEX_HOOK_BINARY) ?? CODEX_HOOK_BINARY);
|
|
108
|
+
let hooks = false;
|
|
109
|
+
let mcp = false;
|
|
110
|
+
if (hooksConfig != null) {
|
|
111
|
+
try {
|
|
112
|
+
addCodexHooks(hooksConfig, command);
|
|
113
|
+
writeJson(hooksPath, hooksConfig);
|
|
114
|
+
hooks = true;
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (config != null) {
|
|
119
|
+
try {
|
|
120
|
+
if (hooks) addCodexHookTrust(config, hooksPath, command);
|
|
121
|
+
if (apiKey) {
|
|
122
|
+
addCodexMcpServer(config, apiKey);
|
|
123
|
+
mcp = true;
|
|
124
|
+
}
|
|
125
|
+
if (hooks || apiKey) writeFileSync(configPath, stringifyTOML(config), "utf-8");
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { reapplied: hooks || mcp, hooks, mcp };
|
|
130
|
+
};
|
|
131
|
+
var reapplyGeminiSettings = (apiKey, paths = {}) => {
|
|
132
|
+
const settingsPath = paths.settingsPath ?? join(homedir(), ".gemini", "settings.json");
|
|
133
|
+
const settings = readJson(settingsPath);
|
|
134
|
+
if (settings == null) return { reapplied: false, hooks: false, mcp: false };
|
|
135
|
+
const configured = hasGeminiHooks(settings) || !!settings.mcpServers?.pushary;
|
|
136
|
+
if (!configured) return { reapplied: false, hooks: false, mcp: false };
|
|
137
|
+
let hooks = false;
|
|
138
|
+
let mcp = false;
|
|
139
|
+
try {
|
|
140
|
+
addGeminiHooks(settings, quoteIfNeeded(resolveGlobalBinary(GEMINI_HOOK_BINARY) ?? GEMINI_HOOK_BINARY));
|
|
141
|
+
hooks = true;
|
|
142
|
+
if (apiKey) {
|
|
143
|
+
addGeminiMcpServer(settings, apiKey);
|
|
144
|
+
mcp = true;
|
|
145
|
+
}
|
|
146
|
+
writeJson(settingsPath, settings);
|
|
147
|
+
} catch {
|
|
148
|
+
}
|
|
149
|
+
return { reapplied: hooks || mcp, hooks, mcp };
|
|
150
|
+
};
|
|
151
|
+
var reapplyCursorPlugin = (apiKey, paths = {}) => {
|
|
152
|
+
const mcpPath = paths.pluginMcpPath ?? join(homedir(), ".cursor", "plugins", "local", "pushary", "mcp.json");
|
|
153
|
+
if (!apiKey) return { reapplied: false, hooks: false, mcp: false };
|
|
154
|
+
const mcpConfig = readJson(mcpPath);
|
|
155
|
+
if (mcpConfig == null) return { reapplied: false, hooks: false, mcp: false };
|
|
156
|
+
const servers = mcpConfig.mcpServers;
|
|
157
|
+
if (!servers?.pushary) return { reapplied: false, hooks: false, mcp: false };
|
|
158
|
+
try {
|
|
159
|
+
addClaudeMcpServer(mcpConfig, apiKey);
|
|
160
|
+
writeJson(mcpPath, mcpConfig);
|
|
161
|
+
return { reapplied: true, hooks: false, mcp: true };
|
|
162
|
+
} catch {
|
|
163
|
+
return { reapplied: false, hooks: false, mcp: false };
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
var reapplyAllAgents = (apiKey) => {
|
|
167
|
+
const runners = [
|
|
168
|
+
{ label: "Claude Code", run: () => reapplyClaudeSettings(apiKey) },
|
|
169
|
+
{ label: "Codex", run: () => reapplyCodexSettings(apiKey) },
|
|
170
|
+
{ label: "Gemini CLI", run: () => reapplyGeminiSettings(apiKey) },
|
|
171
|
+
{ label: "Cursor", run: () => reapplyCursorPlugin(apiKey) }
|
|
172
|
+
];
|
|
173
|
+
const done = [];
|
|
174
|
+
for (const runner of runners) {
|
|
175
|
+
try {
|
|
176
|
+
const result = runner.run();
|
|
177
|
+
if (result.reapplied) done.push({ label: runner.label, result });
|
|
178
|
+
} catch {
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return done;
|
|
182
|
+
};
|
|
65
183
|
|
|
66
184
|
// bin/pushary-upgrade.ts
|
|
185
|
+
exitOnHelpFlag("upgrade");
|
|
186
|
+
var detectInstallModes = () => {
|
|
187
|
+
const candidates = [
|
|
188
|
+
{
|
|
189
|
+
label: "Cursor plugin",
|
|
190
|
+
upgrade: "updates itself through Cursor",
|
|
191
|
+
present: existsSync2(join2(homedir2(), ".cursor", "plugins", "local", "pushary"))
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
label: "Codex config",
|
|
195
|
+
upgrade: "npx @pushary/agent-hooks@latest setup --agents codex",
|
|
196
|
+
present: existsSync2(codexConfigToml())
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
label: "Claude Code config",
|
|
200
|
+
upgrade: "npx @pushary/agent-hooks@latest setup --agents claude_code",
|
|
201
|
+
present: existsSync2(join2(homedir2(), ".claude.json"))
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
label: "Gemini config",
|
|
205
|
+
upgrade: "npx @pushary/agent-hooks@latest setup --agents gemini_cli",
|
|
206
|
+
present: existsSync2(join2(homedir2(), ".gemini", "settings.json"))
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
label: "Hermes plugin (pip)",
|
|
210
|
+
upgrade: "pip install --upgrade pushary-hermes",
|
|
211
|
+
present: existsSync2(join2(homedir2(), ".hermes"))
|
|
212
|
+
}
|
|
213
|
+
];
|
|
214
|
+
return candidates.filter((candidate) => candidate.present).map(({ label, upgrade }) => ({ label, upgrade }));
|
|
215
|
+
};
|
|
67
216
|
var getInstalledVersion = () => {
|
|
68
217
|
try {
|
|
69
218
|
return execNpm("list -g --no-workspaces @pushary/agent-hooks --depth=0", { timeout: 1e4 }).toString().match(/@pushary\/agent-hooks@([\d.]+)/)?.[1] ?? "";
|
|
@@ -95,8 +244,20 @@ var isNewer = (a, b) => {
|
|
|
95
244
|
var main = async () => {
|
|
96
245
|
const installed = getInstalledVersion();
|
|
97
246
|
if (!installed) {
|
|
98
|
-
|
|
99
|
-
console.log("
|
|
247
|
+
const found = detectInstallModes();
|
|
248
|
+
console.log("No global install of @pushary/agent-hooks found, so there is nothing to upgrade here.");
|
|
249
|
+
console.log();
|
|
250
|
+
if (found.length === 0) {
|
|
251
|
+
console.log("Nothing on this machine looks Pushary-configured either.");
|
|
252
|
+
console.log(" Set it up with: npx @pushary/agent-hooks@latest setup");
|
|
253
|
+
} else {
|
|
254
|
+
console.log("What this machine does have:");
|
|
255
|
+
for (const mode of found) {
|
|
256
|
+
console.log(` ${mode.label.padEnd(22)} ${mode.upgrade}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
console.log();
|
|
260
|
+
console.log("Check the result with: pushary doctor");
|
|
100
261
|
return;
|
|
101
262
|
}
|
|
102
263
|
const latest = await fetchLatestVersion();
|
|
@@ -117,14 +278,23 @@ var main = async () => {
|
|
|
117
278
|
} catch {
|
|
118
279
|
apiKey = void 0;
|
|
119
280
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
281
|
+
const refreshed = reapplyAllAgents(apiKey);
|
|
282
|
+
console.log();
|
|
283
|
+
if (refreshed.length > 0) {
|
|
284
|
+
console.log("Refreshed so the new hook set is active now:");
|
|
285
|
+
for (const agent of refreshed) {
|
|
286
|
+
const parts = [agent.result.hooks ? "hooks" : null, agent.result.mcp ? "MCP key" : null].filter(Boolean).join(" + ");
|
|
287
|
+
console.log(` ${agent.label.padEnd(14)} ${parts}`);
|
|
124
288
|
}
|
|
125
|
-
|
|
289
|
+
if (!apiKey) {
|
|
290
|
+
console.log();
|
|
291
|
+
console.log("No key was readable here, so MCP entries kept the key they already had.");
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
console.log("No agent config on this machine needed refreshing.");
|
|
126
295
|
}
|
|
127
|
-
console.log(
|
|
296
|
+
console.log();
|
|
297
|
+
console.log("Done. Your hooks point at the global install.");
|
|
128
298
|
console.log("Verify with: pushary doctor");
|
|
129
299
|
};
|
|
130
300
|
main();
|
package/dist/bin/pushary-wait.js
CHANGED
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
exitOnFailedResponse
|
|
4
|
+
} from "../chunk-ONVEYEVR.js";
|
|
2
5
|
import {
|
|
3
6
|
describeWaitLadder
|
|
4
7
|
} from "../chunk-IIENZE2J.js";
|
|
8
|
+
import "../chunk-YJ7YZRVV.js";
|
|
9
|
+
import {
|
|
10
|
+
createIo
|
|
11
|
+
} from "../chunk-TX7KBKT7.js";
|
|
12
|
+
import "../chunk-7QLSKOSU.js";
|
|
13
|
+
import {
|
|
14
|
+
exitOnHelpFlag
|
|
15
|
+
} from "../chunk-IIZZYUWK.js";
|
|
16
|
+
import {
|
|
17
|
+
EXIT
|
|
18
|
+
} from "../chunk-SP7OZXCQ.js";
|
|
19
|
+
import "../chunk-DQAN3JQP.js";
|
|
5
20
|
import {
|
|
6
21
|
getApiKey,
|
|
7
22
|
getBaseUrl
|
|
8
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-2UMNXADU.js";
|
|
9
24
|
|
|
10
25
|
// bin/pushary-wait.ts
|
|
11
|
-
|
|
12
|
-
var bold = (
|
|
13
|
-
var green = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
14
|
-
var cyan = (s) => `\x1B[36m${s}\x1B[0m`;
|
|
15
|
-
var yellow = (s) => `\x1B[33m${s}\x1B[0m`;
|
|
26
|
+
exitOnHelpFlag("wait");
|
|
27
|
+
var { dim, bold, green, cyan, yellow } = createIo();
|
|
16
28
|
var MAX_WINDOW = 300;
|
|
17
29
|
var printLadder = (data) => {
|
|
18
30
|
console.log();
|
|
@@ -36,7 +48,7 @@ var printLadder = (data) => {
|
|
|
36
48
|
};
|
|
37
49
|
var fetchPolicy = async (baseUrl, headers) => {
|
|
38
50
|
const res = await fetch(`${baseUrl}/api/mcp/policy`, { headers });
|
|
39
|
-
if (!res.ok)
|
|
51
|
+
if (!res.ok) await exitOnFailedResponse(res, baseUrl);
|
|
40
52
|
return res.json();
|
|
41
53
|
};
|
|
42
54
|
var setWindow = async (baseUrl, headers, seconds) => {
|
|
@@ -45,10 +57,7 @@ var setWindow = async (baseUrl, headers, seconds) => {
|
|
|
45
57
|
headers,
|
|
46
58
|
body: JSON.stringify({ defaultPushFirstSeconds: seconds })
|
|
47
59
|
});
|
|
48
|
-
if (!res.ok)
|
|
49
|
-
const err = await res.json().catch(() => ({}));
|
|
50
|
-
throw new Error(err.error ?? res.statusText);
|
|
51
|
-
}
|
|
60
|
+
if (!res.ok) await exitOnFailedResponse(res, baseUrl);
|
|
52
61
|
const data = await res.json();
|
|
53
62
|
return data.defaultPushFirstSeconds;
|
|
54
63
|
};
|
|
@@ -75,7 +84,7 @@ var main = async () => {
|
|
|
75
84
|
if (!Number.isFinite(seconds) || seconds < 0 || seconds > MAX_WINDOW) {
|
|
76
85
|
console.log(` ${yellow("!")} Invalid window: ${arg} ${dim(`(use 0-${MAX_WINDOW} seconds, or "status" / "clear")`)}`);
|
|
77
86
|
console.log(` ${dim("Usage: pushary wait <seconds> | status | clear")}`);
|
|
78
|
-
|
|
87
|
+
process.exit(EXIT.USAGE);
|
|
79
88
|
}
|
|
80
89
|
const value = await setWindow(baseUrl, headers, Math.trunc(seconds));
|
|
81
90
|
console.log(` ${green("\u2713")} Default push window set to ${cyan(`${value}s`)} ${dim("\u2014 ping your phone that long, then the terminal takes over")}`);
|