migrate stage build to native elc; chat restores from localStorage on return

Build pipeline
- build-stage.sh replaces the old in-Dockerfile bootstrap.py path. Host
  pre-compiles src/*.el into dist/main.c via the canonical native elc at
  foundation/el/dist/platform/elc and applies the stub-decl sed before
  docker buildx runs.
- Dockerfile.stage drops bootstrap.py + python3 from the builder stage
  and just runs cc on the host-supplied dist/main.c.
- Pre-rendered HTML shells under /srv/landing/ are now chowned to the
  landing user so the El page-builder's fs_write at startup can rewrite
  them — without that, post-COPY edits never reach the served HTML and
  the served page stays as the stale build-time fallback.

Chat restore
- session.verified + session.verifiedAt persist through localStorage so
  a return visit within 24h skips the Turnstile gate and lands directly
  in the restored conversation.
- restoreOrGreet() is the single source of truth for what shows up in
  the message pane after the gate clears: replays prior messages with
  skipSave, else drops the canned hello once and remembers it.
- applyVerifiedDom() hides the gate / reveals the chat row, called both
  from the verified-on-load path (DOMContentLoaded if loading, else
  immediate) and from the Turnstile callback.
- neuronDemoReset clears verified + verifiedAt so the gate returns next
  open.

Extracted JS assets (src/assets/js/*.js + manifest.json) and the
extract-js.py helper land here too — they match what the new build-stage
flow produces and removes the inline <script> blobs from the served HTML.
This commit is contained in:
Will Anderson
2026-05-02 11:15:09 -05:00
parent cae5028130
commit 640813e42e
27 changed files with 906 additions and 1461 deletions
+1 -60
View File
@@ -182,65 +182,6 @@ fn enterprise() -> String {
}
</style>
<script>
(function() {
var form = document.getElementById('enterprise-form');
var submitBtn = document.getElementById('ent-submit');
var successDiv = document.getElementById('enterprise-success');
var errorDiv = document.getElementById('ent-form-error');
if (!form) return;
window.entHeadcountChange = function(val) {
document.getElementById('ent-filter-msg-secondary').style.display = val === 'secondary' ? 'block' : 'none';
document.getElementById('ent-filter-msg-yes').style.display = val === 'yes' ? 'block' : 'none';
submitBtn.disabled = val === 'yes';
submitBtn.style.opacity = val === 'yes' ? '0.35' : '1';
submitBtn.style.cursor = val === 'yes' ? 'not-allowed' : 'pointer';
};
form.addEventListener('submit', function(e) {
e.preventDefault();
var headcount = document.getElementById('ent-headcount').value;
if (headcount === 'yes') {
document.getElementById('ent-filter-msg-yes').style.display = 'block';
return;
}
var name = document.getElementById('ent-name').value.trim();
var email = document.getElementById('ent-email').value.trim();
var company = document.getElementById('ent-company').value.trim();
var size = document.getElementById('ent-size').value;
var useCase = document.getElementById('ent-use').value.trim();
if (!name || !email || !company || !size || !useCase || !headcount) {
errorDiv.textContent = 'Please fill out all fields.';
errorDiv.style.display = 'block';
return;
}
errorDiv.style.display = 'none';
submitBtn.textContent = 'Sending…';
submitBtn.disabled = true;
fetch('/api/enterprise-inquiry', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: name, email: email, company: company, size: size, use_case: useCase, headcount: headcount })
})
.then(function(r) { return r.json(); })
.then(function(data) {
form.style.display = 'none';
successDiv.style.display = 'block';
})
.catch(function() {
submitBtn.textContent = 'Send inquiry →';
submitBtn.disabled = false;
errorDiv.textContent = 'Something went wrong. Email enterprise@neurontechnologies.ai directly.';
errorDiv.style.display = 'block';
});
});
})();
</script>
<script src=\"/assets/js/67c990f787eb.js\" defer></script>
"
}