opencharm 0.8.6 → 0.8.8

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/main.mjs CHANGED
@@ -997,7 +997,7 @@ function sendAdmin(socketPath, request) {
997
997
  }
998
998
  //#endregion
999
999
  //#region package.json
1000
- var version = "0.8.6";
1000
+ var version = "0.8.8";
1001
1001
  function channelToCube(value) {
1002
1002
  if (value < 48) return 0;
1003
1003
  if (value < 115) return 1;
@@ -3523,12 +3523,13 @@ var TurnController = class {
3523
3523
  signal
3524
3524
  });
3525
3525
  } finally {
3526
- asking = false;
3527
3526
  if (--this.#questions === 0) {
3527
+ asking = false;
3528
3528
  this.#questionsEnd = void 0;
3529
3529
  this.#endQuestions();
3530
+ clearTimeout(timer);
3531
+ if (!signal.aborted) timer = startClock();
3530
3532
  }
3531
- if (!signal.aborted) timer = startClock();
3532
3533
  }
3533
3534
  };
3534
3535
  const reply = this.#deps.agent.reply({
@@ -5055,7 +5056,7 @@ function formatIdentity(unit, version, commit) {
5055
5056
  let cached;
5056
5057
  function identity() {
5057
5058
  if (cached) return cached;
5058
- const commit = "4b349a7";
5059
+ const commit = "89e832a";
5059
5060
  cached = {
5060
5061
  version: `cli@${version}`,
5061
5062
  commit,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencharm",
3
- "version": "0.8.6",
3
+ "version": "0.8.8",
4
4
  "description": "An open-source body for the AI agent you already run: a face, a voice, one key. Claude Code, Codex, Gemini CLI, Hermes, OpenClaw or any ACP or OpenAI-compatible agent; on a small board, your Mac's notch or the browser.",
5
5
  "type": "module",
6
6
  "bin": {
Binary file
package/sim/sim.js CHANGED
@@ -51,6 +51,7 @@ const trace = {
51
51
  connected: false,
52
52
  micReady: false, // the microphone is open right now (only while the key is held)
53
53
  micOpens: 0, // how many times it was opened
54
+ micLatencyMs: null, // key-down to the first mic frame the core took, last hold (includes a 60 ms frame)
54
55
  };
55
56
  window.__charm = trace;
56
57
 
@@ -58,6 +59,8 @@ let ws;
58
59
  let wifiOn = true;
59
60
  let micOn = false;
60
61
  let keyHeld = false;
62
+ let keyDownAt = 0;
63
+ let firstFrame = false;
61
64
  let mic; // {stream, ctx} while the key is held; the microphone is closed otherwise
62
65
  let playCtx;
63
66
  let playAt = 0;
@@ -259,8 +262,12 @@ async function openMic() {
259
262
  opening.stream = await navigator.mediaDevices.getUserMedia({
260
263
  audio: {
261
264
  channelCount: 1,
262
- echoCancellation: true,
263
- noiseSuppression: true,
265
+ // No voice processing: the charm never plays while the mic runs (a hold stops its speech
266
+ // first), and on macOS it makes WebKit open the mic through Apple's voice-processing unit,
267
+ // which ducks other sound and is expected to start slower, cutting a first word.
268
+ echoCancellation: false,
269
+ noiseSuppression: false,
270
+ autoGainControl: false,
264
271
  },
265
272
  });
266
273
  await opening.ctx.audioWorklet.addModule("mic-worklet.js");
@@ -272,6 +279,13 @@ async function openMic() {
272
279
  const ptr = M._malloc(bytes.length);
273
280
  M.HEAPU8.set(bytes, ptr);
274
281
  M._sim_mic_pcm(ptr, data.length);
282
+ if (!firstFrame) {
283
+ firstFrame = true;
284
+ trace.micLatencyMs = Math.round(performance.now() - keyDownAt);
285
+ console.debug(
286
+ `OpenCharm emulator: first mic frame ${trace.micLatencyMs} ms after key-down`
287
+ );
288
+ }
275
289
  M._free(ptr);
276
290
  };
277
291
  if (fakeMic) {
@@ -309,6 +323,10 @@ window.charmKey = (down) => key(down);
309
323
  function key(down) {
310
324
  startPlayback();
311
325
  keyHeld = down;
326
+ if (down) {
327
+ keyDownAt = performance.now();
328
+ firstFrame = false;
329
+ }
312
330
  if (down) void openMic();
313
331
  else closeMic();
314
332
  keyEl.classList.toggle("down", down);