osborn 0.8.34 → 0.8.35

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/index.js CHANGED
@@ -11,7 +11,13 @@ import { setMaxListeners } from 'node:events';
11
11
  setMaxListeners(50);
12
12
  import { createServer } from 'http';
13
13
  import { existsSync, readdirSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
14
- import { join } from 'node:path';
14
+ import { dirname, join } from 'node:path';
15
+ import { fileURLToPath } from 'node:url';
16
+ // Resolve __dirname for this ESM module so we can find sibling files (e.g.
17
+ // meeting-output.html) relative to the compiled JS location, NOT process.cwd().
18
+ // In production cwd is the user's workspace; the static file lives next to dist/index.js.
19
+ const __filename = fileURLToPath(import.meta.url);
20
+ const __dirname = dirname(__filename);
15
21
  import { createPatch } from 'diff';
16
22
  import { loadConfig, getMcpServers, getEnabledMcpServerNames, getVoiceMode, getRealtimeConfig, getDirectConfig, listAllClaudeSessions, getMostRecentSessionId, sessionExists, getSessionSummary, getConversationHistory, ensureSessionWorkspace, getSessionWorkspace, getMcpServerStatusList, buildMcpServersForKeys, listWorkspaceArtifacts } from './config.js';
17
23
  import { createSTT, createTTS, createRealtimeModelFromConfig, DIRECT_MODE_STT, DIRECT_MODE_TTS } from './voice-io.js';
@@ -200,15 +206,35 @@ function startApiServer(workingDir, port) {
200
206
  });
201
207
  return;
202
208
  }
203
- // GET /meeting-output — Output Media webpage for Recall.ai bot audio
209
+ // GET /meeting-output — Output Media webpage for Recall.ai bot audio.
210
+ //
211
+ // The file lives next to this compiled JS (copied by the build script from
212
+ // src/ to dist/). Resolve via __dirname rather than process.cwd() — in
213
+ // production cwd is the user's workspace, NOT the osborn package directory.
204
214
  if (req.method === 'GET' && url.pathname === '/meeting-output') {
205
- const htmlPath = join(process.cwd(), 'src', 'meeting-output.html');
206
- try {
207
- const html = readFileSync(htmlPath, 'utf-8');
215
+ // Try the package-relative path first (post-build location), then fall
216
+ // back to source path for `tsx src/index.ts` dev runs.
217
+ const candidates = [
218
+ join(__dirname, 'meeting-output.html'), // dist/ (production)
219
+ join(__dirname, '..', 'src', 'meeting-output.html'), // dev: dist/ → src/
220
+ join(__dirname, '..', 'meeting-output.html'), // tsx run from src/
221
+ ];
222
+ let html = null;
223
+ let foundPath = null;
224
+ for (const p of candidates) {
225
+ try {
226
+ html = readFileSync(p, 'utf-8');
227
+ foundPath = p;
228
+ break;
229
+ }
230
+ catch { }
231
+ }
232
+ if (html) {
208
233
  res.writeHead(200, { 'Content-Type': 'text/html' });
209
234
  res.end(html);
210
235
  }
211
- catch {
236
+ else {
237
+ console.warn(`[meeting-output] not found in any of: ${candidates.join(', ')}`);
212
238
  res.writeHead(404, { 'Content-Type': 'text/plain' });
213
239
  res.end('meeting-output.html not found');
214
240
  }
@@ -0,0 +1,32 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head><title>Osborn Meeting Output</title></head>
4
+ <body>
5
+ <script>
6
+ const botId = new URLSearchParams(window.location.search).get('bot_id') || 'unknown'
7
+
8
+ function connect() {
9
+ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
10
+ const ws = new WebSocket(`${protocol}//${window.location.host}/meeting-audio?bot_id=${botId}`)
11
+
12
+ ws.onmessage = async (event) => {
13
+ try {
14
+ const audioCtx = new (window.AudioContext || window.webkitAudioContext)()
15
+ const arrayBuffer = await event.data.arrayBuffer()
16
+ const audioBuffer = await audioCtx.decodeAudioData(arrayBuffer)
17
+ const source = audioCtx.createBufferSource()
18
+ source.buffer = audioBuffer
19
+ source.connect(audioCtx.destination)
20
+ source.start()
21
+ } catch (e) {
22
+ console.error('Audio playback error:', e)
23
+ }
24
+ }
25
+
26
+ ws.onclose = () => setTimeout(connect, 1000)
27
+ }
28
+
29
+ connect()
30
+ </script>
31
+ </body>
32
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "osborn",
3
- "version": "0.8.34",
3
+ "version": "0.8.35",
4
4
  "description": "Voice AI coding assistant - local agent that connects to Osborn frontend",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,7 +11,7 @@
11
11
  "dev:logged": "tsx scripts/dev-logged.ts",
12
12
  "review": "tsx scripts/review.ts",
13
13
  "start": "tsx src/index.ts",
14
- "build": "tsc && rm -rf dist/prompts && cp -r src/prompts dist/prompts",
14
+ "build": "tsc && rm -rf dist/prompts && cp -r src/prompts dist/prompts && cp src/meeting-output.html dist/",
15
15
  "room": "tsx src/index.ts --room",
16
16
  "prepublishOnly": "npm run build"
17
17
  },