tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

commit f50246c22afb005e0256a2ea0388cfb42e2e672d
parent 5573c515459decf24799a567ec19ab1a10a5529e
Author: James Eversole <james@eversole.co>
Date:   Sun, 18 Oct 2026 20:17:06 -0500

Load published packages immediately when selected

Use the selected release loader for published-package choices so evaluation does not depend on a Load button hidden in Settings. Preserve explicit evaluation and authenticated package loading, with regression coverage for source-free library expressions.

Diffstat:
Mext/demo-site/README.md | 3++-
Mext/demo-site/dist/app.js | 9++++++---
Mext/demo-site/src/app.ts | 11++++++++---
Mext/demo-site/test/live-ux-probe.mjs | 5++++-
4 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/ext/demo-site/README.md b/ext/demo-site/README.md @@ -280,7 +280,8 @@ The package selector reads `packages.json`, a versioned static index of exact name/version → native manifest + whole-bundle pins. A single **Program** selector controls both result evaluation and stored-definition output, with grouped **Examples**, **Published packages**, and a visible **Load by bundle hash…** option. Versions are listed -newest-first and opening an example or package selects its newest indexed release, +newest-first and choosing an example or published package immediately loads and +verifies its newest indexed release, without requiring the Load button in Settings, independently of publication order. Conventional `MAJOR.MINOR.PATCH` versions use SemVer precedence (including prereleases); other accepted labels sort below them in numeric-aware label order. Examples use curated source and suggested inputs diff --git a/ext/demo-site/dist/app.js b/ext/demo-site/dist/app.js @@ -642,12 +642,15 @@ programPicker.onchange = () => { if (value === 'hash') hashInput.value = ''; invalidateProgram(); - if (value === 'hash') + if (value.startsWith('package:')) + loadSelectedRelease(); + else if (value === 'hash') hashInput.focus(); } }; versionPicker.onchange = invalidateProgram; -el('load-release').onclick = () => { +el('load-release').onclick = loadSelectedRelease; +function loadSelectedRelease() { const name = programPackage(programPicker.value); const release = releases.find(r => r.name === name && r.version === versionPicker.value); if (!release) @@ -657,7 +660,7 @@ el('load-release').onclick = () => { select(demo, release); else loadBundle(release); -}; +} function downloadHash() { const name = programPackage(programPicker.value); if (name) diff --git a/ext/demo-site/src/app.ts b/ext/demo-site/src/app.ts @@ -401,16 +401,21 @@ programPicker.onchange = () => { const value = programPicker.value; if (value.startsWith('demo:')) { const entry = entries.find(e => e.id === value.slice(5)); if (entry) selectExample(entry); - } else { chooseProgram(value); if (value === 'hash') hashInput.value = ''; invalidateProgram(); if (value === 'hash') hashInput.focus(); } + } else { + chooseProgram(value); if (value === 'hash') hashInput.value = ''; invalidateProgram(); + if (value.startsWith('package:')) loadSelectedRelease(); + else if (value === 'hash') hashInput.focus(); + } }; versionPicker.onchange = invalidateProgram; -el<HTMLButtonElement>('load-release').onclick = () => { +el<HTMLButtonElement>('load-release').onclick = loadSelectedRelease; +function loadSelectedRelease(): void { const name = programPackage(programPicker.value); const release = releases.find(r => r.name === name && r.version === versionPicker.value); if (!release) return; const demo = entries.find(e => e.id === release.demo && e.hash === release.hash); if (demo) select(demo, release); else loadBundle(release); -}; +} function downloadHash(): BundleHash | undefined { const name = programPackage(programPicker.value); if (name) return releases.find(r => r.name === name && r.version === versionPicker.value)?.hash; diff --git a/ext/demo-site/test/live-ux-probe.mjs b/ext/demo-site/test/live-ux-probe.mjs @@ -50,7 +50,10 @@ export async function run(control,backend='haskell-wasm',alreadyUsed=false){ await evaluate('identity 23','23'); assert([...el('export').options].map(x=>x.value).join(',')===exports,'Expressions never publish temporary names'); // No editable source required: bind exact published library exports to trees. - change('program-picker','package:tricu-base');el('load-release').click();await status('Ready'); + assert(el('settings-panel').hidden,'Package loading must not require opening Settings'); + change('program-picker','package:tricu-base');await status('Ready'); + assert(!el('run').disabled&&el('settings-panel').hidden,'Selecting a package makes it usable without a hidden Load action'); + assert(el('result').textContent===''&&el('terminal').textContent==='','Package selection only loads; it never evaluates'); assert(el('source-editor').hidden,'Library has no editable source'); assert([...el('export').options].some(x=>x.value==='append'),'Published list export exists'); await evaluate('append "hello " "λ🙂"','hello λ🙂','string');