@1presence/bridge 0.80.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/README.md +2 -0
- package/dist/claude.js +49 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,6 +51,8 @@ Conversations are stateful — the bridge maps each 1Presence conversation to a
|
|
|
51
51
|
|
|
52
52
|
Your OAuth tokens and vault data stay server-side — nothing sensitive is stored locally beyond the auth token.
|
|
53
53
|
|
|
54
|
+
On startup the bridge makes one request to the public npm registry (`registry.npmjs.org`) to check for a newer version, and self-updates via `npx` when one exists. The request carries no account data — it is the same anonymous lookup `npm view` performs — and if the registry is unreachable the bridge starts normally on the version you have. Beyond that check, the bridge talks only to the 1Presence gateway and your local `claude` install.
|
|
55
|
+
|
|
54
56
|
## Model
|
|
55
57
|
|
|
56
58
|
**Every start** the bridge asks which Claude model to use — the choice is held in memory for that run only and nothing is written to disk, so restarting always asks again. Pick "Use Claude Code default" to defer to your local Claude Code default, or pin one of the latest models per family: `claude-opus-5`, `claude-fable-5`, `claude-sonnet-5`, `claude-haiku-4-5`. If the prompt times out it auto-selects "Use Claude Code default", which tracks whatever model Claude Code serves for your plan.
|
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)
|