osborn 0.9.239 → 0.9.240

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.
@@ -63,6 +63,21 @@ export declare function runClaudeAuthFlow(callbacks: ClaudeAuthCallbacks): {
63
63
  handle: ClaudeAuthHandle;
64
64
  done: Promise<void>;
65
65
  };
66
+ /**
67
+ * Re-deliver the current in-flight auth prompt to a frontend that has just
68
+ * (re)subscribed. WHY THIS EXISTS: ensureClaudeAuth runs inside the
69
+ * ParticipantConnected ("User joined") handler and publishes claude_auth_*
70
+ * over the LiveKit reliable data channel — but that fires ~5-6s BEFORE the
71
+ * browser's data channel actually finishes subscribing (observed: auth_url at
72
+ * :01, TrackSubscribed at :07). LiveKit reliable data is NOT buffered for a
73
+ * peer that hasn't subscribed yet, so a no-auth user's one-shot "Connect
74
+ * Claude" prompt is published to nobody and the modal never appears. Calling
75
+ * this on TrackSubscribed (data channel confirmed up) re-delivers the exact
76
+ * cached state. No-op (returns false) when no flow is in-flight — i.e. the
77
+ * user is already authenticated — so it costs nothing on the common path.
78
+ * Idempotent on the frontend (re-setting the same auth status is harmless).
79
+ */
80
+ export declare function replayInFlightAuth(send: (type: string, payload: unknown) => void): boolean;
66
81
  /**
67
82
  * Ensure Claude is authenticated before proceeding.
68
83
  *
@@ -485,6 +485,36 @@ export function runClaudeAuthFlow(callbacks) {
485
485
  return { handle, done };
486
486
  }
487
487
  let inFlightAuth = null;
488
+ /**
489
+ * Re-deliver the current in-flight auth prompt to a frontend that has just
490
+ * (re)subscribed. WHY THIS EXISTS: ensureClaudeAuth runs inside the
491
+ * ParticipantConnected ("User joined") handler and publishes claude_auth_*
492
+ * over the LiveKit reliable data channel — but that fires ~5-6s BEFORE the
493
+ * browser's data channel actually finishes subscribing (observed: auth_url at
494
+ * :01, TrackSubscribed at :07). LiveKit reliable data is NOT buffered for a
495
+ * peer that hasn't subscribed yet, so a no-auth user's one-shot "Connect
496
+ * Claude" prompt is published to nobody and the modal never appears. Calling
497
+ * this on TrackSubscribed (data channel confirmed up) re-delivers the exact
498
+ * cached state. No-op (returns false) when no flow is in-flight — i.e. the
499
+ * user is already authenticated — so it costs nothing on the common path.
500
+ * Idempotent on the frontend (re-setting the same auth status is harmless).
501
+ */
502
+ export function replayInFlightAuth(send) {
503
+ if (!inFlightAuth)
504
+ return false;
505
+ send('claude_auth_required', {
506
+ message: 'Claude authentication required. A login URL will appear shortly.',
507
+ });
508
+ if (inFlightAuth.lastUrl) {
509
+ send('claude_auth_url', { url: inFlightAuth.lastUrl });
510
+ }
511
+ if (inFlightAuth.lastStatus === 'waiting_code') {
512
+ send('claude_auth_waiting_code', {
513
+ message: 'Paste the authentication code from the browser.',
514
+ });
515
+ }
516
+ return true;
517
+ }
488
518
  /**
489
519
  * Ensure Claude is authenticated before proceeding.
490
520
  *
package/dist/index.js CHANGED
@@ -38,7 +38,7 @@ import { cleanupHousekeeping } from './housekeeping.js';
38
38
  import { createSTT, createTTS } from './voice-io.js';
39
39
  import { createClaudeLLM, NAMED_AGENTS, applyTurbo } from './claude-llm.js';
40
40
  import { clearPipelineFastBrainSession, prewarmBM25Index } from './pipeline-fastbrain.js';
41
- import { ensureClaudeAuth, applyAuthFallback } from './claude-auth.js';
41
+ import { ensureClaudeAuth, applyAuthFallback, replayInFlightAuth } from './claude-auth.js';
42
42
  import { createSmitheryProxy, destroySmitheryProxy, parseSmitheryUrl, isSmitheryUrl, SmitheryAuthorizationError } from './smithery-proxy.js';
43
43
  import { DIRECT_MODE_PROMPT } from './prompts.js';
44
44
  import { MCP_CATALOG } from './config.js';
@@ -4035,6 +4035,20 @@ async function main() {
4035
4035
  room.on(RoomEvent.TrackSubscribed, (track, publication, participant) => {
4036
4036
  try {
4037
4037
  console.log(`📥 [ROOM-TRACK-SUBSCRIBED] participant=${participant?.identity} kind=${track?.kind} source=${publication?.source} sid=${publication?.sid} t=${new Date().toISOString()}`);
4038
+ // Auth-prompt race fix: the "Connect Claude" prompt is published in the
4039
+ // ParticipantConnected handler ~5-6s before the browser's data channel
4040
+ // finishes subscribing, so a no-auth user never receives it (reliable
4041
+ // data isn't buffered for a not-yet-subscribed peer) and the modal never
4042
+ // shows. TrackSubscribed means this participant's WebRTC transport (incl.
4043
+ // data channel) is up — re-deliver any pending auth prompt now. No-op
4044
+ // when already authenticated. Covers BOTH resume and new-conversation
4045
+ // paths (both dispatch ensureClaudeAuth in the same participant handler).
4046
+ const pid = participant?.identity;
4047
+ if (typeof pid === 'string' && pid.startsWith('user-')) {
4048
+ const replayed = replayInFlightAuth((type, payload) => sendToFrontend({ type, ...payload }));
4049
+ if (replayed)
4050
+ console.log(`🔑 Re-delivered pending Claude auth prompt to ${pid} on TrackSubscribed`);
4051
+ }
4038
4052
  }
4039
4053
  catch { }
4040
4054
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "osborn",
3
- "version": "0.9.239",
3
+ "version": "0.9.240",
4
4
  "description": "Voice AI coding assistant - local agent that connects to Osborn frontend",
5
5
  "type": "module",
6
6
  "bin": {