opencharm 0.8.9 → 0.10.0

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.9";
1000
+ var version = "0.10.0";
1001
1001
  function channelToCube(value) {
1002
1002
  if (value < 48) return 0;
1003
1003
  if (value < 115) return 1;
@@ -5056,7 +5056,7 @@ function formatIdentity(unit, version, commit) {
5056
5056
  let cached;
5057
5057
  function identity() {
5058
5058
  if (cached) return cached;
5059
- const commit = "b4c1d9d";
5059
+ const commit = "f8ca2fc";
5060
5060
  cached = {
5061
5061
  version: `cli@${version}`,
5062
5062
  commit,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencharm",
3
- "version": "0.8.9",
3
+ "version": "0.10.0",
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": {
package/sim/charm_sim.js CHANGED
@@ -1,2 +1,2 @@
1
- async function createCharm(moduleArg={}){var Module=moduleArg;var ENVIRONMENT_IS_WEB=true;var ENVIRONMENT_IS_WORKER=false;var programArgs=[];var thisProgram="./this.program";var _scriptName=import.meta.url;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var ABORT=false;class EmscriptenEH{}class EmscriptenSjLj extends EmscriptenEH{}var runtimeInitialized=false;function getMemoryBuffer(){return wasmMemory.buffer}function updateMemoryViews(){if(HEAP8?.buffer?.resizable)return;var b=getMemoryBuffer();HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b)}function preRun(){var preRun=Module["preRun"];if(preRun){if(typeof preRun=="function")preRun=[preRun];onPreRuns.push(...preRun)}callRuntimeCallbacks(onPreRuns)}function initRuntime(){runtimeInitialized=true;wasmExports["r"]()}function postRun(){var postRun=Module["postRun"];if(postRun){if(typeof postRun=="function")postRun=[postRun];onPostRuns.push(...postRun)}callRuntimeCallbacks(onPostRuns)}function abort(what){Module["onAbort"]?.(what);what=`Aborted(${what})`;err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var wasmBinaryFile;function findWasmBinary(){if(Module["locateFile"]){return locateFile("charm_sim.wasm")}return new URL("charm_sim.wasm",import.meta.url).href}function getBinarySync(file){if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){var imports={a:wasmImports};return imports}async function createWasm(){function receiveInstance(instance){wasmExports=instance.exports;assignWasmExports(wasmExports);updateMemoryViews();return wasmExports}function receiveInstantiationResult(result){return receiveInstance(result["instance"])}var info=getWasmImports();var instantiateWasm=Module["instantiateWasm"];if(instantiateWasm){return new Promise(resolve=>{instantiateWasm(info,inst=>resolve(receiveInstance(inst)))})}wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var HEAP8;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var onPostRuns=[];var onPreRuns=[];var noExitRuntime=true;var HEAPU32;class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>2]=type}get_type(){return HEAPU32[this.ptr+4>>2]}set_destructor(destructor){HEAPU32[this.ptr+8>>2]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>2]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12]=caught}get_caught(){return HEAP8[this.ptr+12]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13]=rethrown}get_rethrown(){return HEAP8[this.ptr+13]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>2]}}var uncaughtExceptionCount=0;var __Unwind_RaiseException=ex=>{abort()};var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);uncaughtExceptionCount++;__Unwind_RaiseException(ptr)};var __abort_js=()=>abort("");var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var growMemory=size=>{var oldHeapSize=wasmMemory.buffer.byteLength;var pages=(size-oldHeapSize+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var HEAPU8;var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var _fd_close=fd=>52;var printCharBuffers=[null,[],[]];var UTF8Decoder=globalThis.TextDecoder&&new TextDecoder;var findStringEnd=(heapOrArray,idx,maxBytesToRead,ignoreNul)=>{var maxIdx=idx+maxBytesToRead;if(ignoreNul)return maxIdx;while(heapOrArray[idx]&&!(idx>=maxIdx))++idx;return idx};var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead,ignoreNul)=>{var endPtr=findStringEnd(heapOrArray,idx,maxBytesToRead,ignoreNul);if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx<endPtr){var u0=heapOrArray[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=heapOrArray[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=heapOrArray[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|heapOrArray[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}return str};var printChar=(stream,curr)=>{var buffer=printCharBuffers[stream];if(!curr||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer));buffer.length=0}else{buffer.push(curr)}};var UTF8ToString=(ptr,maxBytesToRead,ignoreNul)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead,ignoreNul):"";var _fd_write=(fd,iov,iovcnt,pnum)=>{var num=0;for(var i=0;i<iovcnt;i++){var ptr=HEAPU32[iov>>2];var len=HEAPU32[iov+4>>2];iov+=8;for(var j=0;j<len;j++){printChar(fd,HEAPU8[ptr+j])}num+=len}HEAPU32[pnum>>2]=num;return 0};var HEAPF32;var HEAP16;var HEAP32;var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.codePointAt(i);if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;i++}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var lengthBytesUTF8=str=>{var len=0;for(var i=0;i<str.length;++i){var c=str.charCodeAt(i);if(c<=127){len++}else if(c<=2047){len+=2}else if(c>=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};{if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(Module["print"])out=Module["print"];if(Module["printErr"])err=Module["printErr"];if(Module["arguments"])programArgs=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];var preInit=Module["preInit"];if(preInit){if(typeof preInit=="function")Module["preInit"]=preInit=[preInit];while(preInit.length>0){preInit.shift()()}}}Module["UTF8ToString"]=UTF8ToString;Module["stringToUTF8"]=stringToUTF8;Module["lengthBytesUTF8"]=lengthBytesUTF8;function js_panel(open,height){charmSim.panel(!!open,height)}function js_send_text(json){charmSim.sendText(UTF8ToString(json))}function js_send_binary(data,size){charmSim.sendBinary(HEAPU8.slice(data,data+size))}function js_mic(on){charmSim.mic(!!on)}function js_play_pcm(pcm,samples){charmSim.playPcm(HEAPF32.slice(pcm>>2,(pcm>>2)+samples))}function js_stop_audio(){charmSim.stopAudio()}function js_brightness(percent){charmSim.brightness(percent)}function js_store_get(key){var value=localStorage.getItem((globalThis.charmStore||"opencharm.")+UTF8ToString(key));if(value===null)return 0;var size=lengthBytesUTF8(value)+1;var ptr=_malloc(size);stringToUTF8(value,ptr,size);return ptr}function js_store_set(key,value){localStorage.setItem((globalThis.charmStore||"opencharm.")+UTF8ToString(key),UTF8ToString(value))}function js_store_erase(key){localStorage.removeItem((globalThis.charmStore||"opencharm.")+UTF8ToString(key))}function js_reconnect(){charmSim.reconnect()}var _sim_set_build,_sim_commit,_sim_panel_radius,_sim_init,_sim_frame,_sim_pin_key,_sim_pin_ready,_sim_frame_box,_sim_frame_dirty,_sim_tick,_sim_pointer,_sim_key,_sim_connected,_sim_disconnected,_sim_text,_sim_type,_sim_audio,_sim_mic_pcm,_sim_token,_sim_forget,_free,_malloc,memory,__indirect_function_table,wasmMemory;function assignWasmExports(wasmExports){_sim_set_build=Module["_sim_set_build"]=wasmExports["s"];_sim_commit=Module["_sim_commit"]=wasmExports["t"];_sim_panel_radius=Module["_sim_panel_radius"]=wasmExports["u"];_sim_init=Module["_sim_init"]=wasmExports["v"];_sim_frame=Module["_sim_frame"]=wasmExports["w"];_sim_pin_key=Module["_sim_pin_key"]=wasmExports["x"];_sim_pin_ready=Module["_sim_pin_ready"]=wasmExports["y"];_sim_frame_box=Module["_sim_frame_box"]=wasmExports["z"];_sim_frame_dirty=Module["_sim_frame_dirty"]=wasmExports["A"];_sim_tick=Module["_sim_tick"]=wasmExports["B"];_sim_pointer=Module["_sim_pointer"]=wasmExports["C"];_sim_key=Module["_sim_key"]=wasmExports["D"];_sim_connected=Module["_sim_connected"]=wasmExports["E"];_sim_disconnected=Module["_sim_disconnected"]=wasmExports["F"];_sim_text=Module["_sim_text"]=wasmExports["G"];_sim_type=Module["_sim_type"]=wasmExports["H"];_sim_audio=Module["_sim_audio"]=wasmExports["I"];_sim_mic_pcm=Module["_sim_mic_pcm"]=wasmExports["J"];_sim_token=Module["_sim_token"]=wasmExports["K"];_sim_forget=Module["_sim_forget"]=wasmExports["L"];_free=Module["_free"]=wasmExports["M"];_malloc=Module["_malloc"]=wasmExports["N"];memory=wasmMemory=wasmExports["q"];__indirect_function_table=wasmExports["__indirect_function_table"]}var wasmImports={o:___cxa_throw,l:__abort_js,j:_emscripten_resize_heap,k:_fd_close,b:_fd_write,e:js_brightness,a:js_mic,p:js_panel,g:js_play_pcm,m:js_reconnect,h:js_send_binary,i:js_send_text,f:js_stop_audio,n:js_store_erase,d:js_store_get,c:js_store_set};async function run(){preRun();var setStatus=Module["setStatus"];if(setStatus){setStatus("Running...");await new Promise(resolve=>setTimeout(resolve,1));setTimeout(setStatus,1,"")}if(ABORT)return;initRuntime();Module["onRuntimeInitialized"]?.();postRun()}var wasmExports;wasmExports=await createWasm();await run();
1
+ async function createCharm(moduleArg={}){var Module=moduleArg;var ENVIRONMENT_IS_WEB=true;var ENVIRONMENT_IS_WORKER=false;var programArgs=[];var thisProgram="./this.program";var _scriptName=import.meta.url;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var ABORT=false;class EmscriptenEH{}class EmscriptenSjLj extends EmscriptenEH{}var runtimeInitialized=false;function getMemoryBuffer(){return wasmMemory.buffer}function updateMemoryViews(){if(HEAP8?.buffer?.resizable)return;var b=getMemoryBuffer();HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b)}function preRun(){var preRun=Module["preRun"];if(preRun){if(typeof preRun=="function")preRun=[preRun];onPreRuns.push(...preRun)}callRuntimeCallbacks(onPreRuns)}function initRuntime(){runtimeInitialized=true;wasmExports["r"]()}function postRun(){var postRun=Module["postRun"];if(postRun){if(typeof postRun=="function")postRun=[postRun];onPostRuns.push(...postRun)}callRuntimeCallbacks(onPostRuns)}function abort(what){Module["onAbort"]?.(what);what=`Aborted(${what})`;err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var wasmBinaryFile;function findWasmBinary(){if(Module["locateFile"]){return locateFile("charm_sim.wasm")}return new URL("charm_sim.wasm",import.meta.url).href}function getBinarySync(file){if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){var imports={a:wasmImports};return imports}async function createWasm(){function receiveInstance(instance){wasmExports=instance.exports;assignWasmExports(wasmExports);updateMemoryViews();return wasmExports}function receiveInstantiationResult(result){return receiveInstance(result["instance"])}var info=getWasmImports();var instantiateWasm=Module["instantiateWasm"];if(instantiateWasm){return new Promise(resolve=>{instantiateWasm(info,inst=>resolve(receiveInstance(inst)))})}wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var HEAP8;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var onPostRuns=[];var onPreRuns=[];var noExitRuntime=true;var HEAPU32;class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>2]=type}get_type(){return HEAPU32[this.ptr+4>>2]}set_destructor(destructor){HEAPU32[this.ptr+8>>2]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>2]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12]=caught}get_caught(){return HEAP8[this.ptr+12]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13]=rethrown}get_rethrown(){return HEAP8[this.ptr+13]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>2]}}var uncaughtExceptionCount=0;var __Unwind_RaiseException=ex=>{abort()};var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);uncaughtExceptionCount++;__Unwind_RaiseException(ptr)};var __abort_js=()=>abort("");var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var growMemory=size=>{var oldHeapSize=wasmMemory.buffer.byteLength;var pages=(size-oldHeapSize+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var HEAPU8;var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var _fd_close=fd=>52;var printCharBuffers=[null,[],[]];var UTF8Decoder=globalThis.TextDecoder&&new TextDecoder;var findStringEnd=(heapOrArray,idx,maxBytesToRead,ignoreNul)=>{var maxIdx=idx+maxBytesToRead;if(ignoreNul)return maxIdx;while(heapOrArray[idx]&&!(idx>=maxIdx))++idx;return idx};var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead,ignoreNul)=>{var endPtr=findStringEnd(heapOrArray,idx,maxBytesToRead,ignoreNul);if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx<endPtr){var u0=heapOrArray[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=heapOrArray[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=heapOrArray[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|heapOrArray[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}return str};var printChar=(stream,curr)=>{var buffer=printCharBuffers[stream];if(!curr||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer));buffer.length=0}else{buffer.push(curr)}};var UTF8ToString=(ptr,maxBytesToRead,ignoreNul)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead,ignoreNul):"";var _fd_write=(fd,iov,iovcnt,pnum)=>{var num=0;for(var i=0;i<iovcnt;i++){var ptr=HEAPU32[iov>>2];var len=HEAPU32[iov+4>>2];iov+=8;for(var j=0;j<len;j++){printChar(fd,HEAPU8[ptr+j])}num+=len}HEAPU32[pnum>>2]=num;return 0};var HEAPF32;var HEAP16;var HEAP32;var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.codePointAt(i);if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;i++}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var lengthBytesUTF8=str=>{var len=0;for(var i=0;i<str.length;++i){var c=str.charCodeAt(i);if(c<=127){len++}else if(c<=2047){len+=2}else if(c>=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};{if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(Module["print"])out=Module["print"];if(Module["printErr"])err=Module["printErr"];if(Module["arguments"])programArgs=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];var preInit=Module["preInit"];if(preInit){if(typeof preInit=="function")Module["preInit"]=preInit=[preInit];while(preInit.length>0){preInit.shift()()}}}Module["UTF8ToString"]=UTF8ToString;Module["stringToUTF8"]=stringToUTF8;Module["lengthBytesUTF8"]=lengthBytesUTF8;function js_panel(open,height){charmSim.panel(!!open,height)}function js_send_text(json){charmSim.sendText(UTF8ToString(json))}function js_send_binary(data,size){charmSim.sendBinary(HEAPU8.slice(data,data+size))}function js_mic(on){charmSim.mic(!!on)}function js_play_pcm(pcm,samples){charmSim.playPcm(HEAPF32.slice(pcm>>2,(pcm>>2)+samples))}function js_stop_audio(){charmSim.stopAudio()}function js_brightness(percent){charmSim.brightness(percent)}function js_store_get(key){var value=localStorage.getItem((globalThis.charmStore||"opencharm.")+UTF8ToString(key));if(value===null)return 0;var size=lengthBytesUTF8(value)+1;var ptr=_malloc(size);stringToUTF8(value,ptr,size);return ptr}function js_store_set(key,value){localStorage.setItem((globalThis.charmStore||"opencharm.")+UTF8ToString(key),UTF8ToString(value))}function js_store_erase(key){localStorage.removeItem((globalThis.charmStore||"opencharm.")+UTF8ToString(key))}function js_reconnect(){charmSim.reconnect()}var _sim_set_build,_sim_commit,_sim_panel_radius,_sim_init,_sim_frame,_sim_pin_key,_sim_pin_ready,_sim_frame_box,_sim_frame_dirty,_sim_tick,_sim_pointer,_sim_key,_sim_connected,_sim_disconnected,_sim_text,_sim_type,_sim_audio,_sim_mic_pcm,_sim_token,_sim_forget,_sim_status_open,_sim_status,_free,_malloc,memory,__indirect_function_table,wasmMemory;function assignWasmExports(wasmExports){_sim_set_build=Module["_sim_set_build"]=wasmExports["s"];_sim_commit=Module["_sim_commit"]=wasmExports["t"];_sim_panel_radius=Module["_sim_panel_radius"]=wasmExports["u"];_sim_init=Module["_sim_init"]=wasmExports["v"];_sim_frame=Module["_sim_frame"]=wasmExports["w"];_sim_pin_key=Module["_sim_pin_key"]=wasmExports["x"];_sim_pin_ready=Module["_sim_pin_ready"]=wasmExports["y"];_sim_frame_box=Module["_sim_frame_box"]=wasmExports["z"];_sim_frame_dirty=Module["_sim_frame_dirty"]=wasmExports["A"];_sim_tick=Module["_sim_tick"]=wasmExports["B"];_sim_pointer=Module["_sim_pointer"]=wasmExports["C"];_sim_key=Module["_sim_key"]=wasmExports["D"];_sim_connected=Module["_sim_connected"]=wasmExports["E"];_sim_disconnected=Module["_sim_disconnected"]=wasmExports["F"];_sim_text=Module["_sim_text"]=wasmExports["G"];_sim_type=Module["_sim_type"]=wasmExports["H"];_sim_audio=Module["_sim_audio"]=wasmExports["I"];_sim_mic_pcm=Module["_sim_mic_pcm"]=wasmExports["J"];_sim_token=Module["_sim_token"]=wasmExports["K"];_sim_forget=Module["_sim_forget"]=wasmExports["L"];_sim_status_open=Module["_sim_status_open"]=wasmExports["M"];_sim_status=Module["_sim_status"]=wasmExports["N"];_free=Module["_free"]=wasmExports["O"];_malloc=Module["_malloc"]=wasmExports["P"];memory=wasmMemory=wasmExports["q"];__indirect_function_table=wasmExports["__indirect_function_table"]}var wasmImports={c:___cxa_throw,m:__abort_js,k:_emscripten_resize_heap,l:_fd_close,b:_fd_write,f:js_brightness,a:js_mic,p:js_panel,h:js_play_pcm,n:js_reconnect,i:js_send_binary,j:js_send_text,g:js_stop_audio,o:js_store_erase,e:js_store_get,d:js_store_set};async function run(){preRun();var setStatus=Module["setStatus"];if(setStatus){setStatus("Running...");await new Promise(resolve=>setTimeout(resolve,1));setTimeout(setStatus,1,"")}if(ABORT)return;initRuntime();Module["onRuntimeInitialized"]?.();postRun()}var wasmExports;wasmExports=await createWasm();await run();
2
2
  ;return Module}export default createCharm;
Binary file
package/sim/index.html CHANGED
@@ -32,7 +32,7 @@
32
32
  <p>
33
33
  <b>Hold Space</b> (or the key on the right side) to talk. A short
34
34
  press stops speech or dismisses a line. Tap the face. Type the PIN
35
- on the screen.
35
+ on the screen. <b>Touch and hold the face</b> for the status screen.
36
36
  </p>
37
37
  <p>
38
38
  <b>Orange means it needs you.</b> On a question, hold for yes, press
@@ -46,15 +46,21 @@
46
46
  <p class="mono small" id="url"></p>
47
47
  <p class="mono dim">BUILD</p>
48
48
  <p class="mono small" id="build"></p>
49
+ <p class="mono dim">BATTERY</p>
50
+ <div class="battery">
51
+ <input type="range" id="battery" min="0" max="100" value="80" />
52
+ <span class="mono small" id="battery-value">80%</span>
53
+ </div>
49
54
  <div class="buttons">
55
+ <button class="pill" id="usb">Plug in USB</button>
50
56
  <button class="pill" id="wifi">Drop Wi-Fi</button>
51
57
  <button class="pill" id="shape">Round screen</button>
52
58
  <button class="pill" id="forget">Forget pairing</button>
53
59
  </div>
54
60
  <p class="mono dim">LATER</p>
55
61
  <p class="small dim">
56
- Pick up, face-down, shake and battery arrive with the motion sensor
57
- work (after the MVP).
62
+ Pick up, face-down and shake arrive with the motion sensor work
63
+ (after the MVP).
58
64
  </p>
59
65
  <p class="small dim">
60
66
  Same code as the charm: firmware/core compiled to WebAssembly. No
package/sim/sim.css CHANGED
@@ -150,3 +150,13 @@ aside p {
150
150
  background: var(--ink);
151
151
  color: var(--paper);
152
152
  }
153
+
154
+ .battery {
155
+ display: flex;
156
+ align-items: center;
157
+ gap: 10px;
158
+ }
159
+ .battery input {
160
+ flex: 1;
161
+ accent-color: currentColor;
162
+ }
package/sim/sim.js CHANGED
@@ -52,6 +52,7 @@ const trace = {
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
54
  micLatencyMs: null, // key-down to the first mic frame the core took, last hold (includes a 60 ms frame)
55
+ statusOpen: false, // the status screen is up (spec 009)
55
56
  };
56
57
  window.__charm = trace;
57
58
 
@@ -204,6 +205,7 @@ async function connect() {
204
205
  trace.connected = true;
205
206
  statusEl.textContent = "CONNECTED";
206
207
  M._sim_connected();
208
+ sendStatus();
207
209
  };
208
210
  ws.onmessage = (event) => {
209
211
  if (typeof event.data === "string") {
@@ -224,6 +226,7 @@ async function connect() {
224
226
  trace.connected = false;
225
227
  statusEl.textContent = wifiOn ? "RECONNECTING" : "WI-FI OFF";
226
228
  M._sim_disconnected();
229
+ sendStatus();
227
230
  setTimeout(connect, 1500);
228
231
  };
229
232
  }
@@ -414,6 +417,50 @@ document.getElementById("forget").addEventListener("click", () => {
414
417
  ws?.close();
415
418
  });
416
419
 
420
+ // The battery and status screen (spec 009): the board reads its own once a second; here the side
421
+ // panel stands in for it. The desktop charm (notch) has no battery, so it sends none.
422
+ const batteryEl = document.getElementById("battery");
423
+ const batteryValueEl = document.getElementById("battery-value");
424
+ const usbEl = document.getElementById("usb");
425
+ let usb = false;
426
+ function charmdHost() {
427
+ try {
428
+ return new URL(ws?.url || baseUrl).host;
429
+ } catch {
430
+ return "";
431
+ }
432
+ }
433
+ // Sent only when something changed: at rest the emulator (and the desktop charm, which runs this
434
+ // page) must stay at its slow tick.
435
+ let lastStatus = "";
436
+ function sendStatus() {
437
+ const percent = notch ? -1 : Number(batteryEl.value);
438
+ const host = charmdHost();
439
+ const now = [percent, usb, wifiOn, host, trace.connected].join("|");
440
+ if (now === lastStatus) return;
441
+ lastStatus = now;
442
+ withString(host, (ptr) =>
443
+ M._sim_status(
444
+ percent,
445
+ usb ? 1 : 0,
446
+ wifiOn ? 1 : 0,
447
+ ptr,
448
+ trace.connected ? 1 : 0
449
+ )
450
+ );
451
+ wake(400);
452
+ }
453
+ batteryEl.addEventListener("input", () => {
454
+ batteryValueEl.textContent = `${batteryEl.value}%`;
455
+ sendStatus();
456
+ });
457
+ usbEl.addEventListener("click", () => {
458
+ usb = !usb;
459
+ usbEl.classList.toggle("on", usb);
460
+ usbEl.textContent = usb ? "On USB" : "Plug in USB";
461
+ sendStatus();
462
+ });
463
+
417
464
  // The charm is always on screen, so it must cost next to nothing at rest. The core only redraws what
418
465
  // moved; this loop copies only that box, ticks at 60 Hz while something animates and at 10 Hz at
419
466
  // rest (a breath step or a blink now and then), and wakes at once for input or a message.
@@ -442,6 +489,7 @@ function loop() {
442
489
  const now = performance.now();
443
490
  M._sim_tick(Math.floor(now));
444
491
  const drew = M._sim_frame_dirty() === 1;
492
+ trace.statusOpen = M._sim_status_open() === 1;
445
493
  if (drew) blit();
446
494
  // Two frames in a row means an animation is running: keep up with it.
447
495
  const animating = drew && drewLast;