opencharm 0.6.1 → 0.7.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/README.md +19 -19
- package/dist/main.mjs +33 -9
- package/package.json +1 -1
- package/sim/charm_sim.js +1 -1
- package/sim/charm_sim.wasm +0 -0
- package/sim/sim.js +4 -2
package/README.md
CHANGED
|
@@ -6,25 +6,25 @@ The command line for [OpenCharm](https://opencharm.dev): the open-source charm f
|
|
|
6
6
|
npx opencharm
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
| Command | What it does
|
|
10
|
-
| ----------------------------------------------------------------------------------------------------- |
|
|
11
|
-
| `opencharm` | Says hello with a blinking face
|
|
12
|
-
| `opencharm faces` | Lists all 22 moods
|
|
13
|
-
| `opencharm face [mood]` | Shows one mood (random if omitted), e.g. `opencharm face learned`
|
|
14
|
-
| `opencharm states` | What your agent is doing, and the face for each state
|
|
15
|
-
| `opencharm hardware` | What to buy and print
|
|
16
|
-
| `opencharm init [dir]` | Clone the starter workspace ([opencharm-starter](https://github.com/opencharm-labs/opencharm-starter)) and fit it to this machine (`--agent claude` (default), `codex`, `gemini`, `goose`, `hermes`, `openclaw`; `--from <git url>` for a fork; `--name <name>` and `--colour <colour>` write the charm's identity, the `charm` block) |
|
|
17
|
-
| `opencharm serve` | Start charmd, the charm daemon, next to your agent (`--config <file>`)
|
|
18
|
-
| `opencharm sim` | The charm on screen, in your browser, talking to charmd (`--url`, `--port`, `--no-open`)
|
|
19
|
-
| `sudo opencharm setup --domain <d>` | Install charmd as a hardened systemd service on a Linux server (`--dry-run` prints the plan; see `docs/deploy.md`)
|
|
20
|
-
| `opencharm pair <code>` | Pair the charm showing that code; you choose its PIN (`--name <name>`)
|
|
21
|
-
| `opencharm status` | What's running (charmd, each connected charm's build, the starter commit of the workspace; spec 015), then the paired charms and whether they are connected, locked or blocked
|
|
22
|
-
| `opencharm lock` / `unlock` / `revoke <charm>` | Lock it now; clear a block and unlock; forget it
|
|
23
|
-
| `opencharm replies on\|off` | The desktop charm speaks its replies, or shows them as text, from the next one; a charm on a board always speaks. To keep it, set `"speakReplies": false` in `opencharm.json`
|
|
24
|
-
| `opencharm look` | Show the charm's look, or change it on every unlocked charm until charmd restarts (`--colour <colour>`, `--greeting <text>`, `--motion full\|calm`); to keep it, set `charm` in `opencharm.json`
|
|
25
|
-
| `opencharm dev face <charm> <state> [text]` / `dev say <charm> <text>` / `dev ask <charm> <question>` | Show a face, speak, or ask a question (hold = yes, press = no) on a connected charm (testing)
|
|
26
|
-
| `opencharm voice` / `voice install` | The local voice's models (Parakeet listening, Supertonic speaking): whether they're here, and download them now (charmd does it on its first start otherwise)
|
|
27
|
-
| `opencharm mcp` | The charm's tools for an agent (MCP over stdio): `say`, `show_face`, `ask`, `notify`, `set_look`. charmd adds it to ACP agents by itself. Other agents running as your user can add `opencharm mcp --config <file>` to their MCP settings; never an agent running as another user (it reaches charmd's admin socket)
|
|
9
|
+
| Command | What it does |
|
|
10
|
+
| ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| `opencharm` | Says hello with a blinking face |
|
|
12
|
+
| `opencharm faces` | Lists all 22 moods |
|
|
13
|
+
| `opencharm face [mood]` | Shows one mood (random if omitted), e.g. `opencharm face learned` |
|
|
14
|
+
| `opencharm states` | What your agent is doing, and the face for each state |
|
|
15
|
+
| `opencharm hardware` | What to buy and print |
|
|
16
|
+
| `opencharm init [dir]` | Clone the starter workspace ([opencharm-starter](https://github.com/opencharm-labs/opencharm-starter)) and fit it to this machine (`--agent claude` (default), `codex`, `gemini`, `goose`, `hermes`, `openclaw`; `--from <git url>` for a fork; `--name <name>` and `--colour <colour>` (one of the six, or `#RRGGBB`) write the charm's identity, the `charm` block) |
|
|
17
|
+
| `opencharm serve` | Start charmd, the charm daemon, next to your agent (`--config <file>`) |
|
|
18
|
+
| `opencharm sim` | The charm on screen, in your browser, talking to charmd (`--url`, `--port`, `--no-open`) |
|
|
19
|
+
| `sudo opencharm setup --domain <d>` | Install charmd as a hardened systemd service on a Linux server (`--dry-run` prints the plan; see `docs/deploy.md`) |
|
|
20
|
+
| `opencharm pair <code>` | Pair the charm showing that code; you choose its PIN (`--name <name>`) |
|
|
21
|
+
| `opencharm status` | What's running (charmd, each connected charm's build, the starter commit of the workspace; spec 015), then the paired charms and whether they are connected, locked or blocked |
|
|
22
|
+
| `opencharm lock` / `unlock` / `revoke <charm>` | Lock it now; clear a block and unlock; forget it |
|
|
23
|
+
| `opencharm replies on\|off` | The desktop charm speaks its replies, or shows them as text, from the next one; a charm on a board always speaks. To keep it, set `"speakReplies": false` in `opencharm.json` |
|
|
24
|
+
| `opencharm look` | Show the charm's look, or change it on every unlocked charm until charmd restarts (`--colour <colour>`, `--greeting <text>`, `--motion full\|calm`); to keep it, set `charm` in `opencharm.json` |
|
|
25
|
+
| `opencharm dev face <charm> <state> [text]` / `dev say <charm> <text>` / `dev ask <charm> <question>` | Show a face, speak, or ask a question (hold = yes, press = no) on a connected charm (testing) |
|
|
26
|
+
| `opencharm voice` / `voice install` | The local voice's models (Parakeet listening, Supertonic speaking): whether they're here, and download them now (charmd does it on its first start otherwise) |
|
|
27
|
+
| `opencharm mcp` | The charm's tools for an agent (MCP over stdio): `say`, `show_face`, `ask`, `notify`, `set_look`. charmd adds it to ACP agents by itself. Other agents running as your user can add `opencharm mcp --config <file>` to their MCP settings; never an agent running as another user (it reaches charmd's admin socket) |
|
|
28
28
|
|
|
29
29
|
Options: `--colour white|cobalt|lime|lilac|sun|coal`, `--no-anim`, `--no-color` (also respects `NO_COLOR`).
|
|
30
30
|
|
package/dist/main.mjs
CHANGED
|
@@ -629,10 +629,33 @@ const MAX_NAME_CHARS = 12;
|
|
|
629
629
|
const MAX_NAME_BYTES = 24;
|
|
630
630
|
const MAX_GREETING_BYTES = 40;
|
|
631
631
|
const COLOUR_IDS = facesData.colours.map((colour) => colour.id);
|
|
632
|
+
const OWN_COLOUR = /^#[0-9A-Fa-f]{6}$/;
|
|
632
633
|
const lookName = z.string().min(1, "the name can't be empty").refine((name) => [...name].length <= MAX_NAME_CHARS && utf8Length(name) <= MAX_NAME_BYTES, { message: `at most ${MAX_NAME_CHARS} characters` });
|
|
634
|
+
function ownColourProblem(hex) {
|
|
635
|
+
const [r, g, b] = [
|
|
636
|
+
1,
|
|
637
|
+
3,
|
|
638
|
+
5
|
|
639
|
+
].map((at) => Number.parseInt(hex.slice(at, at + 2), 16) / 255);
|
|
640
|
+
const linear = (v) => v <= .04045 ? v / 12.92 : ((v + .055) / 1.055) ** 2.4;
|
|
641
|
+
if (.2126 * linear(r) + .7152 * linear(g) + .0722 * linear(b) < .05) return "too dark to see on black";
|
|
642
|
+
const max = Math.max(r, g, b);
|
|
643
|
+
const spread = max - Math.min(r, g, b);
|
|
644
|
+
if (max !== r || max < .5 || spread / max < .5) return void 0;
|
|
645
|
+
const hue = 60 * (g - b) / spread;
|
|
646
|
+
return hue >= 6 && hue <= 40 ? "too close to the orange that means 'it needs you'" : void 0;
|
|
647
|
+
}
|
|
648
|
+
const colour = z.string().superRefine((value, context) => {
|
|
649
|
+
if (COLOUR_IDS.includes(value)) return;
|
|
650
|
+
const problem = OWN_COLOUR.test(value) ? ownColourProblem(value) : `the colour is one of ${COLOUR_IDS.join(", ")}, or your own as #RRGGBB`;
|
|
651
|
+
if (problem) context.addIssue({
|
|
652
|
+
code: "custom",
|
|
653
|
+
message: problem
|
|
654
|
+
});
|
|
655
|
+
}).transform((value) => OWN_COLOUR.test(value) ? value.toUpperCase() : value);
|
|
633
656
|
const lookFields = {
|
|
634
657
|
name: lookName.optional(),
|
|
635
|
-
colour:
|
|
658
|
+
colour: colour.optional(),
|
|
636
659
|
greeting: z.string().refine((text) => utf8Length(text) <= MAX_GREETING_BYTES, { message: `at most ${MAX_GREETING_BYTES} bytes` }).optional(),
|
|
637
660
|
sleepAfterMinutes: z.number().int().min(0).max(1440).optional(),
|
|
638
661
|
motion: z.enum(["full", "calm"]).optional()
|
|
@@ -642,6 +665,7 @@ function issues(error) {
|
|
|
642
665
|
return error.issues.map((issue) => `${issue.path.join(".") || "look"}: ${issue.message}`).join("; ");
|
|
643
666
|
}
|
|
644
667
|
function glyphOf(colourId) {
|
|
668
|
+
if (OWN_COLOUR.test(colourId)) return colourId;
|
|
645
669
|
const colour = facesData.colours.find((c) => c.id === colourId);
|
|
646
670
|
if (!colour) throw new Error(`Unknown colour "${colourId}"`);
|
|
647
671
|
return colour.g;
|
|
@@ -969,7 +993,7 @@ function sendAdmin(socketPath, request) {
|
|
|
969
993
|
}
|
|
970
994
|
//#endregion
|
|
971
995
|
//#region package.json
|
|
972
|
-
var version = "0.
|
|
996
|
+
var version = "0.7.0";
|
|
973
997
|
function channelToCube(value) {
|
|
974
998
|
if (value < 48) return 0;
|
|
975
999
|
if (value < 115) return 1;
|
|
@@ -1463,7 +1487,7 @@ function runHelp(ctx) {
|
|
|
1463
1487
|
opencharm hardware what to buy and print
|
|
1464
1488
|
|
|
1465
1489
|
charmd, the charm daemon (runs next to your agent)
|
|
1466
|
-
opencharm init [dir] clone the starter workspace for your agent [--agent claude|codex|gemini|goose|hermes|openclaw] [--from <git url>] [--name <name>] [--colour <colour>]
|
|
1490
|
+
opencharm init [dir] clone the starter workspace for your agent [--agent claude|codex|gemini|goose|hermes|openclaw] [--from <git url>] [--name <name>] [--colour <colour|#RRGGBB>]
|
|
1467
1491
|
opencharm setup --domain <d> install charmd as a service (Linux, sudo) [--dry-run]
|
|
1468
1492
|
opencharm serve start charmd [--config <file>]
|
|
1469
1493
|
opencharm sim the charm on screen, in your browser [--url <ws>] [--port <n>]
|
|
@@ -1474,7 +1498,7 @@ function runHelp(ctx) {
|
|
|
1474
1498
|
opencharm unlock <charm> clear a block and unlock
|
|
1475
1499
|
opencharm revoke <charm> forget a charm (it must pair again)
|
|
1476
1500
|
opencharm replies on|off the desktop charm speaks its replies, or shows them as text
|
|
1477
|
-
opencharm look show or change the charm's look until charmd restarts [--colour <c>] [--greeting <text>] [--motion full|calm]
|
|
1501
|
+
opencharm look show or change the charm's look until charmd restarts [--colour <c|#RRGGBB>] [--greeting <text>] [--motion full|calm]
|
|
1478
1502
|
opencharm dev face <charm> <state> [text] show a face (testing)
|
|
1479
1503
|
opencharm dev say <charm> <text> speak through it (testing)
|
|
1480
1504
|
opencharm dev ask <charm> <question> ask it; hold = yes, press = no (testing)
|
|
@@ -1582,7 +1606,7 @@ const VERSIONS = [
|
|
|
1582
1606
|
"2024-11-05"
|
|
1583
1607
|
];
|
|
1584
1608
|
const FACES = facesData.states.map((state) => state.id);
|
|
1585
|
-
const
|
|
1609
|
+
const COLOUR = `^(${facesData.colours.map((colour) => colour.id).join("|")}|#[0-9A-Fa-f]{6})$`;
|
|
1586
1610
|
const line = z.string().min(1).max(200);
|
|
1587
1611
|
const label = z.string().min(1).max(12);
|
|
1588
1612
|
const TOOLS = [
|
|
@@ -1701,8 +1725,8 @@ const TOOLS = [
|
|
|
1701
1725
|
properties: {
|
|
1702
1726
|
colour: {
|
|
1703
1727
|
type: "string",
|
|
1704
|
-
|
|
1705
|
-
description: "cobalt is blue, lime green, lilac purple, sun yellow; white and coal light the glyphs white."
|
|
1728
|
+
pattern: COLOUR,
|
|
1729
|
+
description: "cobalt is blue, lime green, lilac purple, sun yellow; white and coal light the glyphs white. Any other colour as #RRGGBB (not orange, not too dark)."
|
|
1706
1730
|
},
|
|
1707
1731
|
greeting: {
|
|
1708
1732
|
type: "string",
|
|
@@ -1716,7 +1740,7 @@ const TOOLS = [
|
|
|
1716
1740
|
}
|
|
1717
1741
|
},
|
|
1718
1742
|
args: z.object({
|
|
1719
|
-
colour: z.
|
|
1743
|
+
colour: z.string().regex(new RegExp(COLOUR)).optional(),
|
|
1720
1744
|
greeting: z.string().max(40).optional(),
|
|
1721
1745
|
motion: z.enum(["full", "calm"]).optional()
|
|
1722
1746
|
}).strict(),
|
|
@@ -4941,7 +4965,7 @@ function formatIdentity(unit, version, commit) {
|
|
|
4941
4965
|
let cached;
|
|
4942
4966
|
function identity() {
|
|
4943
4967
|
if (cached) return cached;
|
|
4944
|
-
const commit = "
|
|
4968
|
+
const commit = "d601217";
|
|
4945
4969
|
cached = {
|
|
4946
4970
|
version: `cli@${version}`,
|
|
4947
4971
|
commit,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencharm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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){charmSim.panel(!!open)}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("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("opencharm."+UTF8ToString(key),UTF8ToString(value))}function js_store_erase(key){localStorage.removeItem("opencharm."+UTF8ToString(key))}function js_reconnect(){charmSim.reconnect()}var _sim_set_build,_sim_commit,_sim_init,_sim_frame,_sim_pin_key,_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_init=Module["_sim_init"]=wasmExports["u"];_sim_frame=Module["_sim_frame"]=wasmExports["v"];_sim_pin_key=Module["_sim_pin_key"]=wasmExports["w"];_sim_frame_box=Module["_sim_frame_box"]=wasmExports["x"];_sim_frame_dirty=Module["_sim_frame_dirty"]=wasmExports["y"];_sim_tick=Module["_sim_tick"]=wasmExports["z"];_sim_pointer=Module["_sim_pointer"]=wasmExports["A"];_sim_key=Module["_sim_key"]=wasmExports["B"];_sim_connected=Module["_sim_connected"]=wasmExports["C"];_sim_disconnected=Module["_sim_disconnected"]=wasmExports["D"];_sim_text=Module["_sim_text"]=wasmExports["E"];_sim_type=Module["_sim_type"]=wasmExports["F"];_sim_audio=Module["_sim_audio"]=wasmExports["G"];_sim_mic_pcm=Module["_sim_mic_pcm"]=wasmExports["H"];_sim_token=Module["_sim_token"]=wasmExports["I"];_sim_forget=Module["_sim_forget"]=wasmExports["J"];_free=Module["_free"]=wasmExports["K"];_malloc=Module["_malloc"]=wasmExports["L"];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("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("opencharm."+UTF8ToString(key),UTF8ToString(value))}function js_store_erase(key){localStorage.removeItem("opencharm."+UTF8ToString(key))}function js_reconnect(){charmSim.reconnect()}var _sim_set_build,_sim_commit,_sim_init,_sim_frame,_sim_pin_key,_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_init=Module["_sim_init"]=wasmExports["u"];_sim_frame=Module["_sim_frame"]=wasmExports["v"];_sim_pin_key=Module["_sim_pin_key"]=wasmExports["w"];_sim_frame_box=Module["_sim_frame_box"]=wasmExports["x"];_sim_frame_dirty=Module["_sim_frame_dirty"]=wasmExports["y"];_sim_tick=Module["_sim_tick"]=wasmExports["z"];_sim_pointer=Module["_sim_pointer"]=wasmExports["A"];_sim_key=Module["_sim_key"]=wasmExports["B"];_sim_connected=Module["_sim_connected"]=wasmExports["C"];_sim_disconnected=Module["_sim_disconnected"]=wasmExports["D"];_sim_text=Module["_sim_text"]=wasmExports["E"];_sim_type=Module["_sim_type"]=wasmExports["F"];_sim_audio=Module["_sim_audio"]=wasmExports["G"];_sim_mic_pcm=Module["_sim_mic_pcm"]=wasmExports["H"];_sim_token=Module["_sim_token"]=wasmExports["I"];_sim_forget=Module["_sim_forget"]=wasmExports["J"];_free=Module["_free"]=wasmExports["K"];_malloc=Module["_malloc"]=wasmExports["L"];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();
|
|
2
2
|
;return Module}export default createCharm;
|
package/sim/charm_sim.wasm
CHANGED
|
Binary file
|
package/sim/sim.js
CHANGED
|
@@ -122,8 +122,10 @@ window.charmSim = {
|
|
|
122
122
|
withString(key, (ptr) => M._sim_pin_key(ptr));
|
|
123
123
|
wake();
|
|
124
124
|
},
|
|
125
|
-
// The desktop charm's panel opens below the notch for speech and questions, and closes after
|
|
126
|
-
|
|
125
|
+
// The desktop charm's panel opens below the notch for speech and questions, and closes after;
|
|
126
|
+
// `height` (pixels) is how far: words take only what they need.
|
|
127
|
+
panel: (open, height = H) => {
|
|
128
|
+
if (open) charmEl.style.setProperty("--panel", `${height * scale}px`);
|
|
127
129
|
charmEl.classList.toggle("open", open);
|
|
128
130
|
trace.panelOpen = open;
|
|
129
131
|
},
|