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:
@@ -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>
|
||||
|
||||
@@ -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; }
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user