@1presence/bridge 0.96.0 → 0.97.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 CHANGED
@@ -245,7 +245,9 @@ export function makeGatedPromptStream(messages) {
245
245
  };
246
246
  }
247
247
  export function spawnClaude(params) {
248
- const { conversationId, presenceSessionId, text, uid, history, vaultFileOpen, clientCapabilities, syncedFolders, model: perTurnModel, onEvent, onDone, onError, onNotice } = params;
248
+ const { conversationId, presenceSessionId, chatSessionId, text, uid, history, vaultFileOpen, clientCapabilities, syncedFolders, model: perTurnModel, onEvent, onDone, onError, onNotice } = params;
249
+ const sessionTag = ` · session ${chatSessionId ?? conversationId}`;
250
+ const errLine = (text) => paint(SECTION_COLORS.error, `${text}${sessionTag}`);
249
251
  const systemPromptPath = join(tmpdir(), `agent-${uid}.md`);
250
252
  const mcpConfigPath = join(tmpdir(), `mcp-${uid}.json`);
251
253
  if (verbose) {
@@ -270,7 +272,7 @@ export function spawnClaude(params) {
270
272
  debugBlock('user · this turn', SECTION_COLORS.user, text);
271
273
  }
272
274
  else {
273
- process.stderr.write(`[bridge] session ${presenceSessionId}\n`);
275
+ process.stderr.write(`[bridge] session ${chatSessionId ?? '(none)'} turn ${conversationId}\n`);
274
276
  }
275
277
  void vaultFileOpen;
276
278
  void clientCapabilities;
@@ -392,7 +394,7 @@ export function spawnClaude(params) {
392
394
  if (blockText && TOOL_CALL_XML_RE.test(blockText)) {
393
395
  const cleaned = stripToolCallXml(blockText);
394
396
  if (cleaned !== blockText) {
395
- process.stderr.write(paint(SECTION_COLORS.error, `[bridge] suppressed confabulated tool-call XML in assistant text`) + '\n');
397
+ process.stderr.write(errLine(`[bridge] suppressed confabulated tool-call XML in assistant text`) + '\n');
396
398
  block['text'] = cleaned;
397
399
  blockText = cleaned;
398
400
  }
@@ -406,7 +408,7 @@ export function spawnClaude(params) {
406
408
  apiErrorText = blockText.trim();
407
409
  if (isAuthFailure)
408
410
  sawAuthFailure = true;
409
- process.stderr.write(paint(SECTION_COLORS.error, `[bridge] ${blockText.replace(/\n+/g, ' ')}`) + '\n');
411
+ process.stderr.write(errLine(`[bridge] ${blockText.replace(/\n+/g, ' ')}`) + '\n');
410
412
  return false;
411
413
  }
412
414
  producedRealOutput = true;
@@ -437,7 +439,7 @@ export function spawnClaude(params) {
437
439
  if (block['is_error']) {
438
440
  const detail = toolResultText(out).replace(/\s+/g, ' ').trim();
439
441
  const shown = detail.length > 400 ? `${detail.slice(0, 400)}…` : detail;
440
- process.stderr.write(paint(SECTION_COLORS.error, `[bridge] ✗ tool error ← ${name}: ${shown || 'no detail'}`) + '\n');
442
+ process.stderr.write(errLine(`[bridge] ✗ tool error ← ${name}: ${shown || 'no detail'}`) + '\n');
441
443
  }
442
444
  if (!verbose && !debug)
443
445
  continue;
@@ -464,7 +466,7 @@ export function spawnClaude(params) {
464
466
  const detail = joinErrorDetail(event['result'], event['errors']);
465
467
  apiErrorText = joinErrorDetail(apiErrorText, detail) || apiErrorText;
466
468
  const subtype = event['subtype'] ? ` subtype=${event['subtype']}` : '';
467
- process.stderr.write(paint(SECTION_COLORS.error, `[bridge] result error${status != null ? ` (${status})` : ''}${subtype}: ${apiErrorText || 'unknown'}`) + '\n');
469
+ process.stderr.write(errLine(`[bridge] result error${status != null ? ` (${status})` : ''}${subtype}: ${apiErrorText || 'unknown'}`) + '\n');
468
470
  if (!detail) {
469
471
  let raw;
470
472
  try {
@@ -473,7 +475,7 @@ export function spawnClaude(params) {
473
475
  catch {
474
476
  raw = String(event);
475
477
  }
476
- process.stderr.write(paint(SECTION_COLORS.error, `[bridge] result raw: ${raw.slice(0, 2000)}`) + '\n');
478
+ process.stderr.write(errLine(`[bridge] result raw: ${raw.slice(0, 2000)}`) + '\n');
477
479
  }
478
480
  }
479
481
  }
@@ -553,11 +555,11 @@ export function spawnClaude(params) {
553
555
  return;
554
556
  mcpReconnecting = true;
555
557
  lastMcpReconnectAt = now;
556
- process.stderr.write(paint(SECTION_COLORS.error, '[bridge] remote MCP connection lost — reconnecting and retrying') + '\n');
558
+ process.stderr.write(errLine('[bridge] remote MCP connection lost — reconnecting and retrying') + '\n');
557
559
  onNotice?.('Reconnecting to 1Presence tools…');
558
560
  void q.reconnectMcpServer(REMOTE_MCP_SERVER_NAME)
559
561
  .then(() => process.stderr.write(paint(SECTION_COLORS.result, '[bridge] remote MCP reconnected') + '\n'))
560
- .catch((err) => process.stderr.write(paint(SECTION_COLORS.error, `[bridge] remote MCP reconnect failed: ${err.message}`) + '\n'))
562
+ .catch((err) => process.stderr.write(errLine(`[bridge] remote MCP reconnect failed: ${err.message}`) + '\n'))
561
563
  .finally(() => { mcpReconnecting = false; });
562
564
  };
563
565
  try {
@@ -590,9 +592,9 @@ export function spawnClaude(params) {
590
592
  detail = ` — ${remote.error.replace(/\s+/g, ' ').trim().slice(0, 300)}`;
591
593
  }
592
594
  catch { }
593
- process.stderr.write(paint(SECTION_COLORS.error, `[bridge] FATAL no 1Presence tools this turn (${surface.status}) — ending the turn rather than answering blind${detail}`) + '\n');
595
+ process.stderr.write(errLine(`[bridge] FATAL no 1Presence tools this turn (${surface.status}) — ending the turn rather than answering blind${detail}`) + '\n');
594
596
  if (surface.status === 'needs-auth' && !detail) {
595
- process.stderr.write(paint(SECTION_COLORS.error, '[bridge] ↳ the server asked for OAuth, which Local Mode does not use — this is NOT a stale local token, and restarting will not clear it. The gateway is rejecting this account\'s token on /mcp.') + '\n');
597
+ process.stderr.write(errLine('[bridge] ↳ the server asked for OAuth, which Local Mode does not use — this is NOT a stale local token, and restarting will not clear it. The gateway is rejecting this account\'s token on /mcp.') + '\n');
596
598
  }
597
599
  active.delete(conversationId);
598
600
  clearTimeout(inputReleaseTimer);
@@ -604,7 +606,7 @@ export function spawnClaude(params) {
604
606
  }
605
607
  else if (subtype === 'api_retry') {
606
608
  const r = m;
607
- process.stderr.write(paint(SECTION_COLORS.error, `[bridge] api retry ${r.attempt ?? '?'}/${r.max_retries ?? '?'}${r.error_status != null ? ` (${r.error_status})` : ''}: ${r.error ?? 'unknown'}${r.retry_delay_ms != null ? `, next in ${r.retry_delay_ms}ms` : ''}`) + '\n');
609
+ process.stderr.write(errLine(`[bridge] api retry ${r.attempt ?? '?'}/${r.max_retries ?? '?'}${r.error_status != null ? ` (${r.error_status})` : ''}: ${r.error ?? 'unknown'}${r.retry_delay_ms != null ? `, next in ${r.retry_delay_ms}ms` : ''}`) + '\n');
608
610
  const attempt = r.attempt ?? 0;
609
611
  if (attempt >= 2 || (r.retry_delay_ms ?? 0) >= 2000) {
610
612
  onNotice?.(formatRetryNotice(attempt, r.max_retries ?? 0, r.retry_delay_ms));
@@ -629,7 +631,7 @@ export function spawnClaude(params) {
629
631
  const full = joinErrorDetail(`API Error: ${am.error}`, msgText, rid);
630
632
  if (!apiErrorText || /^API Error: \w+$/.test(apiErrorText))
631
633
  apiErrorText = full;
632
- process.stderr.write(paint(SECTION_COLORS.error, `[bridge] assistant error: ${joinErrorDetail(am.error, msgText, rid)}`) + '\n');
634
+ process.stderr.write(errLine(`[bridge] assistant error: ${joinErrorDetail(am.error, msgText, rid)}`) + '\n');
633
635
  break;
634
636
  }
635
637
  const event = { type: 'assistant', message: am.message, error: am.error };
@@ -652,7 +654,7 @@ export function spawnClaude(params) {
652
654
  const resultText = toolResultText(b['content']);
653
655
  if (b['is_error'] === true && isPermissionTransportFailure(resultText)) {
654
656
  const detail = resultText.replace(/\s+/g, ' ').trim().slice(0, 300);
655
- process.stderr.write(paint(SECTION_COLORS.error, `[bridge] FATAL permission transport lost — ending the turn rather than answering blind: ${detail}`) + '\n');
657
+ process.stderr.write(errLine(`[bridge] FATAL permission transport lost — ending the turn rather than answering blind: ${detail}`) + '\n');
656
658
  active.delete(conversationId);
657
659
  clearTimeout(inputReleaseTimer);
658
660
  input.release();
@@ -742,7 +744,7 @@ export function spawnClaude(params) {
742
744
  return;
743
745
  const message = err?.message ?? String(err);
744
746
  const stack = err?.stack;
745
- process.stderr.write(paint(SECTION_COLORS.error, `[bridge] query() threw: ${stack || message}`) + '\n');
747
+ process.stderr.write(errLine(`[bridge] query() threw: ${stack || message}`) + '\n');
746
748
  if (/40[13]\b|unauthor|invalid (api key|authentication)|please run \/login/i.test(message)) {
747
749
  sawAuthFailure = true;
748
750
  }
package/dist/index.js CHANGED
@@ -280,7 +280,7 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
280
280
  if (!isTokenValid(auth.token)) {
281
281
  const message = 'Authentication expired and refresh failed — please restart the bridge to sign in again.';
282
282
  stopTurnTimer();
283
- console.error(paint(SECTION_COLORS.error, `[bridge] ${message} (${err.message})`));
283
+ console.error(paint(SECTION_COLORS.error, `[bridge] ${message} (${err.message}) · session ${sessionId ?? conversationId}`));
284
284
  if (currentWs?.readyState === WebSocket.OPEN) {
285
285
  currentWs.send(JSON.stringify({ type: 'error', conversationId, message }));
286
286
  }
@@ -294,7 +294,7 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
294
294
  catch (err) {
295
295
  const message = `System prompt refresh failed: ${err.message}`;
296
296
  stopTurnTimer();
297
- console.error(paint(SECTION_COLORS.error, `[${new Date().toLocaleTimeString()}] ✗ ${message}`));
297
+ console.error(paint(SECTION_COLORS.error, `[${new Date().toLocaleTimeString()}] ✗ ${message} · session ${sessionId ?? conversationId}`));
298
298
  if (currentWs?.readyState === WebSocket.OPEN) {
299
299
  currentWs.send(JSON.stringify({ type: 'error', conversationId, message }));
300
300
  }
@@ -352,6 +352,7 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
352
352
  spawnClaude({
353
353
  conversationId,
354
354
  presenceSessionId: claudePinnedSessionId,
355
+ chatSessionId: turnSessionId,
355
356
  text,
356
357
  uid: activeAuth.uid,
357
358
  history,
@@ -414,7 +415,7 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
414
415
  },
415
416
  onError: (message, usage, model) => {
416
417
  const elapsed = stopTurnTimer();
417
- console.error(paint(SECTION_COLORS.error, `[${new Date().toLocaleTimeString()}] ✗ ${message} (${formatElapsed(elapsed)})`));
418
+ console.error(paint(SECTION_COLORS.error, `[${new Date().toLocaleTimeString()}] ✗ ${message} (${formatElapsed(elapsed)}) · session ${turnSessionId}`));
418
419
  const mapped = toBridgeUsage(usage);
419
420
  if (currentWs?.readyState === WebSocket.OPEN) {
420
421
  currentWs.send(JSON.stringify({
@@ -555,7 +556,7 @@ function connect(auth, retryDelay = 1000) {
555
556
  startTurnTimer();
556
557
  handleMessage(conversationId, text, sessionId ?? null, hist, auth, vaultFileOpen, clientCapabilities, syncedFolders, agentSlug, model).catch((err) => {
557
558
  stopTurnTimer();
558
- console.error(paint(SECTION_COLORS.error, `[bridge] handleMessage error: ${err.message}`));
559
+ console.error(paint(SECTION_COLORS.error, `[bridge] handleMessage error: ${err.message} · session ${sessionId ?? conversationId}`));
559
560
  });
560
561
  });
561
562
  ws.on('close', (code) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1presence/bridge",
3
- "version": "0.96.0",
3
+ "version": "0.97.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",