omnius 1.0.415 → 1.0.416

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
@@ -604087,7 +604087,9 @@ async function discoverAudioOutputs() {
604087
604087
  return { devices: dedupeDevices(devices), errors };
604088
604088
  }
604089
604089
  async function recordAudioSample(device, durationSec, outputPath3) {
604090
- const seconds = String(Math.max(1, Math.min(30, Math.ceil(durationSec))));
604090
+ const duration = Math.max(0.2, Math.min(30, Number.isFinite(durationSec) ? durationSec : 1));
604091
+ const ffmpegSeconds = duration < 1 ? duration.toFixed(3) : String(Math.ceil(duration));
604092
+ const arecordSeconds = String(Math.max(1, Math.ceil(duration)));
604091
604093
  if (device.startsWith("pulse:") && await commandExists2("ffmpeg", 1500)) {
604092
604094
  const source = device.slice("pulse:".length);
604093
604095
  await execFileText4("ffmpeg", [
@@ -604099,14 +604101,38 @@ async function recordAudioSample(device, durationSec, outputPath3) {
604099
604101
  "-i",
604100
604102
  source,
604101
604103
  "-t",
604102
- seconds,
604104
+ ffmpegSeconds,
604103
604105
  "-ac",
604104
604106
  "1",
604105
604107
  "-ar",
604106
604108
  "16000",
604109
+ "-acodec",
604110
+ "pcm_s16le",
604107
604111
  "-y",
604108
604112
  outputPath3
604109
- ], { timeout: (Number(seconds) + 10) * 1e3 });
604113
+ ], { timeout: (Math.ceil(duration) + 10) * 1e3 });
604114
+ return;
604115
+ }
604116
+ if (duration < 1 && await commandExists2("ffmpeg", 1500)) {
604117
+ await execFileText4("ffmpeg", [
604118
+ "-hide_banner",
604119
+ "-loglevel",
604120
+ "error",
604121
+ "-f",
604122
+ "alsa",
604123
+ "-i",
604124
+ device || "default",
604125
+ "-t",
604126
+ ffmpegSeconds,
604127
+ "-ac",
604128
+ "1",
604129
+ "-ar",
604130
+ "16000",
604131
+ "-acodec",
604132
+ "pcm_s16le",
604133
+ "-y",
604134
+ outputPath3
604135
+ ], { timeout: (Math.ceil(duration) + 10) * 1e3 });
604110
604136
  return;
604111
604137
  }
604112
604138
  await execFileText4("arecord", [
@@ -604119,10 +604145,10 @@ async function recordAudioSample(device, durationSec, outputPath3) {
604119
604145
  "-c",
604120
604146
  "1",
604121
604147
  "-d",
604122
- seconds,
604148
+ arecordSeconds,
604123
604149
  "-q",
604124
604150
  outputPath3
604125
- ], { timeout: (Number(seconds) + 10) * 1e3 });
604151
+ ], { timeout: (Number(arecordSeconds) + 10) * 1e3 });
604126
604152
  }
604127
604153
  async function scoreCameraOrientationWithOpenCv(framePath) {
604128
604154
  if (!await commandExists2("python3", 1200)) return null;
@@ -604196,19 +604222,25 @@ function hasLiveAudioSignal(activity) {
604196
604222
  function audioCaptureMethod(device) {
604197
604223
  return device.startsWith("pulse:") ? "pulse/ffmpeg" : "arecord";
604198
604224
  }
604199
- async function recordAudioSampleWithRecovery(preferred, devices, durationSec, outputPath3) {
604225
+ async function recordAudioSampleWithRecovery(preferred, devices, durationSec, outputPath3, options2 = {}) {
604226
+ const allowFallback = options2.allowFallback !== false;
604227
+ const requireSignal = options2.requireSignal !== false;
604200
604228
  const ordered = [];
604201
604229
  const add3 = (id2) => {
604202
604230
  const clean5 = String(id2 ?? "").trim();
604203
604231
  if (clean5 && !ordered.includes(clean5)) ordered.push(clean5);
604204
604232
  };
604205
604233
  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);
604234
+ if (allowFallback) {
604235
+ add3(preferredInput);
604236
+ if (preferred) add3(preferred);
604237
+ for (const device of rankLiveAudioInputDevices(devices, preferred).filter((entry) => !isAudioOutputMonitorDevice(entry))) add3(device.id);
604238
+ add3("pulse:default");
604239
+ add3("default");
604240
+ for (const device of rankLiveAudioInputDevices(devices, preferred).filter((entry) => isAudioOutputMonitorDevice(entry))) add3(device.id);
604241
+ } else {
604242
+ add3(preferred || preferredInput || "default");
604243
+ }
604212
604244
  const errors = [];
604213
604245
  const attempts = [];
604214
604246
  let firstQuietCapture = null;
@@ -604218,8 +604250,9 @@ async function recordAudioSampleWithRecovery(preferred, devices, durationSec, ou
604218
604250
  await tryRecordAudioDevice(candidate, durationSec, outputPath3);
604219
604251
  const activity = readPcm16WavActivity(outputPath3);
604220
604252
  const method = audioCaptureMethod(candidate);
604221
- if (hasLiveAudioSignal(activity)) {
604222
- return { ok: true, device: candidate, method, errors, attempts, activity, signalDetected: true };
604253
+ const signalDetected = hasLiveAudioSignal(activity);
604254
+ if (!requireSignal || signalDetected) {
604255
+ return { ok: true, device: candidate, method, errors, attempts, activity, signalDetected };
604223
604256
  }
604224
604257
  if (!firstQuietCapture) {
604225
604258
  firstQuietCapture = {
@@ -604325,7 +604358,7 @@ function formatLiveStatus(snapshot) {
604325
604358
  }
604326
604359
  return lines.join("\n");
604327
604360
  }
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;
604361
+ 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
604362
  var init_live_sensors = __esm({
604330
604363
  "packages/cli/src/tui/live-sensors.ts"() {
604331
604364
  "use strict";
@@ -604336,6 +604369,8 @@ var init_live_sensors = __esm({
604336
604369
  LOW_LATENCY_VIDEO_INTERVAL_MS = 250;
604337
604370
  MIN_AUDIO_INTERVAL_MS = 1500;
604338
604371
  LOW_LATENCY_AUDIO_INTERVAL_MS = 2e3;
604372
+ AUDIO_ACTIVITY_INTERVAL_MS = 200;
604373
+ AUDIO_ACTIVITY_SAMPLE_SEC = 0.2;
604339
604374
  DEFAULT_CONFIG7 = {
604340
604375
  videoEnabled: false,
604341
604376
  audioEnabled: false,
@@ -604368,8 +604403,10 @@ var init_live_sensors = __esm({
604368
604403
  snapshot;
604369
604404
  videoTimer = null;
604370
604405
  audioTimer = null;
604406
+ audioActivityTimer = null;
604371
604407
  videoInFlight = false;
604372
604408
  audioInFlight = false;
604409
+ audioActivityInFlight = false;
604373
604410
  statusSink = null;
604374
604411
  feedbackSink = null;
604375
604412
  agentActionSink = null;
@@ -604580,10 +604617,7 @@ var init_live_sensors = __esm({
604580
604617
  errors
604581
604618
  };
604582
604619
  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
- }
604620
+ if (!this.config.selectedAudioInput) this.config.selectedAudioInput = preferredLiveAudioInputId(inputs.devices);
604587
604621
  if (!this.config.selectedAudioOutput) this.config.selectedAudioOutput = firstDeviceId(outputs.devices);
604588
604622
  this.persist();
604589
604623
  return this.devices;
@@ -604987,13 +605021,93 @@ ${output}`).join("\n\n");
604987
605021
  this.videoInFlight = false;
604988
605022
  }
604989
605023
  }
605024
+ resolveAudioInput() {
605025
+ const selected = String(this.config.selectedAudioInput ?? "").trim();
605026
+ if (selected) return selected;
605027
+ const input = preferredLiveAudioInputId(this.devices.audioInputs) || "default";
605028
+ this.config.selectedAudioInput = input;
605029
+ this.persist();
605030
+ return input;
605031
+ }
605032
+ async previewAudioInput(device = this.config.selectedAudioInput) {
605033
+ const input = String(device || "").trim() || this.resolveAudioInput();
605034
+ ensureLiveDir(this.repoRoot);
605035
+ const recordingPath = join124(liveDir(this.repoRoot), `audio-preview-${Date.now()}.wav`);
605036
+ const capture = await recordAudioSampleWithRecovery(input, this.devices.audioInputs, 0.8, recordingPath, {
605037
+ allowFallback: false
605038
+ });
605039
+ const now2 = Date.now();
605040
+ const activity = capture.activity ?? (capture.ok ? readPcm16WavActivity(recordingPath) : void 0);
605041
+ if (capture.ok) {
605042
+ this.snapshot.audio = {
605043
+ ...this.snapshot.audio ?? { updatedAt: now2 },
605044
+ updatedAt: now2,
605045
+ input,
605046
+ output: this.config.selectedAudioOutput,
605047
+ recordingPath,
605048
+ activity,
605049
+ error: void 0
605050
+ };
605051
+ this.persist();
605052
+ this.emitDashboard();
605053
+ const signal = capture.signalDetected === false ? "quiet/no clear mic signal" : "signal detected";
605054
+ return {
605055
+ ok: true,
605056
+ input,
605057
+ recordingPath,
605058
+ activity,
605059
+ message: [
605060
+ `Audio input preview from ${input}: ${signal}`,
605061
+ activity ? `activity ${activity.waveform} rms=${activity.rmsDb.toFixed(1)}dB active=${Math.round(activity.activeRatio * 100)}% peak=${activity.peak.toFixed(3)}` : "",
605062
+ `recording: ${recordingPath}`
605063
+ ].filter(Boolean).join("\n")
605064
+ };
605065
+ }
605066
+ const message2 = `Audio input preview failed for ${input}: ${capture.errors.slice(0, 5).join(" | ") || "capture failed"}`;
605067
+ this.snapshot.audio = {
605068
+ ...this.snapshot.audio ?? { updatedAt: now2 },
605069
+ updatedAt: now2,
605070
+ input,
605071
+ output: this.config.selectedAudioOutput,
605072
+ error: message2
605073
+ };
605074
+ this.persist();
605075
+ this.emitDashboard();
605076
+ return { ok: false, input, message: message2 };
605077
+ }
605078
+ async sampleAudioActivityNow() {
605079
+ if (!this.config.audioEnabled || this.audioActivityInFlight) return;
605080
+ this.audioActivityInFlight = true;
605081
+ const input = this.resolveAudioInput();
605082
+ try {
605083
+ ensureLiveDir(this.repoRoot);
605084
+ const recordingPath = join124(liveDir(this.repoRoot), "audio-activity.wav");
605085
+ const capture = await recordAudioSampleWithRecovery(input, this.devices.audioInputs, AUDIO_ACTIVITY_SAMPLE_SEC, recordingPath, {
605086
+ allowFallback: false,
605087
+ requireSignal: false
605088
+ });
605089
+ const now2 = Date.now();
605090
+ const activity = capture.activity ?? (capture.ok ? readPcm16WavActivity(recordingPath) : void 0);
605091
+ this.snapshot.audio = {
605092
+ ...this.snapshot.audio ?? { updatedAt: now2 },
605093
+ updatedAt: now2,
605094
+ input,
605095
+ output: this.config.selectedAudioOutput,
605096
+ recordingPath,
605097
+ activity,
605098
+ error: capture.ok ? this.snapshot.audio?.error : `Audio activity capture failed from ${input}: ${capture.errors.slice(0, 3).join(" | ")}`
605099
+ };
605100
+ this.persist();
605101
+ this.emitDashboard();
605102
+ } finally {
605103
+ this.audioActivityInFlight = false;
605104
+ }
605105
+ }
604990
605106
  async sampleAudioNow() {
604991
605107
  if (this.audioInFlight) return "Audio sampler is already running.";
604992
605108
  this.audioInFlight = true;
604993
605109
  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;
605110
+ const input = this.resolveAudioInput();
604997
605111
  if (this.isLiveAudioMutedForTts()) {
604998
605112
  const now2 = Date.now();
604999
605113
  this.snapshot.audio = {
@@ -605016,9 +605130,11 @@ ${output}`).join("\n\n");
605016
605130
  let analysis = "";
605017
605131
  let intake;
605018
605132
  const audioErrors = [];
605019
- const capture = await recordAudioSampleWithRecovery(input, this.devices.audioInputs, 3, recordingPath);
605133
+ const capture = await recordAudioSampleWithRecovery(input, this.devices.audioInputs, 3, recordingPath, {
605134
+ allowFallback: false
605135
+ });
605020
605136
  if (!capture.ok) {
605021
- const message2 = `Audio capture failed from ${input}; tried fallbacks: ${capture.errors.slice(0, 5).join(" | ")}`;
605137
+ const message2 = `Audio capture failed from selected input ${input}: ${capture.errors.slice(0, 5).join(" | ")}`;
605022
605138
  this.snapshot.audio = {
605023
605139
  updatedAt: Date.now(),
605024
605140
  input,
@@ -605035,12 +605151,9 @@ ${output}`).join("\n\n");
605035
605151
  this.emitDashboard();
605036
605152
  return message2;
605037
605153
  }
605038
- if (capture.device !== this.config.selectedAudioInput) {
605039
- this.config.selectedAudioInput = capture.device;
605040
- }
605041
605154
  const activity = capture.activity ?? readPcm16WavActivity(recordingPath);
605042
605155
  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}`);
605156
+ audioErrors.push(`No live input signal detected from selected input ${capture.device}; keeping the explicit selection.`);
605044
605157
  }
605045
605158
  if (this.config.asrEnabled) {
605046
605159
  try {
@@ -605135,7 +605248,7 @@ ${output}`).join("\n\n");
605135
605248
  }
605136
605249
  this.emitDashboard();
605137
605250
  return [
605138
- `Audio sample captured from ${capture.device}${capture.device !== input ? ` (recovered from ${input})` : ""}: ${recordingPath}`,
605251
+ `Audio sample captured from selected input ${capture.device}: ${recordingPath}`,
605139
605252
  transcript ? `
605140
605253
  ASR${asrBackend ? ` (${asrBackend})` : ""}:
605141
605254
  ${transcript}` : "",
@@ -605158,6 +605271,10 @@ ${analysis}` : ""
605158
605271
  clearTimeout(this.audioTimer);
605159
605272
  this.audioTimer = null;
605160
605273
  }
605274
+ if (this.audioActivityTimer) {
605275
+ clearTimeout(this.audioActivityTimer);
605276
+ this.audioActivityTimer = null;
605277
+ }
605161
605278
  }
605162
605279
  scheduleVideoLoop(delayMs) {
605163
605280
  if (!this.config.videoEnabled || this.videoTimer) return;
@@ -605194,6 +605311,22 @@ ${analysis}` : ""
605194
605311
  }, Math.max(0, delayMs));
605195
605312
  this.audioTimer.unref?.();
605196
605313
  }
605314
+ scheduleAudioActivityLoop(delayMs) {
605315
+ if (!this.config.audioEnabled || this.audioActivityTimer) return;
605316
+ this.audioActivityTimer = setTimeout(async () => {
605317
+ const startedAt2 = Date.now();
605318
+ this.audioActivityTimer = null;
605319
+ if (!this.config.audioEnabled) return;
605320
+ try {
605321
+ await this.sampleAudioActivityNow();
605322
+ } catch {
605323
+ } finally {
605324
+ const elapsedMs2 = Date.now() - startedAt2;
605325
+ if (this.config.audioEnabled) this.scheduleAudioActivityLoop(Math.max(0, AUDIO_ACTIVITY_INTERVAL_MS - elapsedMs2));
605326
+ }
605327
+ }, Math.max(0, delayMs));
605328
+ this.audioActivityTimer.unref?.();
605329
+ }
605197
605330
  ensureLoops() {
605198
605331
  if (this.config.videoEnabled && !this.videoTimer) {
605199
605332
  this.scheduleVideoLoop(0);
@@ -605208,6 +605341,12 @@ ${analysis}` : ""
605208
605341
  clearTimeout(this.audioTimer);
605209
605342
  this.audioTimer = null;
605210
605343
  }
605344
+ if (this.config.audioEnabled && !this.audioActivityTimer) {
605345
+ this.scheduleAudioActivityLoop(0);
605346
+ } else if (!this.config.audioEnabled && this.audioActivityTimer) {
605347
+ clearTimeout(this.audioActivityTimer);
605348
+ this.audioActivityTimer = null;
605349
+ }
605211
605350
  }
605212
605351
  emitStatus() {
605213
605352
  this.statusSink?.({
@@ -657472,7 +657611,15 @@ async function showLiveMenu(ctx3, manager) {
657472
657611
  }
657473
657612
  case "audio-input": {
657474
657613
  const device = await chooseLiveDevice(ctx3, "Select Audio Input", devices.audioInputs, cfg.selectedAudioInput);
657475
- if (device) manager.configure({ selectedAudioInput: device.id, audioEnabled: true });
657614
+ if (device) {
657615
+ manager.configure({ selectedAudioInput: device.id, audioEnabled: true });
657616
+ renderInfo(`Selected audio input: ${device.id}
657617
+ Previewing microphone activity...`);
657618
+ const preview = await manager.previewAudioInput(device.id);
657619
+ if (preview.ok) renderInfo(preview.message);
657620
+ else renderWarning(preview.message);
657621
+ renderLiveDashboard(ctx3, manager);
657622
+ }
657476
657623
  continue;
657477
657624
  }
657478
657625
  case "audio-output": {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.415",
3
+ "version": "1.0.416",
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.416",
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.416",
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",