Files
Niko1221 0b3299a019 apps/host: the owner's UI and the Node App Host
The UI source from the 14 October handoff (src/, public/, index.html, vite and
tsconfig, tests, audit-fixes, design docs) and the App Host (server/*.mjs): model
import and monitor routes, API-provider catalog and streaming (OpenAI chat, OpenAI Responses,
the Messages API), serving, tunnel, tasks, plus the host routes for Time-skip
(server/timeskip.mjs) and the tuning plan/reports. src/lib/time-skip.ts renders a real
job's own record.

The UI design is unchanged. The rebuild routed #/tuning to a new TunePanel; that is
reverted: src/screens/ModelRun.tsx and src/main.tsx are the handoff's again (#/tuning
goes where the handoff sends it), and src/components/TunePanel.tsx and
src/styles/tuning.css, which only that route used, are not carried over. Left out of
git on purpose: dist/ (build output), node_modules, and docs/evidence + docs/checkpoints
(170 MB of screenshots, kept in StrataSplit\evidence-archive).

From the owner's rebuild branch strata/rebuild-2026-10.
2026-10-15 10:24:09 +02:00

35 lines
1.3 KiB
JavaScript

/** One active inference request; queued work is cancellable and never survives host exit. */
export class RequestQueue {
#pending = [];
#active = false;
constructor(onChange = () => {}) { this.onChange = onChange; }
get waiting() { return this.#pending.length; }
run(signal, task) {
return new Promise((resolve, reject) => {
const entry = { signal, task, resolve, reject, abort: null };
entry.abort = () => {
const index = this.#pending.indexOf(entry);
if (index < 0) return;
this.#pending.splice(index, 1);
reject(signal.reason ?? new DOMException('Request cancelled', 'AbortError'));
this.onChange(this.waiting);
};
if (signal.aborted) { reject(signal.reason); return; }
signal.addEventListener('abort', entry.abort, { once: true });
this.#pending.push(entry);
this.#drain();
});
}
async #drain() {
if (this.#active) { this.onChange(this.waiting); return; }
const entry = this.#pending.shift();
if (!entry) { this.onChange(0); return; }
this.#active = true;
entry.signal.removeEventListener('abort', entry.abort);
this.onChange(this.waiting);
try { entry.signal.throwIfAborted(); entry.resolve(await entry.task()); }
catch (error) { entry.reject(error); }
finally { this.#active = false; this.#drain(); }
}
}