omnius 1.0.415 → 1.0.417

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
@@ -603131,25 +603131,29 @@ function liveDashboardRotationActionFromClick(snapshot, lineText, col) {
603131
603131
  }
603132
603132
  function pushDashboardWrapped(lines, value2, width) {
603133
603133
  const contentWidth = Math.max(10, width - 2);
603134
- const words = stripDashboardAnsi(value2).replace(/\s+/g, " ").trim().split(" ").filter(Boolean);
603134
+ const normalized = stripDashboardAnsi(value2).replace(/\s+/g, " ").trimEnd();
603135
+ const leading = normalized.match(/^ */)?.[0] ?? "";
603136
+ const words = normalized.slice(leading.length).trimStart().split(" ").filter(Boolean);
603135
603137
  if (words.length === 0) {
603136
603138
  lines.push(`│${" ".repeat(contentWidth)}│`);
603137
603139
  return;
603138
603140
  }
603139
- let current = "";
603141
+ let current = leading;
603140
603142
  for (const word2 of words) {
603141
- if (!current) {
603142
- current = word2.length > contentWidth ? word2.slice(0, contentWidth) : word2;
603143
+ if (current === leading) {
603144
+ const available = Math.max(1, contentWidth - leading.length);
603145
+ current = `${leading}${word2.length > available ? word2.slice(0, available) : word2}`;
603143
603146
  continue;
603144
603147
  }
603145
603148
  if (current.length + 1 + word2.length <= contentWidth) {
603146
603149
  current += ` ${word2}`;
603147
603150
  } else {
603148
603151
  lines.push(`│${truncateCell(` ${current}`, contentWidth)}│`);
603149
- current = word2.length > contentWidth ? word2.slice(0, contentWidth) : word2;
603152
+ const available = Math.max(1, contentWidth - leading.length);
603153
+ current = `${leading}${word2.length > available ? word2.slice(0, available) : word2}`;
603150
603154
  }
603151
603155
  }
603152
- if (current) lines.push(`│${truncateCell(` ${current}`, contentWidth)}│`);
603156
+ if (current.trim()) lines.push(`│${truncateCell(` ${current}`, contentWidth)}│`);
603153
603157
  }
603154
603158
  function isAudioFailureText(value2) {
603155
603159
  const text2 = String(value2 ?? "").trim();
@@ -603159,6 +603163,9 @@ function isAudioFailureText(value2) {
603159
603163
  function sanitizeLiveAudioError(value2) {
603160
603164
  const text2 = String(value2 ?? "").trim();
603161
603165
  if (!text2) return "";
603166
+ if (/No live input signal detected after probing \d+ audio source/i.test(text2)) {
603167
+ return "No clear live input signal on selected audio input.";
603168
+ }
603162
603169
  if (/transcribe-cli module:\s*No module named ['"]?transcribe_cli/i.test(text2) || /No module named ['"]?transcribe_cli/i.test(text2)) {
603163
603170
  const parts = text2.split(/\s*\|\s*/g).map((part) => part.trim()).filter((part) => part && !/transcribe-cli module:\s*No module named ['"]?transcribe_cli/i.test(part) && !/No module named ['"]?transcribe_cli/i.test(part));
603164
603171
  const preserved = parts.join(" | ").trim();
@@ -603541,6 +603548,104 @@ function cameraClassificationsSummary(camera, maxChars = 220) {
603541
603548
  });
603542
603549
  return trimOneLine(items.join("; "), maxChars);
603543
603550
  }
603551
+ function cameraClassPriority(kind) {
603552
+ if (kind === "face" || kind === "identity") return 0;
603553
+ if (kind === "segment") return 1;
603554
+ if (kind === "object") return 2;
603555
+ if (kind === "track") return 3;
603556
+ if (kind === "clip") return 4;
603557
+ return 5;
603558
+ }
603559
+ function groupedDashboardClassifications(camera, kinds) {
603560
+ const wanted = new Set(kinds);
603561
+ const grouped = /* @__PURE__ */ new Map();
603562
+ for (const item of camera.classifications ?? []) {
603563
+ if (!wanted.has(item.kind)) continue;
603564
+ const label = trimOneLine(item.label || item.kind, 64) || item.kind;
603565
+ const key = `${item.kind}:${label.toLowerCase()}`;
603566
+ const existing = grouped.get(key);
603567
+ const count = Math.max(1, item.count);
603568
+ if (!existing) {
603569
+ grouped.set(key, {
603570
+ kind: item.kind,
603571
+ label,
603572
+ count,
603573
+ confidence: item.confidence
603574
+ });
603575
+ continue;
603576
+ }
603577
+ existing.count += count;
603578
+ if (item.confidence !== void 0) {
603579
+ existing.confidence = existing.confidence === void 0 ? item.confidence : Math.max(existing.confidence, item.confidence);
603580
+ }
603581
+ }
603582
+ return [...grouped.values()].sort((a2, b) => {
603583
+ const priority = cameraClassPriority(a2.kind) - cameraClassPriority(b.kind);
603584
+ if (priority !== 0) return priority;
603585
+ return (b.confidence ?? 0) - (a2.confidence ?? 0) || b.count - a2.count || a2.label.localeCompare(b.label);
603586
+ });
603587
+ }
603588
+ function formatDashboardClassList(groups, maxItems = 6) {
603589
+ return groups.slice(0, maxItems).map((group) => {
603590
+ const count = group.count > 1 ? ` x${group.count}` : "";
603591
+ const confidence2 = group.confidence !== void 0 ? ` ${group.confidence.toFixed(2)}` : "";
603592
+ return `${group.label}${count}${confidence2}`;
603593
+ }).join("; ");
603594
+ }
603595
+ function cleanCameraSummaryForDashboard(value2) {
603596
+ const raw = String(value2 ?? "").trim();
603597
+ if (!raw) return "";
603598
+ const withoutClip = raw.split(/\s+\|\s+clip:/i)[0] ?? raw;
603599
+ return trimOneLine(
603600
+ withoutClip.replace(/\b(?:mask|crop)=\S+/gi, "").replace(/\bbbox=\[[^\]]*\]/gi, "").replace(/\s{2,}/g, " "),
603601
+ 220
603602
+ );
603603
+ }
603604
+ function formatClipDashboardSummary(value2) {
603605
+ const text2 = String(value2 ?? "").trim();
603606
+ if (!text2) return "";
603607
+ const clipText = text2.match(/\bclip:\s*([\s\S]+)$/i)?.[1] ?? text2;
603608
+ const parsed = parseJsonObjectFromText(clipText);
603609
+ if (!parsed) return /\bclip:\s*/i.test(text2) ? `clip: ${trimOneLine(clipText, 120)}` : "";
603610
+ const matches = Array.isArray(parsed["matches"]) ? parsed["matches"] : [];
603611
+ if (matches.length > 0) {
603612
+ const labels = matches.slice(0, 4).map((match) => {
603613
+ const label = trimOneLine(match["label"] ?? match["name"] ?? match["title"] ?? match["id"] ?? "match", 48);
603614
+ const score = boundedConfidence(match["score"] ?? match["similarity"] ?? match["confidence"]);
603615
+ return `${label || "match"}${score !== void 0 ? ` ${score.toFixed(2)}` : ""}`;
603616
+ });
603617
+ return `clip: ${labels.join("; ")}`;
603618
+ }
603619
+ const recognized = Math.max(0, Number(parsed["recognized_count"] ?? 0));
603620
+ const extra = parsed["extra_labels"];
603621
+ if (Array.isArray(extra) && extra.length > 0) {
603622
+ return `clip: extra labels ${extra.slice(0, 4).map((entry) => trimOneLine(entry, 36)).join("; ")}`;
603623
+ }
603624
+ if (typeof extra === "string" && extra.trim()) return `clip: ${trimOneLine(extra, 120)}`;
603625
+ return recognized > 0 ? `clip: ${recognized} recognized match(es)` : "clip: no visual-memory matches";
603626
+ }
603627
+ function formatAudioAnalysisDashboardSummary(value2) {
603628
+ const text2 = String(value2 ?? "").trim();
603629
+ if (!text2) return "";
603630
+ const parsed = parseJsonObjectFromText(text2);
603631
+ const classifications = Array.isArray(parsed?.["classifications"]) ? parsed["classifications"] : [];
603632
+ if (classifications.length > 0) {
603633
+ return `sound classes: ${classifications.slice(0, 4).map((entry) => {
603634
+ const label = trimOneLine(entry["class"] ?? entry["label"] ?? entry["name"] ?? "sound", 44);
603635
+ const score = boundedConfidence(entry["score"] ?? entry["confidence"]);
603636
+ return `${label || "sound"}${score !== void 0 ? ` ${score.toFixed(2)}` : ""}`;
603637
+ }).join("; ")}`;
603638
+ }
603639
+ return `sound: ${trimOneLine(text2.replace(/\{[\s\S]*$/, ""), 140) || trimOneLine(text2, 140)}`;
603640
+ }
603641
+ function formatCameraRotationDashboard(camera) {
603642
+ const orientation = camera.orientation;
603643
+ const rotation = orientation?.rotation ?? camera.rotation ?? 0;
603644
+ const base3 = formatCameraRotation(rotation);
603645
+ if (!orientation) return base3;
603646
+ const confidence2 = orientation.confidence !== void 0 ? ` ${orientation.confidence.toFixed(2)}` : "";
603647
+ return `${base3} (${orientation.source}${confidence2})`;
603648
+ }
603544
603649
  function cameraPaneBadge(camera) {
603545
603650
  const classifications = camera.classifications ?? [];
603546
603651
  const faceCount = classifications.filter((item) => item.kind === "face" || item.kind === "identity").reduce((sum, item) => sum + Math.max(1, item.count), 0);
@@ -603559,7 +603664,44 @@ function cameraPaneBadge(camera) {
603559
603664
  }
603560
603665
  function cameraSnapshotSummary(camera) {
603561
603666
  if (camera.error) return `error: ${trimOneLine(camera.error, 160)}`;
603562
- return camera.summary || (camera.classifications?.length ? `classifications: ${cameraClassificationsSummary(camera)}` : "") || summarizeInference(camera.inference);
603667
+ return cleanCameraSummaryForDashboard(camera.summary) || (camera.classifications?.length ? `classifications: ${cameraClassificationsSummary(camera)}` : "") || summarizeInference(camera.inference);
603668
+ }
603669
+ function cameraDashboardObservationLines(camera, now2, isLast) {
603670
+ const age = Math.max(0, Math.round((now2 - camera.updatedAt) / 1e3));
603671
+ const root = isLast ? "└─" : "├─";
603672
+ const stem = isLast ? " " : "│ ";
603673
+ const lines = [
603674
+ `${root} ${compactSourceId(camera.source)} age=${age}s rotation=${formatCameraRotationDashboard(camera)}`
603675
+ ];
603676
+ if (camera.error) {
603677
+ lines.push(`${stem}└─ error: ${trimOneLine(camera.error, 180)}`);
603678
+ return lines;
603679
+ }
603680
+ const faces = formatDashboardClassList(groupedDashboardClassifications(camera, ["face", "identity"]), 4);
603681
+ const segments = formatDashboardClassList(groupedDashboardClassifications(camera, ["segment"]), 6);
603682
+ const objects = formatDashboardClassList(groupedDashboardClassifications(camera, ["object"]), 6);
603683
+ const tracks = formatDashboardClassList(groupedDashboardClassifications(camera, ["track"]), 4);
603684
+ const triggers = formatDashboardClassList(groupedDashboardClassifications(camera, ["trigger"]), 3);
603685
+ const clip3 = formatClipDashboardSummary(camera.summary) || formatDashboardClassList(groupedDashboardClassifications(camera, ["clip"]), 4);
603686
+ const summary = cameraSnapshotSummary(camera);
603687
+ const includeSummary = summary && !summary.startsWith("classifications:") && !(objects && /^objects:/i.test(summary)) && !(segments && /^segments?:/i.test(summary));
603688
+ const detailLines = [
603689
+ faces ? `faces: ${faces}` : "",
603690
+ segments ? `segments: ${segments}` : "",
603691
+ objects ? `objects: ${objects}` : "",
603692
+ tracks ? `tracks: ${tracks}` : "",
603693
+ triggers ? `triggers: ${triggers}` : "",
603694
+ includeSummary ? summary : "",
603695
+ clip3,
603696
+ camera.framePath ? `frame: ${camera.displayPath || camera.framePath}` : "",
603697
+ camera.orientation?.evidence ? `orientation: ${trimOneLine(camera.orientation.evidence, 120)}` : ""
603698
+ ].filter(Boolean);
603699
+ const last2 = Math.max(0, detailLines.length - 1);
603700
+ detailLines.forEach((detail, index) => {
603701
+ lines.push(`${stem}${index === last2 ? "└─" : "├─"} ${detail}`);
603702
+ });
603703
+ if (detailLines.length === 0) lines.push(`${stem}└─ preview pending`);
603704
+ return lines;
603563
603705
  }
603564
603706
  function formatLiveDashboardFromSnapshot(snapshot, opts = {}) {
603565
603707
  const width = Math.max(60, opts.width ?? 100);
@@ -603599,35 +603741,27 @@ function formatLiveDashboardFromSnapshot(snapshot, opts = {}) {
603599
603741
  lines.push(`├${horizontal}┤`);
603600
603742
  lines.push(`│${truncateCell(" camera observations", width - 2)}│`);
603601
603743
  }
603602
- for (const camera of cameras) {
603603
- const age = Math.max(0, Math.round((now2 - camera.updatedAt) / 1e3));
603604
- const rotation = camera.orientation ? formatCameraRotation(camera.orientation.rotation) : "upright/no correction";
603605
- const classifications = cameraClassificationsSummary(camera);
603606
- const detailLines = [
603607
- `${compactSourceId(camera.source)} age=${age}s rotation=${rotation}`,
603608
- classifications ? `classifications: ${classifications}` : "",
603609
- cameraSnapshotSummary(camera),
603610
- camera.framePath ? `frame: ${camera.displayPath || camera.framePath}` : "",
603611
- camera.orientation?.evidence ? `orientation: ${trimOneLine(camera.orientation.evidence, 120)}` : ""
603612
- ].filter(Boolean);
603613
- for (const detail of detailLines.length ? detailLines : ["preview pending"]) {
603744
+ cameras.forEach((camera, index) => {
603745
+ const detailLines = cameraDashboardObservationLines(camera, now2, index === cameras.length - 1);
603746
+ for (const detail of detailLines) {
603614
603747
  pushDashboardWrapped(lines, detail, width);
603615
603748
  }
603616
- }
603749
+ });
603617
603750
  if (snapshot.audio) {
603618
603751
  lines.push(`├${horizontal}┤`);
603752
+ lines.push(`│${truncateCell(" audio monitor", width - 2)}│`);
603619
603753
  const transcriptFailure = isAudioFailureText(snapshot.audio.transcript) ? snapshot.audio.transcript : "";
603620
603754
  const transcript = transcriptFailure ? "" : snapshot.audio.transcript;
603621
603755
  const audioError = sanitizeLiveAudioError([snapshot.audio.error, transcriptFailure].filter(Boolean).join(" | "));
603622
603756
  const audioBits = [
603623
- `audio input=${snapshot.audio.input || snapshot.config.selectedAudioInput || "none"}`,
603624
- snapshot.audio.activity ? `activity ${snapshot.audio.activity.waveform} rms=${snapshot.audio.activity.rmsDb.toFixed(1)}dB active=${Math.round(snapshot.audio.activity.activeRatio * 100)}%` : "",
603625
- audioError ? `error=${trimOneLine(audioError, 120)}` : "",
603626
- transcript ? `asr${snapshot.audio.asrBackend ? `(${snapshot.audio.asrBackend})` : ""}=${trimOneLine(transcript, 120)}` : "",
603627
- snapshot.audio.intake ? `intake=${snapshot.audio.intake.intendedForAgent ? "for-agent" : "ambient"} conf=${snapshot.audio.intake.confidence.toFixed(2)} ${snapshot.audio.intake.action}` : "",
603628
- snapshot.audio.analysis ? `sound=${trimOneLine(snapshot.audio.analysis, 120)}` : ""
603757
+ `├─ input: ${snapshot.audio.input || snapshot.config.selectedAudioInput || "none"}`,
603758
+ snapshot.audio.activity ? `│ ├─ activity: ${snapshot.audio.activity.waveform} rms=${snapshot.audio.activity.rmsDb.toFixed(1)}dB active=${Math.round(snapshot.audio.activity.activeRatio * 100)}%` : "",
603759
+ audioError ? `│ ├─ error: ${trimOneLine(audioError, 140)}` : "",
603760
+ transcript ? `│ ├─ asr${snapshot.audio.asrBackend ? ` (${snapshot.audio.asrBackend})` : ""}: ${trimOneLine(transcript, 140)}` : "",
603761
+ snapshot.audio.intake ? `│ ├─ intake: ${snapshot.audio.intake.intendedForAgent ? "for-agent" : "ambient"} conf=${snapshot.audio.intake.confidence.toFixed(2)} action=${snapshot.audio.intake.action}` : "",
603762
+ snapshot.audio.analysis ? `│ └─ ${formatAudioAnalysisDashboardSummary(snapshot.audio.analysis)}` : ""
603629
603763
  ].filter(Boolean);
603630
- for (const item of audioBits.slice(0, 6)) lines.push(`│${truncateCell(` ${item}`, width - 2)}│`);
603764
+ for (const item of audioBits.slice(0, 6)) pushDashboardWrapped(lines, item, width);
603631
603765
  }
603632
603766
  lines.push(`╰${horizontal}╯`);
603633
603767
  return lines;
@@ -604087,7 +604221,9 @@ async function discoverAudioOutputs() {
604087
604221
  return { devices: dedupeDevices(devices), errors };
604088
604222
  }
604089
604223
  async function recordAudioSample(device, durationSec, outputPath3) {
604090
- const seconds = String(Math.max(1, Math.min(30, Math.ceil(durationSec))));
604224
+ const duration = Math.max(0.2, Math.min(30, Number.isFinite(durationSec) ? durationSec : 1));
604225
+ const ffmpegSeconds = duration < 1 ? duration.toFixed(3) : String(Math.ceil(duration));
604226
+ const arecordSeconds = String(Math.max(1, Math.ceil(duration)));
604091
604227
  if (device.startsWith("pulse:") && await commandExists2("ffmpeg", 1500)) {
604092
604228
  const source = device.slice("pulse:".length);
604093
604229
  await execFileText4("ffmpeg", [
@@ -604099,14 +604235,38 @@ async function recordAudioSample(device, durationSec, outputPath3) {
604099
604235
  "-i",
604100
604236
  source,
604101
604237
  "-t",
604102
- seconds,
604238
+ ffmpegSeconds,
604239
+ "-ac",
604240
+ "1",
604241
+ "-ar",
604242
+ "16000",
604243
+ "-acodec",
604244
+ "pcm_s16le",
604245
+ "-y",
604246
+ outputPath3
604247
+ ], { timeout: (Math.ceil(duration) + 10) * 1e3 });
604248
+ return;
604249
+ }
604250
+ if (duration < 1 && await commandExists2("ffmpeg", 1500)) {
604251
+ await execFileText4("ffmpeg", [
604252
+ "-hide_banner",
604253
+ "-loglevel",
604254
+ "error",
604255
+ "-f",
604256
+ "alsa",
604257
+ "-i",
604258
+ device || "default",
604259
+ "-t",
604260
+ ffmpegSeconds,
604103
604261
  "-ac",
604104
604262
  "1",
604105
604263
  "-ar",
604106
604264
  "16000",
604265
+ "-acodec",
604266
+ "pcm_s16le",
604107
604267
  "-y",
604108
604268
  outputPath3
604109
- ], { timeout: (Number(seconds) + 10) * 1e3 });
604269
+ ], { timeout: (Math.ceil(duration) + 10) * 1e3 });
604110
604270
  return;
604111
604271
  }
604112
604272
  await execFileText4("arecord", [
@@ -604119,10 +604279,10 @@ async function recordAudioSample(device, durationSec, outputPath3) {
604119
604279
  "-c",
604120
604280
  "1",
604121
604281
  "-d",
604122
- seconds,
604282
+ arecordSeconds,
604123
604283
  "-q",
604124
604284
  outputPath3
604125
- ], { timeout: (Number(seconds) + 10) * 1e3 });
604285
+ ], { timeout: (Number(arecordSeconds) + 10) * 1e3 });
604126
604286
  }
604127
604287
  async function scoreCameraOrientationWithOpenCv(framePath) {
604128
604288
  if (!await commandExists2("python3", 1200)) return null;
@@ -604196,19 +604356,25 @@ function hasLiveAudioSignal(activity) {
604196
604356
  function audioCaptureMethod(device) {
604197
604357
  return device.startsWith("pulse:") ? "pulse/ffmpeg" : "arecord";
604198
604358
  }
604199
- async function recordAudioSampleWithRecovery(preferred, devices, durationSec, outputPath3) {
604359
+ async function recordAudioSampleWithRecovery(preferred, devices, durationSec, outputPath3, options2 = {}) {
604360
+ const allowFallback = options2.allowFallback !== false;
604361
+ const requireSignal = options2.requireSignal !== false;
604200
604362
  const ordered = [];
604201
604363
  const add3 = (id2) => {
604202
604364
  const clean5 = String(id2 ?? "").trim();
604203
604365
  if (clean5 && !ordered.includes(clean5)) ordered.push(clean5);
604204
604366
  };
604205
604367
  const preferredInput = preferredLiveAudioInputId(devices, preferred);
604206
- add3(preferredInput);
604207
- if (preferred && !isAudioOutputMonitorId(preferred)) add3(preferred);
604208
- for (const device of rankLiveAudioInputDevices(devices, preferred).filter((entry) => !isAudioOutputMonitorDevice(entry))) add3(device.id);
604209
- add3("pulse:default");
604210
- add3("default");
604211
- for (const device of rankLiveAudioInputDevices(devices, preferred).filter((entry) => isAudioOutputMonitorDevice(entry))) add3(device.id);
604368
+ if (allowFallback) {
604369
+ add3(preferredInput);
604370
+ if (preferred) add3(preferred);
604371
+ for (const device of rankLiveAudioInputDevices(devices, preferred).filter((entry) => !isAudioOutputMonitorDevice(entry))) add3(device.id);
604372
+ add3("pulse:default");
604373
+ add3("default");
604374
+ for (const device of rankLiveAudioInputDevices(devices, preferred).filter((entry) => isAudioOutputMonitorDevice(entry))) add3(device.id);
604375
+ } else {
604376
+ add3(preferred || preferredInput || "default");
604377
+ }
604212
604378
  const errors = [];
604213
604379
  const attempts = [];
604214
604380
  let firstQuietCapture = null;
@@ -604218,8 +604384,9 @@ async function recordAudioSampleWithRecovery(preferred, devices, durationSec, ou
604218
604384
  await tryRecordAudioDevice(candidate, durationSec, outputPath3);
604219
604385
  const activity = readPcm16WavActivity(outputPath3);
604220
604386
  const method = audioCaptureMethod(candidate);
604221
- if (hasLiveAudioSignal(activity)) {
604222
- return { ok: true, device: candidate, method, errors, attempts, activity, signalDetected: true };
604387
+ const signalDetected = hasLiveAudioSignal(activity);
604388
+ if (!requireSignal || signalDetected) {
604389
+ return { ok: true, device: candidate, method, errors, attempts, activity, signalDetected };
604223
604390
  }
604224
604391
  if (!firstQuietCapture) {
604225
604392
  firstQuietCapture = {
@@ -604325,7 +604492,7 @@ function formatLiveStatus(snapshot) {
604325
604492
  }
604326
604493
  return lines.join("\n");
604327
604494
  }
604328
- var MIN_VIDEO_INTERVAL_MS, LOW_LATENCY_VIDEO_INTERVAL_MS, MIN_AUDIO_INTERVAL_MS, LOW_LATENCY_AUDIO_INTERVAL_MS, DEFAULT_CONFIG7, managers, DASHBOARD_ANSI_STICKY_PATTERN, LiveSensorManager;
604495
+ var MIN_VIDEO_INTERVAL_MS, LOW_LATENCY_VIDEO_INTERVAL_MS, MIN_AUDIO_INTERVAL_MS, LOW_LATENCY_AUDIO_INTERVAL_MS, AUDIO_ACTIVITY_INTERVAL_MS, AUDIO_ACTIVITY_SAMPLE_SEC, DEFAULT_CONFIG7, managers, DASHBOARD_ANSI_STICKY_PATTERN, LiveSensorManager;
604329
604496
  var init_live_sensors = __esm({
604330
604497
  "packages/cli/src/tui/live-sensors.ts"() {
604331
604498
  "use strict";
@@ -604336,6 +604503,8 @@ var init_live_sensors = __esm({
604336
604503
  LOW_LATENCY_VIDEO_INTERVAL_MS = 250;
604337
604504
  MIN_AUDIO_INTERVAL_MS = 1500;
604338
604505
  LOW_LATENCY_AUDIO_INTERVAL_MS = 2e3;
604506
+ AUDIO_ACTIVITY_INTERVAL_MS = 200;
604507
+ AUDIO_ACTIVITY_SAMPLE_SEC = 0.2;
604339
604508
  DEFAULT_CONFIG7 = {
604340
604509
  videoEnabled: false,
604341
604510
  audioEnabled: false,
@@ -604368,8 +604537,10 @@ var init_live_sensors = __esm({
604368
604537
  snapshot;
604369
604538
  videoTimer = null;
604370
604539
  audioTimer = null;
604540
+ audioActivityTimer = null;
604371
604541
  videoInFlight = false;
604372
604542
  audioInFlight = false;
604543
+ audioActivityInFlight = false;
604373
604544
  statusSink = null;
604374
604545
  feedbackSink = null;
604375
604546
  agentActionSink = null;
@@ -604580,10 +604751,7 @@ var init_live_sensors = __esm({
604580
604751
  errors
604581
604752
  };
604582
604753
  if (!this.config.selectedCamera) this.config.selectedCamera = firstDeviceId(video);
604583
- const preferredInput = preferredLiveAudioInputId(inputs.devices, this.config.selectedAudioInput);
604584
- if (!this.config.selectedAudioInput || isAudioOutputMonitorId(this.config.selectedAudioInput) && preferredInput && !isAudioOutputMonitorId(preferredInput)) {
604585
- this.config.selectedAudioInput = preferredInput;
604586
- }
604754
+ if (!this.config.selectedAudioInput) this.config.selectedAudioInput = preferredLiveAudioInputId(inputs.devices);
604587
604755
  if (!this.config.selectedAudioOutput) this.config.selectedAudioOutput = firstDeviceId(outputs.devices);
604588
604756
  this.persist();
604589
604757
  return this.devices;
@@ -604943,7 +605111,8 @@ var init_live_sensors = __esm({
604943
605111
  clipSummary = await this.recognizeFrameObjects(preview.framePath, source, sampledAt, { emit: false });
604944
605112
  const current = this.snapshot.cameras?.[source];
604945
605113
  if (current) {
604946
- current.summary = [current.summary, clipSummary ? `clip: ${trimOneLine(clipSummary, 160)}` : ""].filter(Boolean).join(" | ");
605114
+ const clipLine = formatClipDashboardSummary(clipSummary);
605115
+ current.summary = [cleanCameraSummaryForDashboard(current.summary), clipLine].filter(Boolean).join(" | ");
604947
605116
  current.classifications = mergeCameraClassifications(
604948
605117
  current.classifications,
604949
605118
  classificationsFromClipSummary(clipSummary, sampledAt, preview.framePath)
@@ -604987,13 +605156,93 @@ ${output}`).join("\n\n");
604987
605156
  this.videoInFlight = false;
604988
605157
  }
604989
605158
  }
605159
+ resolveAudioInput() {
605160
+ const selected = String(this.config.selectedAudioInput ?? "").trim();
605161
+ if (selected) return selected;
605162
+ const input = preferredLiveAudioInputId(this.devices.audioInputs) || "default";
605163
+ this.config.selectedAudioInput = input;
605164
+ this.persist();
605165
+ return input;
605166
+ }
605167
+ async previewAudioInput(device = this.config.selectedAudioInput) {
605168
+ const input = String(device || "").trim() || this.resolveAudioInput();
605169
+ ensureLiveDir(this.repoRoot);
605170
+ const recordingPath = join124(liveDir(this.repoRoot), `audio-preview-${Date.now()}.wav`);
605171
+ const capture = await recordAudioSampleWithRecovery(input, this.devices.audioInputs, 0.8, recordingPath, {
605172
+ allowFallback: false
605173
+ });
605174
+ const now2 = Date.now();
605175
+ const activity = capture.activity ?? (capture.ok ? readPcm16WavActivity(recordingPath) : void 0);
605176
+ if (capture.ok) {
605177
+ this.snapshot.audio = {
605178
+ ...this.snapshot.audio ?? { updatedAt: now2 },
605179
+ updatedAt: now2,
605180
+ input,
605181
+ output: this.config.selectedAudioOutput,
605182
+ recordingPath,
605183
+ activity,
605184
+ error: void 0
605185
+ };
605186
+ this.persist();
605187
+ this.emitDashboard();
605188
+ const signal = capture.signalDetected === false ? "quiet/no clear mic signal" : "signal detected";
605189
+ return {
605190
+ ok: true,
605191
+ input,
605192
+ recordingPath,
605193
+ activity,
605194
+ message: [
605195
+ `Audio input preview from ${input}: ${signal}`,
605196
+ activity ? `activity ${activity.waveform} rms=${activity.rmsDb.toFixed(1)}dB active=${Math.round(activity.activeRatio * 100)}% peak=${activity.peak.toFixed(3)}` : "",
605197
+ `recording: ${recordingPath}`
605198
+ ].filter(Boolean).join("\n")
605199
+ };
605200
+ }
605201
+ const message2 = `Audio input preview failed for ${input}: ${capture.errors.slice(0, 5).join(" | ") || "capture failed"}`;
605202
+ this.snapshot.audio = {
605203
+ ...this.snapshot.audio ?? { updatedAt: now2 },
605204
+ updatedAt: now2,
605205
+ input,
605206
+ output: this.config.selectedAudioOutput,
605207
+ error: message2
605208
+ };
605209
+ this.persist();
605210
+ this.emitDashboard();
605211
+ return { ok: false, input, message: message2 };
605212
+ }
605213
+ async sampleAudioActivityNow() {
605214
+ if (!this.config.audioEnabled || this.audioActivityInFlight) return;
605215
+ this.audioActivityInFlight = true;
605216
+ const input = this.resolveAudioInput();
605217
+ try {
605218
+ ensureLiveDir(this.repoRoot);
605219
+ const recordingPath = join124(liveDir(this.repoRoot), "audio-activity.wav");
605220
+ const capture = await recordAudioSampleWithRecovery(input, this.devices.audioInputs, AUDIO_ACTIVITY_SAMPLE_SEC, recordingPath, {
605221
+ allowFallback: false,
605222
+ requireSignal: false
605223
+ });
605224
+ const now2 = Date.now();
605225
+ const activity = capture.activity ?? (capture.ok ? readPcm16WavActivity(recordingPath) : void 0);
605226
+ this.snapshot.audio = {
605227
+ ...this.snapshot.audio ?? { updatedAt: now2 },
605228
+ updatedAt: now2,
605229
+ input,
605230
+ output: this.config.selectedAudioOutput,
605231
+ recordingPath,
605232
+ activity,
605233
+ error: capture.ok ? this.snapshot.audio?.error : `Audio activity capture failed from ${input}: ${capture.errors.slice(0, 3).join(" | ")}`
605234
+ };
605235
+ this.persist();
605236
+ this.emitDashboard();
605237
+ } finally {
605238
+ this.audioActivityInFlight = false;
605239
+ }
605240
+ }
604990
605241
  async sampleAudioNow() {
604991
605242
  if (this.audioInFlight) return "Audio sampler is already running.";
604992
605243
  this.audioInFlight = true;
604993
605244
  try {
604994
- const preferredInput = preferredLiveAudioInputId(this.devices.audioInputs, this.config.selectedAudioInput) || "default";
604995
- const input = this.config.selectedAudioInput && !isAudioOutputMonitorId(this.config.selectedAudioInput) ? this.config.selectedAudioInput : preferredInput;
604996
- if (input !== this.config.selectedAudioInput) this.config.selectedAudioInput = input;
605245
+ const input = this.resolveAudioInput();
604997
605246
  if (this.isLiveAudioMutedForTts()) {
604998
605247
  const now2 = Date.now();
604999
605248
  this.snapshot.audio = {
@@ -605016,9 +605265,11 @@ ${output}`).join("\n\n");
605016
605265
  let analysis = "";
605017
605266
  let intake;
605018
605267
  const audioErrors = [];
605019
- const capture = await recordAudioSampleWithRecovery(input, this.devices.audioInputs, 3, recordingPath);
605268
+ const capture = await recordAudioSampleWithRecovery(input, this.devices.audioInputs, 3, recordingPath, {
605269
+ allowFallback: false
605270
+ });
605020
605271
  if (!capture.ok) {
605021
- const message2 = `Audio capture failed from ${input}; tried fallbacks: ${capture.errors.slice(0, 5).join(" | ")}`;
605272
+ const message2 = `Audio capture failed from selected input ${input}: ${capture.errors.slice(0, 5).join(" | ")}`;
605022
605273
  this.snapshot.audio = {
605023
605274
  updatedAt: Date.now(),
605024
605275
  input,
@@ -605035,12 +605286,9 @@ ${output}`).join("\n\n");
605035
605286
  this.emitDashboard();
605036
605287
  return message2;
605037
605288
  }
605038
- if (capture.device !== this.config.selectedAudioInput) {
605039
- this.config.selectedAudioInput = capture.device;
605040
- }
605041
605289
  const activity = capture.activity ?? readPcm16WavActivity(recordingPath);
605042
605290
  if (capture.ok && capture.signalDetected === false) {
605043
- audioErrors.push(`No live input signal detected after probing ${capture.attempts?.length ?? 1} audio source(s); using quiet capture from ${capture.device}`);
605291
+ audioErrors.push(`No live input signal detected from selected input ${capture.device}; keeping the explicit selection.`);
605044
605292
  }
605045
605293
  if (this.config.asrEnabled) {
605046
605294
  try {
@@ -605135,7 +605383,7 @@ ${output}`).join("\n\n");
605135
605383
  }
605136
605384
  this.emitDashboard();
605137
605385
  return [
605138
- `Audio sample captured from ${capture.device}${capture.device !== input ? ` (recovered from ${input})` : ""}: ${recordingPath}`,
605386
+ `Audio sample captured from selected input ${capture.device}: ${recordingPath}`,
605139
605387
  transcript ? `
605140
605388
  ASR${asrBackend ? ` (${asrBackend})` : ""}:
605141
605389
  ${transcript}` : "",
@@ -605158,6 +605406,10 @@ ${analysis}` : ""
605158
605406
  clearTimeout(this.audioTimer);
605159
605407
  this.audioTimer = null;
605160
605408
  }
605409
+ if (this.audioActivityTimer) {
605410
+ clearTimeout(this.audioActivityTimer);
605411
+ this.audioActivityTimer = null;
605412
+ }
605161
605413
  }
605162
605414
  scheduleVideoLoop(delayMs) {
605163
605415
  if (!this.config.videoEnabled || this.videoTimer) return;
@@ -605194,6 +605446,22 @@ ${analysis}` : ""
605194
605446
  }, Math.max(0, delayMs));
605195
605447
  this.audioTimer.unref?.();
605196
605448
  }
605449
+ scheduleAudioActivityLoop(delayMs) {
605450
+ if (!this.config.audioEnabled || this.audioActivityTimer) return;
605451
+ this.audioActivityTimer = setTimeout(async () => {
605452
+ const startedAt2 = Date.now();
605453
+ this.audioActivityTimer = null;
605454
+ if (!this.config.audioEnabled) return;
605455
+ try {
605456
+ await this.sampleAudioActivityNow();
605457
+ } catch {
605458
+ } finally {
605459
+ const elapsedMs2 = Date.now() - startedAt2;
605460
+ if (this.config.audioEnabled) this.scheduleAudioActivityLoop(Math.max(0, AUDIO_ACTIVITY_INTERVAL_MS - elapsedMs2));
605461
+ }
605462
+ }, Math.max(0, delayMs));
605463
+ this.audioActivityTimer.unref?.();
605464
+ }
605197
605465
  ensureLoops() {
605198
605466
  if (this.config.videoEnabled && !this.videoTimer) {
605199
605467
  this.scheduleVideoLoop(0);
@@ -605208,6 +605476,12 @@ ${analysis}` : ""
605208
605476
  clearTimeout(this.audioTimer);
605209
605477
  this.audioTimer = null;
605210
605478
  }
605479
+ if (this.config.audioEnabled && !this.audioActivityTimer) {
605480
+ this.scheduleAudioActivityLoop(0);
605481
+ } else if (!this.config.audioEnabled && this.audioActivityTimer) {
605482
+ clearTimeout(this.audioActivityTimer);
605483
+ this.audioActivityTimer = null;
605484
+ }
605211
605485
  }
605212
605486
  emitStatus() {
605213
605487
  this.statusSink?.({
@@ -657472,7 +657746,15 @@ async function showLiveMenu(ctx3, manager) {
657472
657746
  }
657473
657747
  case "audio-input": {
657474
657748
  const device = await chooseLiveDevice(ctx3, "Select Audio Input", devices.audioInputs, cfg.selectedAudioInput);
657475
- if (device) manager.configure({ selectedAudioInput: device.id, audioEnabled: true });
657749
+ if (device) {
657750
+ manager.configure({ selectedAudioInput: device.id, audioEnabled: true });
657751
+ renderInfo(`Selected audio input: ${device.id}
657752
+ Previewing microphone activity...`);
657753
+ const preview = await manager.previewAudioInput(device.id);
657754
+ if (preview.ok) renderInfo(preview.message);
657755
+ else renderWarning(preview.message);
657756
+ renderLiveDashboard(ctx3, manager);
657757
+ }
657476
657758
  continue;
657477
657759
  }
657478
657760
  case "audio-output": {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.415",
3
+ "version": "1.0.417",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.415",
9
+ "version": "1.0.417",
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.415",
3
+ "version": "1.0.417",
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",