@pushary/agent-hooks 0.89.11 → 0.89.12
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 +38 -0
- package/README.md +3 -2
- package/dist/bin/pushary-bell-hook.js +5 -5
- package/dist/bin/pushary-bell.js +11 -11
- package/dist/bin/pushary-claude.js +104 -32
- package/dist/bin/pushary-clean.js +39 -28
- package/dist/bin/pushary-codex-bridge.js +17 -16
- package/dist/bin/pushary-codex-hook.js +11 -10
- package/dist/bin/pushary-codex.js +7 -7
- package/dist/bin/pushary-connect.js +12 -12
- package/dist/bin/pushary-daemon-supervisor.d.ts +1 -0
- package/dist/bin/pushary-daemon-supervisor.js +27 -0
- package/dist/bin/pushary-daemon.js +22 -22
- package/dist/bin/pushary-disconnect.js +9 -9
- package/dist/bin/pushary-doctor.js +59 -49
- package/dist/bin/pushary-elicitation-hook.js +4 -4
- package/dist/bin/pushary-gemini-bridge.js +16 -15
- package/dist/bin/pushary-gemini-hook.js +10 -9
- package/dist/bin/pushary-hook.js +13 -13
- package/dist/bin/pushary-login.js +11 -11
- package/dist/bin/pushary-logout.js +11 -11
- package/dist/bin/pushary-mode.js +5 -5
- package/dist/bin/pushary-notification-hook.js +7 -7
- package/dist/bin/pushary-opencode-hook.js +10 -9
- package/dist/bin/pushary-permission-denied-hook.js +11 -11
- package/dist/bin/pushary-permission-hook.js +11 -11
- package/dist/bin/pushary-post-hook.js +7 -7
- package/dist/bin/pushary-prompt-hook.js +7 -7
- package/dist/bin/pushary-session-end-hook.js +7 -7
- package/dist/bin/pushary-session-start-hook.js +7 -7
- package/dist/bin/pushary-setup.js +87 -59
- package/dist/bin/pushary-stats.js +4 -4
- package/dist/bin/pushary-status.js +14 -14
- package/dist/bin/pushary-stop-hook.js +7 -7
- package/dist/bin/pushary-stopfailure-hook.js +7 -7
- package/dist/bin/pushary-suggestions.js +2 -2
- package/dist/bin/pushary-upgrade.js +21 -21
- package/dist/bin/pushary-wait.js +5 -5
- package/dist/bin/pushary.js +1 -1
- package/dist/{chunk-253WC6O5.js → chunk-327YMKP5.js} +1 -1
- package/dist/{chunk-6XUABEX2.js → chunk-3OXHYPZG.js} +1 -1
- package/dist/{chunk-MZGWKIUZ.js → chunk-3XSP5SML.js} +7 -3
- package/dist/{chunk-XX2V4QS5.js → chunk-4LL6LG5X.js} +2 -2
- package/dist/{chunk-DKWM5T3P.js → chunk-5NDB3YOE.js} +2 -2
- package/dist/{chunk-TEZ2FZD6.js → chunk-6GU55AQQ.js} +2 -2
- package/dist/{chunk-Q223OM5J.js → chunk-6V7ZDH3A.js} +4 -4
- package/dist/{chunk-OLAGKKSR.js → chunk-6VXNA5JB.js} +16 -6
- package/dist/{chunk-34GN3IPX.js → chunk-7DK3ZH3N.js} +1 -1
- package/dist/{chunk-PZRWFWSR.js → chunk-7HYJPOGG.js} +7 -7
- package/dist/{chunk-TY5HVMXT.js → chunk-DHR4F2CR.js} +1 -1
- package/dist/{chunk-3HFK3UXM.js → chunk-FCUUVHTS.js} +1 -1
- package/dist/{chunk-NCVIWGVA.js → chunk-GKPURU7P.js} +1 -1
- package/dist/chunk-JJV5Q4KG.js +20 -0
- package/dist/{chunk-TG3T3M4K.js → chunk-JVZX5YRJ.js} +6 -2
- package/dist/{chunk-6EKQZA6R.js → chunk-KVHP5ZME.js} +1 -1
- package/dist/{chunk-X4ZUUFKV.js → chunk-L4ZCFMWW.js} +63 -1
- package/dist/{chunk-2LPEZYMC.js → chunk-MFNQ5IMW.js} +1 -1
- package/dist/{chunk-KVE5RCQL.js → chunk-NBRM3FMD.js} +1 -1
- package/dist/{chunk-FZ73G2RO.js → chunk-NESKLV6R.js} +25 -6
- package/dist/{chunk-FXIL7RCL.js → chunk-OADGBOP7.js} +4 -4
- package/dist/{chunk-J4K75V4D.js → chunk-OCMOTJTW.js} +10 -9
- package/dist/{chunk-LURY4WNF.js → chunk-OTPJ4FUR.js} +1 -1
- package/dist/{chunk-QA72MKIT.js → chunk-OVEGEQSB.js} +5 -5
- package/dist/{chunk-3SQYKLBW.js → chunk-PS7DQ2SU.js} +46 -18
- package/dist/{chunk-UDBJHQMG.js → chunk-QFJZHVVL.js} +1 -1
- package/dist/chunk-QZCFVWA7.js +58 -0
- package/dist/{chunk-3XTFX4CL.js → chunk-RLQWNEPM.js} +3 -2
- package/dist/{chunk-3CUDMTL4.js → chunk-RNKPLUWC.js} +10 -3
- package/dist/{chunk-SYUIXXQW.js → chunk-VF3RTVWY.js} +1 -1
- package/dist/{chunk-TRVIRETT.js → chunk-VPLQFXCH.js} +1 -1
- package/dist/{chunk-IUN6VOKV.js → chunk-WDVQ6O4C.js} +2 -42
- package/dist/{chunk-IUWRVTQK.js → chunk-XREW7RQ3.js} +1 -1
- package/dist/{chunk-BLODMQKJ.js → chunk-Y4WVZIEI.js} +1 -1
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +15 -11
- package/package.json +2 -1
- /package/dist/{chunk-X6RXX2NF.js → chunk-3MCEES6Z.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.89.12
|
|
4
|
+
|
|
5
|
+
### Phone control installs as a native service, without a VM
|
|
6
|
+
|
|
7
|
+
Fresh setup enables phone-start when a supported provider and the operating
|
|
8
|
+
system's own per-user service manager are available: launchd on macOS, systemd
|
|
9
|
+
on Linux, and Task Scheduler on Windows. Existing installs keep their stored
|
|
10
|
+
choice. Service replacement is transactional, verifies the new process before
|
|
11
|
+
committing, and restores the previous running or stopped state on failure.
|
|
12
|
+
|
|
13
|
+
Claude Code, Codex and Gemini sessions started from the phone now use the same
|
|
14
|
+
supervised control path. Setup checks both the local heartbeat and the server's
|
|
15
|
+
view of the machine before calling control ready.
|
|
16
|
+
|
|
17
|
+
### Fresh and partial installs repair themselves
|
|
18
|
+
|
|
19
|
+
Setup now verifies every global command, its local JavaScript imports, and the
|
|
20
|
+
Cursor and VS Code runtime assets before reusing an installed version. A
|
|
21
|
+
same-version package missing any of them is reinstalled instead of failing the
|
|
22
|
+
same setup forever. Fresh installs also cover Codex on Windows and recover from
|
|
23
|
+
partially configured providers without disturbing unrelated settings.
|
|
24
|
+
|
|
25
|
+
### The CLI and macOS app keep their own wiring
|
|
26
|
+
|
|
27
|
+
Cursor setup writes one gate per event even when the other installer ran first.
|
|
28
|
+
`pushary clean` removes the CLI gate while preserving the app's bridge, and
|
|
29
|
+
`pushary doctor` validates the MCP entry from the installer that actually wired
|
|
30
|
+
Cursor. This keeps mixed CLI/app machines working and avoids false repair
|
|
31
|
+
failures on app-only installs.
|
|
32
|
+
|
|
33
|
+
### Transcript control works in every shell
|
|
34
|
+
|
|
35
|
+
Setup discloses encrypted transcript sync and its audited compliance-recovery
|
|
36
|
+
path before enabling it for a new install; older installs remain off until setup
|
|
37
|
+
runs again. `pushary setup --transcripts on|off` now provides the same persistent
|
|
38
|
+
choice in POSIX shells, PowerShell and Command Prompt. The existing
|
|
39
|
+
`PUSHARY_TRANSCRIPTS` environment override remains compatible.
|
|
40
|
+
|
|
3
41
|
## 0.89.11
|
|
4
42
|
|
|
5
43
|
### Phone-spawned Codex and Gemini sessions record their conversation again
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@pushary/agent-hooks)
|
|
5
5
|
[](./LICENSE)
|
|
6
6
|
|
|
7
|
-
Push notifications, questions, and permission approvals for AI
|
|
7
|
+
Push notifications, questions, and permission approvals for AI agents. Get a push when your agent finishes work, answer its questions from your phone, and approve risky commands before they run. Works with Claude Code, Codex, Cursor, VS Code, OpenCode, Gemini CLI, and Hermes.
|
|
8
8
|
|
|
9
9
|
Your agent froze waiting for a yes. This is how it reaches you.
|
|
10
10
|
|
|
@@ -110,6 +110,7 @@ npx @pushary/agent-hooks@latest doctor
|
|
|
110
110
|
| Gemini CLI | yes | yes | yes |
|
|
111
111
|
| Hermes | yes | yes | yes |
|
|
112
112
|
| VS Code | yes | yes | yes |
|
|
113
|
+
| OpenCode | yes | yes | yes |
|
|
113
114
|
|
|
114
115
|
Any other MCP client can use notify and ask by pointing at the Pushary MCP endpoint directly.
|
|
115
116
|
|
|
@@ -182,7 +183,7 @@ failing closed would let one malformed download silence every hook on the machin
|
|
|
182
183
|
asserts this list matches it. Do not edit one without the other. -->
|
|
183
184
|
|
|
184
185
|
```
|
|
185
|
-
setup Configure Claude Code, Codex, Gemini CLI, Hermes, Cursor,
|
|
186
|
+
setup Configure Claude Code, Codex, Gemini CLI, Hermes, Cursor, VS Code, or OpenCode with Pushary
|
|
186
187
|
claude Run Claude Code through Pushary, reachable from your phone even when idle
|
|
187
188
|
daemon Keep this machine reachable so your phone can START a new session
|
|
188
189
|
status One screen: which key is in force, whether the server accepts it, what can receive an approval
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handleBell
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-VPLQFXCH.js";
|
|
5
5
|
import {
|
|
6
6
|
readHookInput
|
|
7
7
|
} from "../chunk-6CUUA7HO.js";
|
|
8
|
-
import "../chunk-
|
|
8
|
+
import "../chunk-RNKPLUWC.js";
|
|
9
9
|
import "../chunk-BC3VCZ3E.js";
|
|
10
|
-
import "../chunk-
|
|
11
|
-
import "../chunk-
|
|
10
|
+
import "../chunk-XREW7RQ3.js";
|
|
11
|
+
import "../chunk-4LL6LG5X.js";
|
|
12
12
|
import "../chunk-2UMNXADU.js";
|
|
13
|
-
import "../chunk-
|
|
13
|
+
import "../chunk-3MCEES6Z.js";
|
|
14
14
|
|
|
15
15
|
// bin/pushary-bell-hook.ts
|
|
16
16
|
var main = async () => {
|
package/dist/bin/pushary-bell.js
CHANGED
|
@@ -5,38 +5,38 @@ import {
|
|
|
5
5
|
liveAgentCount,
|
|
6
6
|
ring,
|
|
7
7
|
upgradeThreshold
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-VPLQFXCH.js";
|
|
9
9
|
import {
|
|
10
10
|
guardBinary
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-VF3RTVWY.js";
|
|
12
|
+
import "../chunk-L4ZCFMWW.js";
|
|
13
13
|
import {
|
|
14
14
|
claudeSettings
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-OVEGEQSB.js";
|
|
16
16
|
import {
|
|
17
17
|
createIo
|
|
18
18
|
} from "../chunk-5RUIFDTP.js";
|
|
19
|
-
import "../chunk-3CUDMTL4.js";
|
|
20
19
|
import {
|
|
21
20
|
parseFlags
|
|
22
21
|
} from "../chunk-GMXKITVA.js";
|
|
23
22
|
import {
|
|
24
23
|
exitOnHelpFlag
|
|
25
|
-
} from "../chunk-
|
|
26
|
-
import "../chunk-
|
|
27
|
-
import "../chunk-BC3VCZ3E.js";
|
|
24
|
+
} from "../chunk-OTPJ4FUR.js";
|
|
25
|
+
import "../chunk-RLQWNEPM.js";
|
|
28
26
|
import "../chunk-DINDL2CF.js";
|
|
29
|
-
import "../chunk-
|
|
27
|
+
import "../chunk-RNKPLUWC.js";
|
|
28
|
+
import "../chunk-BC3VCZ3E.js";
|
|
30
29
|
import "../chunk-7QLSKOSU.js";
|
|
31
30
|
import {
|
|
32
31
|
EXIT
|
|
33
32
|
} from "../chunk-KZERVKTD.js";
|
|
33
|
+
import "../chunk-XREW7RQ3.js";
|
|
34
34
|
import {
|
|
35
35
|
readJsonSafe,
|
|
36
36
|
writeJsonAtomic
|
|
37
|
-
} from "../chunk-
|
|
37
|
+
} from "../chunk-4LL6LG5X.js";
|
|
38
38
|
import "../chunk-2UMNXADU.js";
|
|
39
|
-
import "../chunk-
|
|
39
|
+
import "../chunk-3MCEES6Z.js";
|
|
40
40
|
|
|
41
41
|
// src/bell/install.ts
|
|
42
42
|
import { join } from "path";
|
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ensureDaemonRunning
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-PS7DQ2SU.js";
|
|
5
5
|
import {
|
|
6
6
|
buildTranscriptRecords,
|
|
7
7
|
decodePublicKey,
|
|
8
|
-
fetchAccountPublicKey,
|
|
9
8
|
generateSessionKey,
|
|
10
|
-
uploadTranscriptRecords,
|
|
11
9
|
wrapSessionKey
|
|
12
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-WDVQ6O4C.js";
|
|
11
|
+
import {
|
|
12
|
+
fetchTranscriptRecipients,
|
|
13
|
+
uploadTranscriptRecords
|
|
14
|
+
} from "../chunk-QZCFVWA7.js";
|
|
15
|
+
import {
|
|
16
|
+
transcriptsEnabled
|
|
17
|
+
} from "../chunk-JJV5Q4KG.js";
|
|
13
18
|
import {
|
|
14
19
|
startProcessOwnership,
|
|
15
20
|
withSpawnProcessOwnership
|
|
16
|
-
} from "../chunk-
|
|
21
|
+
} from "../chunk-6GU55AQQ.js";
|
|
17
22
|
import {
|
|
18
23
|
needsShell,
|
|
19
24
|
spawnClaude
|
|
20
25
|
} from "../chunk-XHKBHWLX.js";
|
|
21
|
-
import "../chunk-
|
|
26
|
+
import "../chunk-L4ZCFMWW.js";
|
|
22
27
|
import {
|
|
23
28
|
isDeferAnswer
|
|
24
29
|
} from "../chunk-YHG74UFF.js";
|
|
@@ -27,7 +32,7 @@ import {
|
|
|
27
32
|
getPolicy,
|
|
28
33
|
repoKeyFor,
|
|
29
34
|
reportEvent
|
|
30
|
-
} from "../chunk-
|
|
35
|
+
} from "../chunk-OADGBOP7.js";
|
|
31
36
|
import {
|
|
32
37
|
DEFAULT_SESSION,
|
|
33
38
|
askUser,
|
|
@@ -41,21 +46,24 @@ import {
|
|
|
41
46
|
waitForAnswer
|
|
42
47
|
} from "../chunk-JHJHCMAF.js";
|
|
43
48
|
import {
|
|
49
|
+
UNNAMED_ACTION,
|
|
44
50
|
deriveToolTarget,
|
|
45
51
|
describeToolCall,
|
|
46
52
|
scopePathFor
|
|
47
|
-
} from "../chunk-
|
|
53
|
+
} from "../chunk-JVZX5YRJ.js";
|
|
48
54
|
import {
|
|
49
55
|
getMachineId
|
|
50
|
-
} from "../chunk-
|
|
51
|
-
import "../chunk-
|
|
56
|
+
} from "../chunk-5NDB3YOE.js";
|
|
57
|
+
import "../chunk-OVEGEQSB.js";
|
|
52
58
|
import "../chunk-DINDL2CF.js";
|
|
59
|
+
import "../chunk-RNKPLUWC.js";
|
|
60
|
+
import "../chunk-BC3VCZ3E.js";
|
|
53
61
|
import "../chunk-BSZYIAZL.js";
|
|
54
62
|
import "../chunk-SAF6HGAA.js";
|
|
55
|
-
import "../chunk-IUWRVTQK.js";
|
|
56
63
|
import "../chunk-7QLSKOSU.js";
|
|
57
64
|
import "../chunk-KZERVKTD.js";
|
|
58
|
-
import "../chunk-
|
|
65
|
+
import "../chunk-XREW7RQ3.js";
|
|
66
|
+
import "../chunk-4LL6LG5X.js";
|
|
59
67
|
import {
|
|
60
68
|
getApiKey,
|
|
61
69
|
getBaseUrl
|
|
@@ -63,7 +71,7 @@ import {
|
|
|
63
71
|
import {
|
|
64
72
|
KILL_REASON,
|
|
65
73
|
resolveGate
|
|
66
|
-
} from "../chunk-
|
|
74
|
+
} from "../chunk-3MCEES6Z.js";
|
|
67
75
|
|
|
68
76
|
// src/wrapper/claudeBinary.ts
|
|
69
77
|
import { statSync } from "fs";
|
|
@@ -142,7 +150,6 @@ import { basename } from "path";
|
|
|
142
150
|
import { homedir } from "os";
|
|
143
151
|
import { join as join2, resolve } from "path";
|
|
144
152
|
import { existsSync, readFileSync } from "fs";
|
|
145
|
-
var transcriptsEnabled = () => process.env.PUSHARY_TRANSCRIPTS === "1";
|
|
146
153
|
var claudeTranscriptPath = (cwd, sessionId) => {
|
|
147
154
|
const projectId = resolve(cwd).replace(/[^a-zA-Z0-9-]/g, "-");
|
|
148
155
|
const configDir = process.env.CLAUDE_CONFIG_DIR || join2(homedir(), ".claude");
|
|
@@ -151,6 +158,8 @@ var claudeTranscriptPath = (cwd, sessionId) => {
|
|
|
151
158
|
var createSyncState = () => ({
|
|
152
159
|
sessionKey: null,
|
|
153
160
|
wrappedKey: null,
|
|
161
|
+
providerWrappedKey: null,
|
|
162
|
+
providerKeyId: null,
|
|
154
163
|
seen: /* @__PURE__ */ new Set(),
|
|
155
164
|
keyUploaded: false,
|
|
156
165
|
keyRejected: false
|
|
@@ -159,30 +168,77 @@ var syncTick = async (lines, state, uploader, sessionId, machineId) => {
|
|
|
159
168
|
if (state.keyRejected) return state;
|
|
160
169
|
let sessionKey = state.sessionKey;
|
|
161
170
|
let wrappedKey = state.wrappedKey;
|
|
171
|
+
let providerWrappedKey = state.providerWrappedKey;
|
|
172
|
+
let providerKeyId = state.providerKeyId;
|
|
162
173
|
if (!sessionKey) {
|
|
163
|
-
const
|
|
164
|
-
if (!
|
|
174
|
+
const recipients = await uploader.fetchTranscriptRecipients();
|
|
175
|
+
if (!recipients) return state;
|
|
165
176
|
sessionKey = generateSessionKey();
|
|
166
|
-
wrappedKey = wrapSessionKey(sessionKey, decodePublicKey(
|
|
177
|
+
wrappedKey = wrapSessionKey(sessionKey, decodePublicKey(recipients.phonePublicKey));
|
|
178
|
+
if (recipients.provider) {
|
|
179
|
+
providerWrappedKey = wrapSessionKey(sessionKey, decodePublicKey(recipients.provider.publicKey));
|
|
180
|
+
providerKeyId = recipients.provider.keyId;
|
|
181
|
+
}
|
|
167
182
|
}
|
|
168
183
|
const built = buildTranscriptRecords(lines, sessionKey, state.seen);
|
|
169
184
|
if (built.records.length === 0) {
|
|
170
|
-
return { ...state, sessionKey, wrappedKey, seen: built.seen };
|
|
185
|
+
return { ...state, sessionKey, wrappedKey, providerWrappedKey, providerKeyId, seen: built.seen };
|
|
186
|
+
}
|
|
187
|
+
const seen = new Set(state.seen);
|
|
188
|
+
let keyUploaded = state.keyUploaded;
|
|
189
|
+
let keyRejected = false;
|
|
190
|
+
let rejected = 0;
|
|
191
|
+
for (const chunk of chunkRecords(built.records)) {
|
|
192
|
+
const result = await uploader.uploadRecords({
|
|
193
|
+
sessionId,
|
|
194
|
+
machineId,
|
|
195
|
+
dataEncryptionKey: keyUploaded ? void 0 : wrappedKey ?? void 0,
|
|
196
|
+
providerWrappedSessionKey: keyUploaded ? void 0 : providerWrappedKey ?? void 0,
|
|
197
|
+
providerKeyId: keyUploaded ? void 0 : providerKeyId ?? void 0,
|
|
198
|
+
records: chunk
|
|
199
|
+
});
|
|
200
|
+
keyUploaded = keyUploaded || result.keyRegistered;
|
|
201
|
+
if (result.keyConflict) {
|
|
202
|
+
keyRejected = true;
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
if (!result.ok) break;
|
|
206
|
+
for (const id of result.settledIds ?? chunk.map((r) => r.localId)) seen.add(id);
|
|
207
|
+
rejected += result.rejectedIds.length;
|
|
208
|
+
}
|
|
209
|
+
if (rejected > 0) {
|
|
210
|
+
process.stderr.write(`[pushary] transcript: ${rejected} record${rejected === 1 ? "" : "s"} could not be stored and will not be retried.
|
|
211
|
+
`);
|
|
171
212
|
}
|
|
172
|
-
const result = await uploader.uploadRecords({
|
|
173
|
-
sessionId,
|
|
174
|
-
machineId,
|
|
175
|
-
dataEncryptionKey: state.keyUploaded ? void 0 : wrappedKey ?? void 0,
|
|
176
|
-
records: built.records
|
|
177
|
-
});
|
|
178
213
|
return {
|
|
179
214
|
sessionKey,
|
|
180
215
|
wrappedKey,
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
216
|
+
providerWrappedKey,
|
|
217
|
+
providerKeyId,
|
|
218
|
+
seen,
|
|
219
|
+
keyUploaded,
|
|
220
|
+
keyRejected
|
|
184
221
|
};
|
|
185
222
|
};
|
|
223
|
+
var MAX_RECORDS_PER_BATCH = 200;
|
|
224
|
+
var MAX_BATCH_BYTES = 3e6;
|
|
225
|
+
var chunkRecords = (records) => {
|
|
226
|
+
const chunks = [];
|
|
227
|
+
let current = [];
|
|
228
|
+
let bytes = 0;
|
|
229
|
+
for (const record of records) {
|
|
230
|
+
const size = record.content.length;
|
|
231
|
+
if (current.length > 0 && (current.length >= MAX_RECORDS_PER_BATCH || bytes + size > MAX_BATCH_BYTES)) {
|
|
232
|
+
chunks.push(current);
|
|
233
|
+
current = [];
|
|
234
|
+
bytes = 0;
|
|
235
|
+
}
|
|
236
|
+
current.push(record);
|
|
237
|
+
bytes += size;
|
|
238
|
+
}
|
|
239
|
+
if (current.length > 0) chunks.push(current);
|
|
240
|
+
return chunks;
|
|
241
|
+
};
|
|
186
242
|
var readLines = (path) => {
|
|
187
243
|
try {
|
|
188
244
|
return existsSync(path) ? readFileSync(path, "utf-8").split("\n") : [];
|
|
@@ -190,9 +246,11 @@ var readLines = (path) => {
|
|
|
190
246
|
return [];
|
|
191
247
|
}
|
|
192
248
|
};
|
|
249
|
+
var IDLE_CEILING_MS = 6e4;
|
|
250
|
+
var nextInterval = (previousMs, idle, baseMs, maxMs) => idle ? Math.min(previousMs * 2, maxMs) : baseMs;
|
|
193
251
|
var startTranscriptSync = (opts) => {
|
|
194
252
|
const uploader = {
|
|
195
|
-
|
|
253
|
+
fetchTranscriptRecipients: () => fetchTranscriptRecipients(opts.apiKey),
|
|
196
254
|
uploadRecords: (params) => uploadTranscriptRecords(opts.apiKey, params)
|
|
197
255
|
};
|
|
198
256
|
const path = claudeTranscriptPath(opts.cwd, opts.sessionId);
|
|
@@ -209,12 +267,26 @@ var startTranscriptSync = (opts) => {
|
|
|
209
267
|
inFlight = false;
|
|
210
268
|
}
|
|
211
269
|
};
|
|
212
|
-
const
|
|
213
|
-
|
|
270
|
+
const baseIntervalMs = opts.intervalMs ?? 3e3;
|
|
271
|
+
const maxIntervalMs = Math.max(baseIntervalMs, IDLE_CEILING_MS);
|
|
272
|
+
let timer;
|
|
273
|
+
const schedule = (delayMs) => {
|
|
274
|
+
if (!running) return;
|
|
275
|
+
timer = setTimeout(() => {
|
|
276
|
+
void (async () => {
|
|
277
|
+
const before = state.sessionKey;
|
|
278
|
+
await tick();
|
|
279
|
+
const idle = state.sessionKey === null && before === null;
|
|
280
|
+
schedule(nextInterval(delayMs, idle, baseIntervalMs, maxIntervalMs));
|
|
281
|
+
})();
|
|
282
|
+
}, delayMs);
|
|
283
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
284
|
+
};
|
|
214
285
|
void tick();
|
|
286
|
+
schedule(baseIntervalMs);
|
|
215
287
|
return () => {
|
|
216
288
|
running = false;
|
|
217
|
-
|
|
289
|
+
if (timer) clearTimeout(timer);
|
|
218
290
|
};
|
|
219
291
|
};
|
|
220
292
|
|
|
@@ -486,7 +558,7 @@ var createRemoteApprover = (deps) => {
|
|
|
486
558
|
let question;
|
|
487
559
|
try {
|
|
488
560
|
question = await askUser2(deps.apiKey, {
|
|
489
|
-
question: `Allow ${description}?`,
|
|
561
|
+
question: `Allow ${description || UNNAMED_ACTION}?`,
|
|
490
562
|
type: "confirm",
|
|
491
563
|
context: `Your agent wants to run this in ${deps.projectName} (you are away)`,
|
|
492
564
|
agentName: `Claude Code - ${deps.projectName}`,
|
|
@@ -3,13 +3,16 @@ import {
|
|
|
3
3
|
HERMES_CONFIG_SCRIPT,
|
|
4
4
|
resolveHermesPython,
|
|
5
5
|
runHermesPythonScript
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-QFJZHVVL.js";
|
|
7
7
|
import {
|
|
8
8
|
removeInstructionBlock,
|
|
9
9
|
shortenHome,
|
|
10
10
|
unregisterPluginLocation,
|
|
11
11
|
vscodeSettingsTargets
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-3XSP5SML.js";
|
|
13
|
+
import {
|
|
14
|
+
pusharyHookExecutable
|
|
15
|
+
} from "../chunk-NESKLV6R.js";
|
|
13
16
|
import {
|
|
14
17
|
OPENCODE_PLUGIN_SIBLING,
|
|
15
18
|
OPENCODE_PLUGIN_SIBLING_CONTENTS,
|
|
@@ -19,25 +22,25 @@ import {
|
|
|
19
22
|
openCodePluginDir,
|
|
20
23
|
openCodePluginFile,
|
|
21
24
|
removeOpenCodeMcpServer
|
|
22
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-7DK3ZH3N.js";
|
|
23
26
|
import {
|
|
24
27
|
isClaudeMcpSnapshot,
|
|
25
28
|
removeClaudeMcpServers,
|
|
26
29
|
removeGeminiSettings,
|
|
27
30
|
removePusharySettings,
|
|
28
31
|
restoreClaudeMcpServer
|
|
29
|
-
} from "../chunk-
|
|
30
|
-
import "../chunk-
|
|
31
|
-
import "../chunk-
|
|
32
|
+
} from "../chunk-6V7ZDH3A.js";
|
|
33
|
+
import "../chunk-KVHP5ZME.js";
|
|
34
|
+
import "../chunk-VF3RTVWY.js";
|
|
32
35
|
import {
|
|
33
36
|
disableDaemonService
|
|
34
|
-
} from "../chunk-
|
|
37
|
+
} from "../chunk-PS7DQ2SU.js";
|
|
35
38
|
import "../chunk-XHKBHWLX.js";
|
|
36
39
|
import {
|
|
37
40
|
execNpm
|
|
38
|
-
} from "../chunk-
|
|
39
|
-
import "../chunk-
|
|
40
|
-
import "../chunk-
|
|
41
|
+
} from "../chunk-L4ZCFMWW.js";
|
|
42
|
+
import "../chunk-JVZX5YRJ.js";
|
|
43
|
+
import "../chunk-5NDB3YOE.js";
|
|
41
44
|
import {
|
|
42
45
|
claudeJson,
|
|
43
46
|
claudeMcpReceipt,
|
|
@@ -55,32 +58,33 @@ import {
|
|
|
55
58
|
geminiMd,
|
|
56
59
|
geminiSettings,
|
|
57
60
|
hermesConfigReceipt,
|
|
61
|
+
isProtectedByScope,
|
|
58
62
|
pusharyDir,
|
|
59
63
|
removeCodexHookTrust,
|
|
60
64
|
removeCodexHooks,
|
|
61
65
|
vscodePluginDir
|
|
62
|
-
} from "../chunk-
|
|
66
|
+
} from "../chunk-OVEGEQSB.js";
|
|
63
67
|
import {
|
|
64
68
|
rejectUnknownFlags
|
|
65
69
|
} from "../chunk-GMXKITVA.js";
|
|
66
70
|
import {
|
|
67
71
|
exitOnHelpFlag
|
|
68
|
-
} from "../chunk-
|
|
69
|
-
import "../chunk-
|
|
72
|
+
} from "../chunk-OTPJ4FUR.js";
|
|
73
|
+
import "../chunk-RLQWNEPM.js";
|
|
74
|
+
import "../chunk-DINDL2CF.js";
|
|
70
75
|
import {
|
|
71
76
|
removeClaudeAlias
|
|
72
77
|
} from "../chunk-BC3VCZ3E.js";
|
|
73
|
-
import "../chunk-DINDL2CF.js";
|
|
74
78
|
import "../chunk-7QLSKOSU.js";
|
|
75
79
|
import {
|
|
76
80
|
EXIT
|
|
77
81
|
} from "../chunk-KZERVKTD.js";
|
|
78
|
-
import "../chunk-
|
|
82
|
+
import "../chunk-4LL6LG5X.js";
|
|
79
83
|
import "../chunk-2UMNXADU.js";
|
|
80
84
|
import {
|
|
81
85
|
CURSOR_GATE_EVENTS,
|
|
82
86
|
HOOK_LOCATOR_BINARY
|
|
83
|
-
} from "../chunk-
|
|
87
|
+
} from "../chunk-3MCEES6Z.js";
|
|
84
88
|
|
|
85
89
|
// bin/pushary-clean.ts
|
|
86
90
|
import { existsSync, readFileSync, copyFileSync, readdirSync } from "fs";
|
|
@@ -146,9 +150,9 @@ var VSCODE_PLUGIN_DIR = vscodePluginDir();
|
|
|
146
150
|
var PUSHARY_DIR = pusharyDir();
|
|
147
151
|
var SHELL_FILES = [".zshrc", ".zprofile", ".bashrc", ".bash_profile"].map((f) => join(homedir(), f));
|
|
148
152
|
var macAppInstalled = () => existsSync(join(PUSHARY_DIR, "bin", HOOK_LOCATOR_BINARY));
|
|
149
|
-
var removalScope = () => ({
|
|
153
|
+
var removalScope = (keepMcpServer) => ({
|
|
150
154
|
keepAppWiring: true,
|
|
151
|
-
keepMcpServer
|
|
155
|
+
keepMcpServer
|
|
152
156
|
});
|
|
153
157
|
var readJson = (path) => {
|
|
154
158
|
try {
|
|
@@ -189,7 +193,7 @@ var guardedAliasRemoval = () => {
|
|
|
189
193
|
var writeJson = (path, data) => {
|
|
190
194
|
guardedWrite(path, JSON.stringify(data, null, 2) + "\n");
|
|
191
195
|
};
|
|
192
|
-
var removeCursorUserHook = () => {
|
|
196
|
+
var removeCursorUserHook = (scope) => {
|
|
193
197
|
if (!existsSync(CURSOR_USER_HOOKS)) return "absent";
|
|
194
198
|
let parsed;
|
|
195
199
|
try {
|
|
@@ -202,7 +206,10 @@ var removeCursorUserHook = () => {
|
|
|
202
206
|
let removedAny = false;
|
|
203
207
|
for (const event of CURSOR_GATE_EVENTS) {
|
|
204
208
|
const existing = Array.isArray(hooks[event]) ? hooks[event] : [];
|
|
205
|
-
const others = existing.filter((h) =>
|
|
209
|
+
const others = existing.filter((h) => {
|
|
210
|
+
const command = String(h.command ?? "");
|
|
211
|
+
return pusharyHookExecutable(command) === null || isProtectedByScope(command, scope);
|
|
212
|
+
});
|
|
206
213
|
if (others.length === existing.length) continue;
|
|
207
214
|
removedAny = true;
|
|
208
215
|
if (others.length === 0) delete hooks[event];
|
|
@@ -221,7 +228,10 @@ var removeCursorUserHook = () => {
|
|
|
221
228
|
const afterHooks = after?.hooks ?? {};
|
|
222
229
|
const stillThere = CURSOR_GATE_EVENTS.some((event) => {
|
|
223
230
|
const entries = afterHooks[event];
|
|
224
|
-
return Array.isArray(entries) && entries.some((h) =>
|
|
231
|
+
return Array.isArray(entries) && entries.some((h) => {
|
|
232
|
+
const command = String(h?.command ?? "");
|
|
233
|
+
return pusharyHookExecutable(command) !== null && !isProtectedByScope(command, scope);
|
|
234
|
+
});
|
|
225
235
|
});
|
|
226
236
|
if (stillThere) return "failed";
|
|
227
237
|
} catch {
|
|
@@ -229,13 +239,13 @@ var removeCursorUserHook = () => {
|
|
|
229
239
|
}
|
|
230
240
|
return "removed";
|
|
231
241
|
};
|
|
232
|
-
var cleanSettingsFile = (path, label) => {
|
|
242
|
+
var cleanSettingsFile = (path, label, scope) => {
|
|
233
243
|
const data = readJson(path);
|
|
234
244
|
if (!data) {
|
|
235
245
|
console.log(` ${skip} ${label} ${dim("(not found)")}`);
|
|
236
246
|
return;
|
|
237
247
|
}
|
|
238
|
-
const changed = removePusharySettings(data,
|
|
248
|
+
const changed = removePusharySettings(data, scope);
|
|
239
249
|
if (changed) {
|
|
240
250
|
writeJson(path, data);
|
|
241
251
|
console.log(` ${check} ${label} ${dim(did("cleaned"))}`);
|
|
@@ -280,6 +290,7 @@ var main = async () => {
|
|
|
280
290
|
}
|
|
281
291
|
console.log();
|
|
282
292
|
const keepShared = macAppInstalled();
|
|
293
|
+
const scope = removalScope(keepShared);
|
|
283
294
|
if (keepShared) {
|
|
284
295
|
console.log(` ${dim("The Mac app is installed, so its wiring and the state it owns are left alone.")}`);
|
|
285
296
|
console.log();
|
|
@@ -293,8 +304,8 @@ var main = async () => {
|
|
|
293
304
|
process.exit(EXIT.FAILED);
|
|
294
305
|
}
|
|
295
306
|
console.log(` ${check} Background service ${dim(did("uninstalled"))}`);
|
|
296
|
-
cleanSettingsFile(CLAUDE_SETTINGS, "Claude Code settings");
|
|
297
|
-
cleanSettingsFile(CLAUDE_SETTINGS_LOCAL, "Claude Code settings.local");
|
|
307
|
+
cleanSettingsFile(CLAUDE_SETTINGS, "Claude Code settings", scope);
|
|
308
|
+
cleanSettingsFile(CLAUDE_SETTINGS_LOCAL, "Claude Code settings.local", scope);
|
|
298
309
|
const claudeJson2 = keepShared ? null : readJson(CLAUDE_JSON);
|
|
299
310
|
if (keepShared) {
|
|
300
311
|
console.log(` ${skip} Claude Code MCP servers ${dim("(kept: the Mac app uses it)")}`);
|
|
@@ -332,7 +343,7 @@ var main = async () => {
|
|
|
332
343
|
} else {
|
|
333
344
|
console.log(` ${skip} Cursor MCP config ${dim("(not found)")}`);
|
|
334
345
|
}
|
|
335
|
-
const cursorGate = removeCursorUserHook();
|
|
346
|
+
const cursorGate = removeCursorUserHook(scope);
|
|
336
347
|
if (cursorGate === "removed") {
|
|
337
348
|
console.log(` ${check} Cursor gate ${dim("(removed from ~/.cursor/hooks.json)")}`);
|
|
338
349
|
} else if (cursorGate === "absent") {
|
|
@@ -410,7 +421,7 @@ var main = async () => {
|
|
|
410
421
|
console.log(` ${skip} Codex config ${dim("(not found)")}`);
|
|
411
422
|
}
|
|
412
423
|
if (codexHooksData) {
|
|
413
|
-
if (removeCodexHooks(codexHooksData,
|
|
424
|
+
if (removeCodexHooks(codexHooksData, scope)) {
|
|
414
425
|
writeJson(codexHooksJson2, codexHooksData);
|
|
415
426
|
console.log(` ${check} Codex hooks ${dim("(removed from ~/.codex/hooks.json)")}`);
|
|
416
427
|
} else {
|
|
@@ -435,7 +446,7 @@ var main = async () => {
|
|
|
435
446
|
const geminiSettingsPath = geminiSettings();
|
|
436
447
|
const geminiSettings2 = readJson(geminiSettingsPath);
|
|
437
448
|
if (geminiSettings2) {
|
|
438
|
-
if (removeGeminiSettings(geminiSettings2,
|
|
449
|
+
if (removeGeminiSettings(geminiSettings2, scope)) {
|
|
439
450
|
writeJson(geminiSettingsPath, geminiSettings2);
|
|
440
451
|
console.log(` ${check} Gemini CLI settings ${dim(did("cleaned"))}`);
|
|
441
452
|
} else {
|
|
@@ -1,33 +1,40 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "../chunk-
|
|
2
|
+
import "../chunk-3OXHYPZG.js";
|
|
3
3
|
import {
|
|
4
4
|
LiveTranscriptRelay,
|
|
5
5
|
liveSessionSleep,
|
|
6
6
|
postLiveSession,
|
|
7
7
|
postLiveSessionUntilAccepted,
|
|
8
8
|
startLiveSessionHeartbeat
|
|
9
|
-
} from "../chunk-
|
|
10
|
-
import "../chunk-
|
|
9
|
+
} from "../chunk-6VXNA5JB.js";
|
|
10
|
+
import "../chunk-WDVQ6O4C.js";
|
|
11
|
+
import "../chunk-QZCFVWA7.js";
|
|
12
|
+
import {
|
|
13
|
+
transcriptsEnabled
|
|
14
|
+
} from "../chunk-JJV5Q4KG.js";
|
|
11
15
|
import {
|
|
12
16
|
startProcessOwnership,
|
|
13
17
|
withSpawnProcessOwnership
|
|
14
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-6GU55AQQ.js";
|
|
15
19
|
import {
|
|
16
20
|
spawnClaude
|
|
17
21
|
} from "../chunk-XHKBHWLX.js";
|
|
18
22
|
import {
|
|
19
23
|
resolveBinary
|
|
20
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-L4ZCFMWW.js";
|
|
21
25
|
import {
|
|
22
26
|
getMachineId
|
|
23
|
-
} from "../chunk-
|
|
24
|
-
import "../chunk-
|
|
25
|
-
import "../chunk-
|
|
27
|
+
} from "../chunk-5NDB3YOE.js";
|
|
28
|
+
import "../chunk-OVEGEQSB.js";
|
|
29
|
+
import "../chunk-RNKPLUWC.js";
|
|
30
|
+
import "../chunk-BC3VCZ3E.js";
|
|
31
|
+
import "../chunk-XREW7RQ3.js";
|
|
32
|
+
import "../chunk-4LL6LG5X.js";
|
|
26
33
|
import {
|
|
27
34
|
getApiKey,
|
|
28
35
|
getBaseUrl
|
|
29
36
|
} from "../chunk-2UMNXADU.js";
|
|
30
|
-
import "../chunk-
|
|
37
|
+
import "../chunk-3MCEES6Z.js";
|
|
31
38
|
|
|
32
39
|
// bin/pushary-codex-bridge.ts
|
|
33
40
|
import { existsSync } from "fs";
|
|
@@ -371,13 +378,7 @@ var outcome = await withSpawnProcessOwnership(spawnId, () => runCodexBridge({
|
|
|
371
378
|
args: ["app-server", "--stdio"]
|
|
372
379
|
},
|
|
373
380
|
signal: abort.signal,
|
|
374
|
-
|
|
375
|
-
// on an explicit `false`), but `=== '1'` can never produce `undefined`, so an
|
|
376
|
-
// unset env var forced the opt-out on every spawn and the live relay was never
|
|
377
|
-
// built. Pass the opt-out only when the user asks for one. The relay stays a
|
|
378
|
-
// hard no-op until this account's phone has registered a public key, and what
|
|
379
|
-
// it sends is encrypted to that key on this machine.
|
|
380
|
-
...process.env.PUSHARY_TRANSCRIPTS === "0" ? { transcripts: false } : {}
|
|
381
|
+
transcripts: transcriptsEnabled()
|
|
381
382
|
}));
|
|
382
383
|
for (const signal of signals) process.off(signal, stop);
|
|
383
384
|
process.exit(outcome === "stopped" ? 0 : 1);
|