@pushary/agent-hooks 1.9.71 → 1.9.73
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 +12 -0
- package/dist/{api-HEIRLMTZ.js → api-JVWXPKEW.js} +10 -10
- package/dist/bin/pushary-bell-hook.js +25 -25
- package/dist/bin/pushary-bell.js +10 -10
- package/dist/bin/pushary-claude.js +202 -67
- package/dist/bin/pushary-clean.js +33 -33
- package/dist/bin/pushary-codex-bridge.js +23 -21
- package/dist/bin/pushary-codex-hook.js +30 -30
- package/dist/bin/pushary-codex-session.js +8 -8
- package/dist/bin/pushary-codex.js +13 -13
- package/dist/bin/pushary-connect.js +26 -26
- package/dist/bin/pushary-cowork.js +5 -5
- package/dist/bin/pushary-daemon.js +38 -38
- package/dist/bin/pushary-disconnect.js +25 -25
- package/dist/bin/pushary-doctor.js +41 -41
- package/dist/bin/pushary-elicitation-hook.js +25 -25
- package/dist/bin/pushary-gemini-bridge.js +45 -48
- package/dist/bin/pushary-gemini-hook.js +27 -27
- package/dist/bin/pushary-hook.js +29 -29
- package/dist/bin/pushary-login.js +20 -20
- package/dist/bin/pushary-logout.js +24 -24
- package/dist/bin/pushary-mcp.js +11 -11
- package/dist/bin/pushary-mode.js +15 -15
- package/dist/bin/pushary-notification-hook.js +24 -24
- package/dist/bin/pushary-opencode-hook.js +26 -26
- package/dist/bin/pushary-permission-denied-hook.js +29 -29
- package/dist/bin/pushary-permission-hook.js +29 -29
- package/dist/bin/pushary-post-hook.js +24 -24
- package/dist/bin/pushary-prompt-hook.js +24 -24
- package/dist/bin/pushary-session-end-hook.js +26 -26
- package/dist/bin/pushary-session-start-hook.js +34 -34
- package/dist/bin/pushary-setup.js +47 -46
- package/dist/bin/pushary-stats.js +5 -5
- package/dist/bin/pushary-status.js +31 -31
- package/dist/bin/pushary-stop-hook.js +24 -24
- package/dist/bin/pushary-stopfailure-hook.js +24 -24
- package/dist/bin/pushary-suggestions.js +15 -15
- package/dist/bin/pushary-transcript-register.js +16 -16
- package/dist/bin/pushary-transcripts.js +20 -19
- package/dist/bin/pushary-upgrade.js +39 -39
- package/dist/bin/pushary-wait.js +15 -15
- package/dist/bin/pushary.js +7 -7
- package/dist/{chunk-EVJRITSI.js → chunk-2HFC4W6J.js} +1 -1
- package/dist/{chunk-4QPF4BGP.js → chunk-2JFEMKDG.js} +6 -6
- package/dist/{chunk-KGZH5RTB.js → chunk-2NG3ANMT.js} +6 -6
- package/dist/{chunk-JMACQEPU.js → chunk-2QB7HJVJ.js} +2 -2
- package/dist/{chunk-XJMUEOXT.js → chunk-3JJI5O5N.js} +1 -1
- package/dist/{chunk-BZ7XGS5L.js → chunk-3QBKMSOZ.js} +1 -1
- package/dist/{chunk-AN26S5DC.js → chunk-3RAWW5DH.js} +6 -6
- package/dist/{chunk-J7BLYQ7Z.js → chunk-4LAD5A2Q.js} +4 -4
- package/dist/{chunk-VSQDVH43.js → chunk-4UIR25GA.js} +1 -1
- package/dist/{chunk-AUOVB62W.js → chunk-56GK65Z6.js} +3 -3
- package/dist/{chunk-AERRQEWZ.js → chunk-7FROPPIH.js} +2 -2
- package/dist/{chunk-GIE7PLZD.js → chunk-7M4AA7QF.js} +4 -4
- package/dist/{chunk-SWQTCKLM.js → chunk-7RX5TOU3.js} +6 -6
- package/dist/{chunk-SMIU5URV.js → chunk-7S46LCKD.js} +2 -2
- package/dist/{chunk-IYMYGKFB.js → chunk-AC5TVOAH.js} +10 -11
- package/dist/{chunk-5NQ3SMVP.js → chunk-AJWGZJFS.js} +122 -35
- package/dist/{chunk-JGEPODEP.js → chunk-AVHL2ZTS.js} +85 -3
- package/dist/{chunk-3CN2EFKK.js → chunk-AXZ67XVN.js} +1 -1
- package/dist/{chunk-MZ6GL46A.js → chunk-BLX6KRK5.js} +1 -1
- package/dist/{chunk-ZBPBX656.js → chunk-CGWUVEOB.js} +3 -3
- package/dist/{chunk-YG3NFC5N.js → chunk-CMYFV3VC.js} +5 -5
- package/dist/{chunk-C3YAMEO2.js → chunk-DT6VCMXS.js} +2 -2
- package/dist/{chunk-7OYWCOVC.js → chunk-EITOMPFB.js} +4 -4
- package/dist/{chunk-QWCOMSDH.js → chunk-EUEGCEA7.js} +3 -3
- package/dist/{chunk-5WHSFMV2.js → chunk-EUHTC7K5.js} +1 -1
- package/dist/{chunk-HR6M44CX.js → chunk-F3WI32HG.js} +7 -7
- package/dist/{chunk-6W2ASRZO.js → chunk-FAKEKFCI.js} +3 -3
- package/dist/{chunk-FTOKESSK.js → chunk-FB262EOM.js} +1 -1
- package/dist/{chunk-4XFFGFHN.js → chunk-FK3JSDH5.js} +13 -13
- package/dist/{chunk-3FY5ZPIZ.js → chunk-GBR6E7AY.js} +1 -1
- package/dist/{chunk-NHC5YUH6.js → chunk-IN3MPEFA.js} +5 -5
- package/dist/{chunk-LA3MMHLO.js → chunk-JC7XUZST.js} +6 -3
- package/dist/{chunk-2XD4TTUM.js → chunk-JNTYPMVU.js} +10 -10
- package/dist/{chunk-B3KPRSCM.js → chunk-JWBZUTYF.js} +5 -5
- package/dist/{chunk-LKAO35SY.js → chunk-JYOR57ZW.js} +3 -3
- package/dist/{chunk-MGF7D2ZL.js → chunk-KDQLKND5.js} +36 -35
- package/dist/{chunk-DOMDCMGC.js → chunk-KSLBS3II.js} +5 -5
- package/dist/chunk-L2FQBHIR.js +74 -0
- package/dist/{chunk-JEZGDP55.js → chunk-N4VRSFRZ.js} +5 -5
- package/dist/chunk-N5P2FLOJ.js +82 -0
- package/dist/{chunk-D536PHXF.js → chunk-NGNBX3YH.js} +4 -4
- package/dist/{chunk-EZHM6I2V.js → chunk-NJSW2REO.js} +4 -4
- package/dist/{chunk-XSUWXBHF.js → chunk-O4EAMVSC.js} +3 -3
- package/dist/{chunk-YRWGCYHH.js → chunk-OJ3ZD5VX.js} +1 -1
- package/dist/{chunk-25W6AD3W.js → chunk-PGJMSREY.js} +6 -6
- package/dist/{chunk-OJFOIKRM.js → chunk-PM2MHBMF.js} +3 -3
- package/dist/{chunk-ITKAMUHG.js → chunk-PNXNWZ5P.js} +3 -3
- package/dist/{chunk-AZ56FPRG.js → chunk-PPKIL4EL.js} +1 -1
- package/dist/{chunk-WOZLV3LN.js → chunk-QAWWTRDD.js} +4 -4
- package/dist/{chunk-NPO3ZTR4.js → chunk-QMPM3CAN.js} +1 -1
- package/dist/{chunk-X2KK42JA.js → chunk-R5PZPROX.js} +1 -1
- package/dist/{chunk-T7FPZN5V.js → chunk-RZVWEDIS.js} +3 -3
- package/dist/{chunk-TATE22GH.js → chunk-S63VIM7E.js} +1 -1
- package/dist/{chunk-ZZ7VB6QC.js → chunk-S7VMHSJW.js} +3 -3
- package/dist/{chunk-X6CSZSSQ.js → chunk-SQ5XCMPB.js} +4 -4
- package/dist/{chunk-BJRLJJS2.js → chunk-TFDMJHAB.js} +1 -1
- package/dist/{chunk-VMQEB56V.js → chunk-TQ2L3ECX.js} +2 -2
- package/dist/{chunk-IPSO7DUB.js → chunk-TTGBS5JB.js} +3 -3
- package/dist/{chunk-YX6VQGLG.js → chunk-U3EBM73X.js} +2 -2
- package/dist/{chunk-LRS4TJU2.js → chunk-UIF7HWHX.js} +4 -4
- package/dist/{chunk-LWAYXE7G.js → chunk-UUCRWEEU.js} +2 -2
- package/dist/{chunk-LMP2FAS6.js → chunk-VBSPP4QY.js} +3 -3
- package/dist/{chunk-XZTFYFC7.js → chunk-VJUDBZGC.js} +2 -2
- package/dist/{chunk-ONZ3UGNY.js → chunk-W47XZJSH.js} +2 -2
- package/dist/{chunk-G3J5JKEJ.js → chunk-WJJVCDEU.js} +6 -6
- package/dist/{chunk-FA6INGK7.js → chunk-WXV7J3DG.js} +3 -3
- package/dist/{chunk-EBOGB7JR.js → chunk-XKQ7CQGG.js} +1 -1
- package/dist/{chunk-KEPESIIR.js → chunk-XMSDA5WA.js} +1 -70
- package/dist/{chunk-LKKIFFUC.js → chunk-YZ6DMGZZ.js} +1 -1
- package/dist/{chunk-YMBJU4CT.js → chunk-Z7AIYWZ2.js} +2 -2
- package/dist/{chunk-QSZQCKPB.js → chunk-ZBZBYUNZ.js} +5 -5
- package/dist/{codex-app-cards-switch-A77HUVKT.js → codex-app-cards-switch-M7VH7AZH.js} +11 -11
- package/dist/{codex-desktop-launch-FSHKRCRL.js → codex-desktop-launch-6DASTBBA.js} +1 -1
- package/dist/{codex-session-launch-VAXYRXK6.js → codex-session-launch-2XSMFA4K.js} +20 -18
- package/dist/{config-SMJ2QWQF.js → config-7QQOIFTW.js} +3 -3
- package/dist/{global-upgrade-63X4UFFP.js → global-upgrade-XAKX26AN.js} +10 -10
- package/dist/{identity-3L2YHAZP.js → identity-7AS5MBNM.js} +4 -4
- package/dist/{live-capabilities-QBQX7RFM.js → live-capabilities-DV4F7MIB.js} +5 -5
- package/dist/{paths-5VPGINSP.js → paths-GSMXYKT5.js} +3 -3
- package/dist/{reapply-MSIZJULX.js → reapply-MR7UWBXR.js} +27 -27
- package/dist/src/index.d.ts +2 -6
- package/dist/src/index.js +28 -28
- package/dist/{upgrade-lock-KKW6XZ7B.js → upgrade-lock-6OTHLCBZ.js} +4 -4
- package/dist/{usage-ICF3NG4F.js → usage-H53PO3VQ.js} +3 -3
- package/package.json +3 -1
|
@@ -2,43 +2,50 @@
|
|
|
2
2
|
import {
|
|
3
3
|
WRAPPER_ACTIVE_ENV,
|
|
4
4
|
findClaudeBinary
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-U3EBM73X.js";
|
|
6
|
+
import {
|
|
7
|
+
CommandReceipts,
|
|
8
|
+
controllerCommandSchema
|
|
9
|
+
} from "../chunk-N5P2FLOJ.js";
|
|
10
|
+
import {
|
|
11
|
+
external_exports
|
|
12
|
+
} from "../chunk-XMSDA5WA.js";
|
|
6
13
|
import {
|
|
7
14
|
SESSION_IDLE_TIMEOUT_MS,
|
|
8
15
|
describeIdleWindow,
|
|
9
16
|
startProcessOwnership,
|
|
10
17
|
withSpawnProcessOwnership
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
18
|
+
} from "../chunk-PNXNWZ5P.js";
|
|
19
|
+
import "../chunk-TFDMJHAB.js";
|
|
13
20
|
import {
|
|
14
21
|
announceSubscriptionRequired,
|
|
15
22
|
isDeferAnswer
|
|
16
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-AXZ67XVN.js";
|
|
17
24
|
import {
|
|
18
25
|
claudeTranscriptPath,
|
|
19
26
|
loadSessionKey,
|
|
20
27
|
registerTranscript,
|
|
21
28
|
registeredTranscriptEnabled
|
|
22
|
-
} from "../chunk-
|
|
23
|
-
import "../chunk-
|
|
29
|
+
} from "../chunk-AC5TVOAH.js";
|
|
30
|
+
import "../chunk-FB262EOM.js";
|
|
24
31
|
import {
|
|
25
32
|
ensureDaemonRunning
|
|
26
|
-
} from "../chunk-
|
|
27
|
-
import "../chunk-
|
|
28
|
-
import "../chunk-
|
|
29
|
-
import "../chunk-
|
|
33
|
+
} from "../chunk-WJJVCDEU.js";
|
|
34
|
+
import "../chunk-QAWWTRDD.js";
|
|
35
|
+
import "../chunk-2HFC4W6J.js";
|
|
36
|
+
import "../chunk-BLX6KRK5.js";
|
|
30
37
|
import "../chunk-NMUI3ZWG.js";
|
|
31
38
|
import {
|
|
32
39
|
encryptRecord
|
|
33
|
-
} from "../chunk-
|
|
40
|
+
} from "../chunk-JC7XUZST.js";
|
|
34
41
|
import {
|
|
35
42
|
transcriptsEnabled
|
|
36
|
-
} from "../chunk-
|
|
43
|
+
} from "../chunk-S63VIM7E.js";
|
|
37
44
|
import {
|
|
38
45
|
needsShell,
|
|
39
46
|
spawnClaude
|
|
40
47
|
} from "../chunk-XHKBHWLX.js";
|
|
41
|
-
import "../chunk-
|
|
48
|
+
import "../chunk-NGNBX3YH.js";
|
|
42
49
|
import {
|
|
43
50
|
DEFAULT_SESSION,
|
|
44
51
|
UNNAMED_ACTION,
|
|
@@ -55,10 +62,10 @@ import {
|
|
|
55
62
|
reportEvent,
|
|
56
63
|
savePendingCommand,
|
|
57
64
|
scopePathFor
|
|
58
|
-
} from "../chunk-
|
|
65
|
+
} from "../chunk-AJWGZJFS.js";
|
|
59
66
|
import {
|
|
60
67
|
repoKeyFor
|
|
61
|
-
} from "../chunk-
|
|
68
|
+
} from "../chunk-QMPM3CAN.js";
|
|
62
69
|
import {
|
|
63
70
|
askUser,
|
|
64
71
|
cancelQuestion,
|
|
@@ -70,30 +77,30 @@ import {
|
|
|
70
77
|
waitForAnswer,
|
|
71
78
|
waitsForThePhone,
|
|
72
79
|
withdrawQuestion
|
|
73
|
-
} from "../chunk-
|
|
80
|
+
} from "../chunk-CMYFV3VC.js";
|
|
74
81
|
import "../chunk-POFBE6ZY.js";
|
|
75
82
|
import {
|
|
76
83
|
SubscriptionRequiredError
|
|
77
|
-
} from "../chunk-
|
|
78
|
-
import "../chunk-
|
|
79
|
-
import "../chunk-
|
|
84
|
+
} from "../chunk-7M4AA7QF.js";
|
|
85
|
+
import "../chunk-S7VMHSJW.js";
|
|
86
|
+
import "../chunk-O4EAMVSC.js";
|
|
80
87
|
import {
|
|
81
88
|
getMachineId
|
|
82
|
-
} from "../chunk-
|
|
89
|
+
} from "../chunk-UUCRWEEU.js";
|
|
83
90
|
import "../chunk-PPY5N2E6.js";
|
|
84
91
|
import "../chunk-KZERVKTD.js";
|
|
85
|
-
import "../chunk-
|
|
92
|
+
import "../chunk-7FROPPIH.js";
|
|
86
93
|
import {
|
|
87
94
|
claudeConfigDir
|
|
88
|
-
} from "../chunk-
|
|
89
|
-
import "../chunk-
|
|
95
|
+
} from "../chunk-7S46LCKD.js";
|
|
96
|
+
import "../chunk-RZVWEDIS.js";
|
|
90
97
|
import {
|
|
91
98
|
getApiKey,
|
|
92
99
|
getBaseUrl
|
|
93
|
-
} from "../chunk-
|
|
100
|
+
} from "../chunk-R5PZPROX.js";
|
|
94
101
|
import {
|
|
95
102
|
NPX_LATEST_COMMAND
|
|
96
|
-
} from "../chunk-
|
|
103
|
+
} from "../chunk-PPKIL4EL.js";
|
|
97
104
|
import "../chunk-QTOLNRET.js";
|
|
98
105
|
import {
|
|
99
106
|
DECISION_STOP_REASON,
|
|
@@ -101,12 +108,13 @@ import {
|
|
|
101
108
|
KILL_REASON,
|
|
102
109
|
SESSION_PAUSED_REASON,
|
|
103
110
|
UNVERIFIABLE_APPROVAL_REASON,
|
|
111
|
+
extractMessageText,
|
|
104
112
|
questionLimitHandBack,
|
|
105
113
|
redactSecretsFromContent,
|
|
106
114
|
refusesWhenUnanswered,
|
|
107
115
|
resolveGate,
|
|
108
116
|
timeoutActionWithoutLocalPrompt
|
|
109
|
-
} from "../chunk-
|
|
117
|
+
} from "../chunk-AVHL2ZTS.js";
|
|
110
118
|
import "../chunk-MLKGABMK.js";
|
|
111
119
|
|
|
112
120
|
// src/wrapper/localPassthrough.ts
|
|
@@ -153,6 +161,36 @@ var runLocalPassthrough = (binary, args2) => {
|
|
|
153
161
|
});
|
|
154
162
|
};
|
|
155
163
|
|
|
164
|
+
// src/wrapper/command-history.ts
|
|
165
|
+
import { open } from "fs/promises";
|
|
166
|
+
var userRecord = external_exports.object({ type: external_exports.literal("user"), uuid: external_exports.string(), message: external_exports.object({ role: external_exports.literal("user") }) });
|
|
167
|
+
var MAX_HISTORY_BYTES = 16 * 1024 * 1024;
|
|
168
|
+
var historyAcceptedCommand = async (file, commandId) => {
|
|
169
|
+
try {
|
|
170
|
+
const handle = await open(file, "r");
|
|
171
|
+
try {
|
|
172
|
+
const stat = await handle.stat();
|
|
173
|
+
const start = Math.max(0, stat.size - MAX_HISTORY_BYTES);
|
|
174
|
+
const buffer = Buffer.alloc(Math.min(stat.size, MAX_HISTORY_BYTES));
|
|
175
|
+
const { bytesRead } = await handle.read(buffer, 0, buffer.length, start);
|
|
176
|
+
const lines = buffer.subarray(0, bytesRead).toString("utf8").split("\n");
|
|
177
|
+
for (const line of start ? lines.slice(1) : lines) {
|
|
178
|
+
try {
|
|
179
|
+
const record = userRecord.safeParse(JSON.parse(line));
|
|
180
|
+
if (record.success && record.data.uuid === commandId) return true;
|
|
181
|
+
} catch {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
} finally {
|
|
186
|
+
await handle.close();
|
|
187
|
+
}
|
|
188
|
+
} catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
return false;
|
|
192
|
+
};
|
|
193
|
+
|
|
156
194
|
// src/wrapper/dualMode.ts
|
|
157
195
|
import { existsSync as existsSync2 } from "fs";
|
|
158
196
|
|
|
@@ -170,6 +208,7 @@ var redactDraft = (text, complete = false) => {
|
|
|
170
208
|
}
|
|
171
209
|
return redactSecretsFromContent(text.slice(0, end));
|
|
172
210
|
};
|
|
211
|
+
var isDraftObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
173
212
|
var DraftText = class {
|
|
174
213
|
messageId = "";
|
|
175
214
|
text = "";
|
|
@@ -177,18 +216,28 @@ var DraftText = class {
|
|
|
177
216
|
interrupted = false;
|
|
178
217
|
add(message) {
|
|
179
218
|
if (message.parent_tool_use_id) return;
|
|
180
|
-
const event = message.event;
|
|
219
|
+
const event = isDraftObject(message.event) ? message.event : null;
|
|
181
220
|
if (message.type === "stream_event" && event?.type === "message_start") {
|
|
182
|
-
|
|
221
|
+
const start = isDraftObject(event.message) ? event.message : null;
|
|
222
|
+
this.messageId = typeof start?.id === "string" ? start.id : "";
|
|
183
223
|
this.text = "";
|
|
184
224
|
this.complete = false;
|
|
185
225
|
this.interrupted = false;
|
|
186
|
-
} else if (message.type === "stream_event" && event?.type === "
|
|
187
|
-
|
|
188
|
-
|
|
226
|
+
} else if (message.type === "stream_event" && event?.type === "content_block_start") {
|
|
227
|
+
const block = isDraftObject(event.content_block) ? event.content_block : null;
|
|
228
|
+
if (block?.type === "text") {
|
|
229
|
+
const separator = this.text.length > 0 ? "\n" : "";
|
|
230
|
+
this.text = (this.text + separator + (typeof block.text === "string" ? block.text : "")).slice(0, 32 * 1024);
|
|
231
|
+
}
|
|
232
|
+
} else if (message.type === "stream_event" && event?.type === "content_block_delta") {
|
|
233
|
+
const delta = isDraftObject(event.delta) ? event.delta : null;
|
|
234
|
+
if (delta?.type === "text_delta" && typeof delta.text === "string") {
|
|
235
|
+
this.text = (this.text + delta.text).slice(0, 32 * 1024);
|
|
236
|
+
}
|
|
237
|
+
} else if (message.type === "assistant" && isDraftObject(message.message)) {
|
|
189
238
|
const body = message.message;
|
|
190
|
-
if (body
|
|
191
|
-
this.text = body.content
|
|
239
|
+
if (body.id === this.messageId && (Array.isArray(body.content) || typeof body.content === "string")) {
|
|
240
|
+
this.text = extractMessageText(body.content).slice(0, 32 * 1024);
|
|
192
241
|
this.complete = true;
|
|
193
242
|
}
|
|
194
243
|
}
|
|
@@ -201,7 +250,7 @@ var DraftText = class {
|
|
|
201
250
|
return this.messageId && text ? { messageId: this.messageId, text, status: this.interrupted ? "interrupted" : this.complete ? "complete" : "streaming" } : null;
|
|
202
251
|
}
|
|
203
252
|
};
|
|
204
|
-
var startTranscriptDraft = (apiKey, getSessionId) => {
|
|
253
|
+
var startTranscriptDraft = (apiKey, getSessionId, runtime = {}) => {
|
|
205
254
|
const text = new DraftText();
|
|
206
255
|
const startedAt = Date.now();
|
|
207
256
|
let revision = 0;
|
|
@@ -210,17 +259,17 @@ var startTranscriptDraft = (apiKey, getSessionId) => {
|
|
|
210
259
|
let ending = false;
|
|
211
260
|
let sent = "";
|
|
212
261
|
const flush = async () => {
|
|
213
|
-
if (stopped || pending || !transcriptsEnabled()) return;
|
|
262
|
+
if (stopped || pending || !(runtime.enabled ?? transcriptsEnabled)()) return;
|
|
214
263
|
const sessionId = getSessionId();
|
|
215
264
|
const snapshot = text.snapshot();
|
|
216
|
-
if (!sessionId || !snapshot || !registeredTranscriptEnabled(apiKey, sessionId)) return;
|
|
265
|
+
if (!sessionId || !snapshot || !(runtime.registered ? runtime.registered(sessionId) : registeredTranscriptEnabled(apiKey, sessionId))) return;
|
|
217
266
|
const raw = JSON.stringify(snapshot);
|
|
218
267
|
if (raw === sent) return;
|
|
219
|
-
const key = loadSessionKey(sessionId);
|
|
268
|
+
const key = loadSessionKey(sessionId, runtime.keyDirectory);
|
|
220
269
|
if (!key?.keyUploaded) return;
|
|
221
270
|
pending = (async () => {
|
|
222
271
|
try {
|
|
223
|
-
const response = await fetch(`${getBaseUrl()}/api/agent/transcript`, {
|
|
272
|
+
const response = await fetch(`${runtime.baseUrl ?? getBaseUrl()}/api/agent/transcript`, {
|
|
224
273
|
method: "POST",
|
|
225
274
|
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
226
275
|
body: JSON.stringify({ sessionId, draft: { startedAt, revision: ++revision, content: encryptRecord(raw, key.sessionKey) } }),
|
|
@@ -236,7 +285,7 @@ var startTranscriptDraft = (apiKey, getSessionId) => {
|
|
|
236
285
|
pending = void 0;
|
|
237
286
|
}
|
|
238
287
|
};
|
|
239
|
-
const timer = setInterval(() => void flush(),
|
|
288
|
+
const timer = setInterval(() => void flush(), 500);
|
|
240
289
|
timer.unref();
|
|
241
290
|
return {
|
|
242
291
|
add: (message) => {
|
|
@@ -284,6 +333,7 @@ var importSdk = async (specifierOrUrl) => {
|
|
|
284
333
|
}
|
|
285
334
|
};
|
|
286
335
|
var loadClaudeSdk = async () => {
|
|
336
|
+
if (process.env.PUSHARY_REMOTE_SDK_DIR?.trim()) return importSdk(pathToFileURL(cachedSdkEntry()).href);
|
|
287
337
|
const fromResolution = await importSdk(SDK_PACKAGE);
|
|
288
338
|
if (fromResolution) return fromResolution;
|
|
289
339
|
const entry = cachedSdkEntry();
|
|
@@ -713,7 +763,10 @@ var startCommandPoller = (opts) => {
|
|
|
713
763
|
command = drained.command;
|
|
714
764
|
}
|
|
715
765
|
errorStreak = 0;
|
|
716
|
-
if (command) {
|
|
766
|
+
if (command && typeof command !== "string" && command.receipt && opts.onClaimedCommand) {
|
|
767
|
+
idleTicks = 0;
|
|
768
|
+
await opts.onClaimedCommand(command.receipt.command, command.receipt.acknowledge);
|
|
769
|
+
} else if (command) {
|
|
717
770
|
idleTicks = 0;
|
|
718
771
|
const text = typeof command === "string" ? command : command.text;
|
|
719
772
|
let accepted = false;
|
|
@@ -743,6 +796,11 @@ var startCommandPoller = (opts) => {
|
|
|
743
796
|
schedule(fast);
|
|
744
797
|
opts.log?.("[pushary] command poller active");
|
|
745
798
|
return {
|
|
799
|
+
wake() {
|
|
800
|
+
if (stopped || inflight) return;
|
|
801
|
+
if (timer) clearTimeout(timer);
|
|
802
|
+
schedule(1);
|
|
803
|
+
},
|
|
746
804
|
stop() {
|
|
747
805
|
stopped = true;
|
|
748
806
|
if (timer) clearTimeout(timer);
|
|
@@ -754,11 +812,11 @@ var startCommandPoller = (opts) => {
|
|
|
754
812
|
|
|
755
813
|
// src/wrapper/pollClient.ts
|
|
756
814
|
var APPROVAL_MODES = /* @__PURE__ */ new Set(["push_only", "terminal_only", "push_first", "notify_only"]);
|
|
757
|
-
var pollAgent = async (apiKey, sessionId, wantCommand, signal, baseUrl = getBaseUrl(), machineId, controlMode, takeoverDeclined) => {
|
|
815
|
+
var pollAgent = async (apiKey, sessionId, wantCommand, signal, baseUrl = getBaseUrl(), machineId, controlMode, takeoverDeclined, durableReceipts = false) => {
|
|
758
816
|
try {
|
|
759
817
|
const sessionKey = sessionId || DEFAULT_SESSION;
|
|
760
818
|
const receiptNamespace = `${apiKey}:${machineId}:claude_code`;
|
|
761
|
-
let storedCommand = machineId ? readPendingCommand(sessionKey, receiptNamespace) : null;
|
|
819
|
+
let storedCommand = machineId && !durableReceipts ? readPendingCommand(sessionKey, receiptNamespace) : null;
|
|
762
820
|
let acknowledgedCommandId = null;
|
|
763
821
|
const acknowledge = async (id, state) => {
|
|
764
822
|
const persisted = state === "delivered" ? markPendingCommandDelivered(sessionKey, id, receiptNamespace) : markPendingCommandFailed(sessionKey, id, receiptNamespace);
|
|
@@ -797,6 +855,7 @@ var pollAgent = async (apiKey, sessionId, wantCommand, signal, baseUrl = getBase
|
|
|
797
855
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
|
|
798
856
|
body: JSON.stringify({
|
|
799
857
|
...sessionId ? { sessionId } : {},
|
|
858
|
+
...durableReceipts ? { receiptVersion: 1 } : {},
|
|
800
859
|
...controlMode ? { controlMode } : {},
|
|
801
860
|
...takeoverDeclined ? { takeoverDeclined } : {},
|
|
802
861
|
...machineId ? { machineId } : {},
|
|
@@ -815,6 +874,24 @@ var pollAgent = async (apiKey, sessionId, wantCommand, signal, baseUrl = getBase
|
|
|
815
874
|
let command = typeof data.command === "string" && data.command.length > 0 ? data.command : null;
|
|
816
875
|
if (storedCommand) {
|
|
817
876
|
command = storedCommand.delivered || storedCommand.failed ? null : claimedCommand(storedCommand.id, storedCommand.text);
|
|
877
|
+
} else if (durableReceipts) {
|
|
878
|
+
const parsed = controllerCommandSchema.safeParse(data.command);
|
|
879
|
+
if (parsed.success && machineId) {
|
|
880
|
+
const acknowledge2 = async (state, dispatchId) => {
|
|
881
|
+
try {
|
|
882
|
+
const result = await fetch(`${baseUrl}/api/agent/command/ack`, {
|
|
883
|
+
method: "POST",
|
|
884
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
|
|
885
|
+
body: JSON.stringify({ commandId: parsed.data.id, sessionId, machineId, state, dispatchId }),
|
|
886
|
+
signal: AbortSignal.timeout(5e3)
|
|
887
|
+
});
|
|
888
|
+
return result.ok;
|
|
889
|
+
} catch {
|
|
890
|
+
return false;
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
command = { ...parsed.data, receipt: { command: parsed.data, acknowledge: acknowledge2 } };
|
|
894
|
+
} else command = null;
|
|
818
895
|
} else if (data.command && typeof data.command === "object") {
|
|
819
896
|
const claimed = data.command;
|
|
820
897
|
if (typeof claimed.id === "string" && typeof claimed.text === "string" && claimed.id !== acknowledgedCommandId) {
|
|
@@ -944,7 +1021,7 @@ var createRelayClient = (options) => {
|
|
|
944
1021
|
return true;
|
|
945
1022
|
};
|
|
946
1023
|
const sendFrame = (frame) => {
|
|
947
|
-
if (!socket
|
|
1024
|
+
if (!socket) return;
|
|
948
1025
|
try {
|
|
949
1026
|
socket.send(encodeFrame(frame));
|
|
950
1027
|
} catch {
|
|
@@ -978,9 +1055,15 @@ var createRelayClient = (options) => {
|
|
|
978
1055
|
switch (frame.t) {
|
|
979
1056
|
case "welcome":
|
|
980
1057
|
attempt = 0;
|
|
1058
|
+
isConnected = true;
|
|
1059
|
+
options.onCommandAvailable?.();
|
|
981
1060
|
log("[pushary] relay connected");
|
|
982
1061
|
break;
|
|
983
1062
|
case "command":
|
|
1063
|
+
if (options.onCommandAvailable) {
|
|
1064
|
+
options.onCommandAvailable();
|
|
1065
|
+
break;
|
|
1066
|
+
}
|
|
984
1067
|
if (pendingCommands.has(frame.id)) {
|
|
985
1068
|
await pendingCommands.get(frame.id);
|
|
986
1069
|
acknowledgeStored(frame.id);
|
|
@@ -1050,9 +1133,11 @@ var createRelayClient = (options) => {
|
|
|
1050
1133
|
if (pongTimer) clearTimeout(pongTimer);
|
|
1051
1134
|
heartbeatTimer = void 0;
|
|
1052
1135
|
pongTimer = void 0;
|
|
1053
|
-
|
|
1136
|
+
const previous = socket;
|
|
1137
|
+
socket = void 0;
|
|
1138
|
+
if (previous) {
|
|
1054
1139
|
try {
|
|
1055
|
-
|
|
1140
|
+
previous.close();
|
|
1056
1141
|
} catch {
|
|
1057
1142
|
}
|
|
1058
1143
|
}
|
|
@@ -1090,13 +1175,15 @@ var createRelayClient = (options) => {
|
|
|
1090
1175
|
}
|
|
1091
1176
|
socket = created;
|
|
1092
1177
|
created.onOpen(() => {
|
|
1093
|
-
|
|
1178
|
+
if (socket !== created || stopped) return;
|
|
1094
1179
|
sendHello();
|
|
1095
1180
|
startHeartbeat();
|
|
1096
1181
|
});
|
|
1097
|
-
created.onMessage((data) =>
|
|
1182
|
+
created.onMessage((data) => {
|
|
1183
|
+
if (socket === created && !stopped) void onServerFrame(data);
|
|
1184
|
+
});
|
|
1098
1185
|
created.onClose(() => {
|
|
1099
|
-
if (stopped) return;
|
|
1186
|
+
if (stopped || socket !== created) return;
|
|
1100
1187
|
dropAndReconnect();
|
|
1101
1188
|
});
|
|
1102
1189
|
created.onError(() => {
|
|
@@ -1375,6 +1462,7 @@ var runRemoteLoop = async (deps) => {
|
|
|
1375
1462
|
options: {
|
|
1376
1463
|
resume: resumeId,
|
|
1377
1464
|
includePartialMessages: true,
|
|
1465
|
+
extraArgs: { "replay-user-messages": null },
|
|
1378
1466
|
permissionMode: deps.permissionMode,
|
|
1379
1467
|
model: deps.model,
|
|
1380
1468
|
settings: deps.settings,
|
|
@@ -1423,7 +1511,7 @@ var runRemoteLoop = async (deps) => {
|
|
|
1423
1511
|
return ended(1, "failed");
|
|
1424
1512
|
}
|
|
1425
1513
|
resumeId = message.session_id;
|
|
1426
|
-
deps.onSessionId?.(resumeId);
|
|
1514
|
+
await deps.onSessionId?.(resumeId);
|
|
1427
1515
|
}
|
|
1428
1516
|
if (message.type === "result" && typeof message.total_cost_usd === "number") {
|
|
1429
1517
|
totalCost = message.total_cost_usd;
|
|
@@ -1479,7 +1567,7 @@ var runRemoteLeg = async (session, sdk, deps = {}) => {
|
|
|
1479
1567
|
};
|
|
1480
1568
|
session.setActiveLeg(control);
|
|
1481
1569
|
session.stdin.captureForWrapper((data) => {
|
|
1482
|
-
if (data.includes(CTRL_RIGHT_BRACKET)) {
|
|
1570
|
+
if (deps.allowLocalHandoff !== false && data.includes(CTRL_RIGHT_BRACKET)) {
|
|
1483
1571
|
switchBack = true;
|
|
1484
1572
|
if (!legAbort.signal.aborted) legAbort.abort();
|
|
1485
1573
|
} else if (data.includes(CTRL_C)) {
|
|
@@ -1487,7 +1575,7 @@ var runRemoteLeg = async (session, sdk, deps = {}) => {
|
|
|
1487
1575
|
}
|
|
1488
1576
|
});
|
|
1489
1577
|
process.stderr.write(
|
|
1490
|
-
"[pushary] remote \u2014 driving from your phone \xB7 press Ctrl-] for the local terminal\n"
|
|
1578
|
+
deps.allowLocalHandoff === false ? "[pushary] ready for phone control \xB7 Ctrl-C stops this session\n" : "[pushary] remote \u2014 driving from your phone \xB7 press Ctrl-] for the local terminal\n"
|
|
1491
1579
|
);
|
|
1492
1580
|
let exitCode = 0;
|
|
1493
1581
|
try {
|
|
@@ -1522,7 +1610,7 @@ var runRemoteLeg = async (session, sdk, deps = {}) => {
|
|
|
1522
1610
|
session.stdin.releaseToChild();
|
|
1523
1611
|
session.setActiveLeg(null);
|
|
1524
1612
|
}
|
|
1525
|
-
if (idleEnded && attended) {
|
|
1613
|
+
if (idleEnded && attended && deps.allowLocalHandoff !== false) {
|
|
1526
1614
|
process.stderr.write("[pushary] handing the terminal back to local mode\n");
|
|
1527
1615
|
return "switch";
|
|
1528
1616
|
}
|
|
@@ -1563,7 +1651,7 @@ var extractAssistantText = (message) => {
|
|
|
1563
1651
|
}
|
|
1564
1652
|
return void 0;
|
|
1565
1653
|
};
|
|
1566
|
-
var runDualMode = async (binary, args2, startingMode) => {
|
|
1654
|
+
var runDualMode = async (binary, args2, startingMode, runtime = {}) => {
|
|
1567
1655
|
const compatibilityIssue = remoteCompatibilityIssue(args2);
|
|
1568
1656
|
if (startingMode === "remote" && compatibilityIssue) {
|
|
1569
1657
|
process.stderr.write(`[pushary] ${compatibilityIssue}
|
|
@@ -1586,7 +1674,7 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1586
1674
|
let noticedUnavailable = false;
|
|
1587
1675
|
const ensureSdk = async () => {
|
|
1588
1676
|
if (sdk === void 0) {
|
|
1589
|
-
sdkLoading ??= ensureClaudeSdk((message) => process.stderr.write(`${message}
|
|
1677
|
+
sdkLoading ??= runtime.sdk ? Promise.resolve(runtime.sdk) : ensureClaudeSdk((message) => process.stderr.write(`${message}
|
|
1590
1678
|
`));
|
|
1591
1679
|
sdk = await sdkLoading;
|
|
1592
1680
|
if (!sdk) remoteAvailable = false;
|
|
@@ -1599,7 +1687,7 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1599
1687
|
}
|
|
1600
1688
|
const projectName = basename(process.cwd());
|
|
1601
1689
|
const agentName = `Claude Code - ${projectName}`;
|
|
1602
|
-
const machineId = getMachineId();
|
|
1690
|
+
const machineId = runtime.machineId ?? getMachineId();
|
|
1603
1691
|
const stdin = createStdinHandoff();
|
|
1604
1692
|
const verbose = process.env.PUSHARY_VERBOSE === "1";
|
|
1605
1693
|
const verboseLog = (message) => {
|
|
@@ -1625,8 +1713,7 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1625
1713
|
const input = new BoundedInputQueue({
|
|
1626
1714
|
cap: INPUT_QUEUE_CAP,
|
|
1627
1715
|
onDrop: (_dropped, total) => process.stderr.write(`[pushary] input queue full; refused ${total} instruction(s)
|
|
1628
|
-
`)
|
|
1629
|
-
coalesce: (items) => userMessage(items.map((m) => m.message.content).join("\n\n"))
|
|
1716
|
+
`)
|
|
1630
1717
|
});
|
|
1631
1718
|
const approver = createRemoteApprover({
|
|
1632
1719
|
apiKey,
|
|
@@ -1646,6 +1733,7 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1646
1733
|
agentType: "claude_code",
|
|
1647
1734
|
getSessionId: () => sessionId,
|
|
1648
1735
|
onCommand: (command) => onPhoneCommand(command),
|
|
1736
|
+
onCommandAvailable: () => poller.wake?.(),
|
|
1649
1737
|
onFatal: (message) => verboseLog(`[pushary] relay unavailable (${message}); using polling`),
|
|
1650
1738
|
log: verboseLog
|
|
1651
1739
|
});
|
|
@@ -1673,13 +1761,19 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1673
1761
|
{ event, agentType: "claude_code", agentName, action, sessionId, machineId, pid: process.pid },
|
|
1674
1762
|
{ maxAttempts: event === "session_start" ? 4 : 2, timeoutMs: 4e3, requireOk: event === "session_start" }
|
|
1675
1763
|
);
|
|
1676
|
-
} catch {
|
|
1764
|
+
} catch (error) {
|
|
1765
|
+
if (runtime.onReady && event === "session_start") throw error;
|
|
1677
1766
|
}
|
|
1678
1767
|
};
|
|
1679
1768
|
let presenceHeartbeat;
|
|
1680
1769
|
let transcriptStarted;
|
|
1681
1770
|
const ensureTranscriptSync = () => {
|
|
1682
|
-
if (
|
|
1771
|
+
if (!sessionId) return;
|
|
1772
|
+
if (runtime.registerTranscript) {
|
|
1773
|
+
runtime.registerTranscript(sessionId, false);
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
if (transcriptStarted === sessionId || !transcriptsEnabled()) return;
|
|
1683
1777
|
transcriptStarted = sessionId;
|
|
1684
1778
|
registerTranscript("claude", { session_id: sessionId, cwd: process.cwd() });
|
|
1685
1779
|
};
|
|
@@ -1691,14 +1785,25 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1691
1785
|
);
|
|
1692
1786
|
presenceHeartbeat.unref();
|
|
1693
1787
|
};
|
|
1694
|
-
|
|
1788
|
+
let readySessionId;
|
|
1789
|
+
const setSessionId = async (id) => {
|
|
1695
1790
|
const isNew = sessionId !== id;
|
|
1696
1791
|
sessionId = id;
|
|
1697
1792
|
sessionCreated = true;
|
|
1698
1793
|
relay?.reannounce();
|
|
1699
|
-
if (
|
|
1794
|
+
if (runtime.onReady && readySessionId !== id) {
|
|
1795
|
+
const control = await pollAgent(apiKey, id, false, AbortSignal.any([AbortSignal.timeout(5e3), ...runtime.signal ? [runtime.signal] : []]), void 0, machineId, "remote");
|
|
1796
|
+
if (!control.mode || control.rejected || control.mode.kill) throw new Error("Phone control could not register or was stopped");
|
|
1797
|
+
}
|
|
1798
|
+
if (isNew || readySessionId !== id) {
|
|
1799
|
+
const registered = announcePresence("session_start", "Remote session ready \u2014 reachable from your phone");
|
|
1800
|
+
if (runtime.onReady) await registered;
|
|
1801
|
+
else void registered;
|
|
1802
|
+
}
|
|
1700
1803
|
ensurePresenceHeartbeat();
|
|
1701
1804
|
ensureTranscriptSync();
|
|
1805
|
+
if (readySessionId !== id) await runtime.onReady?.(id);
|
|
1806
|
+
readySessionId = id;
|
|
1702
1807
|
};
|
|
1703
1808
|
const onPhoneCommand = async (command) => {
|
|
1704
1809
|
if (controlMode !== "remote") return false;
|
|
@@ -1711,10 +1816,26 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1711
1816
|
}
|
|
1712
1817
|
if (finished || !input.push(userMessage(command))) return false;
|
|
1713
1818
|
activeLeg?.onPhoneCommand();
|
|
1819
|
+
void announcePresence("user_prompt", "Working on your message");
|
|
1714
1820
|
return true;
|
|
1715
1821
|
};
|
|
1822
|
+
const receipts = new CommandReceipts({
|
|
1823
|
+
wasAccepted: (commandId) => sessionId ? historyAcceptedCommand(claudeTranscriptPath(process.cwd(), sessionId), commandId) : Promise.resolve(false),
|
|
1824
|
+
submit: async (command) => {
|
|
1825
|
+
if (controlMode !== "remote" || finished || !remoteAvailable || !sessionId) return "failed";
|
|
1826
|
+
if (!input.push({ ...userMessage(command.text), uuid: command.id })) return "failed";
|
|
1827
|
+
activeLeg?.onPhoneCommand();
|
|
1828
|
+
void announcePresence("user_prompt", "Working on your message");
|
|
1829
|
+
},
|
|
1830
|
+
log: (message) => process.stderr.write(`${message}
|
|
1831
|
+
`)
|
|
1832
|
+
});
|
|
1716
1833
|
let draft;
|
|
1717
1834
|
const streamMessage = (message) => {
|
|
1835
|
+
if (message.type === "user" && typeof message.uuid === "string" && !message.parent_tool_use_id) {
|
|
1836
|
+
receipts.accepted(message.uuid);
|
|
1837
|
+
void receipts.flush();
|
|
1838
|
+
}
|
|
1718
1839
|
draft?.add(message);
|
|
1719
1840
|
if (message.type === "assistant") {
|
|
1720
1841
|
const text = extractAssistantText(message);
|
|
@@ -1756,13 +1877,15 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1756
1877
|
apiKey,
|
|
1757
1878
|
getSessionId: () => sessionId,
|
|
1758
1879
|
onCommand: (command) => onPhoneCommand(command),
|
|
1759
|
-
|
|
1880
|
+
onClaimedCommand: (command, acknowledge) => receipts.receive(command, acknowledge),
|
|
1881
|
+
shouldDrainCommands: () => controlMode === "remote" && Boolean(sessionId),
|
|
1760
1882
|
// Unified poll: one request per tick for both command + mode/kill (half the
|
|
1761
1883
|
// requests and the per-poll DB write of the old drain + mode pair).
|
|
1762
1884
|
poll: async (key, id, wantCommand, signal) => {
|
|
1885
|
+
await receipts.flush();
|
|
1763
1886
|
const declined = takeoverDecline;
|
|
1764
1887
|
takeoverDecline = void 0;
|
|
1765
|
-
const result = await pollAgent(key, id, wantCommand, signal, void 0, machineId, controlMode, declined);
|
|
1888
|
+
const result = await pollAgent(key, id, wantCommand, signal, void 0, machineId, controlMode, declined, true);
|
|
1766
1889
|
if (result.takeoverRequested) void takeOver();
|
|
1767
1890
|
return result;
|
|
1768
1891
|
},
|
|
@@ -1773,8 +1896,12 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1773
1896
|
// of Redis round trips. Takeover already sits behind a confirm and a biometric.
|
|
1774
1897
|
slowPollMs: 15e3,
|
|
1775
1898
|
onAuthRejected: () => {
|
|
1899
|
+
if (runtime.remoteOnly) {
|
|
1900
|
+
finished = true;
|
|
1901
|
+
activeLeg?.stop("kill");
|
|
1902
|
+
}
|
|
1776
1903
|
process.stderr.write(
|
|
1777
|
-
"[pushary] this key was rejected \u2014 remote stop and phone messages are NOT active; run `pushary login` to reconnect\n"
|
|
1904
|
+
runtime.remoteOnly ? "[pushary] Mac account access was rejected. Sign in to Pushary on this Mac and retry.\n" : "[pushary] this key was rejected \u2014 remote stop and phone messages are NOT active; run `pushary login` to reconnect\n"
|
|
1778
1905
|
);
|
|
1779
1906
|
},
|
|
1780
1907
|
onModeState: (state) => {
|
|
@@ -1793,6 +1920,8 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1793
1920
|
activeLeg?.stop("signal");
|
|
1794
1921
|
};
|
|
1795
1922
|
for (const signal of signals) process.on(signal, onSignal);
|
|
1923
|
+
runtime.signal?.addEventListener("abort", onSignal, { once: true });
|
|
1924
|
+
if (runtime.signal?.aborted) onSignal();
|
|
1796
1925
|
const restoreStdin = () => stdin.dispose();
|
|
1797
1926
|
process.once("exit", restoreStdin);
|
|
1798
1927
|
const session = {
|
|
@@ -1833,6 +1962,7 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1833
1962
|
const exitCode = await driveModeLoop({
|
|
1834
1963
|
startingMode,
|
|
1835
1964
|
runLocal: async () => {
|
|
1965
|
+
if (runtime.remoteOnly) return { type: "exit", code: 1 };
|
|
1836
1966
|
controlMode = "local";
|
|
1837
1967
|
await draft?.stop();
|
|
1838
1968
|
draft = void 0;
|
|
@@ -1841,6 +1971,7 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1841
1971
|
return runLocalLeg(session);
|
|
1842
1972
|
},
|
|
1843
1973
|
runRemote: async () => {
|
|
1974
|
+
if (finished) return { type: "exit", code: 130 };
|
|
1844
1975
|
controlMode = "remote";
|
|
1845
1976
|
startRelay();
|
|
1846
1977
|
const ready = await ensureSdk();
|
|
@@ -1861,8 +1992,8 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1861
1992
|
}
|
|
1862
1993
|
return "switch";
|
|
1863
1994
|
}
|
|
1864
|
-
draft = startTranscriptDraft(apiKey, () => sessionId);
|
|
1865
|
-
return runRemoteLeg(session, ready);
|
|
1995
|
+
draft = (runtime.startDraft ?? startTranscriptDraft)(apiKey, () => sessionId);
|
|
1996
|
+
return runRemoteLeg(session, ready, { allowLocalHandoff: !runtime.remoteOnly, ...runtime.remoteOnly ? { attended: false } : {} });
|
|
1866
1997
|
},
|
|
1867
1998
|
isFinished: () => finished,
|
|
1868
1999
|
minDwellMs: MIN_MODE_DWELL_MS
|
|
@@ -1870,6 +2001,7 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1870
2001
|
return { implemented: true, exitCode };
|
|
1871
2002
|
} finally {
|
|
1872
2003
|
for (const signal of signals) process.off(signal, onSignal);
|
|
2004
|
+
runtime.signal?.removeEventListener("abort", onSignal);
|
|
1873
2005
|
process.removeListener("exit", restoreStdin);
|
|
1874
2006
|
await draft?.stop();
|
|
1875
2007
|
relay?.stop();
|
|
@@ -1878,7 +2010,10 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1878
2010
|
approver.teardown();
|
|
1879
2011
|
input.close();
|
|
1880
2012
|
stdin.dispose();
|
|
1881
|
-
if (sessionId)
|
|
2013
|
+
if (sessionId) {
|
|
2014
|
+
if (runtime.registerTranscript) runtime.registerTranscript(sessionId, true);
|
|
2015
|
+
else registerTranscript("claude", { session_id: sessionId, cwd: process.cwd() }, void 0, { ended: true });
|
|
2016
|
+
}
|
|
1882
2017
|
await announcePresence("session_closed", "Session ended");
|
|
1883
2018
|
ownership?.stop();
|
|
1884
2019
|
if (totalCostUsd > 0) {
|