{"_id":"@cansirin/tuval-calc","_rev":"5-4cb84ea8869df33167bad5920cec6234","name":"@cansirin/tuval-calc","dist-tags":{"latest":"0.1.3"},"versions":{"0.1.0":{"name":"@cansirin/tuval-calc","version":"0.1.0","author":{"name":"Can Sirin","email":"mail@csirin.com"},"license":"MIT","_id":"@cansirin/tuval-calc@0.1.0","maintainers":[{"name":"cansirin","email":"cansirin12@gmail.com"}],"homepage":"https://github.com/cansirin/monorepo#readme","bugs":{"url":"https://github.com/cansirin/monorepo/issues"},"dist":{"shasum":"9c653da2cca91991a26d93d377bb5c8899a1e971","tarball":"https://registry.npmjs.org/@cansirin/tuval-calc/-/tuval-calc-0.1.0.tgz","fileCount":27,"integrity":"sha512-etyFEQt4SLG2SjkT9ZiKgRwvdhG0eVT4FCFWrUW9LJo2Yhzdi8ZCyK9VMPM7e/LO6Q9HYS+RDaUB5/3ZRNv4yg==","signatures":[{"sig":"MEYCIQC0+BeWsfejsJxK+ce2YMOy2Pv3IoXxzgHdYxvRKseo+AIhAJuL0gBiz7LIEsSBR63HhUfblHQCTwiZyUdBaiwWl5b/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":127272},"type":"module","_from":"file:cansirin-tuval-calc-0.1.0.tgz","exports":{".":"./src/index.ts","./packs":"./src/packs/index.ts","./window":"./src/window/index.ts"},"scripts":{"lint":"biome check src","test":"vitest run","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"cansirin","email":"cansirin12@gmail.com"},"_resolved":"/private/var/folders/7l/10nvtdw13mn_cgvnnnc93td00000gn/T/1b897900cffd34faf9ec194e44f76bc3/cansirin-tuval-calc-0.1.0.tgz","_integrity":"sha512-etyFEQt4SLG2SjkT9ZiKgRwvdhG0eVT4FCFWrUW9LJo2Yhzdi8ZCyK9VMPM7e/LO6Q9HYS+RDaUB5/3ZRNv4yg==","repository":{"url":"git+https://github.com/cansirin/monorepo.git","type":"git","directory":"packages/tuval-calc"},"_npmVersion":"10.9.4","description":"A calculating buffer for Tuval — Soulver-style arithmetic with domain packs, as a Tuval program","directories":{},"_nodeVersion":"22.21.1","dependencies":{"big.js":"^6.2.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^26.0.0","react":"19.0.0","effect":"4.0.0-rc.112","vitest":"^3.2.1","react-dom":"19.0.0","typescript":"5.7.3","@demlik/tea":"0.12.0","@types/react":"19.0.8","@types/big.js":"^6.2.2","@types/react-dom":"19.0.3","@testing-library/react":"^16.3.0"},"peerDependencies":{"react":"^19.0.0","effect":"^4.0.0-rc.112","@demlik/tea":"^0.12.0"},"peerDependenciesMeta":{"react":{"optional":true},"@demlik/tea":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/tuval-calc_0.1.0_1788684098350_0.2426979426423821","host":"s3://npm-registry-packages-npm-production"},"deprecated":"retired — the spike is done; see kamp-us/phoenix#8716 for Tuval's authoring API"},"0.1.1":{"name":"@cansirin/tuval-calc","version":"0.1.1","author":{"name":"Can Sirin","email":"mail@csirin.com"},"license":"MIT","_id":"@cansirin/tuval-calc@0.1.1","maintainers":[{"name":"cansirin","email":"cansirin12@gmail.com"}],"homepage":"https://github.com/cansirin/monorepo#readme","bugs":{"url":"https://github.com/cansirin/monorepo/issues"},"dist":{"shasum":"82a2d42d50b58777921cc11e5464be57fe29b344","tarball":"https://registry.npmjs.org/@cansirin/tuval-calc/-/tuval-calc-0.1.1.tgz","fileCount":70,"integrity":"sha512-LbkRxFWH0g8D7G0RK5cPiKI4+30ZkKtBdOfEkHCjpQEuRNJZQpUOhZE6LMtwDpDfo3iPrY0jCY0vvnv8GIgP2Q==","signatures":[{"sig":"MEYCIQCp78AxojN5d38uE1XZJFDCo+r8NxEDxofpmBhOIJrXVwIhAK/trowfalJSLncUE3zMS6q6AKMz9D25bJN9YTB/smr4","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":178373},"type":"module","_from":"file:cansirin-tuval-calc-0.1.1.tgz","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./packs":{"types":"./dist/packs/index.d.ts","default":"./dist/packs/index.js"},"./window":{"types":"./dist/window/index.d.ts","default":"./dist/window/index.js"}},"scripts":{"lint":"biome check src","test":"vitest run","build":"rm -rf dist && tsc -p tsconfig.build.json && tsc -p tsconfig.build.window.json && cp src/window/calc-window.css dist/window/calc-window.css","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"cansirin","email":"cansirin12@gmail.com"},"_resolved":"/private/var/folders/7l/10nvtdw13mn_cgvnnnc93td00000gn/T/d8ca9190f4d36b2e7a04fdfe1ee11272/cansirin-tuval-calc-0.1.1.tgz","_integrity":"sha512-LbkRxFWH0g8D7G0RK5cPiKI4+30ZkKtBdOfEkHCjpQEuRNJZQpUOhZE6LMtwDpDfo3iPrY0jCY0vvnv8GIgP2Q==","repository":{"url":"git+https://github.com/cansirin/monorepo.git","type":"git","directory":"packages/tuval-calc"},"_npmVersion":"10.9.4","description":"A calculating buffer for Tuval — Soulver-style arithmetic with domain packs, as a Tuval program","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.21.1","dependencies":{"big.js":"^6.2.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^26.0.0","react":"19.0.0","effect":"4.0.0-rc.112","vitest":"^3.2.1","react-dom":"19.0.0","typescript":"5.7.3","@demlik/tea":"0.12.0","@types/react":"19.0.8","@types/big.js":"^6.2.2","@types/react-dom":"19.0.3","@testing-library/react":"^16.3.0"},"peerDependencies":{"react":"^19.0.0","effect":"^4.0.0-rc.112","@demlik/tea":"^0.12.0"},"peerDependenciesMeta":{"react":{"optional":true},"@demlik/tea":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/tuval-calc_0.1.1_1788687390765_0.17663857410516104","host":"s3://npm-registry-packages-npm-production"},"deprecated":"retired — the spike is done; see kamp-us/phoenix#8716 for Tuval's authoring API"},"0.1.2":{"name":"@cansirin/tuval-calc","version":"0.1.2","author":{"name":"Can Sirin","email":"mail@csirin.com"},"license":"MIT","_id":"@cansirin/tuval-calc@0.1.2","maintainers":[{"name":"cansirin","email":"cansirin12@gmail.com"}],"homepage":"https://github.com/cansirin/monorepo#readme","bugs":{"url":"https://github.com/cansirin/monorepo/issues"},"dist":{"shasum":"b093f5c493d7ba53ff9b1b4c0d1b6c77ccb395db","tarball":"https://registry.npmjs.org/@cansirin/tuval-calc/-/tuval-calc-0.1.2.tgz","fileCount":70,"integrity":"sha512-/DhFyO9XUSRmIFcmpIJN+278RaSZmg3pCNqMcl2nTP562btEGLefmzSD73uHtC6K5GtMrDb2b4AnIISVB+tuqA==","signatures":[{"sig":"MEQCIDAemChYatQ2YIVfAartwDtlAP+/oFbM5KEgppMplRt0AiBdx3hfF8fJ51VXQsQ+iJfk2XZ81ddmG209uDqRFLgyoQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":187706},"type":"module","_from":"file:cansirin-tuval-calc-0.1.2.tgz","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./packs":{"types":"./dist/packs/index.d.ts","default":"./dist/packs/index.js"},"./window":{"types":"./dist/window/index.d.ts","default":"./dist/window/index.js"}},"scripts":{"lint":"biome check src","test":"vitest run","build":"rm -rf dist && tsc -p tsconfig.build.json && tsc -p tsconfig.build.window.json && cp src/window/calc-window.css dist/window/calc-window.css","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"cansirin","email":"cansirin12@gmail.com"},"_resolved":"/private/var/folders/7l/10nvtdw13mn_cgvnnnc93td00000gn/T/17672ef9bb7147ad9a20e8c114617f44/cansirin-tuval-calc-0.1.2.tgz","_integrity":"sha512-/DhFyO9XUSRmIFcmpIJN+278RaSZmg3pCNqMcl2nTP562btEGLefmzSD73uHtC6K5GtMrDb2b4AnIISVB+tuqA==","repository":{"url":"git+https://github.com/cansirin/monorepo.git","type":"git","directory":"packages/tuval-calc"},"_npmVersion":"10.9.4","description":"A calculating buffer for Tuval — Soulver-style arithmetic with domain packs, as a Tuval program","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.21.1","dependencies":{"big.js":"^6.2.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^26.0.0","react":"19.0.0","effect":"4.0.0-rc.112","vitest":"^3.2.1","react-dom":"19.0.0","typescript":"5.7.3","@demlik/tea":"0.12.0","@types/react":"19.0.8","@types/big.js":"^6.2.2","@types/react-dom":"19.0.3","@testing-library/react":"^16.3.0"},"peerDependencies":{"react":"^19.0.0","effect":"^4.0.0-rc.112","@demlik/tea":"^0.12.0"},"peerDependenciesMeta":{"react":{"optional":true},"@demlik/tea":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/tuval-calc_0.1.2_1788729519003_0.5462136375424158","host":"s3://npm-registry-packages-npm-production"},"deprecated":"retired — the spike is done; see kamp-us/phoenix#8716 for Tuval's authoring API"},"0.1.3":{"name":"@cansirin/tuval-calc","version":"0.1.3","author":{"name":"Can Sirin","email":"mail@csirin.com"},"license":"MIT","_id":"@cansirin/tuval-calc@0.1.3","maintainers":[{"name":"cansirin","email":"cansirin12@gmail.com"}],"homepage":"https://github.com/cansirin/monorepo#readme","bugs":{"url":"https://github.com/cansirin/monorepo/issues"},"dist":{"shasum":"951d2fe4225430bd4b52c577082a11fd36306130","tarball":"https://registry.npmjs.org/@cansirin/tuval-calc/-/tuval-calc-0.1.3.tgz","fileCount":70,"integrity":"sha512-+TN+W0AWi4DbuRVsNxgiXC4tao8uGQhH6uXkD3LcX6wmVRsIhDWj2dtq3fL/LJY02aqS8ksDT7rdFzJqGkAJZg==","signatures":[{"sig":"MEYCIQDTflg9XELinaRsoWxeO8k51Cpe5Ods5z+SzK78hXfXAwIhAMuhcKwxae3Ofb9zo/Uw+2UW+0RqPY666XbaIA2sC7ae","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":192520},"type":"module","_from":"file:cansirin-tuval-calc-0.1.3.tgz","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./packs":{"types":"./dist/packs/index.d.ts","default":"./dist/packs/index.js"},"./window":{"types":"./dist/window/index.d.ts","default":"./dist/window/index.js"}},"scripts":{"lint":"biome check src","test":"vitest run","build":"rm -rf dist && tsc -p tsconfig.build.json && tsc -p tsconfig.build.window.json && cp src/window/calc-window.css dist/window/calc-window.css","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"cansirin","email":"cansirin12@gmail.com"},"_resolved":"/private/var/folders/7l/10nvtdw13mn_cgvnnnc93td00000gn/T/3f494c4a34893904c52f28a6832a6752/cansirin-tuval-calc-0.1.3.tgz","_integrity":"sha512-+TN+W0AWi4DbuRVsNxgiXC4tao8uGQhH6uXkD3LcX6wmVRsIhDWj2dtq3fL/LJY02aqS8ksDT7rdFzJqGkAJZg==","repository":{"url":"git+https://github.com/cansirin/monorepo.git","type":"git","directory":"packages/tuval-calc"},"_npmVersion":"10.9.4","description":"A calculating buffer for Tuval — Soulver-style arithmetic with domain packs, as a Tuval program","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.21.1","dependencies":{"big.js":"^6.2.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^26.0.0","react":"19.0.0","effect":"4.0.0-rc.112","vitest":"^3.2.1","react-dom":"19.0.0","typescript":"5.7.3","@demlik/tea":"0.12.0","@types/react":"19.0.8","@types/big.js":"^6.2.2","@types/react-dom":"19.0.3","@testing-library/react":"^16.3.0"},"peerDependencies":{"react":"^19.0.0","effect":"^4.0.0-rc.112","@demlik/tea":"^0.12.0"},"peerDependenciesMeta":{"react":{"optional":true},"@demlik/tea":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/tuval-calc_0.1.3_1788749818778_0.8234252825236499","host":"s3://npm-registry-packages-npm-production"},"deprecated":"retired — the spike is done; see kamp-us/phoenix#8716 for Tuval's authoring API"}},"time":{"created":"2026-09-06T08:41:38.102Z","modified":"2026-09-10T08:15:20.887Z","0.1.0":"2026-09-06T08:41:38.475Z","0.1.1":"2026-09-06T09:36:30.909Z","0.1.2":"2026-09-06T21:18:39.158Z","0.1.3":"2026-09-07T02:56:58.938Z"},"bugs":{"url":"https://github.com/cansirin/monorepo/issues"},"author":{"name":"Can Sirin","email":"mail@csirin.com"},"license":"MIT","homepage":"https://github.com/cansirin/monorepo#readme","repository":{"url":"git+https://github.com/cansirin/monorepo.git","type":"git","directory":"packages/tuval-calc"},"description":"A calculating buffer for Tuval — Soulver-style arithmetic with domain packs, as a Tuval program","maintainers":[{"name":"cansirin","email":"cansirin12@gmail.com"}],"readme":"# @cansirin/tuval-calc\n\nA calculating buffer for [Tuval](https://github.com/kamp-us/phoenix/tree/main/apps/tuval) —\nSoulver-style arithmetic with domain packs, shipped as a Tuval program.\n\n## What it is\n\nYou type lines; each line gets an answer. Variables carry across lines, units convert, and a\n**domain pack** teaches the buffer vocabulary — currencies, cloud pricing, whatever you define.\n\n```\n# Budget\nrent: 1500\ngroceries: 400\nutilities: 150\ntotal                  -> 2050\n\n1200 try in gbp        -> £28.34\n25% of 840             -> 210\n```\n\nInside Tuval it is not a page you visit. It is a **process on the desk**: it checkpoints and\nrestores with everything else, splits into two windows over one buffer, answers on the command\nline, and — because its commands register as spells — an AI agent in the next window can call it\ninstead of doing arithmetic in its head.\n\n## Why it exists\n\nThe calculator started life as a web app. On the web, an agent that wants a number has to POST to\na server that runs the engine and hands back text. In Tuval the direction inverts: the engine is\nalready a process on the same desk, its spells self-describe as JSON Schema through Tuval's\nregistry, and the round-trip disappears. No server, no endpoint, no hand-written tool definition.\n\nIt is also deliberately a separate npm package rather than in-tree code: `calc` is Tuval's first\n**external** program, so building it is what proves a third party can write one.\n\n## Install\n\nTuval has no plugin system, by design — the Neovim model. Your config is code, and a program is a\nmodule your config imports.\n\n```bash\npnpm add @cansirin/tuval-calc\n```\n\nThe package ships compiled ESM plus `.d.ts` declarations — `node` refuses to strip types for\nanything under `node_modules`, and Tuval loads your config with plain `node`. Source lives in\n[the repo](https://github.com/cansirin/monorepo/tree/main/packages/tuval-calc).\n\n```ts\n// ~/.tuval/tuval.config.ts\nimport {calcProgram} from \"@cansirin/tuval-calc\";\nimport {basePack, currencyPack} from \"@cansirin/tuval-calc/packs\";\n\nexport default {\n  version: 1,\n  programs: [calcProgram({packs: [basePack, currencyPack]})],\n} satisfies TuvalConfigInput;\n```\n\n`calc` is not placed in the `graph`, so nothing launches it at boot. Open it when you want it:\n`<c-b> :` then `window:open calc`, or pick it in an empty window.\n\nTo get the window, the page also needs its renderer:\n\n```ts\n// ~/.tuval/renderers.ts\nimport {CalcWindow, CALC_WINDOW_REF} from \"@cansirin/tuval-calc/window\";\n\nexport default {[CALC_WINDOW_REF.ref]: CalcWindow};\n```\n\n## Domain packs\n\nA pack is units plus preset variables. Packs merge, and `basePack` is always the base layer.\n\nFour ship in the box: `basePack` (pi, e), `currencyPack`, `cloudflarePack` (Workers/D1/R2/KV\npricing), `dotaPack`.\n\nYour own packs are config, not data in a database — which means they may carry code:\n\n```ts\nexport const myPack = {\n  id: \"binclusive\",\n  name: \"Binclusive\",\n  units: [{name: \"audit\", aliases: [\"audits\"], category: \"work\", baseRate: 1}],\n  presetVariables: [\n    {name: \"seat\", value: 49, unit: \"usd\", description: \"Per-seat monthly\"},\n  ],\n  // optional, and only available to a config pack:\n  formatResult: (value, unit) => ...,\n};\n```\n\n## In the window\n\n| Key | Does |\n|---|---|\n| `Enter` | Open a line below the caret. |\n| `Backspace` at the start of an empty line | Delete it and move the caret up. |\n| `ArrowUp` / `ArrowDown` | Move the caret between lines. |\n| `Alt+P` | Jump to the pack switcher in the footer. |\n\nThe footer's pack control is a native `<select>` over the roster the row was constructed with, so\nswitching the pack is a `setPack` on the process and every window over that buffer follows. `Ctrl+`\nchords are left alone: the desk reserves `Ctrl+B` as its prefix.\n\n## Spells\n\nEvery command registers under the program id, so they are addressable as `calc <path>` from the\ncommand line, from a key binding, and from an agent — one registry, no second catalogue.\n\n| Spell | Does |\n|---|---|\n| `calc eval` | Evaluate one expression. Does not touch the buffer. |\n| `calc set` | Write a line and read its answer back. |\n| `calc lines` | Read the whole document. |\n| `calc pack` | Switch the active pack. |\n| `calc packs` | List available packs and their units. |\n| `calc export` | Render the document as markdown, CSV or JSON. |\n\nAn agent discovers these on its own — `spell list`, then `spell describe calc.eval` returns the\nparameter JSON Schema. Nothing is hand-written on the agent side.\n\n## Trust model — read this\n\nTuval runs local program code with **full trust and no sandbox, ever**. Its own registry says so\nabout the `capabilities`, `identity` and `placement` fields a program declares:\n\n> INERT DATA, ENFORCED BY NOTHING. The kernel stores and reports them and enforces nothing on\n> them: local program code is fully trusted, there is no sandbox, ever. They are not a security\n> boundary and must not be read as one.\n\nSo installing this package is exactly as consequential as installing a Neovim plugin or a VS Code\nextension: it runs with your user's authority. `capabilities: []` on this program grants nothing\nand restricts nothing — it is a declaration, not a limit. Read the source — linked from Install\nabove — before you install it, the same as you would any other plugin.\n\nThis program requests nothing and reaches no network: it is arithmetic over text you typed.\n\n## Testing\n\n```bash\npnpm test        # the engine's spec — the same suite the web engine passes\npnpm typecheck\n```\n\nThe engine carries an end-to-end suite covering arithmetic, SI suffixes, percentages, variables,\nsum boundaries, unit conversion and every built-in pack. It imports only the public API, never\nEffect, which is what let the engine move to Effect 4 without the spec moving with it.\n\n## Relationship to `scratchpad-engine`\n\nThis package's engine began as a fork of `packages/scratchpad-engine`, which still serves the web\napp on Effect 3. The fork migrated to Effect 4 to match Tuval's pin. The two are expected to\nconverge — the web app moving onto this package — once the window ships.\n","readmeFilename":"README.md"}