@pushary/agent-hooks 0.92.0 → 0.92.1
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 +23 -0
- package/dist/bin/pushary-claude.js +25 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.92.1
|
|
4
|
+
|
|
5
|
+
### A rejected key is an answer, not an empty poll
|
|
6
|
+
|
|
7
|
+
`pollAgent` returned `{ command: null, mode: null }` for every non-OK response,
|
|
8
|
+
so a 401 was indistinguishable from a healthy poll with nothing queued. That
|
|
9
|
+
landed on the success branch of `startCommandPoller`, which resets `errorStreak`
|
|
10
|
+
to zero, so the backoff never engaged and the wrapper polled a dead key at the
|
|
11
|
+
idle cadence forever. Because `mode` was null, `onModeState` never fired, and
|
|
12
|
+
`onModeState` is the only place `dualMode` sets `killed` and stops the active
|
|
13
|
+
leg. A wrapper whose key the server rejects therefore reported `kill=false` to
|
|
14
|
+
itself indefinitely: remote stop could not reach it, phone messages never
|
|
15
|
+
landed, and nothing was printed.
|
|
16
|
+
|
|
17
|
+
`PollResult` now carries `rejected`, set only for 401 and 403, which is the same
|
|
18
|
+
line `fetchModeState` already drew between an answer and a blip. A rejected poll
|
|
19
|
+
takes the error path, so the existing exponential backoff applies, and the
|
|
20
|
+
wrapper prints once that remote stop and phone messages are not active. A 500 or
|
|
21
|
+
a dropped connection is still a blip and still retried at the normal cadence.
|
|
22
|
+
|
|
23
|
+
A rejected response is also no longer trusted for its contents: neither the
|
|
24
|
+
command nor the mode state it carries is applied.
|
|
25
|
+
|
|
3
26
|
## 0.92.0
|
|
4
27
|
|
|
5
28
|
### A Claude Code upgrade registers the events it just gained
|
|
@@ -744,6 +744,8 @@ var FAST_DECAY_TICKS = 3;
|
|
|
744
744
|
var MAX_ERROR_BACKOFF_MS = 12e4;
|
|
745
745
|
var MAX_ERROR_STREAK = 6;
|
|
746
746
|
var REQUEST_TIMEOUT_MS = 1e4;
|
|
747
|
+
var PollRejectedError = class extends Error {
|
|
748
|
+
};
|
|
747
749
|
var startCommandPoller = (opts) => {
|
|
748
750
|
const drain = opts.drain ?? drainPendingCommand;
|
|
749
751
|
const slow = opts.slowPollMs ?? SLOW_POLL_MS;
|
|
@@ -754,6 +756,16 @@ var startCommandPoller = (opts) => {
|
|
|
754
756
|
let inflight;
|
|
755
757
|
let idleTicks = 0;
|
|
756
758
|
let errorStreak = 0;
|
|
759
|
+
let authRejectionReported = false;
|
|
760
|
+
const reportAuthRejection = () => {
|
|
761
|
+
if (authRejectionReported) return;
|
|
762
|
+
authRejectionReported = true;
|
|
763
|
+
try {
|
|
764
|
+
opts.onAuthRejected?.();
|
|
765
|
+
} catch {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
};
|
|
757
769
|
const jitter = (ms) => {
|
|
758
770
|
const r = opts.jitter ? opts.jitter() : Math.random();
|
|
759
771
|
return Math.max(1, Math.round(ms * (0.85 + r * 0.3)));
|
|
@@ -789,6 +801,10 @@ var startCommandPoller = (opts) => {
|
|
|
789
801
|
let command;
|
|
790
802
|
if (opts.poll) {
|
|
791
803
|
const result = await opts.poll(opts.apiKey, opts.getSessionId?.(), wantCommands, controller.signal);
|
|
804
|
+
if (result.rejected) {
|
|
805
|
+
reportAuthRejection();
|
|
806
|
+
throw new PollRejectedError();
|
|
807
|
+
}
|
|
792
808
|
command = result.command;
|
|
793
809
|
if (result.mode && opts.onModeState) {
|
|
794
810
|
try {
|
|
@@ -845,6 +861,7 @@ var startCommandPoller = (opts) => {
|
|
|
845
861
|
|
|
846
862
|
// src/wrapper/pollClient.ts
|
|
847
863
|
var APPROVAL_MODES = /* @__PURE__ */ new Set(["push_only", "terminal_only", "push_first", "notify_only"]);
|
|
864
|
+
var isRejection = (status) => status === 401 || status === 403;
|
|
848
865
|
var pollAgent = async (apiKey, sessionId, wantCommand, signal, baseUrl = getBaseUrl(), machineId) => {
|
|
849
866
|
try {
|
|
850
867
|
const sessionKey = sessionId || DEFAULT_SESSION;
|
|
@@ -894,7 +911,7 @@ var pollAgent = async (apiKey, sessionId, wantCommand, signal, baseUrl = getBase
|
|
|
894
911
|
}),
|
|
895
912
|
signal
|
|
896
913
|
});
|
|
897
|
-
if (!response.ok) return { command: null, mode: null };
|
|
914
|
+
if (!response.ok) return { command: null, mode: null, rejected: isRejection(response.status) };
|
|
898
915
|
const data = await response.json();
|
|
899
916
|
const claimedCommand = (id, text) => ({
|
|
900
917
|
id,
|
|
@@ -923,9 +940,9 @@ var pollAgent = async (apiKey, sessionId, wantCommand, signal, baseUrl = getBase
|
|
|
923
940
|
policyVersion: typeof data.policyVersion === "string" && data.policyVersion.length > 0 ? data.policyVersion : null,
|
|
924
941
|
relayUrl: typeof data.relayUrl === "string" && data.relayUrl.length > 0 ? data.relayUrl : null
|
|
925
942
|
};
|
|
926
|
-
return { command, mode };
|
|
943
|
+
return { command, mode, rejected: false };
|
|
927
944
|
} catch {
|
|
928
|
-
return { command: null, mode: null };
|
|
945
|
+
return { command: null, mode: null, rejected: false };
|
|
929
946
|
}
|
|
930
947
|
};
|
|
931
948
|
|
|
@@ -1734,6 +1751,11 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1734
1751
|
// Relay-primary: idle the safety-net poll at 60s (see RELAY_FALLBACK_POLL_MS).
|
|
1735
1752
|
// No relay advertised -> the poller IS the command path, so keep the default.
|
|
1736
1753
|
slowPollMs: relayAdvertised ? RELAY_FALLBACK_POLL_MS : void 0,
|
|
1754
|
+
onAuthRejected: () => {
|
|
1755
|
+
process.stderr.write(
|
|
1756
|
+
"[pushary] this key was rejected \u2014 remote stop and phone messages are NOT active; run `pushary login` to reconnect\n"
|
|
1757
|
+
);
|
|
1758
|
+
},
|
|
1737
1759
|
onModeState: (state) => {
|
|
1738
1760
|
if (state.kill && !killed) {
|
|
1739
1761
|
killed = true;
|