omnius 1.0.407 → 1.0.408

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -602166,6 +602166,103 @@ function describeCameraOrientation(orientation) {
602166
602166
  if (!orientation) return "upright/no correction (default)";
602167
602167
  return `${formatCameraRotation(orientation.rotation)} (${orientation.source}${orientation.confidence !== void 0 ? ` confidence=${orientation.confidence.toFixed(2)}` : ""}, updated=${nowIso3(orientation.updatedAt)})`;
602168
602168
  }
602169
+ function chooseCameraOrientationFromScores(scores) {
602170
+ const sorted = [...scores].filter((score) => Number.isFinite(score.score)).sort((a2, b) => b.score - a2.score);
602171
+ const best = sorted[0];
602172
+ if (!best || best.score <= 0 || best.faces <= 0) return null;
602173
+ const second3 = sorted[1];
602174
+ const gap = best.score - (second3?.score ?? 0);
602175
+ const total = sorted.reduce((sum, score) => sum + Math.max(0, score.score), 0);
602176
+ const share = total > 0 ? best.score / total : 1;
602177
+ const confidence2 = Math.max(0.55, Math.min(0.98, share * 0.75 + Math.min(0.23, gap / Math.max(1, best.score))));
602178
+ if (confidence2 < 0.58 && gap < 0.4) return null;
602179
+ return {
602180
+ rotation: best.rotation,
602181
+ confidence: confidence2,
602182
+ reason: `cv-face-orientation faces=${best.faces} score=${best.score.toFixed(2)} next=${(second3?.score ?? 0).toFixed(2)} area=${(best.faceAreaRatio ?? 0).toFixed(3)}`
602183
+ };
602184
+ }
602185
+ function trimOneLine(value2, maxChars) {
602186
+ return String(value2 ?? "").replace(/\r/g, " ").replace(/\n/g, " ").replace(/\s+/g, " ").trim().slice(0, maxChars);
602187
+ }
602188
+ function compactSourceId(source) {
602189
+ return source.replace(/^\/dev\//, "");
602190
+ }
602191
+ function truncateCell(value2, width) {
602192
+ if (width <= 1) return value2.slice(0, Math.max(0, width));
602193
+ return value2.length <= width ? value2.padEnd(width, " ") : `${value2.slice(0, Math.max(1, width - 1))}…`;
602194
+ }
602195
+ function summarizeInference(value2) {
602196
+ if (!value2) return "objects: pending";
602197
+ const lines = value2.split("\n").map((line) => line.trim()).filter(Boolean);
602198
+ const objectsIndex = lines.findIndex((line) => /^##\s+Objects/i.test(line));
602199
+ if (objectsIndex >= 0) {
602200
+ const objects = lines.slice(objectsIndex + 1).filter((line) => line.startsWith("- ")).slice(0, 4).map((line) => line.replace(/^-\s*/, ""));
602201
+ if (objects.length > 0) return `objects: ${objects.join("; ")}`;
602202
+ }
602203
+ const sampled = lines.find((line) => /^objects:/i.test(line));
602204
+ return sampled ? trimOneLine(sampled, 160) : trimOneLine(lines.slice(0, 4).join("; "), 160);
602205
+ }
602206
+ function cameraSnapshotSummary(camera) {
602207
+ if (camera.error) return `error: ${trimOneLine(camera.error, 160)}`;
602208
+ return camera.summary || summarizeInference(camera.inference);
602209
+ }
602210
+ function formatLiveDashboardFromSnapshot(snapshot, opts = {}) {
602211
+ const width = Math.max(60, opts.width ?? 100);
602212
+ const now2 = opts.now ?? Date.now();
602213
+ const maxCameras = opts.maxCameras ?? 4;
602214
+ const cameras = Object.values(snapshot.cameras ?? (snapshot.video ? { [snapshot.video.source]: snapshot.video } : {})).sort((a2, b) => {
602215
+ if (a2.source === snapshot.config.selectedCamera) return -1;
602216
+ if (b.source === snapshot.config.selectedCamera) return 1;
602217
+ return a2.source.localeCompare(b.source);
602218
+ }).slice(0, maxCameras);
602219
+ const audioAge = snapshot.audio?.updatedAt ? `${Math.max(0, Math.round((now2 - snapshot.audio.updatedAt) / 1e3))}s` : "none";
602220
+ const title = `live audio/video cameras=${cameras.length}/${snapshot.devices.video.length} audio=${snapshot.config.audioEnabled ? "on" : "off"} age=${audioAge}`;
602221
+ const horizontal = "─".repeat(Math.max(0, width - 2));
602222
+ const lines = [`╭${horizontal}╮`];
602223
+ lines.push(`│${truncateCell(` ${title}`, width - 2)}│`);
602224
+ if (cameras.length === 0) {
602225
+ lines.push(`│${truncateCell(" no camera frames captured yet", width - 2)}│`);
602226
+ }
602227
+ for (const camera of cameras) {
602228
+ const age = Math.max(0, Math.round((now2 - camera.updatedAt) / 1e3));
602229
+ const rotation = camera.orientation ? formatCameraRotation(camera.orientation.rotation) : "upright/no correction";
602230
+ lines.push(`├${horizontal}┤`);
602231
+ lines.push(`│${truncateCell(` ${compactSourceId(camera.source)} age=${age}s rotation=${rotation}`, width - 2)}│`);
602232
+ const asciiLines = (camera.ascii ?? "").split("\n").filter((line) => line.length > 0).slice(0, 10);
602233
+ const detailLines = [
602234
+ cameraSnapshotSummary(camera),
602235
+ camera.framePath ? `frame: ${camera.displayPath || camera.framePath}` : "",
602236
+ camera.orientation?.evidence ? `orientation: ${trimOneLine(camera.orientation.evidence, 120)}` : ""
602237
+ ].filter(Boolean);
602238
+ if (asciiLines.length === 0) {
602239
+ for (const detail of detailLines.length ? detailLines : ["preview pending"]) {
602240
+ lines.push(`│${truncateCell(` ${detail}`, width - 2)}│`);
602241
+ }
602242
+ continue;
602243
+ }
602244
+ const imageWidth = Math.max(24, Math.min(52, Math.floor((width - 5) * 0.58)));
602245
+ const detailWidth = Math.max(18, width - imageWidth - 5);
602246
+ const rowCount = Math.max(asciiLines.length, detailLines.length);
602247
+ for (let i2 = 0; i2 < rowCount; i2++) {
602248
+ const image = truncateCell(asciiLines[i2] ?? "", imageWidth);
602249
+ const detail = truncateCell(detailLines[i2] ?? "", detailWidth);
602250
+ lines.push(`│ ${image} │ ${detail}│`);
602251
+ }
602252
+ }
602253
+ if (snapshot.audio) {
602254
+ lines.push(`├${horizontal}┤`);
602255
+ const audioBits = [
602256
+ `audio input=${snapshot.audio.input || snapshot.config.selectedAudioInput || "none"}`,
602257
+ snapshot.audio.error ? `error=${trimOneLine(snapshot.audio.error, 120)}` : "",
602258
+ snapshot.audio.transcript ? `asr=${trimOneLine(snapshot.audio.transcript, 120)}` : "",
602259
+ snapshot.audio.analysis ? `sound=${trimOneLine(snapshot.audio.analysis, 120)}` : ""
602260
+ ].filter(Boolean);
602261
+ for (const item of audioBits.slice(0, 4)) lines.push(`│${truncateCell(` ${item}`, width - 2)}│`);
602262
+ }
602263
+ lines.push(`╰${horizontal}╯`);
602264
+ return lines;
602265
+ }
602169
602266
  function parseLiveMediaPayload(value2) {
602170
602267
  const parsed = parseJsonObject3(value2);
602171
602268
  if (!parsed) return null;
@@ -602425,6 +602522,21 @@ function formatLiveSensorContextFromSnapshot(snapshot, opts = {}) {
602425
602522
  lines.push(`Selected camera: ${snapshot.config.selectedCamera}`);
602426
602523
  lines.push(`Camera orientation correction: ${describeCameraOrientation(orientation)}`);
602427
602524
  }
602525
+ const cameraSnapshots = Object.values(snapshot.cameras ?? (snapshot.video ? { [snapshot.video.source]: snapshot.video } : {})).sort((a2, b) => {
602526
+ if (a2.source === snapshot.config.selectedCamera) return -1;
602527
+ if (b.source === snapshot.config.selectedCamera) return 1;
602528
+ return b.updatedAt - a2.updatedAt;
602529
+ });
602530
+ if (cameraSnapshots.length > 0) {
602531
+ lines.push("Camera snapshot set:");
602532
+ for (const camera of cameraSnapshots.slice(0, 6)) {
602533
+ const age = Math.max(0, Math.round((now2 - camera.updatedAt) / 1e3));
602534
+ const rotation = camera.orientation ? formatCameraRotation(camera.orientation.rotation) : "upright/no correction";
602535
+ lines.push(`- ${camera.source} age=${age}s rotation=${rotation}${camera.framePath ? ` frame=${camera.framePath}` : ""}${camera.error ? ` error=${trimOneLine(camera.error, 240)}` : ""}`);
602536
+ const summary = cameraSnapshotSummary(camera);
602537
+ if (summary) lines.push(` summary: ${summary}`);
602538
+ }
602539
+ }
602428
602540
  if (snapshot.config.selectedAudioInput) lines.push(`Selected audio input: ${snapshot.config.selectedAudioInput}`);
602429
602541
  if (snapshot.config.selectedAudioOutput) lines.push(`Selected audio output: ${snapshot.config.selectedAudioOutput}`);
602430
602542
  const cameraEvents = (snapshot.events ?? []).filter((event) => event.kind.startsWith("camera_") || event.kind === "clip_recognition" || event.kind === "visual_trigger").sort((a2, b) => b.observedAt - a2.observedAt).slice(0, 18);
@@ -602481,6 +602593,19 @@ function formatLiveSensorContextFromSnapshot(snapshot, opts = {}) {
602481
602593
  lines.push(cleanPreview(snapshot.video.inference, 1800));
602482
602594
  }
602483
602595
  }
602596
+ if (cameraSnapshots.length > 1) {
602597
+ lines.push("");
602598
+ lines.push("## LIVE CAMERA LATEST FRAMES");
602599
+ for (const camera of cameraSnapshots.slice(0, 6)) {
602600
+ const age = now2 - camera.updatedAt;
602601
+ const rotation = camera.orientation ? formatCameraRotation(camera.orientation.rotation) : "upright/no correction";
602602
+ lines.push(`### ${camera.source}`);
602603
+ lines.push(`timestamp: ${nowIso3(camera.updatedAt)} age=${Math.max(0, Math.round(age / 1e3))}s rotation=${rotation}${age > maxAgeMs ? " STALE" : ""}`);
602604
+ if (camera.error) lines.push(`error: ${camera.error}`);
602605
+ if (camera.framePath) lines.push(`frame: ${camera.framePath}`);
602606
+ lines.push(`summary: ${cameraSnapshotSummary(camera)}`);
602607
+ }
602608
+ }
602484
602609
  if (snapshot.audio) {
602485
602610
  const audioEvents = (snapshot.events ?? []).filter((event) => event.kind === "audio_transcript" || event.kind === "audio_sound").sort((a2, b) => b.observedAt - a2.observedAt).slice(0, 8);
602486
602611
  if (audioEvents.length > 0) {
@@ -602587,6 +602712,93 @@ async function recordAudioSample(device, durationSec, outputPath3) {
602587
602712
  outputPath3
602588
602713
  ], { timeout: (Number(seconds) + 10) * 1e3 });
602589
602714
  }
602715
+ async function scoreCameraOrientationWithOpenCv(framePath) {
602716
+ if (!await commandExists2("python3", 1200)) return null;
602717
+ const script = String.raw`
602718
+ import json, sys
602719
+ try:
602720
+ import cv2
602721
+ except Exception as exc:
602722
+ print(json.dumps({"ok": False, "error": str(exc)}))
602723
+ raise SystemExit(0)
602724
+
602725
+ path = sys.argv[1]
602726
+ img = cv2.imread(path)
602727
+ if img is None:
602728
+ print(json.dumps({"ok": False, "error": "could not read image"}))
602729
+ raise SystemExit(0)
602730
+
602731
+ face = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
602732
+ eye = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_eye.xml")
602733
+
602734
+ def rotate(mat, deg):
602735
+ if deg == 90:
602736
+ return cv2.rotate(mat, cv2.ROTATE_90_CLOCKWISE)
602737
+ if deg == 180:
602738
+ return cv2.rotate(mat, cv2.ROTATE_180)
602739
+ if deg == 270:
602740
+ return cv2.rotate(mat, cv2.ROTATE_90_COUNTERCLOCKWISE)
602741
+ return mat
602742
+
602743
+ scores = []
602744
+ for deg in [0, 90, 180, 270]:
602745
+ frame = rotate(img, deg)
602746
+ gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
602747
+ h, w = gray.shape[:2]
602748
+ faces = face.detectMultiScale(gray, scaleFactor=1.08, minNeighbors=4, minSize=(32, 32))
602749
+ face_area = 0.0
602750
+ eye_count = 0
602751
+ for (x, y, fw, fh) in faces[:8]:
602752
+ face_area += float(fw * fh) / max(1.0, float(w * h))
602753
+ roi = gray[y:y+fh, x:x+fw]
602754
+ try:
602755
+ eye_count += len(eye.detectMultiScale(roi, scaleFactor=1.1, minNeighbors=3, minSize=(8, 8)))
602756
+ except Exception:
602757
+ pass
602758
+ score = len(faces) * 2.5 + min(4.0, face_area * 35.0) + min(2.0, eye_count * 0.35)
602759
+ scores.append({"rotation": deg, "score": score, "faces": int(len(faces)), "faceAreaRatio": face_area})
602760
+ print(json.dumps({"ok": True, "scores": scores}))
602761
+ `;
602762
+ try {
602763
+ const raw = await execFileText4("python3", ["-c", script, framePath], { timeout: 15e3, maxBuffer: 1024 * 1024 });
602764
+ const parsed = parseJsonObjectFromText(raw);
602765
+ const scores = Array.isArray(parsed?.["scores"]) ? parsed["scores"] : [];
602766
+ if (scores.length === 0) return null;
602767
+ return scores.map((score) => ({
602768
+ rotation: normalizeLiveCameraRotation(score["rotation"]),
602769
+ score: Math.max(0, Number(score["score"] ?? 0)),
602770
+ faces: Math.max(0, Number(score["faces"] ?? 0)),
602771
+ faceAreaRatio: Number.isFinite(Number(score["faceAreaRatio"])) ? Number(score["faceAreaRatio"]) : void 0
602772
+ }));
602773
+ } catch {
602774
+ return null;
602775
+ }
602776
+ }
602777
+ async function tryRecordAudioDevice(device, durationSec, outputPath3) {
602778
+ await recordAudioSample(device, durationSec, outputPath3);
602779
+ }
602780
+ async function recordAudioSampleWithRecovery(preferred, devices, durationSec, outputPath3) {
602781
+ const ordered = [];
602782
+ const add3 = (id2) => {
602783
+ const clean5 = String(id2 ?? "").trim();
602784
+ if (clean5 && !ordered.includes(clean5)) ordered.push(clean5);
602785
+ };
602786
+ add3(preferred);
602787
+ for (const device of devices.filter((entry) => entry.source === "pulse" || entry.source === "pipewire")) add3(device.id);
602788
+ add3("pulse:default");
602789
+ add3("default");
602790
+ for (const device of devices.filter((entry) => entry.source !== "pulse" && entry.source !== "pipewire")) add3(device.id);
602791
+ const errors = [];
602792
+ for (const candidate of ordered) {
602793
+ try {
602794
+ await tryRecordAudioDevice(candidate, durationSec, outputPath3);
602795
+ return { ok: true, device: candidate, method: candidate.startsWith("pulse:") ? "pulse/ffmpeg" : "arecord", errors };
602796
+ } catch (err) {
602797
+ errors.push(`${candidate}: ${err instanceof Error ? err.message : String(err)}`.slice(0, 360));
602798
+ }
602799
+ }
602800
+ return { ok: false, device: preferred || "default", method: "none", errors };
602801
+ }
602590
602802
  function firstDeviceId(devices) {
602591
602803
  return devices.find((device) => device.id && !/metadata\/non-capture/i.test(device.detail ?? ""))?.id ?? devices[0]?.id;
602592
602804
  }
@@ -602677,6 +602889,7 @@ var init_live_sensors = __esm({
602677
602889
  agentActionEnabled = false;
602678
602890
  lastAgentReviewAt = 0;
602679
602891
  autoOrientationInFlight = /* @__PURE__ */ new Set();
602892
+ lastFeedbackAt = /* @__PURE__ */ new Map();
602680
602893
  setStatusSink(sink) {
602681
602894
  this.statusSink = sink ?? null;
602682
602895
  this.emitStatus();
@@ -602693,6 +602906,20 @@ var init_live_sensors = __esm({
602693
602906
  getSnapshot() {
602694
602907
  return this.snapshot;
602695
602908
  }
602909
+ activeVideoSources() {
602910
+ const ordered = [];
602911
+ const add3 = (id2) => {
602912
+ const clean5 = String(id2 ?? "").trim();
602913
+ if (!clean5 || ordered.includes(clean5)) return;
602914
+ const device = this.devices.video.find((entry) => entry.id === clean5);
602915
+ if (device && /metadata\/non-capture/i.test(device.detail ?? "")) return;
602916
+ ordered.push(clean5);
602917
+ };
602918
+ add3(this.config.selectedCamera);
602919
+ for (const device of this.devices.video) add3(device.id);
602920
+ if (ordered.length === 0) add3(firstDeviceId(this.devices.video));
602921
+ return ordered.slice(0, 4);
602922
+ }
602696
602923
  getCameraOrientation(device = this.config.selectedCamera) {
602697
602924
  return device ? this.config.cameraOrientation?.[device] : void 0;
602698
602925
  }
@@ -602763,6 +602990,12 @@ var init_live_sensors = __esm({
602763
602990
  }
602764
602991
  const framePath = extractSavedImagePath(captured.output, this.repoRoot);
602765
602992
  if (!framePath) return `Camera orientation detection captured ${target}, but no frame path was returned.`;
602993
+ const cvScores = await scoreCameraOrientationWithOpenCv(framePath);
602994
+ const cvDecision = cvScores ? chooseCameraOrientationFromScores(cvScores) : null;
602995
+ if (cvDecision && cvDecision.confidence >= 0.68) {
602996
+ const orientation2 = this.setCameraRotation(target, cvDecision.rotation, "auto", cvDecision.reason, cvDecision.confidence);
602997
+ return orientation2 ? `Auto orientation for ${target}: ${describeCameraOrientation(orientation2)}` : `Auto orientation for ${target} could not be persisted.`;
602998
+ }
602766
602999
  const prompt = [
602767
603000
  "Determine whether this camera frame is upright for a human viewer.",
602768
603001
  "Return only JSON with this schema:",
@@ -602777,14 +603010,24 @@ var init_live_sensors = __esm({
602777
603010
  model: "moondream3-preview"
602778
603011
  });
602779
603012
  if (!vision.success) {
603013
+ if (cvDecision) {
603014
+ const orientation2 = this.setCameraRotation(target, cvDecision.rotation, "auto", cvDecision.reason, cvDecision.confidence);
603015
+ return orientation2 ? `Auto orientation for ${target}: ${describeCameraOrientation(orientation2)}` : `Auto orientation for ${target} could not be persisted.`;
603016
+ }
602780
603017
  return `Camera orientation detection captured ${target}, but vision inference was unavailable: ${vision.error || vision.output || "unknown error"}`;
602781
603018
  }
602782
603019
  const decision2 = parseCameraOrientationDecision(vision.llmContent || vision.output);
602783
603020
  if (!decision2) {
603021
+ if (cvDecision) {
603022
+ const orientation2 = this.setCameraRotation(target, cvDecision.rotation, "auto", cvDecision.reason, cvDecision.confidence);
603023
+ return orientation2 ? `Auto orientation for ${target}: ${describeCameraOrientation(orientation2)}` : `Auto orientation for ${target} could not be persisted.`;
603024
+ }
602784
603025
  return `Camera orientation detection for ${target} was inconclusive. Vision output did not contain a structured rotation decision.`;
602785
603026
  }
602786
- const evidence = decision2.reason || boundedText(vision.llmContent || vision.output, 400);
602787
- const orientation = this.setCameraRotation(target, decision2.rotation, "auto", evidence, decision2.confidence);
603027
+ const useCv = cvDecision && (cvDecision.confidence > (decision2.confidence ?? 0) + 0.12 || cvDecision.rotation !== decision2.rotation && cvDecision.confidence >= 0.62 && (decision2.confidence ?? 0) < 0.76);
603028
+ const selected = useCv ? cvDecision : decision2;
603029
+ const evidence = useCv ? cvDecision.reason : `${decision2.reason || boundedText(vision.llmContent || vision.output, 320)}${cvDecision ? `; cv=${cvDecision.reason}` : ""}`;
603030
+ const orientation = this.setCameraRotation(target, selected.rotation, "auto", evidence, selected.confidence);
602788
603031
  return orientation ? `Auto orientation for ${target}: ${describeCameraOrientation(orientation)}` : `Auto orientation for ${target} could not be persisted.`;
602789
603032
  } finally {
602790
603033
  this.autoOrientationInFlight.delete(target);
@@ -602853,22 +603096,25 @@ var init_live_sensors = __esm({
602853
603096
  videoIntervalMs: options2.lowLatency === false ? this.config.videoIntervalMs : Math.min(this.config.videoIntervalMs, 1500),
602854
603097
  audioIntervalMs: options2.lowLatency === false ? this.config.audioIntervalMs : Math.min(this.config.audioIntervalMs, 3e3)
602855
603098
  });
602856
- const source = this.config.selectedCamera || firstDeviceId(this.devices.video);
602857
- if (source && !this.getCameraOrientation(source)) {
602858
- void this.autoOrientCamera(source, { onlyIfUnset: true }).then((message2) => {
602859
- this.emitFeedback({
603099
+ for (const source of this.activeVideoSources()) {
603100
+ const current = this.getCameraOrientation(source);
603101
+ if (current?.source === "manual") continue;
603102
+ if (current && current.confidence !== void 0 && current.confidence >= 0.75 && Date.now() - current.updatedAt < 15 * 6e4) continue;
603103
+ void this.autoOrientCamera(source).then((message2) => {
603104
+ this.emitFeedbackThrottled(`orient:${source}`, {
602860
603105
  kind: "orientation",
602861
603106
  title: "Camera auto-orientation",
602862
603107
  observedAt: Date.now(),
602863
603108
  message: message2
602864
- });
603109
+ }, 3e4);
603110
+ this.emitDashboard();
602865
603111
  }).catch((err) => {
602866
- this.emitFeedback({
603112
+ this.emitFeedbackThrottled(`orient-error:${source}`, {
602867
603113
  kind: "error",
602868
603114
  title: "Camera auto-orientation failed",
602869
603115
  observedAt: Date.now(),
602870
603116
  message: err instanceof Error ? err.message : String(err)
602871
- });
603117
+ }, 6e4);
602872
603118
  });
602873
603119
  }
602874
603120
  void this.sampleVideoNow(true).catch((err) => {
@@ -602895,7 +603141,7 @@ var init_live_sensors = __esm({
602895
603141
  });
602896
603142
  return options2.agent ? "Live PFC run enabled: visual/audio feedback is active and significant events can launch background agent review." : "Live run enabled: visual/audio feedback is active and live context will update each turn.";
602897
603143
  }
602898
- async previewCamera(device = this.config.selectedCamera) {
603144
+ async previewCamera(device = this.config.selectedCamera, options2 = {}) {
602899
603145
  const source = device || firstDeviceId(this.devices.video);
602900
603146
  if (!source) return { ok: false, message: "No camera selected. Use /live to select a camera after device discovery." };
602901
603147
  const orientation = this.getCameraOrientation(source);
@@ -602910,10 +603156,22 @@ var init_live_sensors = __esm({
602910
603156
  if (!result.success) {
602911
603157
  const error = result.error || result.output || "camera capture failed";
602912
603158
  const observedAt2 = Date.now();
602913
- this.snapshot.video = {
603159
+ const errorView = {
602914
603160
  updatedAt: observedAt2,
602915
603161
  source,
602916
- error
603162
+ error,
603163
+ rotation,
603164
+ orientation
603165
+ };
603166
+ if (source === this.config.selectedCamera || !this.snapshot.video) this.snapshot.video = errorView;
603167
+ this.snapshot.cameras = {
603168
+ ...this.snapshot.cameras ?? {},
603169
+ [source]: {
603170
+ ...this.snapshot.cameras?.[source] ?? { source, updatedAt: observedAt2 },
603171
+ ...errorView,
603172
+ updatedAt: observedAt2,
603173
+ source
603174
+ }
602917
603175
  };
602918
603176
  this.snapshot.events = mergeRecentById(this.snapshot.events, [{
602919
603177
  id: stableEventId("camera_error", source, observedAt2, error.slice(0, 80)),
@@ -602924,12 +603182,14 @@ var init_live_sensors = __esm({
602924
603182
  summary: error
602925
603183
  }], 50);
602926
603184
  this.persist();
602927
- this.emitFeedback({
602928
- kind: "error",
602929
- title: "Camera capture failed",
602930
- observedAt: observedAt2,
602931
- message: error
602932
- });
603185
+ if (options2.emit !== false) {
603186
+ this.emitFeedbackThrottled(`camera-capture:${source}:${error.slice(0, 80)}`, {
603187
+ kind: "error",
603188
+ title: "Camera capture failed",
603189
+ observedAt: observedAt2,
603190
+ message: error
603191
+ }, 3e4);
603192
+ }
602933
603193
  return { ok: false, message: error };
602934
603194
  }
602935
603195
  const framePath = extractSavedImagePath(result.output, this.repoRoot);
@@ -602938,15 +603198,26 @@ var init_live_sensors = __esm({
602938
603198
  const preview = await buildImageAsciiPreview(framePath, { width: 72, height: 22 });
602939
603199
  const asciiContext = preview ? formatImageAsciiContext(preview, displayPath) : void 0;
602940
603200
  const observedAt = Date.now();
602941
- this.snapshot.video = {
603201
+ const cameraView = {
602942
603202
  updatedAt: observedAt,
602943
603203
  source,
602944
603204
  framePath,
602945
603205
  displayPath,
603206
+ ascii: preview?.ascii,
603207
+ renderer: preview?.renderer,
602946
603208
  asciiContext,
602947
603209
  rotation,
602948
603210
  orientation
602949
603211
  };
603212
+ if (source === this.config.selectedCamera || !this.snapshot.video) this.snapshot.video = cameraView;
603213
+ this.snapshot.cameras = {
603214
+ ...this.snapshot.cameras ?? {},
603215
+ [source]: {
603216
+ ...cameraView,
603217
+ summary: this.snapshot.cameras?.[source]?.summary,
603218
+ inference: this.snapshot.cameras?.[source]?.inference
603219
+ }
603220
+ };
602950
603221
  this.snapshot.events = mergeRecentById(this.snapshot.events, [{
602951
603222
  id: stableEventId("camera_frame", source, observedAt, framePath),
602952
603223
  kind: "camera_frame",
@@ -602957,16 +603228,18 @@ var init_live_sensors = __esm({
602957
603228
  evidencePath: framePath
602958
603229
  }], 50);
602959
603230
  this.persist();
602960
- this.emitFeedback({
602961
- kind: "camera-frame",
602962
- title: "Live camera frame",
602963
- observedAt,
602964
- message: `Captured from ${source}${orientation ? ` (${formatCameraRotation(orientation.rotation)})` : ""}: ${framePath}`,
602965
- imagePath: framePath,
602966
- displayPath,
602967
- ascii: preview?.ascii,
602968
- renderer: preview?.renderer
602969
- });
603231
+ if (options2.emit !== false) {
603232
+ this.emitFeedback({
603233
+ kind: "camera-frame",
603234
+ title: "Live camera frame",
603235
+ observedAt,
603236
+ message: `Captured from ${source}${orientation ? ` (${formatCameraRotation(orientation.rotation)})` : ""}: ${framePath}`,
603237
+ imagePath: framePath,
603238
+ displayPath,
603239
+ ascii: preview?.ascii,
603240
+ renderer: preview?.renderer
603241
+ });
603242
+ }
602970
603243
  return {
602971
603244
  ok: true,
602972
603245
  message: `Camera frame captured from ${source}: ${framePath}`,
@@ -602976,7 +603249,7 @@ var init_live_sensors = __esm({
602976
603249
  renderer: preview?.renderer
602977
603250
  };
602978
603251
  }
602979
- async recognizeFrameObjects(framePath, source, observedAt = Date.now()) {
603252
+ async recognizeFrameObjects(framePath, source, observedAt = Date.now(), options2 = {}) {
602980
603253
  try {
602981
603254
  const result = await new VisualMemoryTool().execute({
602982
603255
  action: "recognize",
@@ -602996,109 +603269,124 @@ var init_live_sensors = __esm({
602996
603269
  evidencePath: framePath
602997
603270
  }], 50);
602998
603271
  this.persist();
602999
- this.emitFeedback({
603000
- kind: "clip",
603001
- title: result.success ? "CLIP visual-memory recognition" : "CLIP visual-memory unavailable",
603002
- observedAt,
603003
- message: summary
603004
- });
603272
+ if (options2.emit !== false) {
603273
+ this.emitFeedback({
603274
+ kind: "clip",
603275
+ title: result.success ? "CLIP visual-memory recognition" : "CLIP visual-memory unavailable",
603276
+ observedAt,
603277
+ message: summary
603278
+ });
603279
+ }
603005
603280
  return summary;
603006
603281
  } catch (err) {
603007
603282
  const message2 = `CLIP/visual-memory failed: ${err instanceof Error ? err.message : String(err)}`;
603008
- this.emitFeedback({
603009
- kind: "error",
603010
- title: "CLIP visual-memory failed",
603011
- observedAt,
603012
- message: message2
603013
- });
603283
+ if (options2.emit !== false) {
603284
+ this.emitFeedbackThrottled(`clip:${source}`, {
603285
+ kind: "error",
603286
+ title: "CLIP visual-memory failed",
603287
+ observedAt,
603288
+ message: message2
603289
+ }, 6e4);
603290
+ }
603014
603291
  return message2;
603015
603292
  }
603016
603293
  }
603017
- async sampleVideoNow(forceInfer = this.config.inferEnabled) {
603018
- if (this.videoInFlight) return "Video sampler is already running.";
603019
- this.videoInFlight = true;
603020
- try {
603021
- const preview = await this.previewCamera(this.config.selectedCamera);
603022
- let inference = "";
603023
- let clipSummary = "";
603024
- const source = this.config.selectedCamera || firstDeviceId(this.devices.video);
603025
- const orientation = source ? this.getCameraOrientation(source) : void 0;
603026
- const sampledAt = Date.now();
603027
- if (forceInfer && source) {
603028
- const loop = new LiveMediaLoopTool(this.repoRoot);
603029
- const result = await loop.execute({
603030
- action: "watch",
603031
- source_kind: "camera",
603032
- camera: source,
603033
- duration_sec: 4,
603034
- sample_interval_sec: 1,
603035
- max_frames: 4,
603036
- rotate_degrees: orientation?.rotation ?? 0,
603037
- auto_bootstrap: true,
603038
- audio_mode: "none",
603039
- detect_objects: true,
603040
- track_objects: true,
603041
- crop_faces: true,
603042
- recognize_faces: true
603043
- });
603044
- inference = result.success ? String(result.output || result.llmContent || "") : `Video inference failed: ${result.error || result.output || "unknown error"}`;
603045
- const livePayload = result.success ? parseLiveMediaPayload(result.llmContent || result.output) : null;
603046
- const observations = observationsFromLiveMediaPayload(livePayload, sampledAt, source);
603047
- this.snapshot.events = mergeRecentById(this.snapshot.events, observations.events, 50);
603048
- this.snapshot.people = mergeRecentById(this.snapshot.people, observations.people, 24);
603049
- this.snapshot.video = {
603050
- ...this.snapshot.video ?? { updatedAt: Date.now(), source },
603051
- updatedAt: sampledAt,
603052
- source,
603053
- inference,
603054
- rotation: orientation?.rotation ?? 0,
603055
- orientation,
603056
- ...preview.ok ? {} : { error: preview.message }
603057
- };
603058
- this.persist();
603059
- this.emitFeedback({
603060
- kind: result.success ? "video-inference" : "error",
603061
- title: result.success ? "Live video inference" : "Live video inference failed",
603294
+ async sampleSingleVideoNow(source, forceInfer) {
603295
+ const preview = await this.previewCamera(source, { emit: false });
603296
+ let inference = "";
603297
+ let clipSummary = "";
603298
+ const orientation = this.getCameraOrientation(source);
603299
+ const sampledAt = Date.now();
603300
+ if (forceInfer && source) {
603301
+ const loop = new LiveMediaLoopTool(this.repoRoot);
603302
+ const result = await loop.execute({
603303
+ action: "watch",
603304
+ source_kind: "camera",
603305
+ camera: source,
603306
+ duration_sec: 2.5,
603307
+ sample_interval_sec: 1,
603308
+ max_frames: 2,
603309
+ rotate_degrees: orientation?.rotation ?? 0,
603310
+ auto_bootstrap: true,
603311
+ audio_mode: "none",
603312
+ detect_objects: true,
603313
+ track_objects: true,
603314
+ crop_faces: true,
603315
+ recognize_faces: true
603316
+ });
603317
+ inference = result.success ? String(result.output || result.llmContent || "") : `Video inference failed: ${result.error || result.output || "unknown error"}`;
603318
+ const livePayload = result.success ? parseLiveMediaPayload(result.llmContent || result.output) : null;
603319
+ const observations = observationsFromLiveMediaPayload(livePayload, sampledAt, source);
603320
+ this.snapshot.events = mergeRecentById(this.snapshot.events, observations.events, 50);
603321
+ this.snapshot.people = mergeRecentById(this.snapshot.people, observations.people, 24);
603322
+ const existing = this.snapshot.cameras?.[source] ?? this.snapshot.video ?? { updatedAt: Date.now(), source };
603323
+ const camera = {
603324
+ ...existing,
603325
+ updatedAt: sampledAt,
603326
+ source,
603327
+ inference,
603328
+ summary: summarizeInference(inference),
603329
+ rotation: orientation?.rotation ?? 0,
603330
+ orientation,
603331
+ ...preview.ok ? { error: void 0 } : { error: preview.message }
603332
+ };
603333
+ this.snapshot.cameras = {
603334
+ ...this.snapshot.cameras ?? {},
603335
+ [source]: camera
603336
+ };
603337
+ if (source === this.config.selectedCamera || !this.snapshot.video) this.snapshot.video = camera;
603338
+ this.persist();
603339
+ if (!result.success) {
603340
+ this.emitFeedbackThrottled(`video-infer:${source}`, {
603341
+ kind: "error",
603342
+ title: "Live video inference failed",
603062
603343
  observedAt: sampledAt,
603063
- message: boundedText(inference, 1800)
603064
- });
603065
- for (const person of observations.people.filter((entry) => entry.cropPath).slice(0, 4)) {
603066
- const cropPath = person.cropPath;
603067
- const displayPath = relative11(this.repoRoot, cropPath).startsWith("..") ? cropPath : relative11(this.repoRoot, cropPath);
603068
- const facePreview = await buildImageAsciiPreview(cropPath, { width: 38, height: 14 });
603069
- this.emitFeedback({
603070
- kind: "face-crop",
603071
- title: person.status === "known" && person.name ? `Known face: ${person.name}` : "Unknown face awaiting identification",
603072
- observedAt: person.observedAt,
603073
- message: person.status === "known" && person.name ? `Identified ${person.name}${person.confidence !== void 0 ? ` confidence=${person.confidence.toFixed(2)}` : ""}` : `Face crop saved and awaiting identification${person.confidence !== void 0 ? ` confidence=${person.confidence.toFixed(2)}` : ""}`,
603074
- imagePath: cropPath,
603075
- displayPath,
603076
- ascii: facePreview?.ascii,
603077
- renderer: facePreview?.renderer
603078
- });
603079
- }
603080
- const unknownPeople = observations.people.filter((entry) => entry.status === "unknown");
603081
- if (unknownPeople.length > 0) {
603082
- this.maybeRequestAgentReview(
603083
- `${unknownPeople.length} unknown individual(s) observed on live camera`,
603084
- unknownPeople.map((entry) => `${entry.cropPath || entry.trackId || entry.source} ${entry.evidence || ""}`).join("; ")
603085
- );
603086
- }
603087
- const triggerEvents = observations.events.filter((entry) => entry.kind === "visual_trigger");
603088
- if (triggerEvents.length > 0) {
603089
- this.maybeRequestAgentReview(
603090
- "Visual trigger hit in live camera stream",
603091
- triggerEvents.map((entry) => entry.summary).join("; ")
603092
- );
603093
- }
603344
+ message: boundedText(inference, 1200)
603345
+ }, 45e3);
603346
+ }
603347
+ const unknownPeople = observations.people.filter((entry) => entry.status === "unknown");
603348
+ if (unknownPeople.length > 0) {
603349
+ this.maybeRequestAgentReview(
603350
+ `${unknownPeople.length} unknown individual(s) observed on live camera ${source}`,
603351
+ unknownPeople.map((entry) => `${entry.cropPath || entry.trackId || entry.source} ${entry.evidence || ""}`).join("; ")
603352
+ );
603353
+ }
603354
+ const triggerEvents = observations.events.filter((entry) => entry.kind === "visual_trigger");
603355
+ if (triggerEvents.length > 0) {
603356
+ this.maybeRequestAgentReview(
603357
+ `Visual trigger hit in live camera stream ${source}`,
603358
+ triggerEvents.map((entry) => entry.summary).join("; ")
603359
+ );
603094
603360
  }
603095
- if (this.config.clipEnabled && preview.ok && preview.framePath && source) {
603096
- clipSummary = await this.recognizeFrameObjects(preview.framePath, source, sampledAt);
603361
+ }
603362
+ if (this.config.clipEnabled && preview.ok && preview.framePath && source) {
603363
+ clipSummary = await this.recognizeFrameObjects(preview.framePath, source, sampledAt, { emit: false });
603364
+ const current = this.snapshot.cameras?.[source];
603365
+ if (current) {
603366
+ current.summary = [current.summary, clipSummary ? `clip: ${trimOneLine(clipSummary, 160)}` : ""].filter(Boolean).join(" | ");
603367
+ this.snapshot.cameras = { ...this.snapshot.cameras ?? {}, [source]: current };
603368
+ if (this.snapshot.video?.source === source) this.snapshot.video = current;
603369
+ this.persist();
603097
603370
  }
603098
- return [preview.message, inference ? `
603371
+ }
603372
+ return [preview.message, inference ? `
603099
603373
  ${inference}` : "", clipSummary ? `
603100
603374
  CLIP visual memory:
603101
603375
  ${clipSummary}` : ""].filter(Boolean).join("\n");
603376
+ }
603377
+ async sampleVideoNow(forceInfer = this.config.inferEnabled) {
603378
+ if (this.videoInFlight) return "Video sampler is already running.";
603379
+ this.videoInFlight = true;
603380
+ try {
603381
+ const sources = this.activeVideoSources();
603382
+ if (sources.length === 0) return "No camera selected. Use /live refresh after connecting hardware.";
603383
+ const outputs = [];
603384
+ for (const source of sources) {
603385
+ outputs.push(await this.sampleSingleVideoNow(source, forceInfer));
603386
+ }
603387
+ this.emitDashboard();
603388
+ return outputs.map((output, index) => `## Camera ${sources[index]}
603389
+ ${output}`).join("\n\n");
603102
603390
  } finally {
603103
603391
  this.videoInFlight = false;
603104
603392
  }
@@ -603113,10 +603401,9 @@ ${clipSummary}` : ""].filter(Boolean).join("\n");
603113
603401
  const recordingPath = join124(outputDir2, `audio-${Date.now()}.wav`);
603114
603402
  let transcript = "";
603115
603403
  let analysis = "";
603116
- try {
603117
- await recordAudioSample(input, 3, recordingPath);
603118
- } catch (err) {
603119
- const message2 = `Audio capture failed from ${input}: ${err instanceof Error ? err.message : String(err)}`;
603404
+ const capture = await recordAudioSampleWithRecovery(input, this.devices.audioInputs, 3, recordingPath);
603405
+ if (!capture.ok) {
603406
+ const message2 = `Audio capture failed from ${input}; tried fallbacks: ${capture.errors.slice(0, 5).join(" | ")}`;
603120
603407
  this.snapshot.audio = {
603121
603408
  updatedAt: Date.now(),
603122
603409
  input,
@@ -603124,14 +603411,18 @@ ${clipSummary}` : ""].filter(Boolean).join("\n");
603124
603411
  error: message2
603125
603412
  };
603126
603413
  this.persist();
603127
- this.emitFeedback({
603414
+ this.emitFeedbackThrottled(`audio-capture:${input}`, {
603128
603415
  kind: "error",
603129
603416
  title: "Live audio capture failed",
603130
603417
  observedAt: this.snapshot.audio.updatedAt,
603131
603418
  message: message2
603132
- });
603419
+ }, 6e4);
603420
+ this.emitDashboard();
603133
603421
  return message2;
603134
603422
  }
603423
+ if (capture.device !== this.config.selectedAudioInput) {
603424
+ this.config.selectedAudioInput = capture.device;
603425
+ }
603135
603426
  if (this.config.asrEnabled) {
603136
603427
  try {
603137
603428
  const asr = await new TranscribeFileTool(this.repoRoot).execute({ path: recordingPath, model: "tiny" });
@@ -603159,7 +603450,7 @@ ${clipSummary}` : ""].filter(Boolean).join("\n");
603159
603450
  }
603160
603451
  this.snapshot.audio = {
603161
603452
  updatedAt: Date.now(),
603162
- input,
603453
+ input: capture.device,
603163
603454
  output: this.config.selectedAudioOutput,
603164
603455
  recordingPath,
603165
603456
  transcript,
@@ -603168,10 +603459,10 @@ ${clipSummary}` : ""].filter(Boolean).join("\n");
603168
603459
  const audioEvents = [];
603169
603460
  if (transcript) {
603170
603461
  audioEvents.push({
603171
- id: stableEventId("audio_transcript", input, this.snapshot.audio.updatedAt, recordingPath),
603462
+ id: stableEventId("audio_transcript", capture.device, this.snapshot.audio.updatedAt, recordingPath),
603172
603463
  kind: "audio_transcript",
603173
603464
  observedAt: this.snapshot.audio.updatedAt,
603174
- source: input,
603465
+ source: capture.device,
603175
603466
  title: "Live ASR transcript",
603176
603467
  summary: transcript,
603177
603468
  evidencePath: recordingPath
@@ -603179,10 +603470,10 @@ ${clipSummary}` : ""].filter(Boolean).join("\n");
603179
603470
  }
603180
603471
  if (analysis) {
603181
603472
  audioEvents.push({
603182
- id: stableEventId("audio_sound", input, this.snapshot.audio.updatedAt, recordingPath),
603473
+ id: stableEventId("audio_sound", capture.device, this.snapshot.audio.updatedAt, recordingPath),
603183
603474
  kind: "audio_sound",
603184
603475
  observedAt: this.snapshot.audio.updatedAt,
603185
- source: input,
603476
+ source: capture.device,
603186
603477
  title: "Live sound analysis",
603187
603478
  summary: analysis,
603188
603479
  evidencePath: recordingPath
@@ -603190,21 +603481,9 @@ ${clipSummary}` : ""].filter(Boolean).join("\n");
603190
603481
  }
603191
603482
  this.snapshot.events = mergeRecentById(this.snapshot.events, audioEvents, 50);
603192
603483
  this.persist();
603193
- if (transcript || analysis) {
603194
- this.emitFeedback({
603195
- kind: "audio",
603196
- title: "Live audio sample",
603197
- observedAt: this.snapshot.audio.updatedAt,
603198
- message: [
603199
- transcript ? `ASR:
603200
- ${boundedText(transcript, 700)}` : "",
603201
- analysis ? `Sounds:
603202
- ${boundedText(analysis, 900)}` : ""
603203
- ].filter(Boolean).join("\n\n")
603204
- });
603205
- }
603484
+ this.emitDashboard();
603206
603485
  return [
603207
- `Audio sample captured from ${input}: ${recordingPath}`,
603486
+ `Audio sample captured from ${capture.device}${capture.device !== input ? ` (recovered from ${input})` : ""}: ${recordingPath}`,
603208
603487
  transcript ? `
603209
603488
  ASR:
603210
603489
  ${transcript}` : "",
@@ -603256,6 +603535,21 @@ ${analysis}` : ""
603256
603535
  } catch {
603257
603536
  }
603258
603537
  }
603538
+ emitFeedbackThrottled(key, feedback, minIntervalMs) {
603539
+ const now2 = Date.now();
603540
+ const last2 = this.lastFeedbackAt.get(key) ?? 0;
603541
+ if (now2 - last2 < minIntervalMs) return;
603542
+ this.lastFeedbackAt.set(key, now2);
603543
+ this.emitFeedback(feedback);
603544
+ }
603545
+ emitDashboard() {
603546
+ this.emitFeedback({
603547
+ kind: "dashboard",
603548
+ title: "Live audio/video monitor",
603549
+ observedAt: Date.now(),
603550
+ message: "live dashboard refresh"
603551
+ });
603552
+ }
603259
603553
  maybeRequestAgentReview(reason, evidence) {
603260
603554
  if (!this.agentActionEnabled || !this.agentActionSink) return;
603261
603555
  const now2 = Date.now();
@@ -654970,7 +655264,33 @@ function renderLivePreview(preview) {
654970
655264
  renderWarning("Camera preview was captured, but ASCII rendering was unavailable.");
654971
655265
  }
654972
655266
  }
654973
- function renderLiveFeedback(feedback) {
655267
+ function renderLiveDashboard(ctx3, manager) {
655268
+ const host = ctx3.liveDynamicBlockHost;
655269
+ if (!host) {
655270
+ renderInfo(formatLiveDashboardFromSnapshot(manager.getSnapshot(), { width: 100 }).join("\n"));
655271
+ return;
655272
+ }
655273
+ const key = ctx3.repoRoot;
655274
+ let state = liveDashboardBlocks.get(key);
655275
+ if (!state || state.host !== host) {
655276
+ const id2 = `live-dashboard-${Math.random().toString(36).slice(2, 9)}`;
655277
+ state = { host, id: id2, manager };
655278
+ liveDashboardBlocks.set(key, state);
655279
+ host.registerDynamicBlock(
655280
+ id2,
655281
+ (width) => formatLiveDashboardFromSnapshot(manager.getSnapshot(), { width })
655282
+ );
655283
+ host.appendDynamicBlock(id2);
655284
+ return;
655285
+ }
655286
+ state.manager = manager;
655287
+ host.refreshDynamicBlocks?.();
655288
+ }
655289
+ function renderLiveFeedback(ctx3, manager, feedback) {
655290
+ if (feedback.kind === "dashboard") {
655291
+ renderLiveDashboard(ctx3, manager);
655292
+ return;
655293
+ }
654974
655294
  const stamp = new Date(feedback.observedAt).toISOString();
654975
655295
  if (feedback.kind === "error") {
654976
655296
  renderWarning(`[live ${stamp}] ${feedback.title}
@@ -654987,7 +655307,7 @@ ${feedback.message}`);
654987
655307
  }
654988
655308
  function attachLiveSinks(ctx3, manager, agentEnabled = false) {
654989
655309
  manager.setStatusSink(ctx3.setLiveMediaStatus);
654990
- manager.setFeedbackSink((feedback) => renderLiveFeedback(feedback));
655310
+ manager.setFeedbackSink((feedback) => renderLiveFeedback(ctx3, manager, feedback));
654991
655311
  if (agentEnabled && ctx3.startBackgroundPrompt) {
654992
655312
  manager.setAgentActionSink((prompt) => {
654993
655313
  const id2 = ctx3.startBackgroundPrompt?.(prompt);
@@ -660485,7 +660805,7 @@ async function showExposeDashboard(gateway, rl, ctx3) {
660485
660805
  renderInfo("Expose gateway stopped.");
660486
660806
  }
660487
660807
  }
660488
- var OMNIUS_PINNED_DEPENDENCY_SPECS, NEXUS_DIRECTORY_ORIGIN, NEXUS_SPONSORS_URL, _sponsorHeartbeatTimer, _lastRegisteredSponsorPayload, __COMMAND_REGISTRY, DASH_INTERNAL, localGpuMetricsCache, localGpuMetricsProbeAt, localGpuMetricsProbeInFlight;
660808
+ var OMNIUS_PINNED_DEPENDENCY_SPECS, NEXUS_DIRECTORY_ORIGIN, NEXUS_SPONSORS_URL, _sponsorHeartbeatTimer, _lastRegisteredSponsorPayload, __COMMAND_REGISTRY, liveDashboardBlocks, DASH_INTERNAL, localGpuMetricsCache, localGpuMetricsProbeAt, localGpuMetricsProbeInFlight;
660489
660809
  var init_commands = __esm({
660490
660810
  "packages/cli/src/tui/commands.ts"() {
660491
660811
  "use strict";
@@ -660803,6 +661123,7 @@ var init_commands = __esm({
660803
661123
  }
660804
661124
  });
660805
661125
  })();
661126
+ liveDashboardBlocks = /* @__PURE__ */ new Map();
660806
661127
  DASH_INTERNAL = /* @__PURE__ */ new Set(["system_metrics", "__list_capabilities"]);
660807
661128
  localGpuMetricsCache = null;
660808
661129
  localGpuMetricsProbeAt = 0;
@@ -733124,6 +733445,11 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
733124
733445
  setLiveMediaStatus(status) {
733125
733446
  statusBar.setLiveMediaStatus(status);
733126
733447
  },
733448
+ liveDynamicBlockHost: {
733449
+ registerDynamicBlock: (id2, render2) => statusBar.registerDynamicBlock(id2, render2),
733450
+ appendDynamicBlock: (id2) => statusBar.appendDynamicBlock(id2),
733451
+ refreshDynamicBlocks: () => statusBar.refreshDynamicBlocks()
733452
+ },
733127
733453
  // Voice call session — standalone cloudflared tunnel for /call
733128
733454
  // Each connecting WebSocket client gets a dedicated CallSubAgent.
733129
733455
  // Admin callers (matching session key) get full tool access; public callers get read-only.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.407",
3
+ "version": "1.0.408",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.407",
9
+ "version": "1.0.408",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.407",
3
+ "version": "1.0.408",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",