careervivid 2.1.36 → 2.1.38

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.
@@ -1 +1 @@
1
- {"version":3,"file":"interview.d.ts","sourceRoot":"","sources":["../../src/commands/interview.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAi1BpC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmG/D"}
1
+ {"version":3,"file":"interview.d.ts","sourceRoot":"","sources":["../../src/commands/interview.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAu2BpC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmG/D"}
@@ -51,7 +51,7 @@ const CLI_BILL_URL = process.env.CV_FUNCTIONS_URL
51
51
  const CLI_CONTEXT_URL = process.env.CV_FUNCTIONS_URL
52
52
  ? `${process.env.CV_FUNCTIONS_URL}/cliGetInterviewContext`
53
53
  : "https://us-west1-jastalk-firebase.cloudfunctions.net/cliGetInterviewContext";
54
- const LIVE_MODEL = "gemini-3.1-flash-live-preview";
54
+ const LIVE_MODEL = "gemini-live-2.5-flash-native-audio";
55
55
  const FEEDBACK_MODEL = "gemini-2.5-flash";
56
56
  const END_TOKEN = "<END_INTERVIEW>";
57
57
  const WRAP_WIDTH = 80;
@@ -410,6 +410,10 @@ async function runVoiceSession(opts) {
410
410
  // (outputBuf never contains END_TOKEN because chunkClean strips it, so the
411
411
  // turnComplete check on outputBuf would never fire without this flag.)
412
412
  let endTokenSeen = false;
413
+ // Track audio bytes sent to speaker this turn to calculate mute duration
414
+ // 24kHz, 16-bit mono = 48000 bytes/second of playback
415
+ const SPEAKER_BYTES_PER_SEC = RECV_SAMPLE_RATE * 2; // 48000
416
+ let pendingAudioBytes = 0;
413
417
  // ── Audio processes ──────────────────────────────────────────────────
414
418
  const micProc = startMic(soxPath);
415
419
  const speakerProc = startSpeaker(soxPath);
@@ -454,6 +458,7 @@ async function runVoiceSession(opts) {
454
458
  muteTimer = null;
455
459
  }
456
460
  const pcmBuf = Buffer.from(audioPart, "base64");
461
+ pendingAudioBytes += pcmBuf.length;
457
462
  speakerProc.stdin.write(pcmBuf);
458
463
  }
459
464
  // ── Output transcription (Vivid's words) — stream in real-time ──
@@ -535,15 +540,22 @@ async function runVoiceSession(opts) {
535
540
  inputBuf = "";
536
541
  }
537
542
  if (!ended) {
543
+ // Calculate exactly how long the buffered audio will take to play.
544
+ // Show "Listening..." and unmute the mic together when playback ends.
545
+ const playbackMs = Math.ceil((pendingAudioBytes / SPEAKER_BYTES_PER_SEC) * 1000);
546
+ const muteMs = Math.max(playbackMs, 800); // minimum 800ms floor
547
+ pendingAudioBytes = 0;
538
548
  muteTimer = setTimeout(() => {
539
549
  vividSpeaking = false;
540
550
  muteTimer = null;
551
+ // Show "Listening..." right as audio finishes playing
541
552
  if (!userSpeechLineActive) {
542
553
  process.stdout.write(chalk.green("\n ● Listening...\r"));
543
554
  }
544
- }, 800);
555
+ }, muteMs);
545
556
  }
546
557
  else {
558
+ pendingAudioBytes = 0;
547
559
  // Interview ended via END_TOKEN — cancel pending mute timer
548
560
  // so '● Listening...' never appears after the interview concludes
549
561
  if (muteTimer) {
@@ -554,10 +566,19 @@ async function runVoiceSession(opts) {
554
566
  }
555
567
  },
556
568
  onerror: (e) => {
557
- console.log(chalk.red(`\n Connection error: ${e.message ?? e}`));
569
+ const msg = e?.message ?? JSON.stringify(e) ?? "Unknown error";
570
+ console.log(chalk.red(`\n ❌ Live API connection error: ${msg}`));
571
+ console.log(chalk.dim(` Model: ${LIVE_MODEL} | Location: ${location}`));
572
+ ended = true;
573
+ },
574
+ onclose: (e) => {
575
+ if (!ended) {
576
+ const reason = e?.reason ?? e?.code ?? "unexpected close";
577
+ console.log(chalk.yellow(`\n ⚠️ Live API session closed unexpectedly: ${reason}`));
578
+ console.log(chalk.dim(` Model: ${LIVE_MODEL} | Location: ${location}`));
579
+ }
558
580
  ended = true;
559
581
  },
560
- onclose: () => { ended = true; },
561
582
  },
562
583
  config: {
563
584
  responseModalities: [Modality.AUDIO],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "careervivid",
3
- "version": "2.1.36",
3
+ "version": "2.1.38",
4
4
  "description": "Official CLI for CareerVivid — AI voice interviews, autonomous job applications, resume editing, and portfolio publishing from your terminal",
5
5
  "type": "module",
6
6
  "bin": {