@1presence/bridge 0.78.0 → 0.79.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.
Files changed (2) hide show
  1. package/dist/claude.js +45 -15
  2. package/package.json +1 -1
package/dist/claude.js CHANGED
@@ -117,6 +117,21 @@ function joinErrorDetail(...parts) {
117
117
  const SDK_STDERR_ERROR_RE = /\b(error|exception|fail(?:ed|ure)?|invalid|unauthor|forbidden|refus|denied|40[0-9]|429|5\d\d|overloaded|rate.?limit)\b/i;
118
118
  const REMOTE_MCP_SERVER_NAME = '1presence';
119
119
  const MCP_SESSION_EXPIRED_RE = /session not found or expired|Error POSTing to endpoint \(HTTP 404\)/i;
120
+ const MCP_TRANSPORT_DEAD_RE = /SSE (?:stream|error)|not connected|connection (?:closed|error|reset|refused|dropped)|dropped connection|socket hang up|ECONNRESET|ECONNREFUSED|ETIMEDOUT|EPIPE|fetch failed|terminated|transport (?:closed|error)|request timed out|-32001|\(HTTP 50\d\)/i;
121
+ const OUTBOUND_NETWORK_TOOLS = new Set([
122
+ 'mcp__1presence__web_fetch',
123
+ 'mcp__1presence__web_search',
124
+ ]);
125
+ export function shouldReconnectRemoteMcp(args) {
126
+ const { toolName, isError, text } = args;
127
+ if (MCP_SESSION_EXPIRED_RE.test(text))
128
+ return true;
129
+ if (!isError || !toolName.startsWith('mcp__1presence__'))
130
+ return false;
131
+ if (OUTBOUND_NETWORK_TOOLS.has(toolName))
132
+ return false;
133
+ return MCP_TRANSPORT_DEAD_RE.test(text);
134
+ }
120
135
  function toolResultText(content) {
121
136
  if (typeof content === 'string')
122
137
  return content;
@@ -361,22 +376,29 @@ export function spawnClaude(params) {
361
376
  process.stderr.write('\n');
362
377
  }
363
378
  }
364
- if ((verbose || debug) && type === 'user') {
379
+ if (type === 'user') {
365
380
  const msg = event['message'];
366
381
  const content = msg?.['content'];
367
382
  if (Array.isArray(content)) {
368
383
  for (const block of content) {
369
- if (block['type'] === 'tool_result') {
370
- const id = block['tool_use_id'] ?? '';
371
- const out = block['content'];
372
- if (debug) {
373
- const name = toolNames.get(id) ?? id ?? 'result';
374
- const errFlag = block['is_error'] ? ' [error]' : '';
375
- debugBlock(`result ← ${name}${errFlag}`, SECTION_COLORS.result, formatPayload(out));
376
- }
377
- else {
378
- process.stderr.write(paint(SECTION_COLORS.result, `[bridge:verbose] ─── output ${id} ───\n${formatPayload(out)}\n[bridge:verbose] ─── end output ───`) + '\n');
379
- }
384
+ if (block['type'] !== 'tool_result')
385
+ continue;
386
+ const id = block['tool_use_id'] ?? '';
387
+ const out = block['content'];
388
+ const name = toolNames.get(id) ?? id ?? 'result';
389
+ if (block['is_error'] && !verbose && !debug) {
390
+ const detail = toolResultText(out).replace(/\s+/g, ' ').trim();
391
+ const shown = detail.length > 400 ? `${detail.slice(0, 400)}…` : detail;
392
+ process.stderr.write(paint(SECTION_COLORS.result, `[bridge] tool error ← ${name}: ${shown || 'no detail'}`) + '\n');
393
+ }
394
+ if (!verbose && !debug)
395
+ continue;
396
+ if (debug) {
397
+ const errFlag = block['is_error'] ? ' [error]' : '';
398
+ debugBlock(`result ← ${name}${errFlag}`, SECTION_COLORS.result, formatPayload(out));
399
+ }
400
+ else {
401
+ process.stderr.write(paint(SECTION_COLORS.result, `[bridge:verbose] ─── output ${id} ───\n${formatPayload(out)}\n[bridge:verbose] ─── end output ───`) + '\n');
380
402
  }
381
403
  }
382
404
  }
@@ -477,7 +499,7 @@ export function spawnClaude(params) {
477
499
  return;
478
500
  mcpReconnecting = true;
479
501
  lastMcpReconnectAt = now;
480
- process.stderr.write(paint(SECTION_COLORS.result, '[bridge] remote MCP session expired — reconnecting and retrying') + '\n');
502
+ process.stderr.write(paint(SECTION_COLORS.result, '[bridge] remote MCP connection lost — reconnecting and retrying') + '\n');
481
503
  onNotice?.('Reconnecting to 1Presence tools…');
482
504
  void q.reconnectMcpServer(REMOTE_MCP_SERVER_NAME)
483
505
  .then(() => process.stderr.write(paint(SECTION_COLORS.result, '[bridge] remote MCP reconnected') + '\n'))
@@ -540,8 +562,16 @@ export function spawnClaude(params) {
540
562
  const content = um.message?.['content'];
541
563
  if (Array.isArray(content)) {
542
564
  for (const block of content) {
543
- if (block && typeof block === 'object' && block['type'] === 'tool_result'
544
- && MCP_SESSION_EXPIRED_RE.test(toolResultText(block['content']))) {
565
+ if (!block || typeof block !== 'object')
566
+ continue;
567
+ const b = block;
568
+ if (b['type'] !== 'tool_result')
569
+ continue;
570
+ if (shouldReconnectRemoteMcp({
571
+ toolName: toolNames.get(b['tool_use_id'] ?? '') ?? '',
572
+ isError: b['is_error'] === true,
573
+ text: toolResultText(b['content']),
574
+ })) {
545
575
  maybeReconnectRemoteMcp(q);
546
576
  break;
547
577
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1presence/bridge",
3
- "version": "0.78.0",
3
+ "version": "0.79.0",
4
4
  "description": "Run 1Presence on your Mac and use your Claude.ai Pro subscription from any device",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",