@pushary/agent-hooks 0.89.10 → 0.89.11
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 +31 -0
- package/dist/bin/pushary-claude.js +22 -5
- package/dist/bin/pushary-codex-bridge.js +7 -1
- package/dist/bin/pushary-codex-hook.js +2 -2
- package/dist/bin/pushary-codex.js +2 -2
- package/dist/bin/pushary-elicitation-hook.js +1 -1
- package/dist/bin/pushary-gemini-bridge.js +8 -1
- package/dist/bin/pushary-gemini-hook.js +2 -2
- package/dist/bin/pushary-hook.js +3 -3
- package/dist/bin/pushary-notification-hook.js +2 -2
- package/dist/bin/pushary-opencode-hook.js +2 -2
- package/dist/bin/pushary-permission-denied-hook.js +3 -3
- package/dist/bin/pushary-permission-hook.js +3 -3
- package/dist/bin/pushary-post-hook.js +2 -2
- package/dist/bin/pushary-prompt-hook.js +2 -2
- package/dist/bin/pushary-session-end-hook.js +2 -2
- package/dist/bin/pushary-session-start-hook.js +2 -2
- package/dist/bin/pushary-setup.js +2 -2
- package/dist/bin/pushary-stop-hook.js +2 -2
- package/dist/bin/pushary-stopfailure-hook.js +2 -2
- package/dist/{chunk-GTZLL7F4.js → chunk-FXIL7RCL.js} +1 -1
- package/dist/{chunk-GSSFSVAQ.js → chunk-J4K75V4D.js} +33 -16
- package/dist/{chunk-UXHMWF4H.js → chunk-JHJHCMAF.js} +1 -1
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.js +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.89.11
|
|
4
|
+
|
|
5
|
+
### Phone-spawned Codex and Gemini sessions record their conversation again
|
|
6
|
+
|
|
7
|
+
Both bridges relay their turns by default and stop only when told to. The
|
|
8
|
+
launchers told them to stop on every run: the value they passed was an equality
|
|
9
|
+
test against an environment variable nobody sets, which is false whenever it is
|
|
10
|
+
absent and never the "unset" the bridge was looking for. The relay was therefore
|
|
11
|
+
never built, and a session started from the phone had nothing to show but its
|
|
12
|
+
task title. The opt-out is now passed only when it is asked for.
|
|
13
|
+
|
|
14
|
+
### An agent standing by stops reading as working
|
|
15
|
+
|
|
16
|
+
`pushary claude` and the Gemini bridge reported that a session had started, that
|
|
17
|
+
it was still alive, and that it had ended, with nothing in between. Their
|
|
18
|
+
heartbeat kept resetting the clock that would otherwise have aged the session out
|
|
19
|
+
of "active", so the phone showed a working agent for one that had been waiting at
|
|
20
|
+
its prompt since its last reply. That is exactly when someone is looking at the
|
|
21
|
+
screen deciding whether to send it something. Both now report the turn boundary
|
|
22
|
+
they already detect, as the Codex bridge always has.
|
|
23
|
+
|
|
24
|
+
### Taking a session over from your phone says so, and is ready when you ask
|
|
25
|
+
|
|
26
|
+
An instruction from the phone hands the terminal to Pushary so it can drive an
|
|
27
|
+
agent that would otherwise sit idle. That has not changed. The handover is now
|
|
28
|
+
announced before the session is signalled, instead of the terminal appearing to
|
|
29
|
+
lose its agent for no visible reason. The Agent SDK is resolved when the session
|
|
30
|
+
starts rather than during the handover, so the wait is gone, and a machine that
|
|
31
|
+
cannot reach npm reports the instruction as undelivered instead of accepting it
|
|
32
|
+
and then dropping it. An instruction that is dropped now says it was.
|
|
33
|
+
|
|
3
34
|
## 0.89.10
|
|
4
35
|
|
|
5
36
|
### Phone control delivery is crash-safe
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
getPolicy,
|
|
28
28
|
repoKeyFor,
|
|
29
29
|
reportEvent
|
|
30
|
-
} from "../chunk-
|
|
30
|
+
} from "../chunk-FXIL7RCL.js";
|
|
31
31
|
import {
|
|
32
32
|
DEFAULT_SESSION,
|
|
33
33
|
askUser,
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
removePendingCommand,
|
|
40
40
|
savePendingCommand,
|
|
41
41
|
waitForAnswer
|
|
42
|
-
} from "../chunk-
|
|
42
|
+
} from "../chunk-JHJHCMAF.js";
|
|
43
43
|
import {
|
|
44
44
|
deriveToolTarget,
|
|
45
45
|
describeToolCall,
|
|
@@ -342,9 +342,13 @@ var BoundedInputQueue = class {
|
|
|
342
342
|
}
|
|
343
343
|
// Drop every buffered item without closing the queue. Used when phone control
|
|
344
344
|
// turns out to be unavailable (offline SDK setup) so a pending instruction does
|
|
345
|
-
// not make the local leg switch again into a mode that cannot run.
|
|
345
|
+
// not make the local leg switch again into a mode that cannot run. Returns how
|
|
346
|
+
// many were dropped, because these are somebody's words and the caller has to
|
|
347
|
+
// be able to say they are gone.
|
|
346
348
|
clear() {
|
|
349
|
+
const dropped = this.buffer.length;
|
|
347
350
|
this.buffer.length = 0;
|
|
351
|
+
return dropped;
|
|
348
352
|
}
|
|
349
353
|
get isClosed() {
|
|
350
354
|
return this.closed;
|
|
@@ -1128,7 +1132,12 @@ var runLocalLeg = (session, deps = {}) => {
|
|
|
1128
1132
|
const control = {
|
|
1129
1133
|
onPhoneCommand: () => {
|
|
1130
1134
|
if (!exitReason) exitReason = "switch";
|
|
1131
|
-
if (!legAbort.signal.aborted)
|
|
1135
|
+
if (!legAbort.signal.aborted) {
|
|
1136
|
+
process.stderr.write(
|
|
1137
|
+
"\n[pushary] instruction from your phone \u2014 taking this session over to run it (Ctrl-] hands the terminal back)\n"
|
|
1138
|
+
);
|
|
1139
|
+
legAbort.abort();
|
|
1140
|
+
}
|
|
1132
1141
|
},
|
|
1133
1142
|
stop: (reason) => {
|
|
1134
1143
|
if (!exitReason) exitReason = { type: "exit", code: reason === "signal" ? 130 : 0 };
|
|
@@ -1482,6 +1491,7 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1482
1491
|
} else if (message.type === "result") {
|
|
1483
1492
|
if (typeof message.total_cost_usd === "number") totalCostUsd = message.total_cost_usd;
|
|
1484
1493
|
process.stderr.write("[pushary] turn complete \u2014 standing by for phone commands\n");
|
|
1494
|
+
void announcePresence("stop", "Turn complete");
|
|
1485
1495
|
}
|
|
1486
1496
|
};
|
|
1487
1497
|
const poller = startCommandPoller({
|
|
@@ -1546,6 +1556,7 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1546
1556
|
void announcePresence("session_start", "Session ready \u2014 reachable from your phone");
|
|
1547
1557
|
ensurePresenceHeartbeat();
|
|
1548
1558
|
ensureTranscriptSync();
|
|
1559
|
+
void ensureSdk();
|
|
1549
1560
|
}
|
|
1550
1561
|
if (startingMode === "remote" && initialPrompt) input.push(userMessage(initialPrompt));
|
|
1551
1562
|
const exitCode = await driveModeLoop({
|
|
@@ -1555,13 +1566,19 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1555
1566
|
const ready = await ensureSdk();
|
|
1556
1567
|
if (!ready) {
|
|
1557
1568
|
remoteAvailable = false;
|
|
1558
|
-
input.clear();
|
|
1569
|
+
const dropped = input.clear();
|
|
1559
1570
|
if (!noticedUnavailable) {
|
|
1560
1571
|
noticedUnavailable = true;
|
|
1561
1572
|
process.stderr.write(
|
|
1562
1573
|
"[pushary] could not start phone control (offline?); staying in the terminal. Relaunch when online to enable.\n"
|
|
1563
1574
|
);
|
|
1564
1575
|
}
|
|
1576
|
+
if (dropped > 0) {
|
|
1577
|
+
process.stderr.write(
|
|
1578
|
+
`[pushary] ${dropped} instruction(s) from your phone could not be delivered and were dropped.
|
|
1579
|
+
`
|
|
1580
|
+
);
|
|
1581
|
+
}
|
|
1565
1582
|
return "switch";
|
|
1566
1583
|
}
|
|
1567
1584
|
return runRemoteLeg(session, ready);
|
|
@@ -371,7 +371,13 @@ var outcome = await withSpawnProcessOwnership(spawnId, () => runCodexBridge({
|
|
|
371
371
|
args: ["app-server", "--stdio"]
|
|
372
372
|
},
|
|
373
373
|
signal: abort.signal,
|
|
374
|
-
transcripts
|
|
374
|
+
// The bridge's own default is ON (`transcripts?: boolean`, and it opts out only
|
|
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 } : {}
|
|
375
381
|
}));
|
|
376
382
|
for (const signal of signals) process.off(signal, stop);
|
|
377
383
|
process.exit(outcome === "stopped" ? 0 : 1);
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
toCodexWire,
|
|
35
35
|
toPolicyLookup,
|
|
36
36
|
toPolicyLookups
|
|
37
|
-
} from "../chunk-
|
|
37
|
+
} from "../chunk-FXIL7RCL.js";
|
|
38
38
|
import {
|
|
39
39
|
DEFAULT_SESSION,
|
|
40
40
|
askUser,
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
pollForAnswer,
|
|
43
43
|
savePendingQuestion,
|
|
44
44
|
sendNotification
|
|
45
|
-
} from "../chunk-
|
|
45
|
+
} from "../chunk-JHJHCMAF.js";
|
|
46
46
|
import {
|
|
47
47
|
deriveActionBody,
|
|
48
48
|
deriveBlocker,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
reportEvent
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-FXIL7RCL.js";
|
|
5
5
|
import {
|
|
6
6
|
askUser,
|
|
7
7
|
waitForAnswer
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-JHJHCMAF.js";
|
|
9
9
|
import "../chunk-TG3T3M4K.js";
|
|
10
10
|
import {
|
|
11
11
|
getMachineId
|
|
@@ -228,6 +228,7 @@ var runGeminiBridge = async (options) => {
|
|
|
228
228
|
try {
|
|
229
229
|
const outcome2 = await turn(text, commandId);
|
|
230
230
|
if (outcome2 === "aborted") break;
|
|
231
|
+
void report("stop", "Turn completed").catch(() => null);
|
|
231
232
|
pendingAck = {
|
|
232
233
|
commandId,
|
|
233
234
|
sessionId,
|
|
@@ -304,7 +305,13 @@ var outcome = await withSpawnProcessOwnership(spawnId, () => runGeminiBridge({
|
|
|
304
305
|
resumeSessionId: process.env.PUSHARY_BRIDGE_RESUME_SESSION_ID?.trim() || void 0,
|
|
305
306
|
command: { command: process.env.PUSHARY_GEMINI_COMMAND?.trim() || resolveBinary("gemini") || "gemini" },
|
|
306
307
|
signal: abort.signal,
|
|
307
|
-
transcripts
|
|
308
|
+
// The bridge's own default is ON (`transcripts?: boolean`, and it opts out only
|
|
309
|
+
// on an explicit `false`), but `=== '1'` can never produce `undefined`, so an
|
|
310
|
+
// unset env var forced the opt-out on every spawn and the live relay was never
|
|
311
|
+
// built. Pass the opt-out only when the user asks for one. The relay stays a
|
|
312
|
+
// hard no-op until this account's phone has registered a public key, and what
|
|
313
|
+
// it sends is encrypted to that key on this machine.
|
|
314
|
+
...process.env.PUSHARY_TRANSCRIPTS === "0" ? { transcripts: false } : {}
|
|
308
315
|
}));
|
|
309
316
|
for (const signal of signals) process.off(signal, stop);
|
|
310
317
|
process.exit(outcome === "stopped" ? 0 : 1);
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
readLastUserPrompt,
|
|
22
22
|
repoKeyFor,
|
|
23
23
|
reportEvent
|
|
24
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-FXIL7RCL.js";
|
|
25
25
|
import {
|
|
26
26
|
DEFAULT_SESSION,
|
|
27
27
|
askUser,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
savePendingQuestion,
|
|
30
30
|
sendNotification,
|
|
31
31
|
waitForAnswer
|
|
32
|
-
} from "../chunk-
|
|
32
|
+
} from "../chunk-JHJHCMAF.js";
|
|
33
33
|
import {
|
|
34
34
|
deriveActionBody,
|
|
35
35
|
deriveBlocker,
|
package/dist/bin/pushary-hook.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handlePreToolUse
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-J4K75V4D.js";
|
|
5
5
|
import "../chunk-6EKQZA6R.js";
|
|
6
6
|
import "../chunk-NCVIWGVA.js";
|
|
7
7
|
import "../chunk-3HFK3UXM.js";
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
readHookInput
|
|
10
10
|
} from "../chunk-6CUUA7HO.js";
|
|
11
11
|
import "../chunk-YHG74UFF.js";
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
12
|
+
import "../chunk-FXIL7RCL.js";
|
|
13
|
+
import "../chunk-JHJHCMAF.js";
|
|
14
14
|
import "../chunk-TG3T3M4K.js";
|
|
15
15
|
import "../chunk-DKWM5T3P.js";
|
|
16
16
|
import "../chunk-QA72MKIT.js";
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
} from "../chunk-6CUUA7HO.js";
|
|
5
5
|
import {
|
|
6
6
|
handleNotification
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-FXIL7RCL.js";
|
|
8
|
+
import "../chunk-JHJHCMAF.js";
|
|
9
9
|
import "../chunk-TG3T3M4K.js";
|
|
10
10
|
import "../chunk-DKWM5T3P.js";
|
|
11
11
|
import "../chunk-QA72MKIT.js";
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
policyRequestFor,
|
|
20
20
|
readLastPrompt,
|
|
21
21
|
repoKeyFor
|
|
22
|
-
} from "../chunk-
|
|
22
|
+
} from "../chunk-FXIL7RCL.js";
|
|
23
23
|
import {
|
|
24
24
|
DEFAULT_SESSION,
|
|
25
25
|
askUser,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
savePendingQuestion,
|
|
28
28
|
sendNotification,
|
|
29
29
|
waitForAnswer
|
|
30
|
-
} from "../chunk-
|
|
30
|
+
} from "../chunk-JHJHCMAF.js";
|
|
31
31
|
import {
|
|
32
32
|
HOOK_FALLBACK_MAX,
|
|
33
33
|
OPENCODE_TOOL_NAMES,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handlePermissionDenied
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-J4K75V4D.js";
|
|
5
5
|
import "../chunk-6EKQZA6R.js";
|
|
6
6
|
import "../chunk-NCVIWGVA.js";
|
|
7
7
|
import "../chunk-3HFK3UXM.js";
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
readHookInput
|
|
10
10
|
} from "../chunk-6CUUA7HO.js";
|
|
11
11
|
import "../chunk-YHG74UFF.js";
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
12
|
+
import "../chunk-FXIL7RCL.js";
|
|
13
|
+
import "../chunk-JHJHCMAF.js";
|
|
14
14
|
import "../chunk-TG3T3M4K.js";
|
|
15
15
|
import "../chunk-DKWM5T3P.js";
|
|
16
16
|
import "../chunk-QA72MKIT.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handlePermissionRequest
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-J4K75V4D.js";
|
|
5
5
|
import "../chunk-6EKQZA6R.js";
|
|
6
6
|
import "../chunk-NCVIWGVA.js";
|
|
7
7
|
import "../chunk-3HFK3UXM.js";
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
readHookInput
|
|
10
10
|
} from "../chunk-6CUUA7HO.js";
|
|
11
11
|
import "../chunk-YHG74UFF.js";
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
12
|
+
import "../chunk-FXIL7RCL.js";
|
|
13
|
+
import "../chunk-JHJHCMAF.js";
|
|
14
14
|
import "../chunk-TG3T3M4K.js";
|
|
15
15
|
import "../chunk-DKWM5T3P.js";
|
|
16
16
|
import "../chunk-QA72MKIT.js";
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
} from "../chunk-6CUUA7HO.js";
|
|
5
5
|
import {
|
|
6
6
|
handlePostToolUse
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-FXIL7RCL.js";
|
|
8
|
+
import "../chunk-JHJHCMAF.js";
|
|
9
9
|
import "../chunk-TG3T3M4K.js";
|
|
10
10
|
import "../chunk-DKWM5T3P.js";
|
|
11
11
|
import "../chunk-QA72MKIT.js";
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
} from "../chunk-6CUUA7HO.js";
|
|
5
5
|
import {
|
|
6
6
|
handleUserPrompt
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-FXIL7RCL.js";
|
|
8
|
+
import "../chunk-JHJHCMAF.js";
|
|
9
9
|
import "../chunk-TG3T3M4K.js";
|
|
10
10
|
import "../chunk-DKWM5T3P.js";
|
|
11
11
|
import "../chunk-QA72MKIT.js";
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
} from "../chunk-6CUUA7HO.js";
|
|
5
5
|
import {
|
|
6
6
|
handleSessionEnd
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-FXIL7RCL.js";
|
|
8
|
+
import "../chunk-JHJHCMAF.js";
|
|
9
9
|
import "../chunk-TG3T3M4K.js";
|
|
10
10
|
import "../chunk-DKWM5T3P.js";
|
|
11
11
|
import "../chunk-QA72MKIT.js";
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
} from "../chunk-6CUUA7HO.js";
|
|
5
5
|
import {
|
|
6
6
|
handleSessionStart
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-FXIL7RCL.js";
|
|
8
|
+
import "../chunk-JHJHCMAF.js";
|
|
9
9
|
import "../chunk-TG3T3M4K.js";
|
|
10
10
|
import "../chunk-DKWM5T3P.js";
|
|
11
11
|
import "../chunk-QA72MKIT.js";
|
|
@@ -86,8 +86,8 @@ import {
|
|
|
86
86
|
} from "../chunk-X4ZUUFKV.js";
|
|
87
87
|
import {
|
|
88
88
|
reportEvent
|
|
89
|
-
} from "../chunk-
|
|
90
|
-
import "../chunk-
|
|
89
|
+
} from "../chunk-FXIL7RCL.js";
|
|
90
|
+
import "../chunk-JHJHCMAF.js";
|
|
91
91
|
import "../chunk-TG3T3M4K.js";
|
|
92
92
|
import "../chunk-DKWM5T3P.js";
|
|
93
93
|
import {
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
} from "../chunk-6CUUA7HO.js";
|
|
5
5
|
import {
|
|
6
6
|
handleStop
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-FXIL7RCL.js";
|
|
8
|
+
import "../chunk-JHJHCMAF.js";
|
|
9
9
|
import "../chunk-TG3T3M4K.js";
|
|
10
10
|
import "../chunk-DKWM5T3P.js";
|
|
11
11
|
import "../chunk-QA72MKIT.js";
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
} from "../chunk-6CUUA7HO.js";
|
|
5
5
|
import {
|
|
6
6
|
handleStopFailure
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-FXIL7RCL.js";
|
|
8
|
+
import "../chunk-JHJHCMAF.js";
|
|
9
9
|
import "../chunk-TG3T3M4K.js";
|
|
10
10
|
import "../chunk-DKWM5T3P.js";
|
|
11
11
|
import "../chunk-QA72MKIT.js";
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
readLastUserPrompt,
|
|
21
21
|
repoKeyFor,
|
|
22
22
|
throttlePass
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-FXIL7RCL.js";
|
|
24
24
|
import {
|
|
25
25
|
DEFAULT_SESSION,
|
|
26
26
|
askUser,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
pollForAnswer,
|
|
29
29
|
savePendingQuestion,
|
|
30
30
|
sendNotification
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-JHJHCMAF.js";
|
|
32
32
|
import {
|
|
33
33
|
deriveAction,
|
|
34
34
|
deriveActionBody,
|
|
@@ -87,7 +87,16 @@ var allow = () => claudePreToolUseOutput("allow");
|
|
|
87
87
|
var deny = (reason) => claudePreToolUseOutput("deny", reason);
|
|
88
88
|
var allowWithInput = (updatedInput) => claudePreToolUseOutput("allow", void 0, updatedInput);
|
|
89
89
|
var ask = (reason) => claudePreToolUseOutput("ask", reason);
|
|
90
|
+
var storedWaitDeadline = (result, requestedDeadline) => {
|
|
91
|
+
const stored = result.waitEndsAt ? Date.parse(result.waitEndsAt) : Number.NaN;
|
|
92
|
+
return Number.isFinite(stored) ? Math.min(stored, requestedDeadline) : requestedDeadline;
|
|
93
|
+
};
|
|
94
|
+
var returnedAnswer = (result) => result.answered === true ? { answered: true, value: result.value, note: result.note } : null;
|
|
90
95
|
var handlePushOnly = async (apiKey, description, projectName, timeoutSeconds, timeoutAction, sessionId, machineId, toolName, toolTarget, decision, signals) => {
|
|
96
|
+
const effectiveWait = effectiveWaitSeconds(timeoutAction, timeoutSeconds, "claude");
|
|
97
|
+
const now = Date.now();
|
|
98
|
+
const requestedDeadline = hookWaitDeadline(START_MS, effectiveWait, "claude", now);
|
|
99
|
+
const clampCut = hookWaitClamped(START_MS, effectiveWait, "claude", now);
|
|
91
100
|
let result;
|
|
92
101
|
try {
|
|
93
102
|
result = await askUser(apiKey, {
|
|
@@ -99,6 +108,7 @@ var handlePushOnly = async (apiKey, description, projectName, timeoutSeconds, ti
|
|
|
99
108
|
machineId,
|
|
100
109
|
toolName,
|
|
101
110
|
toolTarget,
|
|
111
|
+
waitEndsAt: timeoutAction !== "approve" && timeoutAction !== "deny" || clampCut ? new Date(requestedDeadline).toISOString() : void 0,
|
|
102
112
|
...decision
|
|
103
113
|
});
|
|
104
114
|
} catch {
|
|
@@ -117,6 +127,8 @@ var handlePushOnly = async (apiKey, description, projectName, timeoutSeconds, ti
|
|
|
117
127
|
return ask(result.suppressed ? "You are at the keyboard, approve here." : "Delivery mode is Terminal, approve here.");
|
|
118
128
|
}
|
|
119
129
|
if (result.noDevices) {
|
|
130
|
+
await cancelQuestion(apiKey, result.correlationId).catch(() => {
|
|
131
|
+
});
|
|
120
132
|
switch (timeoutAction) {
|
|
121
133
|
case "approve":
|
|
122
134
|
return allow();
|
|
@@ -126,12 +138,9 @@ var handlePushOnly = async (apiKey, description, projectName, timeoutSeconds, ti
|
|
|
126
138
|
return void 0;
|
|
127
139
|
}
|
|
128
140
|
}
|
|
129
|
-
const
|
|
130
|
-
const now = Date.now();
|
|
131
|
-
const deadline = hookWaitDeadline(START_MS, effectiveWait, "claude", now);
|
|
132
|
-
const clampCut = hookWaitClamped(START_MS, effectiveWait, "claude", now);
|
|
141
|
+
const deadline = storedWaitDeadline(result, requestedDeadline);
|
|
133
142
|
announceWait(effectiveWait, result.answerUrl, sessionId);
|
|
134
|
-
const answer = await pollForAnswer(apiKey, result.correlationId, deadline);
|
|
143
|
+
const answer = returnedAnswer(result) ?? await pollForAnswer(apiKey, result.correlationId, deadline);
|
|
135
144
|
if (answer.answered) {
|
|
136
145
|
if (isDeferAnswer(answer.value)) return ask("Handling on your machine");
|
|
137
146
|
signals.humanDecision = true;
|
|
@@ -147,6 +156,7 @@ var handlePushOnly = async (apiKey, description, projectName, timeoutSeconds, ti
|
|
|
147
156
|
case "deny":
|
|
148
157
|
return deny("No response within timeout");
|
|
149
158
|
default:
|
|
159
|
+
savePendingQuestion(sessionId || DEFAULT_SESSION, result.correlationId);
|
|
150
160
|
return ask("No push response, asking in terminal");
|
|
151
161
|
}
|
|
152
162
|
};
|
|
@@ -154,6 +164,7 @@ var handleTerminalOnly = () => {
|
|
|
154
164
|
return ask();
|
|
155
165
|
};
|
|
156
166
|
var handlePushFirst = async (apiKey, description, projectName, pushFirstSeconds, sessionId, machineId, toolName, toolTarget, decision, signals) => {
|
|
167
|
+
const requestedDeadline = hookWaitDeadline(START_MS, pushFirstSeconds, "claude", Date.now());
|
|
157
168
|
let result;
|
|
158
169
|
try {
|
|
159
170
|
result = await askUser(apiKey, {
|
|
@@ -165,6 +176,7 @@ var handlePushFirst = async (apiKey, description, projectName, pushFirstSeconds,
|
|
|
165
176
|
machineId,
|
|
166
177
|
toolName,
|
|
167
178
|
toolTarget,
|
|
179
|
+
waitEndsAt: new Date(requestedDeadline).toISOString(),
|
|
168
180
|
...decision
|
|
169
181
|
});
|
|
170
182
|
} catch {
|
|
@@ -176,11 +188,13 @@ var handlePushFirst = async (apiKey, description, projectName, pushFirstSeconds,
|
|
|
176
188
|
return ask("You are at the keyboard, approve here.");
|
|
177
189
|
}
|
|
178
190
|
if (result.noDevices) {
|
|
191
|
+
await cancelQuestion(apiKey, result.correlationId).catch(() => {
|
|
192
|
+
});
|
|
179
193
|
return void 0;
|
|
180
194
|
}
|
|
181
195
|
announceWait(pushFirstSeconds, result.answerUrl, sessionId);
|
|
182
|
-
const deadline =
|
|
183
|
-
const answer = await pollForAnswer(apiKey, result.correlationId, deadline, 1500);
|
|
196
|
+
const deadline = storedWaitDeadline(result, requestedDeadline);
|
|
197
|
+
const answer = returnedAnswer(result) ?? await pollForAnswer(apiKey, result.correlationId, deadline, 1500);
|
|
184
198
|
if (answer.answered) {
|
|
185
199
|
if (isDeferAnswer(answer.value)) return ask("Handling on your machine");
|
|
186
200
|
signals.humanDecision = true;
|
|
@@ -330,7 +344,8 @@ var askAsOneCard = async (apiKey, input, parsed, projectName, deadline) => {
|
|
|
330
344
|
sessionId: input.session_id,
|
|
331
345
|
machineId: getMachineId(),
|
|
332
346
|
toolName: "AskUserQuestion",
|
|
333
|
-
toolUseId: input.tool_use_id
|
|
347
|
+
toolUseId: input.tool_use_id,
|
|
348
|
+
waitEndsAt: new Date(deadline).toISOString()
|
|
334
349
|
});
|
|
335
350
|
} catch {
|
|
336
351
|
return void 0;
|
|
@@ -340,7 +355,7 @@ var askAsOneCard = async (apiKey, input, parsed, projectName, deadline) => {
|
|
|
340
355
|
});
|
|
341
356
|
return void 0;
|
|
342
357
|
}
|
|
343
|
-
const answer = await pollForAnswer(apiKey, result.correlationId, deadline);
|
|
358
|
+
const answer = returnedAnswer(result) ?? await pollForAnswer(apiKey, result.correlationId, storedWaitDeadline(result, deadline));
|
|
344
359
|
const values = answer.answered && answer.value ? parseAgentQuestionAnswers(parsed, answer.value) : null;
|
|
345
360
|
if (!values || isDeferAnswer(answer.value)) {
|
|
346
361
|
savePendingQuestion(input.session_id || DEFAULT_SESSION, result.correlationId);
|
|
@@ -366,7 +381,8 @@ var askQuestionByQuestion = async (apiKey, input, parsed, projectName, deadline)
|
|
|
366
381
|
// One AskUserQuestion call raises several questions, and their payload
|
|
367
382
|
// fingerprints are identical (same tool, no target, no body). Without the
|
|
368
383
|
// index they would all collapse onto the first decision.
|
|
369
|
-
toolUseId: input.tool_use_id ? `${input.tool_use_id}#q${index}` : void 0
|
|
384
|
+
toolUseId: input.tool_use_id ? `${input.tool_use_id}#q${index}` : void 0,
|
|
385
|
+
waitEndsAt: new Date(deadline).toISOString()
|
|
370
386
|
});
|
|
371
387
|
} catch {
|
|
372
388
|
return void 0;
|
|
@@ -376,7 +392,7 @@ var askQuestionByQuestion = async (apiKey, input, parsed, projectName, deadline)
|
|
|
376
392
|
});
|
|
377
393
|
return void 0;
|
|
378
394
|
}
|
|
379
|
-
const answer = await pollForAnswer(apiKey, result.correlationId, deadline);
|
|
395
|
+
const answer = returnedAnswer(result) ?? await pollForAnswer(apiKey, result.correlationId, storedWaitDeadline(result, deadline));
|
|
380
396
|
const legacyValue = answer.answered ? answer.value?.trim() : void 0;
|
|
381
397
|
const values = legacyValue ? parseAgentQuestionAnswers([question], legacyValue) ?? parseAgentQuestionAnswers([question], JSON.stringify({
|
|
382
398
|
[question.question]: question.multiSelect ? JSON.stringify([legacyValue]) : legacyValue
|
|
@@ -404,6 +420,7 @@ var PLAN_KEEP_PLANNING = "Keep planning";
|
|
|
404
420
|
var handleExitPlanMode = async (apiKey, input) => {
|
|
405
421
|
const toolInput = input.tool_input ?? {};
|
|
406
422
|
const projectName = basename(input.cwd ?? process.cwd());
|
|
423
|
+
const deadline = hookWaitDeadline(START_MS, effectiveWaitSeconds("wait", 0, "claude"), "claude", Date.now());
|
|
407
424
|
let result;
|
|
408
425
|
try {
|
|
409
426
|
result = await askUser(apiKey, {
|
|
@@ -420,7 +437,8 @@ var handleExitPlanMode = async (apiKey, input) => {
|
|
|
420
437
|
// so approving from a lock screen is a real decision and not a blind yes.
|
|
421
438
|
actionBody: deriveActionBody("ExitPlanMode", toolInput),
|
|
422
439
|
intent: readLastPrompt(input.session_id ?? DEFAULT_SESSION) ?? (input.transcript_path ? readLastUserPrompt(input.transcript_path) : void 0),
|
|
423
|
-
blocker: "Waiting for you to approve the plan"
|
|
440
|
+
blocker: "Waiting for you to approve the plan",
|
|
441
|
+
waitEndsAt: new Date(deadline).toISOString()
|
|
424
442
|
});
|
|
425
443
|
} catch {
|
|
426
444
|
return void 0;
|
|
@@ -430,8 +448,7 @@ var handleExitPlanMode = async (apiKey, input) => {
|
|
|
430
448
|
});
|
|
431
449
|
return void 0;
|
|
432
450
|
}
|
|
433
|
-
const
|
|
434
|
-
const answer = await pollForAnswer(apiKey, result.correlationId, deadline);
|
|
451
|
+
const answer = returnedAnswer(result) ?? await pollForAnswer(apiKey, result.correlationId, storedWaitDeadline(result, deadline));
|
|
435
452
|
const value = answer.answered ? (answer.value ?? "").trim() : "";
|
|
436
453
|
if (!value || isDeferAnswer(answer.value)) {
|
|
437
454
|
savePendingQuestion(input.session_id || DEFAULT_SESSION, result.correlationId);
|
|
@@ -17,7 +17,7 @@ var isPolicyConfig = (data) => {
|
|
|
17
17
|
var isAskUserResponse = (data) => {
|
|
18
18
|
if (!data || typeof data !== "object") return false;
|
|
19
19
|
const d = data;
|
|
20
|
-
return typeof d.correlationId === "string" && typeof d.status === "string";
|
|
20
|
+
return typeof d.correlationId === "string" && typeof d.status === "string" && (d.answered === void 0 || typeof d.answered === "boolean") && (d.value === void 0 || typeof d.value === "string") && (d.note === void 0 || typeof d.note === "string") && (d.waitEndsAt === void 0 || typeof d.waitEndsAt === "string");
|
|
21
21
|
};
|
|
22
22
|
var isWaitForAnswerResponse = (data) => {
|
|
23
23
|
if (!data || typeof data !== "object") return false;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -121,6 +121,7 @@ interface AskUserParams {
|
|
|
121
121
|
actionBody?: string;
|
|
122
122
|
scopePath?: string;
|
|
123
123
|
toolUseId?: string;
|
|
124
|
+
waitEndsAt?: string;
|
|
124
125
|
requestId?: string;
|
|
125
126
|
}
|
|
126
127
|
interface AskUserResponse {
|
|
@@ -132,6 +133,10 @@ interface AskUserResponse {
|
|
|
132
133
|
};
|
|
133
134
|
suppressed?: boolean;
|
|
134
135
|
noDevices?: boolean;
|
|
136
|
+
answered?: boolean;
|
|
137
|
+
value?: string;
|
|
138
|
+
note?: string;
|
|
139
|
+
waitEndsAt?: string;
|
|
135
140
|
answerUrl?: string;
|
|
136
141
|
}
|
|
137
142
|
interface AnswerResult {
|
package/dist/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handlePreToolUse
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-J4K75V4D.js";
|
|
4
4
|
import "../chunk-6EKQZA6R.js";
|
|
5
5
|
import "../chunk-NCVIWGVA.js";
|
|
6
6
|
import "../chunk-3HFK3UXM.js";
|
|
@@ -13,12 +13,12 @@ import {
|
|
|
13
13
|
handlePostToolUse,
|
|
14
14
|
handleStop,
|
|
15
15
|
reportEvent
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-FXIL7RCL.js";
|
|
17
17
|
import {
|
|
18
18
|
askUser,
|
|
19
19
|
cancelQuestion,
|
|
20
20
|
waitForAnswer
|
|
21
|
-
} from "../chunk-
|
|
21
|
+
} from "../chunk-JHJHCMAF.js";
|
|
22
22
|
import "../chunk-TG3T3M4K.js";
|
|
23
23
|
import "../chunk-DKWM5T3P.js";
|
|
24
24
|
import "../chunk-QA72MKIT.js";
|