@1presence/bridge 0.81.0 → 0.82.0
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/dist/claude.js +49 -5
- package/package.json +1 -1
package/dist/claude.js
CHANGED
|
@@ -123,6 +123,10 @@ const OUTBOUND_NETWORK_TOOLS = new Set([
|
|
|
123
123
|
'mcp__1presence__web_fetch',
|
|
124
124
|
'mcp__1presence__web_search',
|
|
125
125
|
]);
|
|
126
|
+
const PERMISSION_TRANSPORT_DEAD_RE = /Tool permission request failed/i;
|
|
127
|
+
export function isPermissionTransportFailure(text) {
|
|
128
|
+
return PERMISSION_TRANSPORT_DEAD_RE.test(text);
|
|
129
|
+
}
|
|
126
130
|
export function shouldReconnectRemoteMcp(args) {
|
|
127
131
|
const { toolName, isError, text } = args;
|
|
128
132
|
if (MCP_SESSION_EXPIRED_RE.test(text))
|
|
@@ -193,9 +197,26 @@ function buildPromptMessages(history) {
|
|
|
193
197
|
});
|
|
194
198
|
return out;
|
|
195
199
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
200
|
+
const INPUT_HOLD_MAX_MS = 20 * 60_000;
|
|
201
|
+
export function makeGatedPromptStream(messages) {
|
|
202
|
+
let open;
|
|
203
|
+
let released = false;
|
|
204
|
+
const gate = new Promise((resolve) => { open = resolve; });
|
|
205
|
+
async function* generate() {
|
|
206
|
+
for (const m of messages)
|
|
207
|
+
yield m;
|
|
208
|
+
await gate;
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
stream: generate(),
|
|
212
|
+
release() {
|
|
213
|
+
if (released)
|
|
214
|
+
return;
|
|
215
|
+
released = true;
|
|
216
|
+
open();
|
|
217
|
+
},
|
|
218
|
+
get isReleased() { return released; },
|
|
219
|
+
};
|
|
199
220
|
}
|
|
200
221
|
export function spawnClaude(params) {
|
|
201
222
|
const { conversationId, presenceSessionId, text, uid, history, vaultFileOpen, clientCapabilities, syncedFolders, model: perTurnModel, onEvent, onDone, onError, onNotice } = params;
|
|
@@ -497,6 +518,10 @@ export function spawnClaude(params) {
|
|
|
497
518
|
...(pinnedModel ? { model: pinnedModel } : {}),
|
|
498
519
|
};
|
|
499
520
|
const promptMessages = buildPromptMessages(history);
|
|
521
|
+
const input = makeGatedPromptStream(promptMessages);
|
|
522
|
+
abort.signal.addEventListener('abort', () => input.release(), { once: true });
|
|
523
|
+
const inputReleaseTimer = setTimeout(() => input.release(), INPUT_HOLD_MAX_MS);
|
|
524
|
+
inputReleaseTimer.unref?.();
|
|
500
525
|
let lastMcpReconnectAt = 0;
|
|
501
526
|
let mcpReconnecting = false;
|
|
502
527
|
const MCP_RECONNECT_THROTTLE_MS = 10_000;
|
|
@@ -514,7 +539,7 @@ export function spawnClaude(params) {
|
|
|
514
539
|
.finally(() => { mcpReconnecting = false; });
|
|
515
540
|
};
|
|
516
541
|
try {
|
|
517
|
-
const q = query({ prompt:
|
|
542
|
+
const q = query({ prompt: input.stream, options });
|
|
518
543
|
for await (const m of q) {
|
|
519
544
|
if (m.isReplay)
|
|
520
545
|
continue;
|
|
@@ -574,10 +599,21 @@ export function spawnClaude(params) {
|
|
|
574
599
|
const b = block;
|
|
575
600
|
if (b['type'] !== 'tool_result')
|
|
576
601
|
continue;
|
|
602
|
+
const resultText = toolResultText(b['content']);
|
|
603
|
+
if (b['is_error'] === true && isPermissionTransportFailure(resultText)) {
|
|
604
|
+
const detail = resultText.replace(/\s+/g, ' ').trim().slice(0, 300);
|
|
605
|
+
process.stderr.write(paint(SECTION_COLORS.error, `[bridge] FATAL permission transport lost — ending the turn rather than answering blind: ${detail}`) + '\n');
|
|
606
|
+
active.delete(conversationId);
|
|
607
|
+
clearTimeout(inputReleaseTimer);
|
|
608
|
+
input.release();
|
|
609
|
+
abort.abort();
|
|
610
|
+
onError('Local Mode lost its tool connection mid-turn, so nothing was read or changed. Please send that again.', usage, extractedModel);
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
577
613
|
if (shouldReconnectRemoteMcp({
|
|
578
614
|
toolName: toolNames.get(b['tool_use_id'] ?? '') ?? '',
|
|
579
615
|
isError: b['is_error'] === true,
|
|
580
|
-
text:
|
|
616
|
+
text: resultText,
|
|
581
617
|
})) {
|
|
582
618
|
maybeReconnectRemoteMcp(q);
|
|
583
619
|
break;
|
|
@@ -602,6 +638,10 @@ export function spawnClaude(params) {
|
|
|
602
638
|
};
|
|
603
639
|
if (handleEvent(event))
|
|
604
640
|
onEvent(event);
|
|
641
|
+
if (producedRealOutput) {
|
|
642
|
+
clearTimeout(inputReleaseTimer);
|
|
643
|
+
input.release();
|
|
644
|
+
}
|
|
605
645
|
break;
|
|
606
646
|
}
|
|
607
647
|
case 'auth_status': {
|
|
@@ -643,6 +683,8 @@ export function spawnClaude(params) {
|
|
|
643
683
|
}
|
|
644
684
|
catch (err) {
|
|
645
685
|
active.delete(conversationId);
|
|
686
|
+
clearTimeout(inputReleaseTimer);
|
|
687
|
+
input.release();
|
|
646
688
|
if (abort.signal.aborted)
|
|
647
689
|
return;
|
|
648
690
|
if (killedForViolation)
|
|
@@ -659,6 +701,8 @@ export function spawnClaude(params) {
|
|
|
659
701
|
return;
|
|
660
702
|
}
|
|
661
703
|
active.delete(conversationId);
|
|
704
|
+
clearTimeout(inputReleaseTimer);
|
|
705
|
+
input.release();
|
|
662
706
|
if (killedForViolation)
|
|
663
707
|
return;
|
|
664
708
|
if (abort.signal.aborted)
|