@pushary/agent-hooks 0.95.2 → 0.95.5
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 +19 -0
- package/README.md +1 -1
- package/data/cursor-plugin/.cursor-plugin/plugin.json +1 -1
- package/data/cursor-plugin/CHANGELOG.md +5 -0
- package/data/cursor-plugin/README.md +6 -8
- package/data/cursor-plugin/hooks/hooks.json +56 -1
- package/data/cursor-plugin/scripts/pushary-gate.mjs +120 -71
- package/data/vscode-plugin/.claude-plugin/plugin.json +1 -1
- package/data/vscode-plugin/CHANGELOG.md +5 -0
- package/data/vscode-plugin/README.md +7 -15
- package/data/vscode-plugin/hooks/hooks.json +49 -0
- package/data/vscode-plugin/scripts/pushary-gate.mjs +208 -88
- package/dist/bin/pushary-bell-hook.js +20 -22
- package/dist/bin/pushary-bell.js +9 -11
- package/dist/bin/pushary-claude.js +58 -46
- package/dist/bin/pushary-clean.js +21 -20
- package/dist/bin/pushary-codex-bridge.js +120 -25
- package/dist/bin/pushary-codex-hook.js +43 -63
- package/dist/bin/pushary-codex.js +11 -10
- package/dist/bin/pushary-connect.js +8 -10
- package/dist/bin/pushary-cowork.js +5 -5
- package/dist/bin/pushary-daemon.js +26 -28
- package/dist/bin/pushary-disconnect.js +11 -10
- package/dist/bin/pushary-doctor.js +25 -25
- package/dist/bin/pushary-elicitation-hook.js +30 -31
- package/dist/bin/pushary-gemini-bridge.js +9 -11
- package/dist/bin/pushary-gemini-hook.js +45 -79
- package/dist/bin/pushary-hook.js +27 -29
- package/dist/bin/pushary-login.js +57 -31
- package/dist/bin/pushary-logout.js +6 -8
- package/dist/bin/pushary-mode.js +5 -5
- package/dist/bin/pushary-notification-hook.js +22 -24
- package/dist/bin/pushary-opencode-hook.js +38 -74
- package/dist/bin/pushary-permission-denied-hook.js +25 -27
- package/dist/bin/pushary-permission-hook.js +25 -27
- package/dist/bin/pushary-post-hook.js +22 -24
- package/dist/bin/pushary-prompt-hook.js +22 -24
- package/dist/bin/pushary-session-end-hook.js +22 -24
- package/dist/bin/pushary-session-start-hook.js +25 -27
- package/dist/bin/pushary-setup.js +78 -55
- package/dist/bin/pushary-stats.js +4 -4
- package/dist/bin/pushary-status.js +10 -12
- package/dist/bin/pushary-stop-hook.js +22 -24
- package/dist/bin/pushary-stopfailure-hook.js +22 -24
- package/dist/bin/pushary-suggestions.js +2 -2
- package/dist/bin/pushary-transcript-register.js +18 -20
- package/dist/bin/pushary-transcripts.js +7 -9
- package/dist/bin/pushary-upgrade.js +17 -19
- package/dist/bin/pushary-wait.js +5 -5
- package/dist/bin/pushary.js +1 -1
- package/dist/{chunk-7LUFYRH4.js → chunk-2D7BAOMY.js} +7 -7
- package/dist/{chunk-3ZUTNTZA.js → chunk-2ZTL3PGN.js} +1 -1
- package/dist/{chunk-EPFDN2ZT.js → chunk-32RMQO5Z.js} +1 -1
- package/dist/{chunk-EZIEXHYM.js → chunk-3AJIK5AO.js} +5 -2
- package/dist/{chunk-IPHOUBTU.js → chunk-4PX4QK2Z.js} +1 -1
- package/dist/{chunk-UW4LWAWY.js → chunk-4RF52LSU.js} +8 -8
- package/dist/{chunk-UOTSWS5N.js → chunk-67YNQ3QA.js} +43 -98
- package/dist/{chunk-G4TL4YWH.js → chunk-6AEM5RCS.js} +1 -1
- package/dist/{chunk-G24SEVCI.js → chunk-6VANQN5Q.js} +3 -7
- package/dist/{chunk-CKOLDI47.js → chunk-BDI2MXTT.js} +2 -2
- package/dist/{chunk-YKLCWWEI.js → chunk-BMANRGJQ.js} +1 -1
- package/dist/{chunk-2XUPP4WM.js → chunk-CUEZMPLJ.js} +1 -1
- package/dist/{chunk-A4R6BZCK.js → chunk-D62EONG3.js} +1 -1
- package/dist/{chunk-ZDAT5KMU.js → chunk-D6PRC3YQ.js} +1 -1
- package/dist/{chunk-MOY5X6HJ.js → chunk-DLLAWCQB.js} +1 -1
- package/dist/{chunk-DSTLA2TC.js → chunk-GOPIMNVC.js} +1 -1
- package/dist/{chunk-CH6DTGQR.js → chunk-HBHEX3JQ.js} +3 -3
- package/dist/{chunk-DNVDKHQD.js → chunk-HCMM3BOW.js} +226 -58
- package/dist/{chunk-76XICHYT.js → chunk-HGUZOUB2.js} +4 -4
- package/dist/{chunk-E3NF5CL2.js → chunk-HQIVR7MM.js} +6 -3
- package/dist/{chunk-JDFB3YKG.js → chunk-I6GZX3FT.js} +3 -3
- package/dist/{chunk-3OXHYPZG.js → chunk-IM2A5H33.js} +4 -1
- package/dist/{chunk-V27AHID3.js → chunk-IVQMNLSA.js} +3 -14
- package/dist/{chunk-4LL6LG5X.js → chunk-KAVDAZ7A.js} +43 -1
- package/dist/chunk-KBITFQST.js +6 -0
- package/dist/{chunk-AMZJ3CKW.js → chunk-KI4PA7MQ.js} +1 -1
- package/dist/{chunk-IAEXPTXA.js → chunk-N4VNLISN.js} +2 -2
- package/dist/{chunk-VX3BWMC5.js → chunk-OEKFD5BC.js} +1 -1
- package/dist/{chunk-QF4RI5CD.js → chunk-OI3DJA7N.js} +1 -1
- package/dist/{chunk-WB2C7VPF.js → chunk-OW6AZDY2.js} +3 -3
- package/dist/{chunk-4XXUHWIK.js → chunk-QHWXUNMN.js} +1 -1
- package/dist/{chunk-M7WWEFG6.js → chunk-QQGNFHIK.js} +2 -2
- package/dist/{chunk-YJAQRKH5.js → chunk-RLXVW4AM.js} +1 -1
- package/dist/{chunk-GUVCYYDK.js → chunk-S5CMLR35.js} +94 -15
- package/dist/{chunk-EUAQ4YAN.js → chunk-UCS65VVR.js} +1 -1
- package/dist/{chunk-WM5XMCID.js → chunk-VOSGZ6PH.js} +4 -4
- package/dist/{chunk-QUE76J4H.js → chunk-VTO3TNIB.js} +1 -1
- package/dist/{chunk-6FAHPGCZ.js → chunk-WDKHZRAS.js} +183 -25
- package/dist/{chunk-5GLPYGKS.js → chunk-WRDLHR2F.js} +2 -2
- package/dist/{chunk-RVSEGFPD.js → chunk-XLOELLAS.js} +9 -4
- package/dist/chunk-XS33QBJA.js +112 -0
- package/dist/{chunk-FQUV5KTM.js → chunk-Z2UWFEJW.js} +8 -8
- package/dist/src/index.d.ts +8 -1
- package/dist/src/index.js +11 -12
- package/package.json +1 -1
- package/dist/chunk-BC3VCZ3E.js +0 -86
- package/dist/chunk-RER3FRTD.js +0 -265
- package/dist/chunk-X7YWD6IS.js +0 -44
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
describeIdleWindow,
|
|
9
9
|
startProcessOwnership,
|
|
10
10
|
withSpawnProcessOwnership
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-QQGNFHIK.js";
|
|
12
12
|
import {
|
|
13
13
|
isDeferAnswer
|
|
14
14
|
} from "../chunk-YHG74UFF.js";
|
|
@@ -17,70 +17,73 @@ import {
|
|
|
17
17
|
loadSessionKey,
|
|
18
18
|
registerTranscript,
|
|
19
19
|
registeredTranscriptEnabled
|
|
20
|
-
} from "../chunk-
|
|
21
|
-
import "../chunk-
|
|
22
|
-
import "../chunk-
|
|
23
|
-
import "../chunk-
|
|
24
|
-
import "../chunk-
|
|
25
|
-
import "../chunk-
|
|
20
|
+
} from "../chunk-4RF52LSU.js";
|
|
21
|
+
import "../chunk-BMANRGJQ.js";
|
|
22
|
+
import "../chunk-VOSGZ6PH.js";
|
|
23
|
+
import "../chunk-2ZTL3PGN.js";
|
|
24
|
+
import "../chunk-CUEZMPLJ.js";
|
|
25
|
+
import "../chunk-HBHEX3JQ.js";
|
|
26
26
|
import {
|
|
27
27
|
ensureDaemonRunning
|
|
28
|
-
} from "../chunk-
|
|
29
|
-
import "../chunk-
|
|
30
|
-
import "../chunk-
|
|
31
|
-
import "../chunk-
|
|
28
|
+
} from "../chunk-XLOELLAS.js";
|
|
29
|
+
import "../chunk-2D7BAOMY.js";
|
|
30
|
+
import "../chunk-GOPIMNVC.js";
|
|
31
|
+
import "../chunk-3AJIK5AO.js";
|
|
32
32
|
import {
|
|
33
33
|
encryptRecord
|
|
34
|
-
} from "../chunk-
|
|
34
|
+
} from "../chunk-4PX4QK2Z.js";
|
|
35
35
|
import "../chunk-EQRS3SGM.js";
|
|
36
36
|
import {
|
|
37
37
|
transcriptsEnabled
|
|
38
|
-
} from "../chunk-
|
|
38
|
+
} from "../chunk-OI3DJA7N.js";
|
|
39
39
|
import {
|
|
40
40
|
needsShell,
|
|
41
41
|
spawnClaude
|
|
42
42
|
} from "../chunk-XHKBHWLX.js";
|
|
43
43
|
import "../chunk-L4ZCFMWW.js";
|
|
44
44
|
import {
|
|
45
|
+
DEFAULT_SESSION,
|
|
45
46
|
fetchModeState,
|
|
46
47
|
getPolicy,
|
|
47
|
-
phoneDrivenEnv,
|
|
48
|
-
repoKeyFor,
|
|
49
|
-
reportEvent
|
|
50
|
-
} from "../chunk-DNVDKHQD.js";
|
|
51
|
-
import {
|
|
52
|
-
DEFAULT_SESSION,
|
|
53
|
-
askUser,
|
|
54
|
-
cancelQuestion,
|
|
55
48
|
markPendingCommandDelivered,
|
|
56
49
|
markPendingCommandFailed,
|
|
50
|
+
phoneDrivenEnv,
|
|
57
51
|
readPendingCommand,
|
|
58
52
|
readPendingCommandById,
|
|
59
53
|
removePendingCommand,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
54
|
+
repoKeyFor,
|
|
55
|
+
reportEvent,
|
|
56
|
+
savePendingCommand
|
|
57
|
+
} from "../chunk-HCMM3BOW.js";
|
|
58
|
+
import {
|
|
59
|
+
DECISION_STOP_REASON,
|
|
60
|
+
askUser,
|
|
61
|
+
cancelQuestion,
|
|
62
|
+
isDecisionStopped,
|
|
63
|
+
isLocalQuestionHandoff,
|
|
64
|
+
nextLongPollMs,
|
|
65
|
+
waitForAnswer,
|
|
66
|
+
withdrawQuestion
|
|
67
|
+
} from "../chunk-XS33QBJA.js";
|
|
63
68
|
import {
|
|
64
69
|
UNNAMED_ACTION,
|
|
65
70
|
deriveToolTarget,
|
|
66
71
|
describeToolCall,
|
|
67
72
|
scopePathFor
|
|
68
|
-
} from "../chunk-
|
|
69
|
-
import "../chunk-
|
|
73
|
+
} from "../chunk-BDI2MXTT.js";
|
|
74
|
+
import "../chunk-IVQMNLSA.js";
|
|
70
75
|
import {
|
|
71
76
|
getMachineId
|
|
72
|
-
} from "../chunk-
|
|
73
|
-
import "../chunk-
|
|
77
|
+
} from "../chunk-N4VNLISN.js";
|
|
78
|
+
import "../chunk-OW6AZDY2.js";
|
|
74
79
|
import "../chunk-GMXKITVA.js";
|
|
75
80
|
import "../chunk-DINDL2CF.js";
|
|
76
|
-
import "../chunk-
|
|
77
|
-
import "../chunk-BC3VCZ3E.js";
|
|
81
|
+
import "../chunk-S5CMLR35.js";
|
|
78
82
|
import "../chunk-EYRGBYZG.js";
|
|
79
83
|
import "../chunk-SAF6HGAA.js";
|
|
80
84
|
import "../chunk-7QLSKOSU.js";
|
|
81
85
|
import "../chunk-KZERVKTD.js";
|
|
82
|
-
import "../chunk-
|
|
83
|
-
import "../chunk-4LL6LG5X.js";
|
|
86
|
+
import "../chunk-KAVDAZ7A.js";
|
|
84
87
|
import {
|
|
85
88
|
getApiKey,
|
|
86
89
|
getBaseUrl
|
|
@@ -89,7 +92,7 @@ import {
|
|
|
89
92
|
KILL_REASON,
|
|
90
93
|
redactSecrets,
|
|
91
94
|
resolveGate
|
|
92
|
-
} from "../chunk-
|
|
95
|
+
} from "../chunk-WDKHZRAS.js";
|
|
93
96
|
|
|
94
97
|
// src/wrapper/localPassthrough.ts
|
|
95
98
|
var SIGNAL_NUMBERS = {
|
|
@@ -448,7 +451,11 @@ var createRemoteApprover = (deps) => {
|
|
|
448
451
|
const waitForPhone = async (entry, correlationId, windowMs) => {
|
|
449
452
|
const deadline = now() + windowMs;
|
|
450
453
|
while (now() < deadline && !entry.controller.signal.aborted) {
|
|
451
|
-
const
|
|
454
|
+
const hold = nextLongPollMs(deadline, now());
|
|
455
|
+
if (hold === null) {
|
|
456
|
+
await sleep(Math.min(500, Math.max(0, deadline - now())));
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
452
459
|
const abortPromise = new Promise((resolve) => {
|
|
453
460
|
entry.controller.signal.addEventListener("abort", () => resolve({ answered: false, aborted: true }), {
|
|
454
461
|
once: true
|
|
@@ -457,18 +464,15 @@ var createRemoteApprover = (deps) => {
|
|
|
457
464
|
let outcome;
|
|
458
465
|
try {
|
|
459
466
|
outcome = await Promise.race([
|
|
460
|
-
waitForAnswer2(deps.apiKey, correlationId,
|
|
467
|
+
waitForAnswer2(deps.apiKey, correlationId, hold, AbortSignal.any([entry.controller.signal, AbortSignal.timeout(Math.max(1, deadline - now()))])),
|
|
461
468
|
abortPromise
|
|
462
469
|
]);
|
|
463
470
|
} catch {
|
|
464
|
-
|
|
465
|
-
await sleep(1e3);
|
|
466
|
-
continue;
|
|
471
|
+
return { answered: false, status: "unavailable" };
|
|
467
472
|
}
|
|
468
|
-
if ("aborted" in outcome) return { answered: false };
|
|
469
|
-
if (outcome.answered) return outcome;
|
|
470
|
-
|
|
471
|
-
await sleep(500);
|
|
473
|
+
if ("aborted" in outcome) return { answered: false, status: "cancelled" };
|
|
474
|
+
if (isDecisionStopped(outcome) || outcome.answered) return outcome;
|
|
475
|
+
await sleep(Math.min(500, Math.max(0, deadline - now())));
|
|
472
476
|
}
|
|
473
477
|
return { answered: false };
|
|
474
478
|
};
|
|
@@ -524,23 +528,31 @@ var createRemoteApprover = (deps) => {
|
|
|
524
528
|
repoKey: repoKeyFor(deps.cwd)
|
|
525
529
|
});
|
|
526
530
|
} catch {
|
|
527
|
-
return
|
|
531
|
+
return deny("Pushary could not create a verifiable approval. Retry the action.");
|
|
528
532
|
}
|
|
533
|
+
if (isDecisionStopped(question)) return deny(DECISION_STOP_REASON);
|
|
529
534
|
entry.correlationId = question.correlationId;
|
|
530
|
-
|
|
531
|
-
|
|
535
|
+
const localHandoff = isLocalQuestionHandoff(question);
|
|
536
|
+
let answer = question.answered ? { ...question, answered: true } : localHandoff ? { answered: false } : await waitForPhone(entry, question.correlationId, windowFor(policy));
|
|
537
|
+
if (isDecisionStopped(answer) || entry.controller.signal.aborted) return deny(DECISION_STOP_REASON);
|
|
538
|
+
if (!answer.answered) {
|
|
539
|
+
answer = await withdrawQuestion(deps.apiKey, question.correlationId, { cancelQuestion: cancelQuestion2, waitForAnswer: waitForAnswer2 });
|
|
540
|
+
entry.correlationId = void 0;
|
|
541
|
+
if (isDecisionStopped(answer)) return deny(DECISION_STOP_REASON);
|
|
542
|
+
}
|
|
532
543
|
answered = answer.answered;
|
|
533
544
|
if (answer.answered) {
|
|
534
545
|
if (isDeferAnswer(answer.value)) return deny("Deferred \u2014 handle it on the machine");
|
|
535
546
|
return answer.value === "yes" ? allow(input) : deny("Denied from your phone");
|
|
536
547
|
}
|
|
548
|
+
if (localHandoff) return deny("This remote session has no local approval UI. Continue in an interactive session or choose a mode that permits remote approval.");
|
|
537
549
|
return applyTimeout(policy, input);
|
|
538
550
|
} catch {
|
|
539
551
|
return deny("Approval unavailable; denied by default");
|
|
540
552
|
} finally {
|
|
541
553
|
if (options?.signal) options.signal.removeEventListener("abort", outerAbort);
|
|
542
554
|
if (entry.correlationId && !answered && !tornDown) {
|
|
543
|
-
|
|
555
|
+
await cancelQuestion2(deps.apiKey, entry.correlationId).catch(() => {
|
|
544
556
|
});
|
|
545
557
|
}
|
|
546
558
|
pending.delete(entry);
|
|
@@ -6,12 +6,13 @@ import {
|
|
|
6
6
|
resolveHermesPython,
|
|
7
7
|
runHermesPythonScript
|
|
8
8
|
} from "../chunk-N6FAXQDD.js";
|
|
9
|
+
import "../chunk-KBITFQST.js";
|
|
9
10
|
import {
|
|
10
11
|
removeInstructionBlock,
|
|
11
12
|
shortenHome,
|
|
12
13
|
unregisterPluginLocation,
|
|
13
14
|
vscodeSettingsTargets
|
|
14
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-6VANQN5Q.js";
|
|
15
16
|
import {
|
|
16
17
|
OPENCODE_PLUGIN_SIBLING,
|
|
17
18
|
OPENCODE_PLUGIN_SIBLING_CONTENTS,
|
|
@@ -21,39 +22,39 @@ import {
|
|
|
21
22
|
openCodePluginDir,
|
|
22
23
|
openCodePluginFile,
|
|
23
24
|
removeOpenCodeMcpServer
|
|
24
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-HQIVR7MM.js";
|
|
25
26
|
import {
|
|
26
27
|
isClaudeMcpSnapshot,
|
|
27
28
|
removeClaudeMcpServers,
|
|
28
29
|
removePusharySettings,
|
|
29
30
|
restoreClaudeMcpServer
|
|
30
|
-
} from "../chunk-
|
|
31
|
+
} from "../chunk-HGUZOUB2.js";
|
|
31
32
|
import {
|
|
32
33
|
hookOwnerOf,
|
|
33
34
|
isHookTakeoverReceipt,
|
|
34
35
|
restoreHookTakeover,
|
|
35
36
|
restoreMcpServer
|
|
36
|
-
} from "../chunk-
|
|
37
|
-
import "../chunk-
|
|
38
|
-
import "../chunk-
|
|
37
|
+
} from "../chunk-VOSGZ6PH.js";
|
|
38
|
+
import "../chunk-2ZTL3PGN.js";
|
|
39
|
+
import "../chunk-CUEZMPLJ.js";
|
|
39
40
|
import {
|
|
40
41
|
pusharyHookExecutable
|
|
41
|
-
} from "../chunk-
|
|
42
|
+
} from "../chunk-HBHEX3JQ.js";
|
|
42
43
|
import {
|
|
43
44
|
disableDaemonService
|
|
44
|
-
} from "../chunk-
|
|
45
|
+
} from "../chunk-XLOELLAS.js";
|
|
45
46
|
import {
|
|
46
47
|
removeGeminiSettings
|
|
47
|
-
} from "../chunk-
|
|
48
|
-
import "../chunk-
|
|
49
|
-
import "../chunk-
|
|
48
|
+
} from "../chunk-2D7BAOMY.js";
|
|
49
|
+
import "../chunk-GOPIMNVC.js";
|
|
50
|
+
import "../chunk-3AJIK5AO.js";
|
|
50
51
|
import "../chunk-XHKBHWLX.js";
|
|
51
52
|
import {
|
|
52
53
|
execNpm
|
|
53
54
|
} from "../chunk-L4ZCFMWW.js";
|
|
54
|
-
import "../chunk-
|
|
55
|
-
import "../chunk-
|
|
56
|
-
import "../chunk-
|
|
55
|
+
import "../chunk-BDI2MXTT.js";
|
|
56
|
+
import "../chunk-IVQMNLSA.js";
|
|
57
|
+
import "../chunk-N4VNLISN.js";
|
|
57
58
|
import {
|
|
58
59
|
claudeJson,
|
|
59
60
|
claudeMcpReceipt,
|
|
@@ -79,28 +80,28 @@ import {
|
|
|
79
80
|
restoreCodexHookTrust,
|
|
80
81
|
vscodePluginDir,
|
|
81
82
|
vscodePluginMcp
|
|
82
|
-
} from "../chunk-
|
|
83
|
+
} from "../chunk-OW6AZDY2.js";
|
|
83
84
|
import {
|
|
84
85
|
exitOnHelpFlag
|
|
85
|
-
} from "../chunk-
|
|
86
|
-
import "../chunk-
|
|
86
|
+
} from "../chunk-DLLAWCQB.js";
|
|
87
|
+
import "../chunk-D6PRC3YQ.js";
|
|
87
88
|
import {
|
|
88
89
|
rejectUnknownFlags
|
|
89
90
|
} from "../chunk-GMXKITVA.js";
|
|
90
91
|
import "../chunk-DINDL2CF.js";
|
|
91
92
|
import {
|
|
92
93
|
removeClaudeAlias
|
|
93
|
-
} from "../chunk-
|
|
94
|
+
} from "../chunk-S5CMLR35.js";
|
|
94
95
|
import "../chunk-7QLSKOSU.js";
|
|
95
96
|
import {
|
|
96
97
|
EXIT
|
|
97
98
|
} from "../chunk-KZERVKTD.js";
|
|
98
|
-
import "../chunk-
|
|
99
|
+
import "../chunk-KAVDAZ7A.js";
|
|
99
100
|
import "../chunk-2UMNXADU.js";
|
|
100
101
|
import {
|
|
101
102
|
CURSOR_GATE_EVENTS,
|
|
102
103
|
HOOK_LOCATOR_BINARY
|
|
103
|
-
} from "../chunk-
|
|
104
|
+
} from "../chunk-WDKHZRAS.js";
|
|
104
105
|
|
|
105
106
|
// bin/pushary-clean.ts
|
|
106
107
|
import { existsSync, readFileSync, copyFileSync, readdirSync } from "fs";
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "../chunk-
|
|
2
|
+
import "../chunk-IM2A5H33.js";
|
|
3
3
|
import {
|
|
4
4
|
LiveTranscriptRelay,
|
|
5
5
|
liveSessionSleep,
|
|
6
6
|
postLiveSession,
|
|
7
7
|
postLiveSessionUntilAccepted,
|
|
8
8
|
startLiveSessionHeartbeat
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-QHWXUNMN.js";
|
|
10
10
|
import {
|
|
11
11
|
SESSION_IDLE_TIMEOUT_MS,
|
|
12
12
|
describeIdleWindow,
|
|
13
13
|
idleDeadlinePassed,
|
|
14
14
|
startProcessOwnership,
|
|
15
15
|
withSpawnProcessOwnership
|
|
16
|
-
} from "../chunk-
|
|
17
|
-
import "../chunk-
|
|
16
|
+
} from "../chunk-QQGNFHIK.js";
|
|
17
|
+
import "../chunk-4PX4QK2Z.js";
|
|
18
18
|
import "../chunk-EQRS3SGM.js";
|
|
19
19
|
import {
|
|
20
20
|
transcriptsEnabled
|
|
21
|
-
} from "../chunk-
|
|
21
|
+
} from "../chunk-OI3DJA7N.js";
|
|
22
22
|
import {
|
|
23
23
|
spawnClaude
|
|
24
24
|
} from "../chunk-XHKBHWLX.js";
|
|
@@ -27,40 +27,42 @@ import {
|
|
|
27
27
|
} from "../chunk-L4ZCFMWW.js";
|
|
28
28
|
import {
|
|
29
29
|
getMachineId
|
|
30
|
-
} from "../chunk-
|
|
31
|
-
import "../chunk-
|
|
32
|
-
import "../chunk-
|
|
33
|
-
import
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
} from "../chunk-N4VNLISN.js";
|
|
31
|
+
import "../chunk-OW6AZDY2.js";
|
|
32
|
+
import "../chunk-S5CMLR35.js";
|
|
33
|
+
import {
|
|
34
|
+
callMcpTool
|
|
35
|
+
} from "../chunk-EYRGBYZG.js";
|
|
36
|
+
import "../chunk-SAF6HGAA.js";
|
|
37
|
+
import "../chunk-7QLSKOSU.js";
|
|
38
|
+
import "../chunk-KZERVKTD.js";
|
|
39
|
+
import "../chunk-KAVDAZ7A.js";
|
|
36
40
|
import {
|
|
37
41
|
getApiKey,
|
|
38
42
|
getBaseUrl
|
|
39
43
|
} from "../chunk-2UMNXADU.js";
|
|
40
|
-
import
|
|
44
|
+
import {
|
|
45
|
+
parseAgentQuestion,
|
|
46
|
+
parseAgentQuestionAnswers
|
|
47
|
+
} from "../chunk-WDKHZRAS.js";
|
|
41
48
|
|
|
42
49
|
// bin/pushary-codex-bridge.ts
|
|
43
50
|
import { existsSync } from "fs";
|
|
44
51
|
|
|
45
52
|
// src/codex-bridge.ts
|
|
53
|
+
import { randomUUID } from "crypto";
|
|
46
54
|
import { spawn } from "child_process";
|
|
47
55
|
import { basename } from "path";
|
|
48
56
|
var MAX_RPC_LINE = 1024 * 1024;
|
|
49
57
|
var STDERR_TAIL_LIMIT = 2e3;
|
|
50
58
|
var FAILURE_MESSAGE_MAX = 240;
|
|
51
59
|
var MAX_PENDING_RPC = 8;
|
|
60
|
+
var LOCAL_QUESTION_UNAVAILABLE = "Pushary handed this question to the current client, but this Codex bridge has no local question UI. Continue in an interactive Codex session, or choose a Pushary mode that permits remote questions.";
|
|
52
61
|
var MAX_TRANSCRIPT_TEXT = 32 * 1024;
|
|
53
62
|
var MAX_MESSAGE_BUFFERS = 16;
|
|
54
63
|
var JsonRpcClient = class {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
notifications = /* @__PURE__ */ new Set();
|
|
58
|
-
nextId = 1;
|
|
59
|
-
buffer = "";
|
|
60
|
-
closed = false;
|
|
61
|
-
stderrTail = "";
|
|
62
|
-
failure = null;
|
|
63
|
-
constructor(command, cwd, timeoutMs) {
|
|
64
|
+
constructor(command, cwd, timeoutMs, bridgeOptions) {
|
|
65
|
+
this.bridgeOptions = bridgeOptions;
|
|
64
66
|
const options = { cwd, env: process.env, stdio: ["pipe", "pipe", "pipe"] };
|
|
65
67
|
this.child = process.platform === "win32" ? spawnClaude(command.command, command.args ?? [], options) : spawn(command.command, command.args ?? [], options);
|
|
66
68
|
this.child.stdout?.setEncoding("utf8");
|
|
@@ -71,6 +73,15 @@ var JsonRpcClient = class {
|
|
|
71
73
|
this.child.once("exit", (code, signal) => this.fail(new Error(this.exitMessage(code, signal))));
|
|
72
74
|
this.timeoutMs = timeoutMs;
|
|
73
75
|
}
|
|
76
|
+
child;
|
|
77
|
+
pending = /* @__PURE__ */ new Map();
|
|
78
|
+
notifications = /* @__PURE__ */ new Set();
|
|
79
|
+
serverRequests = /* @__PURE__ */ new Map();
|
|
80
|
+
nextId = 1;
|
|
81
|
+
buffer = "";
|
|
82
|
+
closed = false;
|
|
83
|
+
stderrTail = "";
|
|
84
|
+
failure = null;
|
|
74
85
|
keepStderrTail(chunk) {
|
|
75
86
|
this.stderrTail = (this.stderrTail + chunk).slice(-STDERR_TAIL_LIMIT);
|
|
76
87
|
}
|
|
@@ -109,6 +120,8 @@ var JsonRpcClient = class {
|
|
|
109
120
|
async close() {
|
|
110
121
|
if (this.closed) return;
|
|
111
122
|
this.closed = true;
|
|
123
|
+
for (const request of this.serverRequests.values()) request.abort();
|
|
124
|
+
this.serverRequests.clear();
|
|
112
125
|
this.child.stdin?.end();
|
|
113
126
|
if (this.child.exitCode != null) return;
|
|
114
127
|
await Promise.race([
|
|
@@ -147,8 +160,28 @@ var JsonRpcClient = class {
|
|
|
147
160
|
} catch {
|
|
148
161
|
return;
|
|
149
162
|
}
|
|
150
|
-
if (
|
|
151
|
-
const
|
|
163
|
+
if (message.id !== void 0 && message.method === "item/tool/requestUserInput") {
|
|
164
|
+
const id = message.id;
|
|
165
|
+
if (this.serverRequests.has(id)) return;
|
|
166
|
+
if (this.serverRequests.size >= MAX_PENDING_RPC) {
|
|
167
|
+
this.write({ id, error: { code: -32e3, message: "Too many pending user questions" } });
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const controller = new AbortController();
|
|
171
|
+
this.serverRequests.set(id, controller);
|
|
172
|
+
const signal = AbortSignal.any([controller.signal, this.bridgeOptions.signal]);
|
|
173
|
+
void answerCodexQuestions(this.bridgeOptions, message.params ?? {}, signal).then(
|
|
174
|
+
(result) => {
|
|
175
|
+
if (!signal.aborted && !this.closed) this.write({ id, result });
|
|
176
|
+
},
|
|
177
|
+
(error) => {
|
|
178
|
+
if (!signal.aborted && !this.closed) this.write({ id, error: { code: -32e3, message: error instanceof Error && error.message === LOCAL_QUESTION_UNAVAILABLE ? LOCAL_QUESTION_UNAVAILABLE : "No user answer was received through Pushary" } });
|
|
179
|
+
}
|
|
180
|
+
).finally(() => this.serverRequests.delete(id));
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (message.id !== void 0 && message.method) {
|
|
184
|
+
const result = message.method === "item/commandExecution/requestApproval" || message.method === "item/fileChange/requestApproval" ? { decision: "decline" } : message.method === "applyPatchApproval" || message.method === "execCommandApproval" ? { decision: { denied: { rejection: "No interactive Codex client is attached" } } } : null;
|
|
152
185
|
this.write(result ? { id: message.id, result } : { id: message.id, error: { code: -32601, message: "Unsupported server request" } });
|
|
153
186
|
return;
|
|
154
187
|
}
|
|
@@ -161,6 +194,10 @@ var JsonRpcClient = class {
|
|
|
161
194
|
else pending.resolve(message.result);
|
|
162
195
|
return;
|
|
163
196
|
}
|
|
197
|
+
if (message.method === "serverRequest/resolved") {
|
|
198
|
+
const id = message.params?.requestId;
|
|
199
|
+
if (typeof id === "number" || typeof id === "string") this.serverRequests.get(id)?.abort();
|
|
200
|
+
}
|
|
164
201
|
if (message.method) {
|
|
165
202
|
for (const listener of this.notifications) listener(message);
|
|
166
203
|
}
|
|
@@ -169,6 +206,8 @@ var JsonRpcClient = class {
|
|
|
169
206
|
if (this.closed) return;
|
|
170
207
|
this.closed = true;
|
|
171
208
|
this.failure = error;
|
|
209
|
+
for (const request of this.serverRequests.values()) request.abort();
|
|
210
|
+
this.serverRequests.clear();
|
|
172
211
|
this.rejectPending(error);
|
|
173
212
|
if (this.child.exitCode == null) this.child.kill();
|
|
174
213
|
}
|
|
@@ -188,11 +227,67 @@ var rpcTurnId = (result) => {
|
|
|
188
227
|
const response = object(result);
|
|
189
228
|
return string(object(response?.turn)?.id) ?? string(response?.turnId);
|
|
190
229
|
};
|
|
230
|
+
var answerCodexQuestions = async (options, params, signal) => {
|
|
231
|
+
if (!Array.isArray(params.questions) || !params.questions.length || params.questions.length > 3) throw new Error("Invalid questions");
|
|
232
|
+
const answers = /* @__PURE__ */ Object.create(null);
|
|
233
|
+
const deadline = Date.now() + Math.min(12e4, typeof params.autoResolutionMs === "number" ? Math.max(0, params.autoResolutionMs) : 12e4);
|
|
234
|
+
for (const raw of params.questions) {
|
|
235
|
+
if (signal.aborted || Date.now() >= deadline) throw new Error("Question expired");
|
|
236
|
+
const question = object(raw);
|
|
237
|
+
const id = string(question?.id);
|
|
238
|
+
const prompt = string(question?.question);
|
|
239
|
+
if (!id || !prompt || id in answers || question?.isSecret === true) throw new Error("Unsupported question");
|
|
240
|
+
const labels = Array.isArray(question?.options) ? question.options.map((option) => string(object(option)?.label)).filter((label) => !!label) : [];
|
|
241
|
+
const structured = labels.length >= 2 ? parseAgentQuestion({ ...question, multiSelect: false, allowOther: question?.isOther === true }) : void 0;
|
|
242
|
+
let correlationId = null;
|
|
243
|
+
let settled = false;
|
|
244
|
+
const call = (name, args, timeoutMs, waitSignal = signal) => callMcpTool(options.apiKey, name, args, { baseUrl: options.baseUrl, signal: waitSignal, timeoutMs, maxRetries: 1 });
|
|
245
|
+
try {
|
|
246
|
+
signal.throwIfAborted();
|
|
247
|
+
if (Date.now() >= deadline) throw new Error("Question expired");
|
|
248
|
+
let result = await call("ask_user", {
|
|
249
|
+
requestId: randomUUID(),
|
|
250
|
+
question: prompt,
|
|
251
|
+
type: labels.length >= 2 ? "select" : "input",
|
|
252
|
+
...labels.length >= 2 ? { options: labels } : {},
|
|
253
|
+
...structured ? { questions: [structured] } : {},
|
|
254
|
+
context: string(question?.header),
|
|
255
|
+
agentName: `Codex - ${basename(options.cwd)}`,
|
|
256
|
+
sessionId: params.threadId,
|
|
257
|
+
machineId: options.machineId,
|
|
258
|
+
toolName: "request_user_input",
|
|
259
|
+
wait: false,
|
|
260
|
+
waitEndsAt: new Date(deadline).toISOString()
|
|
261
|
+
}, Math.min(1e4, deadline - Date.now()));
|
|
262
|
+
correlationId = string(result.correlationId);
|
|
263
|
+
while (!result.answered) {
|
|
264
|
+
if (result.status === "terminal" || result.status === "notified" || result.suppressed || result.mode === "terminal_only" || result.mode === "notify_only") throw new Error(LOCAL_QUESTION_UNAVAILABLE);
|
|
265
|
+
if (!correlationId || result.handoffAction === "stop" || result.noDevices || result.status && result.status !== "pending") throw new Error("Question unavailable");
|
|
266
|
+
const remaining = deadline - Date.now();
|
|
267
|
+
if (remaining <= 0) throw new Error("Question expired");
|
|
268
|
+
result = await call("wait_for_answer", { correlationId, timeoutMs: Math.min(25e3, remaining) }, Math.min(27e3, remaining));
|
|
269
|
+
if (!result.answered) await liveSessionSleep(100, signal);
|
|
270
|
+
}
|
|
271
|
+
if (signal.aborted || Date.now() >= deadline) throw new Error("Question expired");
|
|
272
|
+
settled = true;
|
|
273
|
+
const rawValue = string(result.value);
|
|
274
|
+
const value = rawValue && structured ? (parseAgentQuestionAnswers([structured], rawValue) ?? parseAgentQuestionAnswers([structured], JSON.stringify({ [prompt]: rawValue })))?.[prompt] : rawValue;
|
|
275
|
+
if (!value || value === "defer" || labels.length && question?.isOther !== true && !labels.includes(value)) throw new Error("Invalid answer");
|
|
276
|
+
answers[id] = { answers: [value] };
|
|
277
|
+
} finally {
|
|
278
|
+
if (correlationId && !settled) {
|
|
279
|
+
await call("cancel_question", { correlationId }, 3e3, AbortSignal.timeout(3e3)).catch(() => {
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return { answers };
|
|
285
|
+
};
|
|
191
286
|
var runCodexBridge = async (options) => {
|
|
192
287
|
const timeoutMs = options.requestTimeoutMs ?? 1e4;
|
|
193
288
|
const now = options.now ?? Date.now;
|
|
194
289
|
const idleTimeoutMs = options.idleTimeoutMs ?? SESSION_IDLE_TIMEOUT_MS;
|
|
195
|
-
const rpc = new JsonRpcClient(options.appServer, options.cwd, timeoutMs);
|
|
290
|
+
const rpc = new JsonRpcClient(options.appServer, options.cwd, timeoutMs, options);
|
|
196
291
|
let threadId = options.resumeThreadId ?? null;
|
|
197
292
|
let activeTurnId = null;
|
|
198
293
|
let lastCompletedTurnId = null;
|
|
@@ -249,7 +344,7 @@ var runCodexBridge = async (options) => {
|
|
|
249
344
|
try {
|
|
250
345
|
await rpc.request("initialize", {
|
|
251
346
|
clientInfo: { name: "pushary", title: "Pushary", version: "1" },
|
|
252
|
-
capabilities: { experimentalApi:
|
|
347
|
+
capabilities: { experimentalApi: true, requestAttestation: false }
|
|
253
348
|
});
|
|
254
349
|
rpc.notify("initialized");
|
|
255
350
|
const thread = options.resumeThreadId ? await rpc.request("thread/resume", { threadId: options.resumeThreadId, cwd: options.cwd, excludeTurns: true }) : await rpc.request("thread/start", { cwd: options.cwd, model: options.model ?? null });
|