osborn 0.9.77 → 0.9.79

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/index.js +26 -11
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1169,20 +1169,26 @@ async function main() {
1169
1169
  console.log(`🎯 DIRECT MODE: ${directConfig.stt.provider} STT → Claude Agent SDK → ${directConfig.tts.provider} TTS`);
1170
1170
  console.log(' 🔥 Full coding capabilities!');
1171
1171
  }
1172
- // Determine room code. STABLE PER MACHINE: persisted to ~/.osborn/room-code
1173
- // (the volume on cloud machines) so process restarts don't rotate the room.
1174
- // Rotation raced any client that fetched /room-code just before a restart —
1175
- // observed 2026-07-28: tester joined osborn-bz2m8n while the rebooted agent
1176
- // created fnz7nz; the client sat on "Connecting..." forever. Idle-exit
1177
- // auto-stop/start cycles (0.9.73+) made this race common.
1172
+ // Determine room code. STABLE PER MACHINE, derived from identity we
1173
+ // already have: the Fly app name (one app per user). No new storage, no
1174
+ // rotation — the same user always lands in the same room, and the room
1175
+ // name itself binds to the machine identity. Rotation previously raced
1176
+ // any client that fetched /room-code just before a restart (observed
1177
+ // 2026-07-28: tester joined osborn-bz2m8n while the rebooted agent created
1178
+ // fnz7nz — stuck "Connecting..." forever; idle-exit stop/start cycles made
1179
+ // this common). Local/dev fallback: persist a generated code so restarts
1180
+ // stay stable there too.
1181
+ const identityCode = process.env.FLY_APP_NAME?.replace(/^osborn-/, '') || null;
1178
1182
  const roomCodeFile = join(homedir(), '.osborn', 'room-code');
1179
1183
  let persistedRoomCode = null;
1180
- try {
1181
- persistedRoomCode = readFileSync(roomCodeFile, 'utf8').trim() || null;
1184
+ if (!identityCode) {
1185
+ try {
1186
+ persistedRoomCode = readFileSync(roomCodeFile, 'utf8').trim() || null;
1187
+ }
1188
+ catch { /* first boot */ }
1182
1189
  }
1183
- catch { /* first boot */ }
1184
- const roomCode = cliArgs.roomCode || persistedRoomCode || generateRoomCode();
1185
- if (!cliArgs.roomCode && roomCode !== persistedRoomCode) {
1190
+ const roomCode = cliArgs.roomCode || identityCode || persistedRoomCode || generateRoomCode();
1191
+ if (!cliArgs.roomCode && !identityCode && roomCode !== persistedRoomCode) {
1186
1192
  try {
1187
1193
  mkdirSync(dirname(roomCodeFile), { recursive: true });
1188
1194
  writeFileSync(roomCodeFile, roomCode);
@@ -4789,6 +4795,15 @@ async function main() {
4789
4795
  }
4790
4796
  if (livekitState.status !== 'connected')
4791
4797
  return; // already out — no-op
4798
+ // Never abandon a user who is CURRENTLY in the room. Stale/racing
4799
+ // leave-room calls (a previous client's teardown landing after a new
4800
+ // client joined) were kicking the agent out mid-adopt, stranding the new
4801
+ // user on "Connecting..." (observed 2026-07-28). The alone-timer handles
4802
+ // the real departure when they actually leave.
4803
+ if (room.remoteParticipants.size > 0) {
4804
+ console.log(`🛑 /leave-room ignored (${reason}) — ${room.remoteParticipants.size} participant(s) still in room`);
4805
+ return;
4806
+ }
4792
4807
  intentionalLeave = true;
4793
4808
  console.log(`🚪 Leaving LiveKit room (${reason}) — stops connection-minute burn`);
4794
4809
  armIdleExitTimer(`explicit leave (${reason})`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "osborn",
3
- "version": "0.9.77",
3
+ "version": "0.9.79",
4
4
  "description": "Voice AI coding assistant - local agent that connects to Osborn frontend",
5
5
  "type": "module",
6
6
  "bin": {