WIP: Claude Code progress on #65

Automated salvage commit — agent session ended (exit 124).
Work in progress, may need continuation.
This commit is contained in:
Alexander Whitestone
2026-03-23 16:08:35 -04:00
parent fb847b6e53
commit edbfbac318
5 changed files with 58 additions and 4 deletions

View File

@@ -495,6 +495,12 @@
50% { opacity: 0.2; }
}
/* ── Nostr identity prompt animation ─────────────────────────────── */
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
/* ── Timmy identity card ──────────────────────────────────────────── */
#timmy-id-card {
position: fixed; bottom: 80px; right: 16px;
@@ -520,6 +526,7 @@
<h1>THE WORKSHOP</h1>
<div id="fps">FPS: --</div>
<div id="active-jobs">JOBS: 0</div>
<div id="edge-status" title="Local AI model status">◌ AI: loading</div>
<div id="session-hud">
<span id="session-hud-balance">Balance: -- sats</span>
<a href="#" id="session-hud-topup">⚡ Top Up</a>

View File

@@ -25,6 +25,7 @@
let _worker = null;
let _ready = false;
let _readyCb = null;
let _errorCb = null;
const _pending = new Map(); // id → { resolve, reject }
let _nextId = 1;
@@ -48,6 +49,7 @@ function _init() {
// Resolve all pending with fallback values
for (const [, { resolve }] of _pending) resolve(_fallback(null));
_pending.clear();
if (_errorCb) { _errorCb(data.message); _errorCb = null; }
return;
}
@@ -103,6 +105,10 @@ export function onReady(fn) {
_readyCb = fn;
}
export function onError(fn) {
_errorCb = fn;
}
export function isReady() { return _ready; }
/**

View File

@@ -12,8 +12,8 @@ import { initWebSocket, getConnectionState, getJobCount } from './websocket.js';
import { initPaymentPanel } from './payment.js';
import { initSessionPanel } from './session.js';
import { initNostrIdentity } from './nostr-identity.js';
import { warmup as warmupEdgeWorker, onReady as onEdgeWorkerReady } from './edge-worker-client.js';
import { setEdgeWorkerReady } from './ui.js';
import { warmup as warmupEdgeWorker, onReady as onEdgeWorkerReady, onError as onEdgeWorkerError } from './edge-worker-client.js';
import { setEdgeWorkerReady, setEdgeWorkerError } from './ui.js';
import { initTimmyId } from './timmy-id.js';
import { AGENT_DEFS } from './agent-defs.js';
import { initNavigation, updateNavigation, disposeNavigation } from './navigation.js';
@@ -49,6 +49,7 @@ function buildWorld(firstInit, stateSnapshot) {
void initNostrIdentity('/api');
warmupEdgeWorker();
onEdgeWorkerReady(() => setEdgeWorkerReady());
onEdgeWorkerError(() => setEdgeWorkerError());
void initTimmyId();
}

View File

@@ -32,12 +32,34 @@ export function setInputBarSessionMode(active, placeholder) {
}
// ── Model-ready indicator ─────────────────────────────────────────────────────
// A small badge on the input bar showing when local AI is warm and ready.
// Hidden until the first `ready` event from the edge worker.
// 1. A small status line in the HUD: "◌ AI: loading" → "● AI: ready" / "✕ AI: error"
// 2. A badge on the input bar once the model is warm (subtle "⚡ local AI" cue).
// Both are updated by setEdgeWorkerReady() / setEdgeWorkerError().
let $readyBadge = null;
let _identityReady = false;
function _updateEdgeHud(state) {
const $s = document.getElementById('edge-status');
if (!$s) return;
if (state === 'ready') {
$s.textContent = '● AI: ready';
$s.style.color = '#44cc88';
$s.title = 'Local AI active — trivial queries answered without Lightning payment';
} else if (state === 'error') {
$s.textContent = '✕ AI: error';
$s.style.color = '#cc4444';
$s.title = 'Local AI unavailable — all requests routed to server';
} else {
$s.textContent = '◌ AI: loading';
$s.style.color = '';
$s.title = 'Local AI model loading…';
}
}
export function setEdgeWorkerReady() {
_updateEdgeHud('ready');
if (!$readyBadge) {
$readyBadge = document.createElement('span');
$readyBadge.id = 'edge-ready-badge';
@@ -58,6 +80,23 @@ export function setEdgeWorkerReady() {
$readyBadge.style.display = '';
}
export function setEdgeWorkerError() {
_updateEdgeHud('error');
}
// Listen for Nostr identity resolved — update HUD tooltip to reflect combined state
window.addEventListener('nostr:identity-ready', (e) => {
_identityReady = true;
const pubkey = e.detail?.pubkey;
const $s = document.getElementById('edge-status');
if ($s && $s.textContent.startsWith('●')) {
$s.title = `Local AI active · Nostr identity: ${pubkey ? pubkey.slice(0, 8) + '…' : 'connected'}`;
}
if ($readyBadge) {
$readyBadge.title = `Local AI + Nostr identity active${pubkey ? ' (' + pubkey.slice(0, 8) + '…)' : ''}`;
}
});
// ── Cost preview badge ────────────────────────────────────────────────────────
// Shown beneath the input bar: "~N sats" / "FREE" / "answered locally".
// Fetched from GET /api/estimate once the user stops typing (300 ms debounce).

View File

@@ -9,6 +9,7 @@
"preview": "vite preview"
},
"dependencies": {
"@noble/hashes": "^1.7.2",
"@xenova/transformers": "^2.17.2",
"nostr-tools": "^2.23.3",
"three": "0.171.0"